implement builtin candidate
This commit is contained in:
parent
c8e6a9e8b6
commit
430dab0b42
4 changed files with 129 additions and 0 deletions
|
@ -133,6 +133,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
|||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
@ -259,6 +264,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
G::consider_builtin_fn_trait_candidates(self, goal, kind)
|
||||
} else if lang_items.tuple_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_tuple_candidate(self, goal)
|
||||
} else if lang_items.pointee_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_pointee_candidate(self, goal)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
|||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||
|
@ -391,6 +392,97 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let tcx = ecx.tcx();
|
||||
ecx.infcx.probe(|_| {
|
||||
let metadata_ty = match goal.predicate.self_ty().kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Array(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Ref(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Never
|
||||
| ty::Foreign(..) => tcx.types.unit,
|
||||
|
||||
ty::Error(e) => tcx.ty_error_with_guaranteed(*e),
|
||||
|
||||
ty::Str | ty::Slice(_) => tcx.types.usize,
|
||||
|
||||
ty::Dynamic(_, _, _) => {
|
||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
||||
tcx.bound_type_of(dyn_metadata)
|
||||
.subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
|
||||
}
|
||||
|
||||
ty::Infer(ty::TyVar(..)) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
|
||||
// FIXME(erica_solver, ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
|
||||
let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
|
||||
LangItem::Sized,
|
||||
[ty::GenericArg::from(goal.predicate.self_ty())],
|
||||
))
|
||||
.without_const();
|
||||
|
||||
let mut nested_goals = ecx.infcx.eq(
|
||||
goal.param_env,
|
||||
goal.predicate.term.ty().unwrap(),
|
||||
tcx.types.unit,
|
||||
)?;
|
||||
nested_goals.push(goal.with(tcx, sized_predicate));
|
||||
|
||||
return ecx.evaluate_all_and_make_canonical_response(nested_goals);
|
||||
}
|
||||
|
||||
ty::Adt(def, substs) if def.is_struct() => {
|
||||
match def.non_enum_variant().fields.last() {
|
||||
None => tcx.types.unit,
|
||||
Some(field_def) => {
|
||||
let self_ty = field_def.ty(tcx, substs);
|
||||
let new_goal = goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
|
||||
);
|
||||
return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]);
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Adt(_, _) => tcx.types.unit,
|
||||
|
||||
ty::Tuple(elements) => match elements.last() {
|
||||
None => tcx.types.unit,
|
||||
Some(&self_ty) => {
|
||||
let new_goal = goal.with(
|
||||
tcx,
|
||||
ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
|
||||
);
|
||||
return ecx.evaluate_all_and_make_canonical_response(vec![new_goal]);
|
||||
}
|
||||
},
|
||||
|
||||
ty::Infer(ty::FreshTy(..) | ty::FreshIntTy(..) | ty::FreshFloatTy(..))
|
||||
| ty::Bound(..) => bug!(
|
||||
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
|
||||
goal.predicate.self_ty()
|
||||
),
|
||||
};
|
||||
|
||||
let nested_goals =
|
||||
ecx.infcx.eq(goal.param_env, goal.predicate.term.ty().unwrap(), metadata_ty)?;
|
||||
ecx.evaluate_all_and_make_canonical_response(nested_goals)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
||||
|
|
|
@ -185,6 +185,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
_goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
ecx.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
|
23
tests/ui/traits/new-solver/pointee.rs
Normal file
23
tests/ui/traits/new-solver/pointee.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// compile-flags: -Ztrait-solver=next
|
||||
// check-pass
|
||||
#![feature(ptr_metadata)]
|
||||
|
||||
use std::ptr::{DynMetadata, Pointee};
|
||||
|
||||
trait Trait<U> {}
|
||||
struct MyDst<T: ?Sized>(T);
|
||||
|
||||
fn works<T>() {
|
||||
let _: <T as Pointee>::Metadata = ();
|
||||
let _: <[T] as Pointee>::Metadata = 1_usize;
|
||||
let _: <str as Pointee>::Metadata = 1_usize;
|
||||
let _: <dyn Trait<T> as Pointee>::Metadata = give::<DynMetadata<dyn Trait<T>>>();
|
||||
let _: <MyDst<T> as Pointee>::Metadata = ();
|
||||
let _: <((((([u8],),),),),) as Pointee>::Metadata = 1_usize;
|
||||
}
|
||||
|
||||
fn give<U>() -> U {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in a new issue