diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 47810e2578df6..32bbc18f74696 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -58,6 +58,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{self as hir}; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; @@ -72,12 +73,17 @@ use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; +use crate::error_reporting::traits::ambiguity::{ + CandidateSource, compute_applicable_impls_for_diagnostics, +}; use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs}; use crate::solve::deeply_normalize_for_diagnostics; -use crate::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode}; +use crate::traits::{ + MatchExpressionArmCause, Obligation, ObligationCause, ObligationCauseCode, specialization_graph, +}; mod note_and_explain; mod suggest; @@ -149,11 +155,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { actual: Ty<'tcx>, err: TypeError<'tcx>, ) -> Diag<'a> { - self.report_and_explain_type_error( + let mut diag = self.report_and_explain_type_error( TypeTrace::types(cause, expected, actual), param_env, err, - ) + ); + + self.suggest_param_env_shadowing(&mut diag, expected, actual, param_env); + + diag } pub fn report_mismatched_consts( @@ -240,6 +250,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } + fn suggest_param_env_shadowing( + &self, + diag: &mut Diag<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) { + let (alias, concrete) = match (expected.kind(), found.kind()) { + (ty::Alias(ty::Projection, proj), _) => (proj, found), + (_, ty::Alias(ty::Projection, proj)) => (proj, expected), + _ => return, + }; + + let tcx = self.tcx; + + let trait_ref = alias.trait_ref(tcx); + let obligation = + Obligation::new(tcx, ObligationCause::dummy(), param_env, ty::Binder::dummy(trait_ref)); + + let applicable_impls = compute_applicable_impls_for_diagnostics(self.infcx, &obligation); + + for candidate in applicable_impls { + let impl_def_id = match candidate { + CandidateSource::DefId(did) => did, + CandidateSource::ParamEnv(_) => continue, + }; + + let is_shadowed = self.infcx.probe(|_| { + let impl_substs = self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_substs); + + let expected_trait_ref = alias.trait_ref(tcx); + + if let Err(_) = self.infcx.at(&ObligationCause::dummy(), param_env).eq( + DefineOpaqueTypes::No, + expected_trait_ref, + impl_trait_ref, + ) { + return false; + } + + let trait_def_id = alias.trait_def_id(tcx); + let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs); + + let leaf_def = match specialization_graph::assoc_def(tcx, impl_def_id, alias.def_id) + { + Ok(leaf) => leaf, + Err(_) => return false, + }; + + let impl_item_def_id = leaf_def.item.def_id; + let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args); + + self.infcx.can_eq(param_env, impl_assoc_ty, concrete) + }); + + if is_shadowed { + diag.note(format!( + "the associated type `{}` is defined as `{}` in the implementation, \ + but the where-bound `{}` shadows this definition\n\ + see issue #152409 for more information", + self.ty_to_string(tcx.mk_ty_from_kind(ty::Alias(ty::Projection, *alias))), + self.ty_to_string(concrete), + self.ty_to_string(alias.self_ty()) + )); + return; + } + } + } + fn note_error_origin( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 08f1d947dfb5c..1fde7e5d43b76 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -16,7 +16,7 @@ pub mod project; pub mod query; #[allow(hidden_glob_reexports)] mod select; -mod specialize; +pub mod specialize; mod structural_normalize; #[allow(hidden_glob_reexports)] mod util; diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr index 21bc37bb3ea2d..3b89ed66b355e 100644 --- a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr @@ -6,6 +6,8 @@ LL | const N: C::M = 4u8; | = note: expected associated type `::M` found type `u8` + = note: the associated type `::M` is defined as `u8` in the implementation, but the where-bound `C` shadows this definition + see issue #152409 for more information help: consider constraining the associated type `::M` to `u8` | LL | impl> U for u16 { diff --git a/tests/ui/associated-types/defaults-specialization.stderr b/tests/ui/associated-types/defaults-specialization.stderr index 7d19ac85982a3..d22d9ce659a76 100644 --- a/tests/ui/associated-types/defaults-specialization.stderr +++ b/tests/ui/associated-types/defaults-specialization.stderr @@ -75,6 +75,8 @@ LL | fn make() -> Self::Ty { 0u8 } found type `u8` = help: consider constraining the associated type ` as Tr>::Ty` to `u8` or calling a method that returns ` as Tr>::Ty` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type ` as Tr>::Ty` is defined as `u8` in the implementation, but the where-bound `A2` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:44:29 @@ -89,6 +91,8 @@ LL | fn make() -> Self::Ty { true } | = note: expected associated type ` as Tr>::Ty` found type `bool` + = note: the associated type ` as Tr>::Ty` is defined as `bool` in the implementation, but the where-bound `B2` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:87:32 @@ -121,6 +125,8 @@ help: a method is available that returns ` as Tr>::Ty` | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` + = note: the associated type ` as Tr>::Ty` is defined as `bool` in the implementation, but the where-bound `B<()>` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:89:33 @@ -153,6 +159,8 @@ help: a method is available that returns ` as Tr>::Ty` | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` + = note: the associated type ` as Tr>::Ty` is defined as `bool` in the implementation, but the where-bound `B2<()>` shadows this definition + see issue #152409 for more information error: aborting due to 9 previous errors; 1 warning emitted diff --git a/tests/ui/associated-types/param-env-shadowing-false-positive.rs b/tests/ui/associated-types/param-env-shadowing-false-positive.rs new file mode 100644 index 0000000000000..41993f5cba19c --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-false-positive.rs @@ -0,0 +1,17 @@ +// Regression test for issue #149910. +// The compiler previously incorrectly claimed that the local param-env bound +// shadowed the global impl, but they are actually the same. + +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = T; +} + +fn foo(x: T::Assoc) -> u32 { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/param-env-shadowing-false-positive.stderr b/tests/ui/associated-types/param-env-shadowing-false-positive.stderr new file mode 100644 index 0000000000000..64d7950f41efc --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-false-positive.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/param-env-shadowing-false-positive.rs:14:5 + | +LL | fn foo(x: T::Assoc) -> u32 { + | --- expected `u32` because of return type +LL | x + | ^ expected `u32`, found associated type + | + = note: expected type `u32` + found associated type `::Assoc` +help: consider constraining the associated type `::Assoc` to `u32` + | +LL | fn foo>(x: T::Assoc) -> u32 { + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-types/param-env-shadowing-gat.rs b/tests/ui/associated-types/param-env-shadowing-gat.rs new file mode 100644 index 0000000000000..9dc91a1a14650 --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-gat.rs @@ -0,0 +1,17 @@ +// Regression test for issue #149910. +// This ensures that the diagnostics logic handles Generic Associated Types (GATs) +// correctly without crashing (ICE). + +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = U; +} + +fn foo(x: T::Assoc) -> u32 { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/param-env-shadowing-gat.stderr b/tests/ui/associated-types/param-env-shadowing-gat.stderr new file mode 100644 index 0000000000000..02c024341724a --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-gat.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/param-env-shadowing-gat.rs:14:5 + | +LL | fn foo(x: T::Assoc) -> u32 { + | --- expected `u32` because of return type +LL | x + | ^ expected `u32`, found associated type + | + = note: expected type `u32` + found associated type `::Assoc` +help: consider constraining the associated type `::Assoc` to `u32` + | +LL | fn foo = u32>>(x: T::Assoc) -> u32 { + | ++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-types/param-env-shadowing-issue-149910.rs b/tests/ui/associated-types/param-env-shadowing-issue-149910.rs new file mode 100644 index 0000000000000..bd4df859dc074 --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-issue-149910.rs @@ -0,0 +1,14 @@ +trait Trait { + type Assoc; +} + +impl Trait for T { + type Assoc = T; +} + +fn foo(x: T) -> T::Assoc { + x + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr b/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr new file mode 100644 index 0000000000000..b06770e526353 --- /dev/null +++ b/tests/ui/associated-types/param-env-shadowing-issue-149910.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/param-env-shadowing-issue-149910.rs:10:5 + | +LL | fn foo(x: T) -> T::Assoc { + | - -------- expected `::Assoc` because of return type + | | + | found this type parameter +LL | x + | ^ expected associated type, found type parameter `T` + | + = note: expected associated type `::Assoc` + found type parameter `T` + = note: the associated type `::Assoc` is defined as `T` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information +help: consider further restricting this bound + | +LL | fn foo>(x: T) -> T::Assoc { + | +++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/specialization-default-projection.current.stderr b/tests/ui/specialization/specialization-default-projection.current.stderr index 038c379c43e13..b88c1a94baf91 100644 --- a/tests/ui/specialization/specialization-default-projection.current.stderr +++ b/tests/ui/specialization/specialization-default-projection.current.stderr @@ -21,6 +21,8 @@ LL | () found unit type `()` = help: consider constraining the associated type `::Assoc` to `()` or calling a method that returns `::Assoc` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `::Assoc` is defined as `()` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:32:5 @@ -37,6 +39,8 @@ LL | generic::<()>() found associated type `<() as Foo>::Assoc` = help: consider constraining the associated type `<() as Foo>::Assoc` to `()` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `<() as Foo>::Assoc` is defined as `()` in the implementation, but the where-bound `()` shadows this definition + see issue #152409 for more information error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/specialization/specialization-default-projection.next.stderr b/tests/ui/specialization/specialization-default-projection.next.stderr index 9111f173a9c87..a385b16a2d8bd 100644 --- a/tests/ui/specialization/specialization-default-projection.next.stderr +++ b/tests/ui/specialization/specialization-default-projection.next.stderr @@ -21,6 +21,8 @@ LL | () found unit type `()` = help: consider constraining the associated type `::Assoc` to `()` or calling a method that returns `::Assoc` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `::Assoc` is defined as `()` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:32:5 @@ -37,6 +39,8 @@ LL | generic::<()>() found associated type `<() as Foo>::Assoc` = help: consider constraining the associated type `<() as Foo>::Assoc` to `()` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `<() as Foo>::Assoc` is defined as `()` in the implementation, but the where-bound `()` shadows this definition + see issue #152409 for more information error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/specialization/specialization-default-types.current.stderr b/tests/ui/specialization/specialization-default-types.current.stderr index 09689681740ff..8df170cbb767d 100644 --- a/tests/ui/specialization/specialization-default-types.current.stderr +++ b/tests/ui/specialization/specialization-default-types.current.stderr @@ -20,6 +20,8 @@ LL | Box::new(self) | = note: expected associated type `::Output` found struct `Box` + = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:29:5 @@ -33,6 +35,8 @@ LL | Example::generate(t) found associated type `::Output` = help: consider constraining the associated type `::Output` to `Box` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/specialization/specialization-default-types.next.stderr b/tests/ui/specialization/specialization-default-types.next.stderr index 1535c6473bddf..4ea9b996c86a9 100644 --- a/tests/ui/specialization/specialization-default-types.next.stderr +++ b/tests/ui/specialization/specialization-default-types.next.stderr @@ -20,6 +20,8 @@ LL | Box::new(self) | = note: expected associated type `::Output` found struct `Box` + = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:29:5 @@ -33,6 +35,8 @@ LL | Example::generate(t) found associated type `::Output` = help: consider constraining the associated type `::Output` to `Box` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: the associated type `::Output` is defined as `Box` in the implementation, but the where-bound `T` shadows this definition + see issue #152409 for more information error: aborting due to 2 previous errors; 1 warning emitted