Skip to content

Commit 14bc0f2

Browse files
Rollup merge of rust-lang#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.
2 parents 98e002a + 3448284 commit 14bc0f2

File tree

6 files changed

+106
-5
lines changed

6 files changed

+106
-5
lines changed

compiler/rustc_trait_selection/src/solve/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ mod trait_goals;
4141

4242
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
4343
pub use fulfill::FulfillmentCtxt;
44-
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
44+
pub(crate) use normalize::{
45+
deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes,
46+
};
4547

4648
#[derive(Debug, Clone, Copy)]
4749
enum SolverMode {

compiler/rustc_trait_selection/src/solve/normalize.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
44
use rustc_data_structures::stack::ensure_sufficient_stack;
55
use rustc_infer::infer::at::At;
66
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
7+
use rustc_infer::infer::InferCtxt;
78
use rustc_infer::traits::TraitEngineExt;
89
use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
910
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
10-
use rustc_middle::traits::Reveal;
11+
use rustc_middle::traits::{ObligationCause, Reveal};
1112
use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
12-
use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable};
13+
use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
1314
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
1415

1516
use super::FulfillmentCtxt;
@@ -230,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> {
230231
}
231232
}
232233
}
234+
235+
// Deeply normalize a value and return it
236+
pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
237+
infcx: &InferCtxt<'tcx>,
238+
param_env: ty::ParamEnv<'tcx>,
239+
t: T,
240+
) -> T {
241+
t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
242+
at: infcx.at(&ObligationCause::dummy(), param_env),
243+
})
244+
}
245+
246+
struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
247+
at: At<'a, 'tcx>,
248+
}
249+
250+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
251+
fn interner(&self) -> TyCtxt<'tcx> {
252+
self.at.infcx.tcx
253+
}
254+
255+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
256+
deeply_normalize_with_skipped_universes(
257+
self.at,
258+
ty,
259+
vec![None; ty.outer_exclusive_binder().as_usize()],
260+
)
261+
.unwrap_or_else(|_| ty.super_fold_with(self))
262+
}
263+
264+
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
265+
deeply_normalize_with_skipped_universes(
266+
self.at,
267+
ct,
268+
vec![None; ct.outer_exclusive_binder().as_usize()],
269+
)
270+
.unwrap_or_else(|_| ct.super_fold_with(self))
271+
}
272+
}

compiler/rustc_trait_selection/src/traits/coherence.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
77
use crate::infer::outlives::env::OutlivesEnvironment;
88
use crate::infer::InferOk;
9-
use crate::solve::inspect;
109
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
10+
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
1111
use crate::traits::engine::TraitEngineExt;
1212
use crate::traits::query::evaluate_obligation::InferCtxtExt;
1313
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
@@ -308,7 +308,13 @@ fn overlap<'tcx>(
308308
.iter()
309309
.any(|c| c.0.involves_placeholders());
310310

311-
let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header);
311+
let mut impl_header = infcx.resolve_vars_if_possible(impl1_header);
312+
313+
// Deeply normalize the impl header for diagnostics, ignoring any errors if this fails.
314+
if infcx.next_trait_solver() {
315+
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
316+
}
317+
312318
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
313319
}
314320

@@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
10841090
Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
10851091
Ok(Err(conflict)) => {
10861092
if !trait_ref.references_error() {
1093+
// Normalize the trait ref for diagnostics, ignoring any errors if this fails.
1094+
let trait_ref =
1095+
deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
1096+
10871097
let self_ty = trait_ref.self_ty();
10881098
let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
10891099
ambiguity_cause = Some(match conflict {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)`
2+
--> $DIR/normalize-for-errors.rs:16:1
3+
|
4+
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
5+
| ------------------------------------------------------ first implementation here
6+
LL |
7+
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)`
9+
|
10+
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)`
2+
--> $DIR/normalize-for-errors.rs:16:1
3+
|
4+
LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
5+
| ------------------------------------------------------ first implementation here
6+
LL |
7+
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)`
9+
|
10+
= note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0119`.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// revisions: current next
2+
//[next] compile-flags: -Ztrait-solver=next
3+
4+
struct MyType;
5+
trait MyTrait<S> {}
6+
7+
trait Mirror {
8+
type Assoc;
9+
}
10+
impl<T> Mirror for T {
11+
type Assoc = T;
12+
}
13+
14+
impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {}
15+
//~^ NOTE first implementation here
16+
impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
17+
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
18+
//~| NOTE conflicting implementation for `(Box<(MyType,)>,
19+
//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions
20+
21+
fn main() {}

0 commit comments

Comments
 (0)