Rollup merge of #124415 - compiler-errors:candidates, r=lcnr
Use probes more aggressively in new solver ....so that we have the right candidate information when assembling trait and normalizes-to goals. Also gets rid of misc probes. r? lcnr
This commit is contained in:
commit
4355749b16
@ -332,4 +332,9 @@ pub enum CandidateSource {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
AliasBound,
|
AliasBound,
|
||||||
|
/// A candidate that is registered only during coherence to represent some
|
||||||
|
/// yet-unknown impl that could be produced downstream without violating orphan
|
||||||
|
/// rules.
|
||||||
|
// FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
|
||||||
|
CoherenceUnknowable,
|
||||||
}
|
}
|
||||||
|
@ -141,10 +141,6 @@ pub enum ProbeKind<'tcx> {
|
|||||||
TryNormalizeNonRigid { result: QueryResult<'tcx> },
|
TryNormalizeNonRigid { result: QueryResult<'tcx> },
|
||||||
/// Probe entered when normalizing the self ty during candidate assembly
|
/// Probe entered when normalizing the self ty during candidate assembly
|
||||||
NormalizedSelfTyAssembly,
|
NormalizedSelfTyAssembly,
|
||||||
/// Some candidate to prove the current goal.
|
|
||||||
///
|
|
||||||
/// FIXME: Remove this in favor of always using more strongly typed variants.
|
|
||||||
MiscCandidate { name: &'static str, result: QueryResult<'tcx> },
|
|
||||||
/// A candidate for proving a trait or alias-relate goal.
|
/// A candidate for proving a trait or alias-relate goal.
|
||||||
TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
|
TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
|
||||||
/// Used in the probe that wraps normalizing the non-self type for the unsize
|
/// Used in the probe that wraps normalizing the non-self type for the unsize
|
||||||
@ -154,4 +150,6 @@ pub enum ProbeKind<'tcx> {
|
|||||||
/// do a probe to find out what projection type(s) may be used to prove that
|
/// do a probe to find out what projection type(s) may be used to prove that
|
||||||
/// the source type upholds all of the target type's object bounds.
|
/// the source type upholds all of the target type's object bounds.
|
||||||
UpcastProjectionCompatibility,
|
UpcastProjectionCompatibility,
|
||||||
|
/// Try to unify an opaque type with an existing key in the storage.
|
||||||
|
OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
|
||||||
}
|
}
|
||||||
|
@ -112,8 +112,8 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
|||||||
ProbeKind::UpcastProjectionCompatibility => {
|
ProbeKind::UpcastProjectionCompatibility => {
|
||||||
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
|
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
|
||||||
}
|
}
|
||||||
ProbeKind::MiscCandidate { name, result } => {
|
ProbeKind::OpaqueTypeStorageLookup { result } => {
|
||||||
write!(self.f, "CANDIDATE {name}: {result:?}")
|
write!(self.f, "PROBING FOR AN EXISTING OPAQUE: {result:?}")
|
||||||
}
|
}
|
||||||
ProbeKind::TraitCandidate { source, result } => {
|
ProbeKind::TraitCandidate { source, result } => {
|
||||||
write!(self.f, "CANDIDATE {source:?}: {result:?}")
|
write!(self.f, "CANDIDATE {source:?}: {result:?}")
|
||||||
|
@ -48,21 +48,23 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
|
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
|
||||||
fn probe_and_match_goal_against_assumption(
|
fn probe_and_match_goal_against_assumption(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Clause<'tcx>,
|
assumption: ty::Clause<'tcx>,
|
||||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// Consider a clause, which consists of a "assumption" and some "requirements",
|
/// Consider a clause, which consists of a "assumption" and some "requirements",
|
||||||
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
||||||
/// goal by equating it with the assumption.
|
/// goal by equating it with the assumption.
|
||||||
fn consider_implied_clause(
|
fn probe_and_consider_implied_clause(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Clause<'tcx>,
|
assumption: ty::Clause<'tcx>,
|
||||||
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||||
// FIXME(-Znext-solver=coinductive): check whether this should be
|
// FIXME(-Znext-solver=coinductive): check whether this should be
|
||||||
// `GoalSource::ImplWhereBound` for any caller.
|
// `GoalSource::ImplWhereBound` for any caller.
|
||||||
ecx.add_goals(GoalSource::Misc, requirements);
|
ecx.add_goals(GoalSource::Misc, requirements);
|
||||||
@ -73,15 +75,16 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
/// Consider a clause specifically for a `dyn Trait` self type. This requires
|
/// Consider a clause specifically for a `dyn Trait` self type. This requires
|
||||||
/// additionally checking all of the supertraits and object bounds to hold,
|
/// additionally checking all of the supertraits and object bounds to hold,
|
||||||
/// since they're not implied by the well-formedness of the object type.
|
/// since they're not implied by the well-formedness of the object type.
|
||||||
fn consider_object_bound_candidate(
|
fn probe_and_consider_object_bound_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Clause<'tcx>,
|
assumption: ty::Clause<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||||
bug!("expected object type in `consider_object_bound_candidate`");
|
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
|
||||||
};
|
};
|
||||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||||
ecx.add_goals(
|
ecx.add_goals(
|
||||||
@ -112,7 +115,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_error_guaranteed_candidate(
|
fn consider_error_guaranteed_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
guar: ErrorGuaranteed,
|
guar: ErrorGuaranteed,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A type implements an `auto trait` if its components do as well.
|
/// A type implements an `auto trait` if its components do as well.
|
||||||
///
|
///
|
||||||
@ -121,13 +124,13 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_auto_trait_candidate(
|
fn consider_auto_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A trait alias holds if the RHS traits and `where` clauses hold.
|
/// A trait alias holds if the RHS traits and `where` clauses hold.
|
||||||
fn consider_trait_alias_candidate(
|
fn consider_trait_alias_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A type is `Sized` if its tail component is `Sized`.
|
/// A type is `Sized` if its tail component is `Sized`.
|
||||||
///
|
///
|
||||||
@ -136,7 +139,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_sized_candidate(
|
fn consider_builtin_sized_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
|
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
|
||||||
///
|
///
|
||||||
@ -145,20 +148,20 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_copy_clone_candidate(
|
fn consider_builtin_copy_clone_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A type is `PointerLike` if we can compute its layout, and that layout
|
/// A type is `PointerLike` if we can compute its layout, and that layout
|
||||||
/// matches the layout of `usize`.
|
/// matches the layout of `usize`.
|
||||||
fn consider_builtin_pointer_like_candidate(
|
fn consider_builtin_pointer_like_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
|
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
|
||||||
/// family of traits where `A` is given by the signature of the type.
|
/// family of traits where `A` is given by the signature of the type.
|
||||||
@ -166,7 +169,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
kind: ty::ClosureKind,
|
kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// An async closure is known to implement the `AsyncFn<A>` family of traits
|
/// An async closure is known to implement the `AsyncFn<A>` family of traits
|
||||||
/// where `A` is given by the signature of the type.
|
/// where `A` is given by the signature of the type.
|
||||||
@ -174,7 +177,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
kind: ty::ClosureKind,
|
kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
|
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
|
||||||
/// is used internally to delay computation for async closures until after
|
/// is used internally to delay computation for async closures until after
|
||||||
@ -182,13 +185,13 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// `Tuple` is implemented if the `Self` type is a tuple.
|
/// `Tuple` is implemented if the `Self` type is a tuple.
|
||||||
fn consider_builtin_tuple_candidate(
|
fn consider_builtin_tuple_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// `Pointee` is always implemented.
|
/// `Pointee` is always implemented.
|
||||||
///
|
///
|
||||||
@ -198,7 +201,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_pointee_candidate(
|
fn consider_builtin_pointee_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A coroutine (that comes from an `async` desugaring) is known to implement
|
/// A coroutine (that comes from an `async` desugaring) is known to implement
|
||||||
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
|
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
|
||||||
@ -206,7 +209,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_future_candidate(
|
fn consider_builtin_future_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||||
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
|
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
|
||||||
@ -214,19 +217,19 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_iterator_candidate(
|
fn consider_builtin_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||||
/// `FusedIterator`
|
/// `FusedIterator`
|
||||||
fn consider_builtin_fused_iterator_candidate(
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
|
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
|
||||||
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
|
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
|
||||||
@ -234,27 +237,27 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_builtin_coroutine_candidate(
|
fn consider_builtin_coroutine_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
fn consider_builtin_discriminant_kind_candidate(
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
fn consider_builtin_async_destruct_candidate(
|
fn consider_builtin_async_destruct_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
fn consider_builtin_destruct_candidate(
|
fn consider_builtin_destruct_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
fn consider_builtin_transmute_candidate(
|
fn consider_builtin_transmute_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||||
|
|
||||||
/// Consider (possibly several) candidates to upcast or unsize a type to another
|
/// Consider (possibly several) candidates to upcast or unsize a type to another
|
||||||
/// type, excluding the coercion of a sized type into a `dyn Trait`.
|
/// type, excluding the coercion of a sized type into a `dyn Trait`.
|
||||||
@ -266,7 +269,7 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
fn consider_structural_builtin_unsize_candidates(
|
fn consider_structural_builtin_unsize_candidates(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
|
) -> Vec<Candidate<'tcx>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
@ -282,7 +285,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
|
|
||||||
if normalized_self_ty.is_ty_var() {
|
if normalized_self_ty.is_ty_var() {
|
||||||
debug!("self type has been normalized to infer");
|
debug!("self type has been normalized to infer");
|
||||||
return self.forced_ambiguity(MaybeCause::Ambiguity);
|
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
let goal =
|
let goal =
|
||||||
@ -315,7 +318,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
candidates
|
candidates
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forced_ambiguity(&mut self, cause: MaybeCause) -> Vec<Candidate<'tcx>> {
|
pub(super) fn forced_ambiguity(
|
||||||
|
&mut self,
|
||||||
|
cause: MaybeCause,
|
||||||
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
// This may fail if `try_evaluate_added_goals` overflows because it
|
// This may fail if `try_evaluate_added_goals` overflows because it
|
||||||
// fails to reach a fixpoint but ends up getting an error after
|
// fails to reach a fixpoint but ends up getting an error after
|
||||||
// running for some additional step.
|
// running for some additional step.
|
||||||
@ -323,10 +329,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// cc trait-system-refactor-initiative#105
|
// cc trait-system-refactor-initiative#105
|
||||||
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
||||||
let certainty = Certainty::Maybe(cause);
|
let certainty = Certainty::Maybe(cause);
|
||||||
let result = self
|
self.probe_trait_candidate(source)
|
||||||
.probe_trait_candidate(source)
|
.enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
|
||||||
.enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty));
|
|
||||||
if let Ok(cand) = result { vec![cand] } else { vec![] }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip_all)]
|
#[instrument(level = "debug", skip_all)]
|
||||||
@ -533,20 +537,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
candidates.extend(result);
|
||||||
Ok(result) => candidates.push(Candidate {
|
|
||||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
|
||||||
result,
|
|
||||||
}),
|
|
||||||
Err(NoSolution) => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
// There may be multiple unsize candidates for a trait with several supertraits:
|
// There may be multiple unsize candidates for a trait with several supertraits:
|
||||||
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
||||||
if lang_items.unsize_trait() == Some(trait_def_id) {
|
if lang_items.unsize_trait() == Some(trait_def_id) {
|
||||||
for (result, source) in G::consider_structural_builtin_unsize_candidates(self, goal) {
|
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
|
||||||
candidates.push(Candidate { source: CandidateSource::BuiltinImpl(source), result });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,12 +553,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
candidates: &mut Vec<Candidate<'tcx>>,
|
candidates: &mut Vec<Candidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
||||||
match G::consider_implied_clause(self, goal, assumption, []) {
|
candidates.extend(G::probe_and_consider_implied_clause(
|
||||||
Ok(result) => {
|
self,
|
||||||
candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
|
CandidateSource::ParamEnv(i),
|
||||||
}
|
goal,
|
||||||
Err(NoSolution) => (),
|
assumption,
|
||||||
}
|
[],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,12 +645,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
for assumption in
|
for assumption in
|
||||||
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
|
self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
|
||||||
{
|
{
|
||||||
match G::consider_implied_clause(self, goal, assumption, []) {
|
candidates.extend(G::probe_and_consider_implied_clause(
|
||||||
Ok(result) => {
|
self,
|
||||||
candidates.push(Candidate { source: CandidateSource::AliasBound, result });
|
CandidateSource::AliasBound,
|
||||||
}
|
goal,
|
||||||
Err(NoSolution) => {}
|
assumption,
|
||||||
}
|
[],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind != ty::Projection {
|
if kind != ty::Projection {
|
||||||
@ -728,17 +726,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
ty::ExistentialPredicate::Projection(_)
|
ty::ExistentialPredicate::Projection(_)
|
||||||
| ty::ExistentialPredicate::AutoTrait(_) => {
|
| ty::ExistentialPredicate::AutoTrait(_) => {
|
||||||
match G::consider_object_bound_candidate(
|
candidates.extend(G::probe_and_consider_object_bound_candidate(
|
||||||
self,
|
self,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
bound.with_self_ty(tcx, self_ty),
|
bound.with_self_ty(tcx, self_ty),
|
||||||
) {
|
));
|
||||||
Ok(result) => candidates.push(Candidate {
|
|
||||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
|
||||||
result,
|
|
||||||
}),
|
|
||||||
Err(NoSolution) => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -749,15 +742,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
if let Some(principal) = bounds.principal() {
|
if let Some(principal) = bounds.principal() {
|
||||||
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
|
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
|
||||||
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
|
self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
|
||||||
match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) {
|
candidates.extend(G::probe_and_consider_object_bound_candidate(
|
||||||
Ok(result) => candidates.push(Candidate {
|
ecx,
|
||||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object {
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
|
||||||
vtable_base,
|
goal,
|
||||||
}),
|
assumption.to_predicate(tcx),
|
||||||
result,
|
));
|
||||||
}),
|
|
||||||
Err(NoSolution) => (),
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -775,25 +765,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
candidates: &mut Vec<Candidate<'tcx>>,
|
candidates: &mut Vec<Candidate<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let result = self.probe_misc_candidate("coherence unknowable").enter(|ecx| {
|
|
||||||
let trait_ref = goal.predicate.trait_ref(tcx);
|
|
||||||
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
|
||||||
|
|
||||||
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
|
||||||
Ok(()) => Err(NoSolution),
|
|ecx| {
|
||||||
Err(_) => {
|
let trait_ref = goal.predicate.trait_ref(tcx);
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
let lazily_normalize_ty = |ty| ecx.structurally_normalize_ty(goal.param_env, ty);
|
||||||
|
|
||||||
|
match coherence::trait_ref_is_knowable(tcx, trait_ref, lazily_normalize_ty)? {
|
||||||
|
Ok(()) => Err(NoSolution),
|
||||||
|
Err(_) => {
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
))
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(result) => candidates.push(Candidate {
|
|
||||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
|
||||||
result,
|
|
||||||
}),
|
|
||||||
Err(NoSolution) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If there's a where-bound for the current goal, do not use any impl candidates
|
/// If there's a where-bound for the current goal, do not use any impl candidates
|
||||||
@ -838,6 +823,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
|
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
|
||||||
|
CandidateSource::CoherenceUnknowable => bug!("uh oh"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// If it is still ambiguous we instead just force the whole goal
|
// If it is still ambiguous we instead just force the whole goal
|
||||||
@ -845,7 +831,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
|
// tests/ui/traits/next-solver/env-shadows-impls/ambig-env-no-shadow.rs
|
||||||
Certainty::Maybe(cause) => {
|
Certainty::Maybe(cause) => {
|
||||||
debug!(?cause, "force ambiguity");
|
debug!(?cause, "force ambiguity");
|
||||||
*candidates = self.forced_ambiguity(cause);
|
*candidates = self.forced_ambiguity(cause).into_iter().collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -998,19 +998,24 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
if candidate_key.def_id != key.def_id {
|
if candidate_key.def_id != key.def_id {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
values.extend(self.probe_misc_candidate("opaque type storage").enter(|ecx| {
|
values.extend(
|
||||||
for (a, b) in std::iter::zip(candidate_key.args, key.args) {
|
self.probe(|result| inspect::ProbeKind::OpaqueTypeStorageLookup {
|
||||||
ecx.eq(param_env, a, b)?;
|
result: *result,
|
||||||
}
|
})
|
||||||
ecx.eq(param_env, candidate_ty, ty)?;
|
.enter(|ecx| {
|
||||||
ecx.add_item_bounds_for_hidden_type(
|
for (a, b) in std::iter::zip(candidate_key.args, key.args) {
|
||||||
candidate_key.def_id.to_def_id(),
|
ecx.eq(param_env, a, b)?;
|
||||||
candidate_key.args,
|
}
|
||||||
param_env,
|
ecx.eq(param_env, candidate_ty, ty)?;
|
||||||
candidate_ty,
|
ecx.add_item_bounds_for_hidden_type(
|
||||||
);
|
candidate_key.def_id.to_def_id(),
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
candidate_key.args,
|
||||||
}));
|
param_env,
|
||||||
|
candidate_ty,
|
||||||
|
);
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::solve::assembly::Candidate;
|
use crate::solve::assembly::Candidate;
|
||||||
|
|
||||||
use super::EvalCtxt;
|
use super::EvalCtxt;
|
||||||
|
use rustc_infer::traits::BuiltinImplSource;
|
||||||
use rustc_middle::traits::{
|
use rustc_middle::traits::{
|
||||||
query::NoSolution,
|
query::NoSolution,
|
||||||
solve::{inspect, CandidateSource, QueryResult},
|
solve::{inspect, CandidateSource, QueryResult},
|
||||||
@ -75,24 +76,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||||||
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
|
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::solve) fn probe_misc_candidate(
|
pub(in crate::solve) fn probe_builtin_trait_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
source: BuiltinImplSource,
|
||||||
) -> ProbeCtxt<
|
) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
|
||||||
'_,
|
{
|
||||||
'a,
|
self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
|
||||||
'tcx,
|
|
||||||
impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
|
|
||||||
QueryResult<'tcx>,
|
|
||||||
> {
|
|
||||||
ProbeCtxt {
|
|
||||||
ecx: self,
|
|
||||||
probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::MiscCandidate {
|
|
||||||
name,
|
|
||||||
result: *result,
|
|
||||||
},
|
|
||||||
_result: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::solve) fn probe_trait_candidate(
|
pub(in crate::solve) fn probe_trait_candidate(
|
||||||
|
@ -107,6 +107,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||||||
Ok(Some(ImplSource::Param(vec![])))
|
Ok(Some(ImplSource::Param(vec![])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(_, CandidateSource::CoherenceUnknowable) => bug!(),
|
||||||
|
|
||||||
(Certainty::Maybe(_), _) => Ok(None),
|
(Certainty::Maybe(_), _) => Ok(None),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -45,7 +45,7 @@ pub struct InspectCandidate<'a, 'tcx> {
|
|||||||
nested_goals: Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
nested_goals: Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||||
final_state: inspect::CanonicalState<'tcx, ()>,
|
final_state: inspect::CanonicalState<'tcx, ()>,
|
||||||
result: QueryResult<'tcx>,
|
result: QueryResult<'tcx>,
|
||||||
candidate_certainty: Option<Certainty>,
|
shallow_certainty: Certainty,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||||
@ -59,15 +59,14 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
|||||||
|
|
||||||
/// Certainty passed into `evaluate_added_goals_and_make_canonical_response`.
|
/// Certainty passed into `evaluate_added_goals_and_make_canonical_response`.
|
||||||
///
|
///
|
||||||
/// If this certainty is `Some(Yes)`, then we must be confident that the candidate
|
/// If this certainty is `Yes`, then we must be confident that the candidate
|
||||||
/// must hold iff it's nested goals hold. This is not true if the certainty is
|
/// must hold iff it's nested goals hold. This is not true if the certainty is
|
||||||
/// `Some(Maybe)`, which suggests we forced ambiguity instead, or if it is `None`,
|
/// `Maybe(..)`, which suggests we forced ambiguity instead.
|
||||||
/// which suggests we may have not assembled any candidates at all.
|
|
||||||
///
|
///
|
||||||
/// This is *not* the certainty of the candidate's nested evaluation, which can be
|
/// This is *not* the certainty of the candidate's full nested evaluation, which
|
||||||
/// accessed with [`Self::result`] instead.
|
/// can be accessed with [`Self::result`] instead.
|
||||||
pub fn candidate_certainty(&self) -> Option<Certainty> {
|
pub fn shallow_certainty(&self) -> Certainty {
|
||||||
self.candidate_certainty
|
self.shallow_certainty
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit all nested goals of this candidate without rolling
|
/// Visit all nested goals of this candidate without rolling
|
||||||
@ -174,9 +173,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||||||
nested_goals: &mut Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
nested_goals: &mut Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||||
probe: &inspect::Probe<'tcx>,
|
probe: &inspect::Probe<'tcx>,
|
||||||
) {
|
) {
|
||||||
let mut candidate_certainty = None;
|
let mut shallow_certainty = None;
|
||||||
let num_candidates = candidates.len();
|
|
||||||
|
|
||||||
for step in &probe.steps {
|
for step in &probe.steps {
|
||||||
match step {
|
match step {
|
||||||
&inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
|
&inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
|
||||||
@ -188,8 +185,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||||||
self.candidates_recur(candidates, nested_goals, probe);
|
self.candidates_recur(candidates, nested_goals, probe);
|
||||||
nested_goals.truncate(num_goals);
|
nested_goals.truncate(num_goals);
|
||||||
}
|
}
|
||||||
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } => {
|
inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
|
||||||
assert_eq!(candidate_certainty.replace(*shallow_certainty), None);
|
assert_eq!(shallow_certainty.replace(*c), None);
|
||||||
}
|
}
|
||||||
inspect::ProbeStep::EvaluateGoals(_) => (),
|
inspect::ProbeStep::EvaluateGoals(_) => (),
|
||||||
}
|
}
|
||||||
@ -199,36 +196,26 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||||||
inspect::ProbeKind::NormalizedSelfTyAssembly
|
inspect::ProbeKind::NormalizedSelfTyAssembly
|
||||||
| inspect::ProbeKind::UnsizeAssembly
|
| inspect::ProbeKind::UnsizeAssembly
|
||||||
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
|
| inspect::ProbeKind::UpcastProjectionCompatibility => (),
|
||||||
// We add a candidate for the root evaluation if there
|
|
||||||
|
// We add a candidate even for the root evaluation if there
|
||||||
// is only one way to prove a given goal, e.g. for `WellFormed`.
|
// is only one way to prove a given goal, e.g. for `WellFormed`.
|
||||||
//
|
|
||||||
// FIXME: This is currently wrong if we don't even try any
|
|
||||||
// candidates, e.g. for a trait goal, as in this case `candidates` is
|
|
||||||
// actually supposed to be empty.
|
|
||||||
inspect::ProbeKind::Root { result }
|
inspect::ProbeKind::Root { result }
|
||||||
| inspect::ProbeKind::TryNormalizeNonRigid { result } => {
|
| inspect::ProbeKind::TryNormalizeNonRigid { result }
|
||||||
if candidates.len() == num_candidates {
|
| inspect::ProbeKind::TraitCandidate { source: _, result }
|
||||||
|
| inspect::ProbeKind::OpaqueTypeStorageLookup { result } => {
|
||||||
|
// We only add a candidate if `shallow_certainty` was set, which means
|
||||||
|
// that we ended up calling `evaluate_added_goals_and_make_canonical_response`.
|
||||||
|
if let Some(shallow_certainty) = shallow_certainty {
|
||||||
candidates.push(InspectCandidate {
|
candidates.push(InspectCandidate {
|
||||||
goal: self,
|
goal: self,
|
||||||
kind: probe.kind,
|
kind: probe.kind,
|
||||||
nested_goals: nested_goals.clone(),
|
nested_goals: nested_goals.clone(),
|
||||||
final_state: probe.final_state,
|
final_state: probe.final_state,
|
||||||
result,
|
result,
|
||||||
candidate_certainty,
|
shallow_certainty,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inspect::ProbeKind::MiscCandidate { name: _, result }
|
|
||||||
| inspect::ProbeKind::TraitCandidate { source: _, result } => {
|
|
||||||
candidates.push(InspectCandidate {
|
|
||||||
goal: self,
|
|
||||||
kind: probe.kind,
|
|
||||||
nested_goals: nested_goals.clone(),
|
|
||||||
final_state: probe.final_state,
|
|
||||||
result,
|
|
||||||
candidate_certainty,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,10 @@ use rustc_hir::def_id::DefId;
|
|||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::solve::inspect::ProbeKind;
|
use rustc_infer::traits::solve::inspect::ProbeKind;
|
||||||
|
use rustc_infer::traits::solve::MaybeCause;
|
||||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||||
use rustc_infer::traits::Reveal;
|
use rustc_infer::traits::Reveal;
|
||||||
use rustc_middle::traits::solve::{
|
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||||
CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
|
|
||||||
};
|
|
||||||
use rustc_middle::traits::BuiltinImplSource;
|
use rustc_middle::traits::BuiltinImplSource;
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
use rustc_middle::ty::NormalizesTo;
|
use rustc_middle::ty::NormalizesTo;
|
||||||
@ -119,14 +118,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
fn probe_and_match_goal_against_assumption(
|
fn probe_and_match_goal_against_assumption(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Clause<'tcx>,
|
assumption: ty::Clause<'tcx>,
|
||||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if let Some(projection_pred) = assumption.as_projection_clause() {
|
if let Some(projection_pred) = assumption.as_projection_clause() {
|
||||||
if projection_pred.projection_def_id() == goal.predicate.def_id() {
|
if projection_pred.projection_def_id() == goal.predicate.def_id() {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
ecx.probe_misc_candidate("assumption").enter(|ecx| {
|
ecx.probe_trait_candidate(source).enter(|ecx| {
|
||||||
let assumption_projection_pred =
|
let assumption_projection_pred =
|
||||||
ecx.instantiate_binder_with_infer(projection_pred);
|
ecx.instantiate_binder_with_infer(projection_pred);
|
||||||
ecx.eq(
|
ecx.eq(
|
||||||
@ -300,14 +300,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_error_guaranteed_candidate(
|
fn consider_error_guaranteed_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
_guar: ErrorGuaranteed,
|
_guar: ErrorGuaranteed,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_auto_trait_candidate(
|
fn consider_auto_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
ecx.tcx().dcx().span_delayed_bug(
|
ecx.tcx().dcx().span_delayed_bug(
|
||||||
ecx.tcx().def_span(goal.predicate.def_id()),
|
ecx.tcx().def_span(goal.predicate.def_id()),
|
||||||
"associated types not allowed on auto traits",
|
"associated types not allowed on auto traits",
|
||||||
@ -318,35 +318,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_trait_alias_candidate(
|
fn consider_trait_alias_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("trait aliases do not have associated types: {:?}", goal);
|
bug!("trait aliases do not have associated types: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_sized_candidate(
|
fn consider_builtin_sized_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`Sized` does not have an associated type: {:?}", goal);
|
bug!("`Sized` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_copy_clone_candidate(
|
fn consider_builtin_copy_clone_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_pointer_like_candidate(
|
fn consider_builtin_pointer_like_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`PointerLike` does not have an associated type: {:?}", goal);
|
bug!("`PointerLike` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`FnPtr` does not have an associated type: {:?}", goal);
|
bug!("`FnPtr` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +354,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
let tupled_inputs_and_output =
|
let tupled_inputs_and_output =
|
||||||
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||||
@ -364,8 +364,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
)? {
|
)? {
|
||||||
Some(tupled_inputs_and_output) => tupled_inputs_and_output,
|
Some(tupled_inputs_and_output) => tupled_inputs_and_output,
|
||||||
None => {
|
None => {
|
||||||
return ecx
|
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||||
@ -385,14 +384,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
// A built-in `Fn` impl only holds if the output is sized.
|
// A built-in `Fn` impl only holds if the output is sized.
|
||||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
|
Self::probe_and_consider_implied_clause(
|
||||||
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
|
goal,
|
||||||
|
pred,
|
||||||
|
[goal.with(tcx, output_is_sized_pred)],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_fn_trait_candidates(
|
fn consider_builtin_async_fn_trait_candidates(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
|
|
||||||
let env_region = match goal_kind {
|
let env_region = match goal_kind {
|
||||||
@ -461,8 +466,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
pred,
|
pred,
|
||||||
[goal.with(tcx, output_is_sized_pred)]
|
[goal.with(tcx, output_is_sized_pred)]
|
||||||
@ -474,7 +480,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let [
|
let [
|
||||||
closure_fn_kind_ty,
|
closure_fn_kind_ty,
|
||||||
goal_kind_ty,
|
goal_kind_ty,
|
||||||
@ -489,7 +495,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
// Bail if the upvars haven't been constrained.
|
// Bail if the upvars haven't been constrained.
|
||||||
if tupled_upvars_ty.expect_ty().is_ty_var() {
|
if tupled_upvars_ty.expect_ty().is_ty_var() {
|
||||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
||||||
@ -512,25 +518,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
borrow_region.expect_region(),
|
borrow_region.expect_region(),
|
||||||
);
|
);
|
||||||
|
|
||||||
ecx.instantiate_normalizes_to_term(goal, upvars_ty.into());
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.instantiate_normalizes_to_term(goal, upvars_ty.into());
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_tuple_candidate(
|
fn consider_builtin_tuple_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_pointee_candidate(
|
fn consider_builtin_pointee_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
|
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
|
||||||
assert_eq!(metadata_def_id, goal.predicate.def_id());
|
assert_eq!(metadata_def_id, goal.predicate.def_id());
|
||||||
ecx.probe_misc_candidate("builtin pointee").enter(|ecx| {
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
let metadata_ty = match goal.predicate.self_ty().kind() {
|
let metadata_ty = match goal.predicate.self_ty().kind() {
|
||||||
ty::Bool
|
ty::Bool
|
||||||
| ty::Char
|
| ty::Char
|
||||||
@ -609,7 +617,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_future_candidate(
|
fn consider_builtin_future_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
@ -623,8 +631,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
let term = args.as_coroutine().return_ty().into();
|
let term = args.as_coroutine().return_ty().into();
|
||||||
|
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
ty::ProjectionPredicate {
|
ty::ProjectionPredicate {
|
||||||
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
||||||
@ -640,7 +649,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_iterator_candidate(
|
fn consider_builtin_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
@ -654,8 +663,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
|
|
||||||
let term = args.as_coroutine().yield_ty().into();
|
let term = args.as_coroutine().yield_ty().into();
|
||||||
|
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
ty::ProjectionPredicate {
|
ty::ProjectionPredicate {
|
||||||
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
|
||||||
@ -671,14 +681,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_fused_iterator_candidate(
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
|
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
@ -690,7 +700,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_misc_candidate("builtin AsyncIterator kind").enter(|ecx| {
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
let expected_ty = ecx.next_ty_infer();
|
let expected_ty = ecx.next_ty_infer();
|
||||||
// Take `AsyncIterator<Item = I>` and turn it into the corresponding
|
// Take `AsyncIterator<Item = I>` and turn it into the corresponding
|
||||||
// coroutine yield ty `Poll<Option<I>>`.
|
// coroutine yield ty `Poll<Option<I>>`.
|
||||||
@ -714,7 +724,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_coroutine_candidate(
|
fn consider_builtin_coroutine_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
@ -737,8 +747,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
|
bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
ty::ProjectionPredicate {
|
ty::ProjectionPredicate {
|
||||||
projection_ty: ty::AliasTy::new(
|
projection_ty: ty::AliasTy::new(
|
||||||
@ -758,14 +769,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_structural_builtin_unsize_candidates(
|
fn consider_structural_builtin_unsize_candidates(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
) -> Vec<Candidate<'tcx>> {
|
||||||
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_discriminant_kind_candidate(
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let discriminant_ty = match *self_ty.kind() {
|
let discriminant_ty = match *self_ty.kind() {
|
||||||
ty::Bool
|
ty::Bool
|
||||||
@ -808,7 +819,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
ecx.probe_misc_candidate("builtin discriminant kind").enter(|ecx| {
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
ecx.instantiate_normalizes_to_term(goal, discriminant_ty.into());
|
ecx.instantiate_normalizes_to_term(goal, discriminant_ty.into());
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
})
|
})
|
||||||
@ -817,7 +828,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_async_destruct_candidate(
|
fn consider_builtin_async_destruct_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
let async_destructor_ty = match *self_ty.kind() {
|
let async_destructor_ty = match *self_ty.kind() {
|
||||||
ty::Bool
|
ty::Bool
|
||||||
@ -860,7 +871,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
ecx.probe_misc_candidate("builtin async destruct").enter(|ecx| {
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
ecx.eq(goal.param_env, goal.predicate.term, async_destructor_ty.into())
|
ecx.eq(goal.param_env, goal.predicate.term, async_destructor_ty.into())
|
||||||
.expect("expected goal term to be fully unconstrained");
|
.expect("expected goal term to be fully unconstrained");
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
@ -870,14 +881,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
fn consider_builtin_destruct_candidate(
|
fn consider_builtin_destruct_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_transmute_candidate(
|
fn consider_builtin_transmute_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,9 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{LangItem, Movability};
|
use rustc_hir::{LangItem, Movability};
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
use rustc_infer::traits::solve::MaybeCause;
|
||||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||||
use rustc_middle::traits::solve::{
|
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||||
CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
|
|
||||||
};
|
|
||||||
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||||
@ -94,21 +93,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_error_guaranteed_candidate(
|
fn consider_error_guaranteed_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
_guar: ErrorGuaranteed,
|
_guar: ErrorGuaranteed,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME: don't need to enter a probe here.
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn probe_and_match_goal_against_assumption(
|
fn probe_and_match_goal_against_assumption(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
assumption: ty::Clause<'tcx>,
|
assumption: ty::Clause<'tcx>,
|
||||||
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if let Some(trait_clause) = assumption.as_trait_clause() {
|
if let Some(trait_clause) = assumption.as_trait_clause() {
|
||||||
if trait_clause.def_id() == goal.predicate.def_id()
|
if trait_clause.def_id() == goal.predicate.def_id()
|
||||||
&& trait_clause.polarity() == goal.predicate.polarity
|
&& trait_clause.polarity() == goal.predicate.polarity
|
||||||
{
|
{
|
||||||
ecx.probe_misc_candidate("assumption").enter(|ecx| {
|
ecx.probe_trait_candidate(source).enter(|ecx| {
|
||||||
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
|
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
|
||||||
ecx.eq(
|
ecx.eq(
|
||||||
goal.param_env,
|
goal.param_env,
|
||||||
@ -128,7 +130,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_auto_trait_candidate(
|
fn consider_auto_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -162,6 +164,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
structural_traits::instantiate_constituent_tys_for_auto_trait,
|
structural_traits::instantiate_constituent_tys_for_auto_trait,
|
||||||
)
|
)
|
||||||
@ -170,14 +173,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_trait_alias_candidate(
|
fn consider_trait_alias_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = ecx.tcx();
|
let tcx = ecx.tcx();
|
||||||
|
|
||||||
ecx.probe_misc_candidate("trait alias").enter(|ecx| {
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
let nested_obligations = tcx
|
let nested_obligations = tcx
|
||||||
.predicates_of(goal.predicate.def_id())
|
.predicates_of(goal.predicate.def_id())
|
||||||
.instantiate(tcx, goal.predicate.trait_ref.args);
|
.instantiate(tcx, goal.predicate.trait_ref.args);
|
||||||
@ -193,12 +196,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_sized_candidate(
|
fn consider_builtin_sized_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
structural_traits::instantiate_constituent_tys_for_sized_trait,
|
structural_traits::instantiate_constituent_tys_for_sized_trait,
|
||||||
)
|
)
|
||||||
@ -207,12 +211,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_copy_clone_candidate(
|
fn consider_builtin_copy_clone_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
ecx.probe_and_evaluate_goal_for_constituent_tys(
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
|
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
|
||||||
)
|
)
|
||||||
@ -221,7 +226,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_pointer_like_candidate(
|
fn consider_builtin_pointer_like_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -234,14 +239,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
|
let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
|
||||||
// But if there are inference variables, we have to wait until it's resolved.
|
// But if there are inference variables, we have to wait until it's resolved.
|
||||||
if key.has_non_region_infer() {
|
if key.has_non_region_infer() {
|
||||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(layout) = tcx.layout_of(key)
|
if let Ok(layout) = tcx.layout_of(key)
|
||||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
||||||
{
|
{
|
||||||
// FIXME: We could make this faster by making a no-constraints response
|
// FIXME: We could make this faster by making a no-constraints response
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
@ -250,13 +256,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
match goal.predicate.polarity {
|
match goal.predicate.polarity {
|
||||||
// impl FnPtr for FnPtr {}
|
// impl FnPtr for FnPtr {}
|
||||||
ty::PredicatePolarity::Positive => {
|
ty::PredicatePolarity::Positive => {
|
||||||
if self_ty.is_fn_ptr() {
|
if self_ty.is_fn_ptr() {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
@ -266,7 +274,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// If a type is rigid and not a fn ptr, then we know for certain
|
// If a type is rigid and not a fn ptr, then we know for certain
|
||||||
// that it does *not* implement `FnPtr`.
|
// that it does *not* implement `FnPtr`.
|
||||||
if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
|
if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
@ -278,7 +288,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -292,8 +302,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
)? {
|
)? {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
None => {
|
None => {
|
||||||
return ecx
|
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||||
@ -307,14 +316,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
.to_predicate(tcx);
|
.to_predicate(tcx);
|
||||||
// A built-in `Fn` impl only holds if the output is sized.
|
// A built-in `Fn` impl only holds if the output is sized.
|
||||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)])
|
Self::probe_and_consider_implied_clause(
|
||||||
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
|
goal,
|
||||||
|
pred,
|
||||||
|
[goal.with(tcx, output_is_sized_pred)],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_fn_trait_candidates(
|
fn consider_builtin_async_fn_trait_candidates(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -345,8 +360,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
.to_predicate(tcx);
|
.to_predicate(tcx);
|
||||||
// A built-in `AsyncFn` impl only holds if the output is sized.
|
// A built-in `AsyncFn` impl only holds if the output is sized.
|
||||||
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
// (FIXME: technically we only need to check this if the type is a fn ptr...)
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
pred,
|
pred,
|
||||||
[goal.with(tcx, output_is_sized_pred)]
|
[goal.with(tcx, output_is_sized_pred)]
|
||||||
@ -358,7 +374,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
|
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
|
||||||
bug!();
|
bug!();
|
||||||
};
|
};
|
||||||
@ -369,7 +385,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
};
|
};
|
||||||
let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
|
let goal_kind = goal_kind_ty.expect_ty().to_opt_closure_kind().unwrap();
|
||||||
if closure_kind.extends(goal_kind) {
|
if closure_kind.extends(goal_kind) {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
@ -384,13 +401,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_tuple_candidate(
|
fn consider_builtin_tuple_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
|
if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
@ -399,18 +417,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_pointee_candidate(
|
fn consider_builtin_pointee_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_future_candidate(
|
fn consider_builtin_future_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -428,13 +447,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// Async coroutine unconditionally implement `Future`
|
// Async coroutine unconditionally implement `Future`
|
||||||
// Technically, we need to check that the future output type is Sized,
|
// Technically, we need to check that the future output type is Sized,
|
||||||
// but that's already proven by the coroutine being WF.
|
// but that's already proven by the coroutine being WF.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME: use `consider_implied`
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_iterator_candidate(
|
fn consider_builtin_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -452,13 +473,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// Gen coroutines unconditionally implement `Iterator`
|
// Gen coroutines unconditionally implement `Iterator`
|
||||||
// Technically, we need to check that the iterator output type is Sized,
|
// Technically, we need to check that the iterator output type is Sized,
|
||||||
// but that's already proven by the coroutines being WF.
|
// but that's already proven by the coroutines being WF.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME: use `consider_implied`
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_fused_iterator_candidate(
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -474,13 +497,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gen coroutines unconditionally implement `FusedIterator`
|
// Gen coroutines unconditionally implement `FusedIterator`
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME: use `consider_implied`
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -498,13 +523,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// Gen coroutines unconditionally implement `Iterator`
|
// Gen coroutines unconditionally implement `Iterator`
|
||||||
// Technically, we need to check that the iterator output type is Sized,
|
// Technically, we need to check that the iterator output type is Sized,
|
||||||
// but that's already proven by the coroutines being WF.
|
// but that's already proven by the coroutines being WF.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
// FIXME: use `consider_implied`
|
||||||
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_coroutine_candidate(
|
fn consider_builtin_coroutine_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -521,8 +548,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let coroutine = args.as_coroutine();
|
let coroutine = args.as_coroutine();
|
||||||
Self::consider_implied_clause(
|
Self::probe_and_consider_implied_clause(
|
||||||
ecx,
|
ecx,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
goal,
|
goal,
|
||||||
ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
|
ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
|
||||||
.to_predicate(tcx),
|
.to_predicate(tcx),
|
||||||
@ -535,31 +563,33 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_builtin_discriminant_kind_candidate(
|
fn consider_builtin_discriminant_kind_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `DiscriminantKind` is automatically implemented for every type.
|
// `DiscriminantKind` is automatically implemented for every type.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_destruct_candidate(
|
fn consider_builtin_async_destruct_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
// `AsyncDestruct` is automatically implemented for every type.
|
// `AsyncDestruct` is automatically implemented for every type.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_destruct_candidate(
|
fn consider_builtin_destruct_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -568,13 +598,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
|
|
||||||
// `Destruct` is automatically implemented for every type in
|
// `Destruct` is automatically implemented for every type in
|
||||||
// non-const environments.
|
// non-const environments.
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_transmute_candidate(
|
fn consider_builtin_transmute_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
@ -594,11 +625,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
};
|
};
|
||||||
|
|
||||||
let certainty = ecx.is_transmutable(
|
// FIXME: This actually should destructure the `Result` we get from transmutability and
|
||||||
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
|
// register candiates. We probably need to register >1 since we may have an OR of ANDs.
|
||||||
assume,
|
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
)?;
|
let certainty = ecx.is_transmutable(
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
|
||||||
|
assume,
|
||||||
|
)?;
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```ignore (builtin impl example)
|
/// ```ignore (builtin impl example)
|
||||||
@ -611,20 +646,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
fn consider_structural_builtin_unsize_candidates(
|
fn consider_structural_builtin_unsize_candidates(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
) -> Vec<Candidate<'tcx>> {
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
let misc_candidate = |ecx: &mut EvalCtxt<'_, 'tcx>, certainty| {
|
let result_to_single = |result| match result {
|
||||||
(
|
Ok(resp) => vec![resp],
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty).unwrap(),
|
|
||||||
BuiltinImplSource::Misc,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let result_to_single = |result, source| match result {
|
|
||||||
Ok(resp) => vec![(resp, source)],
|
|
||||||
Err(NoSolution) => vec![],
|
Err(NoSolution) => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -642,7 +670,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
|
let goal = goal.with(ecx.tcx(), (a_ty, b_ty));
|
||||||
match (a_ty.kind(), b_ty.kind()) {
|
match (a_ty.kind(), b_ty.kind()) {
|
||||||
(ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
|
(ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
|
||||||
(_, ty::Infer(ty::TyVar(..))) => vec![misc_candidate(ecx, Certainty::AMBIGUOUS)],
|
|
||||||
|
(_, ty::Infer(ty::TyVar(..))) => {
|
||||||
|
result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
|
||||||
|
}
|
||||||
|
|
||||||
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
|
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
|
||||||
(
|
(
|
||||||
@ -655,14 +686,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
// `T` -> `dyn Trait` unsizing.
|
// `T` -> `dyn Trait` unsizing.
|
||||||
(_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
|
(_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
|
||||||
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
|
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
|
||||||
BuiltinImplSource::Misc,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
// `[T; N]` -> `[T]` unsizing
|
// `[T; N]` -> `[T]` unsizing
|
||||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => result_to_single(
|
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
||||||
ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty),
|
result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
|
||||||
BuiltinImplSource::Misc,
|
}
|
||||||
),
|
|
||||||
|
|
||||||
// `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
// `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
||||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
||||||
@ -670,7 +699,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
{
|
{
|
||||||
result_to_single(
|
result_to_single(
|
||||||
ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
|
ecx.consider_builtin_struct_unsize(goal, a_def, a_args, b_args),
|
||||||
BuiltinImplSource::Misc,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,10 +706,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
|
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
|
||||||
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
|
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
|
||||||
{
|
{
|
||||||
result_to_single(
|
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
|
||||||
ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys),
|
|
||||||
BuiltinImplSource::TupleUnsizing,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
@ -707,7 +732,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
a_region: ty::Region<'tcx>,
|
a_region: ty::Region<'tcx>,
|
||||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
b_region: ty::Region<'tcx>,
|
b_region: ty::Region<'tcx>,
|
||||||
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
|
) -> Vec<Candidate<'tcx>> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
||||||
|
|
||||||
@ -715,35 +740,32 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// If the principal def ids match (or are both none), then we're not doing
|
// If the principal def ids match (or are both none), then we're not doing
|
||||||
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
// trait upcasting. We're just removing auto traits (or shortening the lifetime).
|
||||||
if a_data.principal_def_id() == b_data.principal_def_id() {
|
if a_data.principal_def_id() == b_data.principal_def_id() {
|
||||||
if let Ok(resp) = self.consider_builtin_upcast_to_principal(
|
responses.extend(self.consider_builtin_upcast_to_principal(
|
||||||
goal,
|
goal,
|
||||||
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||||
a_data,
|
a_data,
|
||||||
a_region,
|
a_region,
|
||||||
b_data,
|
b_data,
|
||||||
b_region,
|
b_region,
|
||||||
a_data.principal(),
|
a_data.principal(),
|
||||||
) {
|
));
|
||||||
responses.push((resp, BuiltinImplSource::Misc));
|
|
||||||
}
|
|
||||||
} else if let Some(a_principal) = a_data.principal() {
|
} else if let Some(a_principal) = a_data.principal() {
|
||||||
self.walk_vtable(
|
self.walk_vtable(
|
||||||
a_principal.with_self_ty(tcx, a_ty),
|
a_principal.with_self_ty(tcx, a_ty),
|
||||||
|ecx, new_a_principal, _, vtable_vptr_slot| {
|
|ecx, new_a_principal, _, vtable_vptr_slot| {
|
||||||
if let Ok(resp) = ecx.probe_misc_candidate("dyn upcast").enter(|ecx| {
|
responses.extend(ecx.consider_builtin_upcast_to_principal(
|
||||||
ecx.consider_builtin_upcast_to_principal(
|
goal,
|
||||||
goal,
|
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting {
|
||||||
a_data,
|
vtable_vptr_slot,
|
||||||
a_region,
|
}),
|
||||||
b_data,
|
a_data,
|
||||||
b_region,
|
a_region,
|
||||||
Some(new_a_principal.map_bound(|trait_ref| {
|
b_data,
|
||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
b_region,
|
||||||
})),
|
Some(new_a_principal.map_bound(|trait_ref| {
|
||||||
)
|
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||||
}) {
|
})),
|
||||||
responses
|
));
|
||||||
.push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -756,7 +778,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
b_region: ty::Region<'tcx>,
|
b_region: ty::Region<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let Goal { predicate: (a_ty, _), .. } = goal;
|
let Goal { predicate: (a_ty, _), .. } = goal;
|
||||||
|
|
||||||
@ -765,37 +787,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the type implements all of the predicates of the trait object.
|
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
// Check that the type implements all of the predicates of the trait object.
|
||||||
self.add_goals(
|
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||||
GoalSource::ImplWhereBound,
|
ecx.add_goals(
|
||||||
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
|
||||||
);
|
|
||||||
|
|
||||||
// The type must be `Sized` to be unsized.
|
|
||||||
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
|
||||||
self.add_goal(
|
|
||||||
GoalSource::ImplWhereBound,
|
GoalSource::ImplWhereBound,
|
||||||
goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
|
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return Err(NoSolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
// The type must be `Sized` to be unsized.
|
||||||
self.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.add_goal(
|
||||||
|
GoalSource::ImplWhereBound,
|
||||||
|
goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
||||||
|
ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_upcast_to_principal(
|
fn consider_builtin_upcast_to_principal(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||||
|
source: CandidateSource,
|
||||||
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
a_region: ty::Region<'tcx>,
|
a_region: ty::Region<'tcx>,
|
||||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||||
b_region: ty::Region<'tcx>,
|
b_region: ty::Region<'tcx>,
|
||||||
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let param_env = goal.param_env;
|
let param_env = goal.param_env;
|
||||||
|
|
||||||
// We may upcast to auto traits that are either explicitly listed in
|
// We may upcast to auto traits that are either explicitly listed in
|
||||||
@ -814,7 +839,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// having any inference side-effects. We process obligations because
|
// having any inference side-effects. We process obligations because
|
||||||
// unification may initially succeed due to deferred projection equality.
|
// unification may initially succeed due to deferred projection equality.
|
||||||
let projection_may_match =
|
let projection_may_match =
|
||||||
|ecx: &mut Self,
|
|ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
source_projection: ty::PolyExistentialProjection<'tcx>,
|
source_projection: ty::PolyExistentialProjection<'tcx>,
|
||||||
target_projection: ty::PolyExistentialProjection<'tcx>| {
|
target_projection: ty::PolyExistentialProjection<'tcx>| {
|
||||||
source_projection.item_def_id() == target_projection.item_def_id()
|
source_projection.item_def_id() == target_projection.item_def_id()
|
||||||
@ -828,54 +853,60 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
.is_ok()
|
.is_ok()
|
||||||
};
|
};
|
||||||
|
|
||||||
for bound in b_data {
|
self.probe_trait_candidate(source).enter(|ecx| {
|
||||||
match bound.skip_binder() {
|
for bound in b_data {
|
||||||
// Check that a's supertrait (upcast_principal) is compatible
|
match bound.skip_binder() {
|
||||||
// with the target (b_ty).
|
// Check that a's supertrait (upcast_principal) is compatible
|
||||||
ty::ExistentialPredicate::Trait(target_principal) => {
|
// with the target (b_ty).
|
||||||
self.eq(param_env, upcast_principal.unwrap(), bound.rebind(target_principal))?;
|
ty::ExistentialPredicate::Trait(target_principal) => {
|
||||||
}
|
ecx.eq(
|
||||||
// Check that b_ty's projection is satisfied by exactly one of
|
param_env,
|
||||||
// a_ty's projections. First, we look through the list to see if
|
upcast_principal.unwrap(),
|
||||||
// any match. If not, error. Then, if *more* than one matches, we
|
bound.rebind(target_principal),
|
||||||
// return ambiguity. Otherwise, if exactly one matches, equate
|
)?;
|
||||||
// it with b_ty's projection.
|
|
||||||
ty::ExistentialPredicate::Projection(target_projection) => {
|
|
||||||
let target_projection = bound.rebind(target_projection);
|
|
||||||
let mut matching_projections =
|
|
||||||
a_data.projection_bounds().filter(|source_projection| {
|
|
||||||
projection_may_match(self, *source_projection, target_projection)
|
|
||||||
});
|
|
||||||
let Some(source_projection) = matching_projections.next() else {
|
|
||||||
return Err(NoSolution);
|
|
||||||
};
|
|
||||||
if matching_projections.next().is_some() {
|
|
||||||
return self.evaluate_added_goals_and_make_canonical_response(
|
|
||||||
Certainty::AMBIGUOUS,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
self.eq(param_env, source_projection, target_projection)?;
|
// Check that b_ty's projection is satisfied by exactly one of
|
||||||
}
|
// a_ty's projections. First, we look through the list to see if
|
||||||
// Check that b_ty's auto traits are present in a_ty's bounds.
|
// any match. If not, error. Then, if *more* than one matches, we
|
||||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
// return ambiguity. Otherwise, if exactly one matches, equate
|
||||||
if !a_auto_traits.contains(&def_id) {
|
// it with b_ty's projection.
|
||||||
return Err(NoSolution);
|
ty::ExistentialPredicate::Projection(target_projection) => {
|
||||||
|
let target_projection = bound.rebind(target_projection);
|
||||||
|
let mut matching_projections =
|
||||||
|
a_data.projection_bounds().filter(|source_projection| {
|
||||||
|
projection_may_match(ecx, *source_projection, target_projection)
|
||||||
|
});
|
||||||
|
let Some(source_projection) = matching_projections.next() else {
|
||||||
|
return Err(NoSolution);
|
||||||
|
};
|
||||||
|
if matching_projections.next().is_some() {
|
||||||
|
return ecx.evaluate_added_goals_and_make_canonical_response(
|
||||||
|
Certainty::AMBIGUOUS,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ecx.eq(param_env, source_projection, target_projection)?;
|
||||||
|
}
|
||||||
|
// Check that b_ty's auto traits are present in a_ty's bounds.
|
||||||
|
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||||
|
if !a_auto_traits.contains(&def_id) {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
||||||
self.add_goal(
|
ecx.add_goal(
|
||||||
GoalSource::ImplWhereBound,
|
GoalSource::ImplWhereBound,
|
||||||
Goal::new(
|
Goal::new(
|
||||||
self.tcx(),
|
ecx.tcx(),
|
||||||
param_env,
|
param_env,
|
||||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We have the following builtin impls for arrays:
|
/// We have the following builtin impls for arrays:
|
||||||
@ -891,9 +922,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||||
a_elem_ty: Ty<'tcx>,
|
a_elem_ty: Ty<'tcx>,
|
||||||
b_elem_ty: Ty<'tcx>,
|
b_elem_ty: Ty<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We generate a builtin `Unsize` impls for structs with generic parameters only
|
/// We generate a builtin `Unsize` impls for structs with generic parameters only
|
||||||
@ -915,7 +947,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
def: ty::AdtDef<'tcx>,
|
def: ty::AdtDef<'tcx>,
|
||||||
a_args: ty::GenericArgsRef<'tcx>,
|
a_args: ty::GenericArgsRef<'tcx>,
|
||||||
b_args: ty::GenericArgsRef<'tcx>,
|
b_args: ty::GenericArgsRef<'tcx>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||||
|
|
||||||
@ -957,7 +989,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We generate the following builtin impl for tuples of all sizes.
|
/// We generate the following builtin impl for tuples of all sizes.
|
||||||
@ -975,7 +1008,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||||
a_tys: &'tcx ty::List<Ty<'tcx>>,
|
a_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||||
b_tys: &'tcx ty::List<Ty<'tcx>>,
|
b_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||||
|
|
||||||
@ -999,7 +1032,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing)
|
||||||
|
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return `Some` if there is an impl (built-in or user provided) that may
|
// Return `Some` if there is an impl (built-in or user provided) that may
|
||||||
@ -1009,7 +1043,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
fn disqualify_auto_trait_candidate_due_to_possible_impl(
|
fn disqualify_auto_trait_candidate_due_to_possible_impl(
|
||||||
&mut self,
|
&mut self,
|
||||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
) -> Option<QueryResult<'tcx>> {
|
) -> Option<Result<Candidate<'tcx>, NoSolution>> {
|
||||||
let self_ty = goal.predicate.self_ty();
|
let self_ty = goal.predicate.self_ty();
|
||||||
match *self_ty.kind() {
|
match *self_ty.kind() {
|
||||||
// Stall int and float vars until they are resolved to a concrete
|
// Stall int and float vars until they are resolved to a concrete
|
||||||
@ -1018,7 +1052,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
// we probably don't want to treat an `impl !AutoTrait for i32` as
|
// we probably don't want to treat an `impl !AutoTrait for i32` as
|
||||||
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
|
// disqualifying the built-in auto impl for `i64: AutoTrait` either.
|
||||||
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
|
||||||
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS))
|
Some(self.forced_ambiguity(MaybeCause::Ambiguity))
|
||||||
}
|
}
|
||||||
|
|
||||||
// These types cannot be structurally decomposed into constituent
|
// These types cannot be structurally decomposed into constituent
|
||||||
@ -1039,9 +1073,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
{
|
{
|
||||||
match self.tcx().coroutine_movability(def_id) {
|
match self.tcx().coroutine_movability(def_id) {
|
||||||
Movability::Static => Some(Err(NoSolution)),
|
Movability::Static => Some(Err(NoSolution)),
|
||||||
Movability::Movable => {
|
Movability::Movable => Some(
|
||||||
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||||
}
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
}),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1106,13 +1142,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
/// wrapped in one.
|
/// wrapped in one.
|
||||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
source: CandidateSource,
|
||||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||||
constituent_tys: impl Fn(
|
constituent_tys: impl Fn(
|
||||||
&EvalCtxt<'_, 'tcx>,
|
&EvalCtxt<'_, 'tcx>,
|
||||||
Ty<'tcx>,
|
Ty<'tcx>,
|
||||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
|
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
|
||||||
) -> QueryResult<'tcx> {
|
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||||
self.probe_misc_candidate("constituent tys").enter(|ecx| {
|
self.probe_trait_candidate(source).enter(|ecx| {
|
||||||
ecx.add_goals(
|
ecx.add_goals(
|
||||||
GoalSource::ImplWhereBound,
|
GoalSource::ImplWhereBound,
|
||||||
constituent_tys(ecx, goal.predicate.self_ty())?
|
constituent_tys(ecx, goal.predicate.self_ty())?
|
||||||
|
@ -1078,9 +1078,8 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
|
|||||||
// Add ambiguity causes for unknowable goals.
|
// Add ambiguity causes for unknowable goals.
|
||||||
let mut ambiguity_cause = None;
|
let mut ambiguity_cause = None;
|
||||||
for cand in goal.candidates() {
|
for cand in goal.candidates() {
|
||||||
// FIXME: boiiii, using string comparisions here sure is scuffed.
|
if let inspect::ProbeKind::TraitCandidate {
|
||||||
if let inspect::ProbeKind::MiscCandidate {
|
source: CandidateSource::CoherenceUnknowable,
|
||||||
name: "coherence unknowable",
|
|
||||||
result: Ok(_),
|
result: Ok(_),
|
||||||
} = cand.kind()
|
} = cand.kind()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user