2023-07-04 21:43:21 +00:00
|
|
|
use rustc_hir as hir;
|
2023-06-21 01:22:43 +00:00
|
|
|
use rustc_hir::def_id::DefId;
|
2023-07-24 22:02:52 +00:00
|
|
|
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt};
|
2023-06-21 01:22:43 +00:00
|
|
|
use rustc_infer::traits::{
|
2023-07-07 20:42:37 +00:00
|
|
|
Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
|
2023-06-21 01:22:43 +00:00
|
|
|
};
|
2023-06-29 19:06:27 +00:00
|
|
|
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
|
2023-06-21 01:22:43 +00:00
|
|
|
use rustc_middle::traits::{
|
2023-07-24 22:02:52 +00:00
|
|
|
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError,
|
2023-06-21 01:22:43 +00:00
|
|
|
};
|
2023-07-04 21:43:21 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
2023-06-21 01:22:43 +00:00
|
|
|
use rustc_span::DUMMY_SP;
|
|
|
|
|
2023-07-24 22:02:52 +00:00
|
|
|
use crate::solve::assembly::{Candidate, CandidateSource};
|
2023-06-29 19:06:27 +00:00
|
|
|
use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
|
2023-06-21 01:22:43 +00:00
|
|
|
use crate::solve::inspect::ProofTreeBuilder;
|
2023-06-29 19:06:27 +00:00
|
|
|
use crate::solve::search_graph::OverflowHandler;
|
2023-07-07 20:42:37 +00:00
|
|
|
use crate::traits::StructurallyNormalizeExt;
|
|
|
|
use crate::traits::TraitEngineExt;
|
2023-06-21 01:22:43 +00:00
|
|
|
|
|
|
|
pub trait InferCtxtSelectExt<'tcx> {
|
|
|
|
fn select_in_new_trait_solver(
|
|
|
|
&self,
|
2023-07-03 21:42:31 +00:00
|
|
|
obligation: &PolyTraitObligation<'tcx>,
|
2023-06-21 01:22:43 +00:00
|
|
|
) -> SelectionResult<'tcx, Selection<'tcx>>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
|
|
|
fn select_in_new_trait_solver(
|
|
|
|
&self,
|
2023-07-03 21:42:31 +00:00
|
|
|
obligation: &PolyTraitObligation<'tcx>,
|
2023-06-21 01:22:43 +00:00
|
|
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
|
|
|
assert!(self.next_trait_solver());
|
|
|
|
|
2023-06-29 19:06:27 +00:00
|
|
|
let trait_goal = Goal::new(
|
2023-06-21 01:22:43 +00:00
|
|
|
self.tcx,
|
|
|
|
obligation.param_env,
|
|
|
|
self.instantiate_binder_with_placeholders(obligation.predicate),
|
|
|
|
);
|
|
|
|
|
2023-07-10 15:17:01 +02:00
|
|
|
let (result, _) = EvalCtxt::enter_root(self, GenerateProofTree::Never, |ecx| {
|
2023-06-29 19:06:27 +00:00
|
|
|
let goal = Goal::new(ecx.tcx(), trait_goal.param_env, trait_goal.predicate);
|
|
|
|
let (orig_values, canonical_goal) = ecx.canonicalize_goal(goal);
|
|
|
|
let mut candidates = ecx.compute_canonical_trait_candidates(canonical_goal);
|
|
|
|
|
|
|
|
// pseudo-winnow
|
|
|
|
if candidates.len() == 0 {
|
|
|
|
return Err(SelectionError::Unimplemented);
|
|
|
|
} else if candidates.len() > 1 {
|
|
|
|
let mut i = 0;
|
|
|
|
while i < candidates.len() {
|
|
|
|
let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| {
|
2023-07-04 18:06:41 +00:00
|
|
|
candidate_should_be_dropped_in_favor_of(
|
|
|
|
ecx.tcx(),
|
|
|
|
&candidates[i],
|
|
|
|
&candidates[j],
|
|
|
|
)
|
2023-06-29 19:06:27 +00:00
|
|
|
});
|
|
|
|
if should_drop_i {
|
|
|
|
candidates.swap_remove(i);
|
|
|
|
} else {
|
|
|
|
i += 1;
|
|
|
|
if i > 1 {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-29 19:06:27 +00:00
|
|
|
let candidate = candidates.pop().unwrap();
|
|
|
|
let (certainty, nested_goals) = ecx
|
|
|
|
.instantiate_and_apply_query_response(
|
|
|
|
trait_goal.param_env,
|
|
|
|
orig_values,
|
|
|
|
candidate.result,
|
|
|
|
)
|
|
|
|
.map_err(|_| SelectionError::Unimplemented)?;
|
|
|
|
|
|
|
|
Ok(Some((candidate, certainty, nested_goals)))
|
|
|
|
});
|
|
|
|
|
|
|
|
let (candidate, certainty, nested_goals) = match result {
|
|
|
|
Ok(Some((candidate, certainty, nested_goals))) => (candidate, certainty, nested_goals),
|
|
|
|
Ok(None) => return Ok(None),
|
|
|
|
Err(e) => return Err(e),
|
|
|
|
};
|
2023-06-21 01:22:43 +00:00
|
|
|
|
|
|
|
let nested_obligations: Vec<_> = nested_goals
|
|
|
|
.into_iter()
|
|
|
|
.map(|goal| {
|
|
|
|
Obligation::new(self.tcx, ObligationCause::dummy(), goal.param_env, goal.predicate)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2023-06-29 19:06:27 +00:00
|
|
|
let goal = self.resolve_vars_if_possible(trait_goal);
|
2023-06-21 01:22:43 +00:00
|
|
|
match (certainty, candidate.source) {
|
2023-06-29 19:06:27 +00:00
|
|
|
// Rematching the implementation will instantiate the same nested goals that
|
|
|
|
// would have caused the ambiguity, so we can still make progress here regardless.
|
2023-06-21 01:22:43 +00:00
|
|
|
(_, CandidateSource::Impl(def_id)) => {
|
|
|
|
rematch_impl(self, goal, def_id, nested_obligations)
|
|
|
|
}
|
|
|
|
|
2023-07-29 01:04:04 +00:00
|
|
|
// If an unsize goal is ambiguous, then we can manually rematch it to make
|
|
|
|
// selection progress for coercion during HIR typeck. If it is *not* ambiguous,
|
|
|
|
// but is `BuiltinImplSource::Misc`, it may have nested `Unsize` goals,
|
|
|
|
// and we need to rematch those to detect tuple unsizing and trait upcasting.
|
|
|
|
// FIXME: This will be wrong if we have param-env or where-clause bounds
|
|
|
|
// with the unsize goal -- we may need to mark those with different impl
|
|
|
|
// sources.
|
2023-07-24 22:02:52 +00:00
|
|
|
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
2023-07-29 01:04:04 +00:00
|
|
|
| (Certainty::Yes, CandidateSource::BuiltinImpl(src @ BuiltinImplSource::Misc))
|
2023-07-04 21:43:21 +00:00
|
|
|
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
|
|
|
|
{
|
2023-07-29 01:04:04 +00:00
|
|
|
rematch_unsize(self, goal, nested_obligations, src, certainty)
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
|
|
|
|
2023-06-29 19:06:27 +00:00
|
|
|
// Technically some builtin impls have nested obligations, but if
|
|
|
|
// `Certainty::Yes`, then they should've all been verified and don't
|
|
|
|
// need re-checking.
|
2023-07-24 22:02:52 +00:00
|
|
|
(Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
|
|
|
|
Ok(Some(ImplSource::Builtin(src, nested_obligations)))
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
|
2023-06-29 19:06:27 +00:00
|
|
|
// It's fine not to do anything to rematch these, since there are no
|
|
|
|
// nested obligations.
|
2023-06-21 01:22:43 +00:00
|
|
|
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
|
2023-07-24 22:02:52 +00:00
|
|
|
Ok(Some(ImplSource::Param(ty::BoundConstness::NotConst, nested_obligations)))
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
|
2023-07-24 22:02:52 +00:00
|
|
|
(Certainty::Maybe(_), _) => Ok(None),
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|
|
|
fn compute_canonical_trait_candidates(
|
|
|
|
&mut self,
|
2023-06-29 19:06:27 +00:00
|
|
|
canonical_input: CanonicalInput<'tcx>,
|
2023-06-21 01:22:43 +00:00
|
|
|
) -> Vec<Candidate<'tcx>> {
|
2023-06-29 19:06:27 +00:00
|
|
|
// This doesn't record the canonical goal on the stack during the
|
|
|
|
// candidate assembly step, but that's fine. Selection is conceptually
|
|
|
|
// outside of the solver, and if there were any cycles, we'd encounter
|
|
|
|
// the cycle anyways one step later.
|
|
|
|
EvalCtxt::enter_canonical(
|
|
|
|
self.tcx(),
|
|
|
|
self.search_graph(),
|
|
|
|
canonical_input,
|
|
|
|
// FIXME: This is wrong, idk if we even want to track stuff here.
|
|
|
|
&mut ProofTreeBuilder::new_noop(),
|
|
|
|
|ecx, goal| {
|
|
|
|
let trait_goal = Goal {
|
|
|
|
param_env: goal.param_env,
|
|
|
|
predicate: goal
|
|
|
|
.predicate
|
|
|
|
.to_opt_poly_trait_pred()
|
|
|
|
.expect("we canonicalized a trait goal")
|
|
|
|
.no_bound_vars()
|
|
|
|
.expect("we instantiated all bound vars"),
|
|
|
|
};
|
|
|
|
ecx.assemble_and_evaluate_candidates(trait_goal)
|
|
|
|
},
|
|
|
|
)
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn candidate_should_be_dropped_in_favor_of<'tcx>(
|
2023-07-04 18:06:41 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2023-06-21 01:22:43 +00:00
|
|
|
victim: &Candidate<'tcx>,
|
|
|
|
other: &Candidate<'tcx>,
|
|
|
|
) -> bool {
|
|
|
|
match (victim.source, other.source) {
|
2023-07-04 18:06:41 +00:00
|
|
|
(CandidateSource::ParamEnv(victim_idx), CandidateSource::ParamEnv(other_idx)) => {
|
|
|
|
victim_idx >= other_idx
|
|
|
|
}
|
2023-06-21 01:22:43 +00:00
|
|
|
(_, CandidateSource::ParamEnv(_)) => true,
|
2023-07-06 04:48:33 +00:00
|
|
|
|
2023-07-24 22:02:52 +00:00
|
|
|
// FIXME: we could prefer earlier vtable bases perhaps...
|
2023-07-06 04:48:33 +00:00
|
|
|
(
|
2023-07-24 22:02:52 +00:00
|
|
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
|
|
|
|
CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
|
2023-07-06 04:48:33 +00:00
|
|
|
) => false,
|
2023-07-24 22:02:52 +00:00
|
|
|
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. })) => true,
|
2023-07-06 04:48:33 +00:00
|
|
|
|
2023-07-04 18:06:41 +00:00
|
|
|
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
|
|
|
|
tcx.specializes((other_def_id, victim_def_id))
|
|
|
|
&& other.result.value.certainty == Certainty::Yes
|
|
|
|
}
|
2023-07-06 04:48:33 +00:00
|
|
|
|
2023-06-21 01:22:43 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rematch_impl<'tcx>(
|
|
|
|
infcx: &InferCtxt<'tcx>,
|
|
|
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
|
|
|
impl_def_id: DefId,
|
|
|
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
|
|
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
2023-07-11 22:35:29 +01:00
|
|
|
let args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
|
|
|
|
let impl_trait_ref =
|
|
|
|
infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args);
|
2023-06-21 01:22:43 +00:00
|
|
|
|
|
|
|
nested.extend(
|
|
|
|
infcx
|
|
|
|
.at(&ObligationCause::dummy(), goal.param_env)
|
|
|
|
.eq(DefineOpaqueTypes::No, goal.predicate.trait_ref, impl_trait_ref)
|
|
|
|
.map_err(|_| SelectionError::Unimplemented)?
|
|
|
|
.into_obligations(),
|
|
|
|
);
|
|
|
|
|
|
|
|
nested.extend(
|
2023-07-11 22:35:29 +01:00
|
|
|
infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map(
|
2023-06-21 01:22:43 +00:00
|
|
|
|(pred, _)| Obligation::new(infcx.tcx, ObligationCause::dummy(), goal.param_env, pred),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested })))
|
2023-06-21 01:22:43 +00:00
|
|
|
}
|
|
|
|
|
2023-07-04 21:43:21 +00:00
|
|
|
/// The `Unsize` trait is particularly important to coercion, so we try rematch it.
|
|
|
|
/// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait
|
|
|
|
/// goal assembly in the solver, both for soundness and in order to avoid ICEs.
|
|
|
|
fn rematch_unsize<'tcx>(
|
|
|
|
infcx: &InferCtxt<'tcx>,
|
|
|
|
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
|
|
|
mut nested: Vec<PredicateObligation<'tcx>>,
|
2023-07-24 22:02:52 +00:00
|
|
|
source: BuiltinImplSource,
|
2023-07-29 01:04:04 +00:00
|
|
|
certainty: Certainty,
|
2023-07-04 21:43:21 +00:00
|
|
|
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
|
|
|
let tcx = infcx.tcx;
|
2023-07-06 02:53:21 +00:00
|
|
|
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
|
|
|
|
let b_ty = structurally_normalize(
|
|
|
|
goal.predicate.trait_ref.args.type_at(1),
|
|
|
|
infcx,
|
|
|
|
goal.param_env,
|
|
|
|
&mut nested,
|
|
|
|
);
|
2023-07-04 21:43:21 +00:00
|
|
|
match (a_ty.kind(), b_ty.kind()) {
|
2023-07-29 01:04:04 +00:00
|
|
|
// Stall any ambiguous upcasting goals, since we can't rematch those
|
|
|
|
(ty::Dynamic(_, _, ty::Dyn), ty::Dynamic(_, _, ty::Dyn)) => match certainty {
|
|
|
|
Certainty::Yes => Ok(Some(ImplSource::Builtin(source, nested))),
|
|
|
|
_ => Ok(None),
|
|
|
|
},
|
|
|
|
// `T` -> `dyn Trait` upcasting
|
2023-07-04 21:43:21 +00:00
|
|
|
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
|
|
|
|
// Check that the type implements all of the predicates of the def-id.
|
|
|
|
// (i.e. the principal, all of the associated types match, and any auto traits)
|
|
|
|
nested.extend(data.iter().map(|pred| {
|
|
|
|
Obligation::new(
|
|
|
|
infcx.tcx,
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
goal.param_env,
|
|
|
|
pred.with_self_ty(tcx, a_ty),
|
|
|
|
)
|
|
|
|
}));
|
|
|
|
// The type must be Sized to be unsized.
|
|
|
|
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, None);
|
|
|
|
nested.push(Obligation::new(
|
|
|
|
infcx.tcx,
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
goal.param_env,
|
|
|
|
ty::TraitRef::new(tcx, sized_def_id, [a_ty]),
|
|
|
|
));
|
|
|
|
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
|
|
|
nested.push(Obligation::new(
|
|
|
|
infcx.tcx,
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
goal.param_env,
|
|
|
|
ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
|
|
|
|
));
|
2023-07-24 22:02:52 +00:00
|
|
|
|
|
|
|
Ok(Some(ImplSource::Builtin(source, nested)))
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
|
|
|
// `[T; n]` -> `[T]` unsizing
|
|
|
|
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
|
|
|
nested.extend(
|
|
|
|
infcx
|
|
|
|
.at(&ObligationCause::dummy(), goal.param_env)
|
|
|
|
.eq(DefineOpaqueTypes::No, a_elem_ty, b_elem_ty)
|
|
|
|
.expect("expected rematch to succeed")
|
|
|
|
.into_obligations(),
|
|
|
|
);
|
2023-07-24 22:02:52 +00:00
|
|
|
|
|
|
|
Ok(Some(ImplSource::Builtin(source, nested)))
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
|
|
|
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
2023-07-11 22:35:29 +01:00
|
|
|
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
2023-07-04 21:43:21 +00:00
|
|
|
if a_def.is_struct() && a_def.did() == b_def.did() =>
|
|
|
|
{
|
|
|
|
let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
|
|
|
|
// We must be unsizing some type parameters. This also implies
|
|
|
|
// that the struct has a tail field.
|
|
|
|
if unsizing_params.is_empty() {
|
|
|
|
bug!("expected rematch to succeed")
|
|
|
|
}
|
|
|
|
|
|
|
|
let tail_field = a_def
|
|
|
|
.non_enum_variant()
|
|
|
|
.fields
|
|
|
|
.raw
|
|
|
|
.last()
|
|
|
|
.expect("expected unsized ADT to have a tail field");
|
|
|
|
let tail_field_ty = tcx.type_of(tail_field.did);
|
|
|
|
|
2023-07-11 22:35:29 +01:00
|
|
|
let a_tail_ty = tail_field_ty.instantiate(tcx, a_args);
|
|
|
|
let b_tail_ty = tail_field_ty.instantiate(tcx, b_args);
|
2023-07-04 21:43:21 +00:00
|
|
|
|
|
|
|
// Substitute just the unsizing params from B into A. The type after
|
|
|
|
// this substitution must be equal to B. This is so we don't unsize
|
|
|
|
// unrelated type parameters.
|
2023-07-11 22:35:29 +01:00
|
|
|
let new_a_args = tcx.mk_args_from_iter(
|
|
|
|
a_args
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }),
|
|
|
|
);
|
|
|
|
let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_args);
|
2023-07-04 21:43:21 +00:00
|
|
|
|
|
|
|
nested.extend(
|
|
|
|
infcx
|
|
|
|
.at(&ObligationCause::dummy(), goal.param_env)
|
|
|
|
.eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
|
|
|
|
.expect("expected rematch to succeed")
|
|
|
|
.into_obligations(),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
|
|
|
|
// types.
|
|
|
|
nested.push(Obligation::new(
|
|
|
|
tcx,
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
goal.param_env,
|
|
|
|
ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
|
|
|
|
));
|
2023-07-24 22:02:52 +00:00
|
|
|
|
|
|
|
Ok(Some(ImplSource::Builtin(source, nested)))
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
|
|
|
// Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
|
|
|
|
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
|
|
|
|
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
|
|
|
|
{
|
|
|
|
let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
|
|
|
|
let b_last_ty = b_tys.last().unwrap();
|
|
|
|
|
|
|
|
// Substitute just the tail field of B., and require that they're equal.
|
|
|
|
let unsized_a_ty =
|
|
|
|
Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied());
|
|
|
|
nested.extend(
|
|
|
|
infcx
|
|
|
|
.at(&ObligationCause::dummy(), goal.param_env)
|
|
|
|
.eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
|
|
|
|
.expect("expected rematch to succeed")
|
|
|
|
.into_obligations(),
|
|
|
|
);
|
|
|
|
|
2023-07-28 12:54:56 +02:00
|
|
|
// Similar to ADTs, require that we can unsize the tail.
|
2023-07-04 21:43:21 +00:00
|
|
|
nested.push(Obligation::new(
|
|
|
|
tcx,
|
|
|
|
ObligationCause::dummy(),
|
|
|
|
goal.param_env,
|
|
|
|
ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
|
|
|
|
));
|
2023-07-16 22:42:46 +00:00
|
|
|
|
|
|
|
// We need to be able to detect tuple unsizing to require its feature gate.
|
2023-07-24 22:02:52 +00:00
|
|
|
assert_eq!(
|
|
|
|
source,
|
|
|
|
BuiltinImplSource::TupleUnsizing,
|
|
|
|
"compiler-errors wants to know if this can ever be triggered..."
|
|
|
|
);
|
|
|
|
Ok(Some(ImplSource::Builtin(source, nested)))
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
2023-07-29 01:04:04 +00:00
|
|
|
_ => {
|
|
|
|
assert_ne!(certainty, Certainty::Yes);
|
|
|
|
Ok(None)
|
|
|
|
}
|
2023-07-04 21:43:21 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-07 20:42:37 +00:00
|
|
|
|
|
|
|
fn structurally_normalize<'tcx>(
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
infcx: &InferCtxt<'tcx>,
|
|
|
|
param_env: ty::ParamEnv<'tcx>,
|
|
|
|
nested: &mut Vec<PredicateObligation<'tcx>>,
|
|
|
|
) -> Ty<'tcx> {
|
|
|
|
if matches!(ty.kind(), ty::Alias(..)) {
|
|
|
|
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx);
|
|
|
|
let normalized_ty = infcx
|
|
|
|
.at(&ObligationCause::dummy(), param_env)
|
|
|
|
.structurally_normalize(ty, &mut *engine)
|
|
|
|
.expect("normalization shouldn't fail if we got to here");
|
|
|
|
nested.extend(engine.pending_obligations());
|
|
|
|
normalized_ty
|
|
|
|
} else {
|
|
|
|
ty
|
|
|
|
}
|
|
|
|
}
|