Rollup merge of #118346 - compiler-errors:deeply-normalize-for-diagnostic, r=lcnr
Add `deeply_normalize_for_diagnostics`, use it in coherence r? lcnr Normalize trait refs used for coherence error reporting with `-Ztrait-solver=next-coherence`. Two things: 1. I said before that we can't add this to `TyErrCtxt` because we compute `OverlapResult`s even if there are no diagnostics being emitted, e.g. for a reservation impl. 2. I didn't want to add this to an `InferCtxtExt` trait because I felt it was unnecessary. I don't particularly care about the API though.
This commit is contained in:
commit
598ca0ea3f
@ -41,7 +41,9 @@
|
|||||||
|
|
||||||
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
|
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
|
||||||
pub use fulfill::FulfillmentCtxt;
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum SolverMode {
|
enum SolverMode {
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_infer::infer::at::At;
|
use rustc_infer::infer::at::At;
|
||||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_infer::traits::TraitEngineExt;
|
use rustc_infer::traits::TraitEngineExt;
|
||||||
use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
|
use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
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::{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 rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
||||||
|
|
||||||
use super::FulfillmentCtxt;
|
use super::FulfillmentCtxt;
|
||||||
@ -230,3 +231,42 @@ fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Sel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deeply normalize a value and return it
|
||||||
|
pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||||
|
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<TyCtxt<'tcx>> 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||||
use crate::infer::InferOk;
|
use crate::infer::InferOk;
|
||||||
use crate::solve::inspect;
|
|
||||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||||
|
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||||
use crate::traits::engine::TraitEngineExt;
|
use crate::traits::engine::TraitEngineExt;
|
||||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
|
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
|
||||||
@ -308,7 +308,13 @@ fn overlap<'tcx>(
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|c| c.0.involves_placeholders());
|
.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 })
|
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,6 +1090,10 @@ fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::Brea
|
|||||||
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
|
||||||
Ok(Err(conflict)) => {
|
Ok(Err(conflict)) => {
|
||||||
if !trait_ref.references_error() {
|
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 = trait_ref.self_ty();
|
||||||
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
|
||||||
ambiguity_cause = Some(match conflict {
|
ambiguity_cause = Some(match conflict {
|
||||||
|
14
tests/ui/coherence/normalize-for-errors.current.stderr
Normal file
14
tests/ui/coherence/normalize-for-errors.current.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)`
|
||||||
|
--> $DIR/normalize-for-errors.rs:16:1
|
||||||
|
|
|
||||||
|
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
|
||||||
|
| ------------------------------------------------------ first implementation here
|
||||||
|
LL |
|
||||||
|
LL | impl<S: Iterator> MyTrait<S> 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
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
14
tests/ui/coherence/normalize-for-errors.next.stderr
Normal file
14
tests/ui/coherence/normalize-for-errors.next.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)`
|
||||||
|
--> $DIR/normalize-for-errors.rs:16:1
|
||||||
|
|
|
||||||
|
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
|
||||||
|
| ------------------------------------------------------ first implementation here
|
||||||
|
LL |
|
||||||
|
LL | impl<S: Iterator> MyTrait<S> 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
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0119`.
|
21
tests/ui/coherence/normalize-for-errors.rs
Normal file
21
tests/ui/coherence/normalize-for-errors.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// revisions: current next
|
||||||
|
//[next] compile-flags: -Ztrait-solver=next
|
||||||
|
|
||||||
|
struct MyType;
|
||||||
|
trait MyTrait<S> {}
|
||||||
|
|
||||||
|
trait Mirror {
|
||||||
|
type Assoc;
|
||||||
|
}
|
||||||
|
impl<T> Mirror for T {
|
||||||
|
type Assoc = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
|
||||||
|
//~^ NOTE first implementation here
|
||||||
|
impl<S: Iterator> MyTrait<S> 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() {}
|
Loading…
Reference in New Issue
Block a user