From b726bfb56902eaa743f7164ce502afbdd232562c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 6 Mar 2022 19:51:30 -0800 Subject: [PATCH] allow referencing impl substs from rustc_on_unimplemented --- .../error_reporting/on_unimplemented.rs | 4 +- .../src/traits/on_unimplemented.rs | 46 +++++++++++-------- compiler/rustc_typeck/src/check/check.rs | 9 ++-- src/test/ui/on-unimplemented/impl-substs.rs | 15 ++++++ .../ui/on-unimplemented/impl-substs.stderr | 13 ++++++ 5 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/on-unimplemented/impl-substs.rs create mode 100644 src/test/ui/on-unimplemented/impl-substs.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d05f62ea29e4..6dfbdace8e2a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -231,9 +231,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } }); - if let Ok(Some(command)) = - OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) - { + if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { command.evaluate(self.tcx, trait_ref, &flags) } else { OnUnimplementedNote::default() diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 9752ff453235..2f697c1fa27b 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -54,7 +54,7 @@ fn parse_error( impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, - trait_def_id: DefId, + item_def_id: DefId, items: &[NestedMetaItem], span: Span, is_root: bool, @@ -63,7 +63,7 @@ impl<'tcx> OnUnimplementedDirective { let mut item_iter = items.iter(); let parse_value = |value_str| { - OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) + OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some) }; let condition = if is_root { @@ -135,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective { { if let Some(items) = item.meta_item_list() { if let Ok(subcommand) = - Self::parse(tcx, trait_def_id, &items, item.span(), false) + Self::parse(tcx, item_def_id, &items, item.span(), false) { subcommands.push(subcommand); } else { @@ -178,19 +178,15 @@ impl<'tcx> OnUnimplementedDirective { } } - pub fn of_item( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - impl_def_id: DefId, - ) -> Result, ErrorGuaranteed> { - let attrs = tcx.get_attrs(impl_def_id); + pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { + let attrs = tcx.get_attrs(item_def_id); let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else { return Ok(None); }; let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some) + Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some) } else if let Some(value) = attr.value_str() { Ok(Some(OnUnimplementedDirective { condition: None, @@ -198,7 +194,7 @@ impl<'tcx> OnUnimplementedDirective { subcommands: vec![], label: Some(OnUnimplementedFormatString::try_parse( tcx, - trait_def_id, + item_def_id, value, attr.span, )?), @@ -209,7 +205,7 @@ impl<'tcx> OnUnimplementedDirective { } else { return Err(ErrorGuaranteed); }; - debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result); + debug!("of_item({:?}) = {:?}", item_def_id, result); result } @@ -280,23 +276,29 @@ impl<'tcx> OnUnimplementedDirective { impl<'tcx> OnUnimplementedFormatString { fn try_parse( tcx: TyCtxt<'tcx>, - trait_def_id: DefId, + item_def_id: DefId, from: Symbol, err_sp: Span, ) -> Result { let result = OnUnimplementedFormatString(from); - result.verify(tcx, trait_def_id, err_sp)?; + result.verify(tcx, item_def_id, err_sp)?; Ok(result) } fn verify( &self, tcx: TyCtxt<'tcx>, - trait_def_id: DefId, + item_def_id: DefId, span: Span, ) -> Result<(), ErrorGuaranteed> { - let name = tcx.item_name(trait_def_id); - let generics = tcx.generics_of(trait_def_id); + let trait_def_id = if tcx.is_trait(item_def_id) { + item_def_id + } else { + tcx.trait_id_of_impl(item_def_id) + .expect("expected `on_unimplemented` to correspond to a trait") + }; + let trait_name = tcx.item_name(trait_def_id); + let generics = tcx.generics_of(item_def_id); let s = self.0.as_str(); let parser = Parser::new(s, None, None, false, ParseMode::Format); let mut result = Ok(()); @@ -307,7 +309,7 @@ impl<'tcx> OnUnimplementedFormatString { // `{Self}` is allowed Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (), // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s, _) if s == name => (), + Position::ArgumentNamed(s, _) if s == trait_name => (), // `{from_method}` is allowed Position::ArgumentNamed(s, _) if s == sym::from_method => (), // `{from_desugaring}` is allowed @@ -329,9 +331,13 @@ impl<'tcx> OnUnimplementedFormatString { tcx.sess, span, E0230, - "there is no parameter `{}` on trait `{}`", + "there is no parameter `{}` on {}", s, - name + if trait_def_id == item_def_id { + format!("trait `{}`", trait_name) + } else { + "impl".to_string() + } ) .emit(); result = Err(ErrorGuaranteed); diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 765b752691f2..7c3594175b85 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -742,12 +742,11 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { impl_trait_ref, &impl_.items, ); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); + check_on_unimplemented(tcx, it); } } hir::ItemKind::Trait(_, _, _, _, ref items) => { - check_on_unimplemented(tcx, it.def_id.to_def_id(), it); + check_on_unimplemented(tcx, it); for item in items.iter() { let item = tcx.hir().trait_item(item.id); @@ -857,9 +856,9 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { } } -pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { +pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { // an error would be reported if this fails. - let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id()); + let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id()); } pub(super) fn check_specialization_validity<'tcx>( diff --git a/src/test/ui/on-unimplemented/impl-substs.rs b/src/test/ui/on-unimplemented/impl-substs.rs new file mode 100644 index 000000000000..fe9c50ec3d4a --- /dev/null +++ b/src/test/ui/on-unimplemented/impl-substs.rs @@ -0,0 +1,15 @@ +#![feature(rustc_attrs)] + +trait Foo { + fn foo(self); +} + +#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"] +impl Foo for (A, B, C) { + fn foo(self) {} +} + +fn main() { + Foo::::foo((1i32, 1i32, 1i32)); + //~^ ERROR the trait bound `(i32, i32, i32): Foo` is not satisfied +} diff --git a/src/test/ui/on-unimplemented/impl-substs.stderr b/src/test/ui/on-unimplemented/impl-substs.stderr new file mode 100644 index 000000000000..db66ab0bfaec --- /dev/null +++ b/src/test/ui/on-unimplemented/impl-substs.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `(i32, i32, i32): Foo` is not satisfied + --> $DIR/impl-substs.rs:13:23 + | +LL | Foo::::foo((1i32, 1i32, 1i32)); + | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _ + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is not implemented for `(i32, i32, i32)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.