Skip to content

Commit 5354da0

Browse files
committed
adjust derive_error
1 parent 74eb39d commit 5354da0

File tree

11 files changed

+182
-78
lines changed

11 files changed

+182
-78
lines changed

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

-20
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use derive_where::derive_where;
66
use rustc_type_ir::fold::TypeFoldable;
77
use rustc_type_ir::inherent::*;
88
use rustc_type_ir::lang_items::TraitSolverLangItem;
9-
use rustc_type_ir::solve::inspect;
109
use rustc_type_ir::visit::TypeVisitableExt as _;
1110
use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate};
1211
use tracing::{debug, instrument};
@@ -292,25 +291,6 @@ where
292291
let Ok(normalized_self_ty) =
293292
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
294293
else {
295-
// FIXME: We register a fake candidate when normalization fails so that
296-
// we can point at the reason for *why*. I'm tempted to say that this
297-
// is the wrong way to do this, though.
298-
let result =
299-
self.probe(|&result| inspect::ProbeKind::RigidAlias { result }).enter(|this| {
300-
let normalized_ty = this.next_ty_infer();
301-
let alias_relate_goal = Goal::new(
302-
this.cx(),
303-
goal.param_env,
304-
ty::PredicateKind::AliasRelate(
305-
goal.predicate.self_ty().into(),
306-
normalized_ty.into(),
307-
ty::AliasRelationDirection::Equate,
308-
),
309-
);
310-
this.add_goal(GoalSource::AliasWellFormed, alias_relate_goal);
311-
this.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
312-
});
313-
assert_eq!(result, Err(NoSolution));
314294
return vec![];
315295
};
316296

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
585585
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
586586
let ty = self.resolve_vars_if_possible(ty);
587587
if self.next_trait_solver() {
588+
if let Err(guar) = ty.error_reported() {
589+
return guar;
590+
}
591+
588592
// FIXME: we'll need a better message which takes into account
589593
// which bounds actually failed to hold.
590594
self.dcx().struct_span_err(

compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
172172
{
173173
1
174174
}
175-
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
176175
ty::PredicateKind::Coerce(_) => 2,
176+
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
177177
_ => 0,
178178
});
179179

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+81-24
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_infer::traits::{
77
PredicateObligation, SelectionError,
88
};
99
use rustc_middle::ty::error::{ExpectedFound, TypeError};
10-
use rustc_middle::ty::{self, TyCtxt};
10+
use rustc_middle::ty::{self, Ty, TyCtxt};
1111
use rustc_middle::{bug, span_bug};
1212
use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
1313
use rustc_type_ir::solve::{Goal, NoSolution};
@@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>(
139139
}
140140
}
141141

142+
#[instrument(level = "debug", skip(infcx), ret)]
142143
fn find_best_leaf_obligation<'tcx>(
143144
infcx: &InferCtxt<'tcx>,
144145
obligation: &PredicateObligation<'tcx>,
@@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> {
197198
candidates.retain(|candidate| candidate.result().is_ok());
198199
}
199200
false => {
201+
// We always handle rigid alias candidates separately as we may not add them for
202+
// aliases whose trait bound doesn't hold.
203+
candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
200204
// If we have >1 candidate, one may still be due to "boring" reasons, like
201205
// an alias-relate that failed to hold when deeply evaluated. We really
202206
// don't care about reasons like this.
@@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> {
211215
| GoalSource::AliasBoundConstCondition
212216
| GoalSource::InstantiateHigherRanked
213217
| GoalSource::AliasWellFormed
214-
) && match (self.consider_ambiguities, nested_goal.result()) {
215-
(true, Ok(Certainty::Maybe(MaybeCause::Ambiguity)))
216-
| (false, Err(_)) => true,
217-
_ => false,
218-
}
218+
) && nested_goal.result().is_err()
219219
},
220220
)
221221
})
222222
});
223223
}
224-
225-
// Prefer a non-rigid candidate if there is one.
226-
if candidates.len() > 1 {
227-
candidates.retain(|candidate| {
228-
!matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. })
229-
});
230-
}
231224
}
232225
}
233226

@@ -266,6 +259,37 @@ impl<'tcx> BestObligation<'tcx> {
266259

267260
ControlFlow::Break(self.obligation.clone())
268261
}
262+
263+
/// If a normalization of an associated item or a trait goal fails without trying any
264+
/// candidates it's likely that normalizing its self type failed. We manually detect
265+
/// such cases here.
266+
fn detect_error_in_self_ty_normalization(
267+
&mut self,
268+
goal: &inspect::InspectGoal<'_, 'tcx>,
269+
self_ty: Ty<'tcx>,
270+
) -> ControlFlow<PredicateObligation<'tcx>> {
271+
assert!(!self.consider_ambiguities);
272+
let tcx = goal.infcx().tcx;
273+
if let ty::Alias(..) = self_ty.kind() {
274+
let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
275+
let pred = ty::PredicateKind::AliasRelate(
276+
self_ty.into(),
277+
infer_term.into(),
278+
ty::AliasRelationDirection::Equate,
279+
);
280+
let obligation =
281+
Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
282+
self.with_derived_obligation(obligation, |this| {
283+
goal.infcx().visit_proof_tree_at_depth(
284+
goal.goal().with(tcx, pred),
285+
goal.depth() + 1,
286+
this,
287+
)
288+
})
289+
} else {
290+
ControlFlow::Continue(())
291+
}
292+
}
269293
}
270294

271295
impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -277,11 +301,51 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
277301

278302
#[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
279303
fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
304+
let tcx = goal.infcx().tcx;
305+
// Skip goals that aren't the *reason* for our goal's failure.
306+
match (self.consider_ambiguities, goal.result()) {
307+
(true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
308+
_ => return ControlFlow::Continue(()),
309+
}
310+
let pred_kind = goal.goal().predicate.kind();
311+
280312
let candidates = self.non_trivial_candidates(goal);
281-
trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>());
313+
let candidate = match candidates.as_slice() {
314+
[] => {
315+
match pred_kind.no_bound_vars() {
316+
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
317+
self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
318+
}
319+
Some(ty::PredicateKind::NormalizesTo(pred))
320+
if let ty::AliasTermKind::ProjectionTy
321+
| ty::AliasTermKind::ProjectionConst = pred.alias.kind(tcx) =>
322+
{
323+
self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
324+
// It is likely that `NormalizesTo` failed because the alias is not well-formed.
325+
// As we only enter `RigidAlias` candidates if the trait bound of the associated type
326+
// holds, we discard these candidates in `non_trivial_candidates` and always manually
327+
// check this here.
328+
let obligation = Obligation::new(
329+
tcx,
330+
self.obligation.cause.clone(),
331+
goal.goal().param_env,
332+
pred.alias.trait_ref(tcx),
333+
);
334+
self.with_derived_obligation(obligation, |this| {
335+
goal.infcx().visit_proof_tree_at_depth(
336+
goal.goal().with(tcx, pred.alias.trait_ref(tcx)),
337+
goal.depth() + 1,
338+
this,
339+
)
340+
})?;
341+
}
342+
Some(_) | None => {}
343+
}
282344

283-
let [candidate] = candidates.as_slice() else {
284-
return ControlFlow::Break(self.obligation.clone());
345+
return ControlFlow::Break(self.obligation.clone());
346+
}
347+
[candidate] => candidate,
348+
_ => return ControlFlow::Break(self.obligation.clone()),
285349
};
286350

287351
// Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +355,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
291355
} = candidate.kind()
292356
&& goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
293357
{
358+
trace!("#[do_not_recommend] -> exit");
294359
return ControlFlow::Break(self.obligation.clone());
295360
}
296361

297-
let tcx = goal.infcx().tcx;
298362
// FIXME: Also, what about considering >1 layer up the stack? May be necessary
299363
// for normalizes-to.
300-
let pred_kind = goal.goal().predicate.kind();
301364
let child_mode = match pred_kind.skip_binder() {
302365
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
303366
ChildMode::Trait(pred_kind.rebind(pred))
@@ -390,12 +453,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
390453
}
391454
}
392455

393-
// Skip nested goals that aren't the *reason* for our goal's failure.
394-
match (self.consider_ambiguities, nested_goal.result()) {
395-
(true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
396-
_ => continue,
397-
}
398-
399456
self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
400457
}
401458

tests/crashes/134905.rs

-16
This file was deleted.

tests/ui/auto-traits/assoc-ty.next.stderr

+13-12
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@ LL | | }
2121
= help: add `#![feature(auto_traits)]` to the crate attributes to enable
2222
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2323

24-
error[E0308]: mismatched types
25-
--> $DIR/assoc-ty.rs:15:36
24+
error[E0271]: type mismatch resolving `<() as Trait>::Output normalizes-to _`
25+
--> $DIR/assoc-ty.rs:15:12
2626
|
2727
LL | let _: <() as Trait>::Output = ();
28-
| --------------------- ^^ types differ
29-
| |
30-
| expected due to this
28+
| ^^^^^^^^^^^^^^^^^^^^^ types differ
29+
30+
error[E0271]: type mismatch resolving `<() as Trait>::Output normalizes-to _`
31+
--> $DIR/assoc-ty.rs:15:12
32+
|
33+
LL | let _: <() as Trait>::Output = ();
34+
| ^^^^^^^^^^^^^^^^^^^^^ types differ
3135
|
32-
= note: expected associated type `<() as Trait>::Output`
33-
found unit type `()`
34-
= help: consider constraining the associated type `<() as Trait>::Output` to `()` or calling a method that returns `<() as Trait>::Output`
35-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
36+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
3637

37-
error: aborting due to 3 previous errors
38+
error: aborting due to 4 previous errors
3839

39-
Some errors have detailed explanations: E0308, E0380, E0658.
40-
For more information about an error, try `rustc --explain E0308`.
40+
Some errors have detailed explanations: E0271, E0380, E0658.
41+
For more information about an error, try `rustc --explain E0271`.

tests/ui/auto-traits/assoc-ty.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ auto trait Trait {
1313

1414
fn main() {
1515
let _: <() as Trait>::Output = ();
16-
//~^ ERROR mismatched types
16+
//[current]~^ ERROR mismatched types
17+
//[next]~^^ ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _`
18+
//[next]~| ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _`
1719
}

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr

+13-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,19 @@ error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
2323
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
2424
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
2525

26-
error: aborting due to 3 previous errors
26+
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
27+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:73
28+
|
29+
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
30+
| ^^ types differ
31+
32+
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
33+
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5
34+
|
35+
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
37+
38+
error: aborting due to 5 previous errors
2739

2840
Some errors have detailed explanations: E0049, E0271, E0407.
2941
For more information about an error, try `rustc --explain E0049`.

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ impl X for Y {
2626
//~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
2727
type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>;
2828
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
29-
//[current]~^ ERROR `()` is not a future
30-
//[next]~^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
31-
//~^^^ method `line_stream` is not a member of trait `X`
29+
//~^ method `line_stream` is not a member of trait `X`
30+
//[current]~^^ ERROR `()` is not a future
31+
//[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
32+
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
33+
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
3234
}
3335

3436
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// This test previously tried to use a tainted `EvalCtxt` when emitting
2+
// an error during coherence.
3+
#![feature(specialization)]
4+
//~^ WARN the feature `specialization` is incomplete
5+
trait Iterate<'a> {
6+
type Ty: Valid;
7+
}
8+
impl<'a, T> Iterate<'a> for T
9+
where
10+
T: Check,
11+
{
12+
default type Ty = ();
13+
//~^ ERROR the trait bound `(): Valid` is not satisfied
14+
}
15+
16+
trait Check {}
17+
impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {}
18+
//~^ ERROR type parameter `T` must be used as the type parameter for some local type
19+
20+
trait Valid {}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/fuzzing-ice-134905.rs:3:12
3+
|
4+
LL | #![feature(specialization)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
8+
= help: consider using `min_specialization` instead, which is more stable and complete
9+
= note: `#[warn(incomplete_features)]` on by default
10+
11+
error[E0277]: the trait bound `(): Valid` is not satisfied
12+
--> $DIR/fuzzing-ice-134905.rs:12:23
13+
|
14+
LL | default type Ty = ();
15+
| ^^ the trait `Valid` is not implemented for `()`
16+
|
17+
help: this trait has no implementations, consider adding one
18+
--> $DIR/fuzzing-ice-134905.rs:20:1
19+
|
20+
LL | trait Valid {}
21+
| ^^^^^^^^^^^
22+
note: required by a bound in `Iterate::Ty`
23+
--> $DIR/fuzzing-ice-134905.rs:6:14
24+
|
25+
LL | type Ty: Valid;
26+
| ^^^^^ required by this bound in `Iterate::Ty`
27+
28+
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
29+
--> $DIR/fuzzing-ice-134905.rs:17:10
30+
|
31+
LL | impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {}
32+
| ^ type parameter `T` must be used as the type parameter for some local type
33+
|
34+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
35+
= note: only traits defined in the current crate can be implemented for a type parameter
36+
37+
error: aborting due to 2 previous errors; 1 warning emitted
38+
39+
Some errors have detailed explanations: E0210, E0277.
40+
For more information about an error, try `rustc --explain E0210`.

0 commit comments

Comments
 (0)