mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
adjust derive_error
This commit is contained in:
parent
05bd5ced2d
commit
059288ed44
@ -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![];
|
||||
};
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
});
|
||||
|
||||
|
@ -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))?;
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
@ -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
|
||||
|
|
||||
= 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
|
||||
LL | let _: <() as Trait>::Output = ();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
|
||||
= 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`.
|
||||
|
@ -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 _`
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
||||
|
22
tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs
Normal file
22
tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs
Normal file
@ -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() {}
|
40
tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr
Normal file
40
tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user