diff options
| author | lcnr <rust@lcnr.de> | 2025-02-12 11:41:53 +0100 |
|---|---|---|
| committer | lcnr <rust@lcnr.de> | 2025-02-13 23:49:09 +0100 |
| commit | 059288ed442f34c336c759486bfe4373b61288a0 (patch) | |
| tree | b8b4b60b84e0cd03ea0a48a6ce4881d434887a5a | |
| parent | 05bd5ced2d9af5f155ed8a72b5c1399838c1d653 (diff) | |
| download | rust-059288ed442f34c336c759486bfe4373b61288a0.tar.gz rust-059288ed442f34c336c759486bfe4373b61288a0.zip | |
adjust derive_error
11 files changed, 204 insertions, 79 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 23fe88b1680..b0f59ed1474 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -6,7 +6,6 @@ use derive_where::derive_where; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::solve::inspect; use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; use tracing::{debug, instrument}; @@ -297,25 +296,6 @@ where let Ok(normalized_self_ty) = self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) else { - // FIXME: We register a fake candidate when normalization fails so that - // we can point at the reason for *why*. I'm tempted to say that this - // is the wrong way to do this, though. - let result = - self.probe(|&result| inspect::ProbeKind::RigidAlias { result }).enter(|this| { - let normalized_ty = this.next_ty_infer(); - let alias_relate_goal = Goal::new( - this.cx(), - goal.param_env, - ty::PredicateKind::AliasRelate( - goal.predicate.self_ty().into(), - normalized_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - this.add_goal(GoalSource::AliasWellFormed, alias_relate_goal); - this.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - }); - assert_eq!(result, Err(NoSolution)); return vec![]; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1b43820bac0..49fa21e50c0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -585,6 +585,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { let ty = self.resolve_vars_if_possible(ty); if self.next_trait_solver() { + if let Err(guar) = ty.error_reported() { + return guar; + } + // FIXME: we'll need a better message which takes into account // which bounds actually failed to hold. self.dcx().struct_span_err( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 658fb4009d5..e4f250ca4f5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -172,8 +172,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { 1 } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, ty::PredicateKind::Coerce(_) => 2, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, _ => 0, }); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 7364b4aa343..982782bc57c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::{ PredicateObligation, SelectionError, }; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; use rustc_type_ir::solve::{Goal, NoSolution}; @@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>( } } +#[instrument(level = "debug", skip(infcx), ret)] fn find_best_leaf_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, @@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> { candidates.retain(|candidate| candidate.result().is_ok()); } false => { + // We always handle rigid alias candidates separately as we may not add them for + // aliases whose trait bound doesn't hold. + candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. })); // If we have >1 candidate, one may still be due to "boring" reasons, like // an alias-relate that failed to hold when deeply evaluated. We really // don't care about reasons like this. @@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> { | GoalSource::AliasBoundConstCondition | GoalSource::InstantiateHigherRanked | GoalSource::AliasWellFormed - ) && match (self.consider_ambiguities, nested_goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) - | (false, Err(_)) => true, - _ => false, - } + ) && nested_goal.result().is_err() }, ) }) }); } - - // Prefer a non-rigid candidate if there is one. - if candidates.len() > 1 { - candidates.retain(|candidate| { - !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. }) - }); - } } } @@ -266,6 +259,90 @@ impl<'tcx> BestObligation<'tcx> { ControlFlow::Break(self.obligation.clone()) } + + /// If a normalization of an associated item or a trait goal fails without trying any + /// candidates it's likely that normalizing its self type failed. We manually detect + /// such cases here. + fn detect_error_in_self_ty_normalization( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + self_ty: Ty<'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + assert!(!self.consider_ambiguities); + let tcx = goal.infcx().tcx; + if let ty::Alias(..) = self_ty.kind() { + let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span); + let pred = ty::PredicateKind::AliasRelate( + self_ty.into(), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ); + let obligation = + Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, pred), + goal.depth() + 1, + this, + ) + }) + } else { + ControlFlow::Continue(()) + } + } + + /// It is likely that `NormalizesTo` failed without any applicable candidates + /// because the alias is not well-formed. + /// + /// As we only enter `RigidAlias` candidates if the trait bound of the associated type + /// holds, we discard these candidates in `non_trivial_candidates` and always manually + /// check this here. + fn detect_non_well_formed_assoc_item( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + alias: ty::AliasTerm<'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + let tcx = goal.infcx().tcx; + let obligation = Obligation::new( + tcx, + self.obligation.cause.clone(), + goal.goal().param_env, + alias.trait_ref(tcx), + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, alias.trait_ref(tcx)), + goal.depth() + 1, + this, + ) + }) + } + + /// If we have no candidates, then it's likely that there is a + /// non-well-formed alias in the goal. + fn detect_error_from_empty_candidates( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + let tcx = goal.infcx().tcx; + let pred_kind = goal.goal().predicate.kind(); + + match pred_kind.no_bound_vars() { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => { + self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?; + } + Some(ty::PredicateKind::NormalizesTo(pred)) + if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = + pred.alias.kind(tcx) => + { + self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?; + self.detect_non_well_formed_assoc_item(goal, pred.alias)?; + } + Some(_) | None => {} + } + + ControlFlow::Break(self.obligation.clone()) + } } impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { @@ -277,11 +354,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))] fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { - let candidates = self.non_trivial_candidates(goal); - trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>()); + let tcx = goal.infcx().tcx; + // Skip goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => return ControlFlow::Continue(()), + } + let pred_kind = goal.goal().predicate.kind(); - let [candidate] = candidates.as_slice() else { - return ControlFlow::Break(self.obligation.clone()); + let candidates = self.non_trivial_candidates(goal); + let candidate = match candidates.as_slice() { + [candidate] => candidate, + [] => return self.detect_error_from_empty_candidates(goal), + _ => return ControlFlow::Break(self.obligation.clone()), }; // Don't walk into impls that have `do_not_recommend`. @@ -291,13 +376,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } = candidate.kind() && goal.infcx().tcx.do_not_recommend_impl(impl_def_id) { + trace!("#[do_not_recommend] -> exit"); return ControlFlow::Break(self.obligation.clone()); } - let tcx = goal.infcx().tcx; // FIXME: Also, what about considering >1 layer up the stack? May be necessary // for normalizes-to. - let pred_kind = goal.goal().predicate.kind(); let child_mode = match pred_kind.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { ChildMode::Trait(pred_kind.rebind(pred)) @@ -390,12 +474,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } } - // Skip nested goals that aren't the *reason* for our goal's failure. - match (self.consider_ambiguities, nested_goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} - _ => continue, - } - self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; } diff --git a/tests/crashes/134905.rs b/tests/crashes/134905.rs deleted file mode 100644 index 9f0f0f4b3f2..00000000000 --- a/tests/crashes/134905.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #134905 - -trait Iterate<'a> { - type Ty: Valid; -} -impl<'a, T> Iterate<'a> for T -where - T: Check, -{ - default type Ty = (); -} - -trait Check {} -impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {} - -trait Valid {} diff --git a/tests/ui/auto-traits/assoc-ty.next.stderr b/tests/ui/auto-traits/assoc-ty.next.stderr index b9f56d6c99c..4ce00d17475 100644 --- a/tests/ui/auto-traits/assoc-ty.next.stderr +++ b/tests/ui/auto-traits/assoc-ty.next.stderr @@ -21,20 +21,21 @@ LL | | } = help: add `#![feature(auto_traits)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0308]: mismatched types - --> $DIR/assoc-ty.rs:15:36 +error[E0271]: type mismatch resolving `<() as Trait>::Output normalizes-to _` + --> $DIR/assoc-ty.rs:15:12 | LL | let _: <() as Trait>::Output = (); - | --------------------- ^^ types differ - | | - | expected due to this + | ^^^^^^^^^^^^^^^^^^^^^ types differ + +error[E0271]: type mismatch resolving `<() as Trait>::Output normalizes-to _` + --> $DIR/assoc-ty.rs:15:12 + | +LL | let _: <() as Trait>::Output = (); + | ^^^^^^^^^^^^^^^^^^^^^ types differ | - = note: expected associated type `<() as Trait>::Output` - found unit type `()` - = help: consider constraining the associated type `<() as Trait>::Output` to `()` or calling a method that returns `<() as Trait>::Output` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0380, E0658. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0271, E0380, E0658. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/auto-traits/assoc-ty.rs b/tests/ui/auto-traits/assoc-ty.rs index ada75147f6e..efbfead9cd0 100644 --- a/tests/ui/auto-traits/assoc-ty.rs +++ b/tests/ui/auto-traits/assoc-ty.rs @@ -13,5 +13,7 @@ auto trait Trait { fn main() { let _: <() as Trait>::Output = (); - //~^ ERROR mismatched types + //[current]~^ ERROR mismatched types + //[next]~^^ ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _` + //[next]~| ERROR type mismatch resolving `<() as Trait>::Output normalizes-to _` } diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr index 3c24eb9adbe..ce64a022214 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -23,7 +23,19 @@ error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ -error: aborting due to 3 previous errors +error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:73 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^ types differ + +error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0049, E0271, E0407. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index c97bd179943..cb32723b22d 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -26,9 +26,11 @@ impl X for Y { //~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>; fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} - //[current]~^ ERROR `()` is not a future - //[next]~^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` - //~^^^ method `line_stream` is not a member of trait `X` + //~^ method `line_stream` is not a member of trait `X` + //[current]~^^ ERROR `()` is not a future + //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` + //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` + //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` } pub fn main() {} diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs new file mode 100644 index 00000000000..559c2345527 --- /dev/null +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs @@ -0,0 +1,22 @@ +// This test previously tried to use a tainted `EvalCtxt` when emitting +// an error during coherence. +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete +trait Iterate<'a> { + type Ty: Valid; +} +impl<'a, T> Iterate<'a> for T +where + T: Check, +{ + default type Ty = (); + //~^ ERROR the trait bound `(): Valid` is not satisfied +} + +trait Check {} +impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {} +//~^ ERROR type parameter `T` must be used as the type parameter for some local type + +trait Valid {} + +fn main() {} diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr new file mode 100644 index 00000000000..611fef1df66 --- /dev/null +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr @@ -0,0 +1,40 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/fuzzing-ice-134905.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `(): Valid` is not satisfied + --> $DIR/fuzzing-ice-134905.rs:12:23 + | +LL | default type Ty = (); + | ^^ the trait `Valid` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/fuzzing-ice-134905.rs:20:1 + | +LL | trait Valid {} + | ^^^^^^^^^^^ +note: required by a bound in `Iterate::Ty` + --> $DIR/fuzzing-ice-134905.rs:6:14 + | +LL | type Ty: Valid; + | ^^^^^ required by this bound in `Iterate::Ty` + +error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) + --> $DIR/fuzzing-ice-134905.rs:17:10 + | +LL | impl<'a, T> Eq for T where <T as Iterate<'a>>::Ty: Valid {} + | ^ type parameter `T` must be used as the type parameter for some local type + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + = note: only traits defined in the current crate can be implemented for a type parameter + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0210, E0277. +For more information about an error, try `rustc --explain E0210`. |
