From 334577f0910f64f3865f3803d124b299bf0f3fe5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 27 Nov 2023 03:20:45 +0000 Subject: [PATCH 1/2] Add deeply_normalize_for_diagnostics, use it in coherence --- .../rustc_trait_selection/src/solve/mod.rs | 4 +++- .../src/solve/normalize.rs | 16 +++++++++++++- .../src/traits/coherence.rs | 14 ++++++++++-- .../normalize-for-errors.current.stderr | 14 ++++++++++++ .../normalize-for-errors.next.stderr | 14 ++++++++++++ tests/ui/coherence/normalize-for-errors.rs | 22 +++++++++++++++++++ 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 tests/ui/coherence/normalize-for-errors.current.stderr create mode 100644 tests/ui/coherence/normalize-for-errors.next.stderr create mode 100644 tests/ui/coherence/normalize-for-errors.rs diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b9e256236e940..bf3b72caeb4db 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -41,7 +41,9 @@ mod trait_goals; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; pub use fulfill::FulfillmentCtxt; -pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub(crate) use normalize::{ + deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes, +}; #[derive(Debug, Clone, Copy)] enum SolverMode { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index b0a348985708d..af522799db820 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -4,10 +4,11 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::Reveal; +use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; @@ -41,6 +42,19 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + t: T, +) -> T { + infcx + .commit_if_ok(|_| { + deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone()) + }) + .unwrap_or(t) +} + struct NormalizationFolder<'me, 'tcx> { at: At<'me, 'tcx>, fulfill_cx: FulfillmentCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f3e..9f2e1df8ef8fd 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,8 +6,8 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; -use crate::solve::inspect; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; @@ -308,7 +308,13 @@ fn overlap<'tcx>( .iter() .any(|c| c.0.involves_placeholders()); - let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); + let mut impl_header = infcx.resolve_vars_if_possible(impl1_header); + + // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails. + if infcx.next_trait_solver() { + impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header); + } + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } @@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Err(conflict)) => { if !trait_ref.references_error() { + // Normalize the trait ref for diagnostics, ignoring any errors if this fails. + let trait_ref = + deeply_normalize_for_diagnostics(infcx, param_env, trait_ref); + let self_ty = trait_ref.self_ty(); let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); ambiguity_cause = Some(match conflict { diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr new file mode 100644 index 0000000000000..df71d80e7fbed --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` + --> $DIR/normalize-for-errors.rs:17:1 + | +LL | impl MyTrait for T {} + | --------------------------- first implementation here +LL | +LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr new file mode 100644 index 0000000000000..df71d80e7fbed --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` + --> $DIR/normalize-for-errors.rs:17:1 + | +LL | impl MyTrait for T {} + | --------------------------- first implementation here +LL | +LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs new file mode 100644 index 0000000000000..f488ad3d46862 --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -0,0 +1,22 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +struct MyType; +trait MyTrait { +} + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +impl MyTrait for T {} +//~^ NOTE first implementation here +impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} +//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` +//~| NOTE conflicting implementation for `Box<(MyType,)> +//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +fn main() {} From 3448284f8df0f136835500d220addc1326ab98d6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 28 Nov 2023 21:45:37 +0000 Subject: [PATCH 2/2] Continue folding if deep normalizer fails --- .../src/solve/normalize.rs | 54 ++++++++++++++----- .../normalize-for-errors.current.stderr | 12 ++--- .../normalize-for-errors.next.stderr | 12 ++--- tests/ui/coherence/normalize-for-errors.rs | 11 ++-- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index af522799db820..ea512ba5fa777 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -10,7 +10,7 @@ use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; -use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use super::FulfillmentCtxt; @@ -42,19 +42,6 @@ pub(crate) fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable>>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - t: T, -) -> T { - infcx - .commit_if_ok(|_| { - deeply_normalize(infcx.at(&ObligationCause::dummy(), param_env), t.clone()) - }) - .unwrap_or(t) -} - struct NormalizationFolder<'me, 'tcx> { at: At<'me, 'tcx>, fulfill_cx: FulfillmentCtxt<'tcx>, @@ -244,3 +231,42 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } } } + +// Deeply normalize a value and return it +pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable>>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + t: T, +) -> T { + t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder { + at: infcx.at(&ObligationCause::dummy(), param_env), + }) +} + +struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { + at: At<'a, 'tcx>, +} + +impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.at.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ty.super_fold_with(self)) + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ct.super_fold_with(self)) + } +} diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr index df71d80e7fbed..0e48aaed87991 100644 --- a/tests/ui/coherence/normalize-for-errors.current.stderr +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` - --> $DIR/normalize-for-errors.rs:17:1 +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)` + --> $DIR/normalize-for-errors.rs:16:1 | -LL | impl MyTrait for T {} - | --------------------------- first implementation here +LL | impl MyTrait for (T, S::Item) {} + | ------------------------------------------------------ first implementation here LL | -LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` +LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr index df71d80e7fbed..a8a7d437b32d3 100644 --- a/tests/ui/coherence/normalize-for-errors.next.stderr +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -1,11 +1,11 @@ -error[E0119]: conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` - --> $DIR/normalize-for-errors.rs:17:1 +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)` + --> $DIR/normalize-for-errors.rs:16:1 | -LL | impl MyTrait for T {} - | --------------------------- first implementation here +LL | impl MyTrait for (T, S::Item) {} + | ------------------------------------------------------ first implementation here LL | -LL | impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<(MyType,)>` +LL | impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)` | = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index f488ad3d46862..367d34251ae30 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -2,8 +2,7 @@ //[next] compile-flags: -Ztrait-solver=next struct MyType; -trait MyTrait { -} +trait MyTrait {} trait Mirror { type Assoc; @@ -12,11 +11,11 @@ impl Mirror for T { type Assoc = T; } -impl MyTrait for T {} +impl MyTrait for (T, S::Item) {} //~^ NOTE first implementation here -impl MyTrait for Box<<(MyType,) as Mirror>::Assoc> {} -//~^ ERROR conflicting implementations of trait `MyTrait` for type `Box<(MyType,)>` -//~| NOTE conflicting implementation for `Box<(MyType,)> +impl MyTrait for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} +//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, +//~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions fn main() {}