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>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
fn consider_builtin_pointee_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
@ -259,6 +264,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
G::consider_builtin_fn_trait_candidates(self, goal, kind)
|
G::consider_builtin_fn_trait_candidates(self, goal, kind)
|
||||||
} else if lang_items.tuple_trait() == Some(trait_def_id) {
|
} else if lang_items.tuple_trait() == Some(trait_def_id) {
|
||||||
G::consider_builtin_tuple_candidate(self, goal)
|
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 {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@ use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_hir::LangItem;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_infer::traits::specialization_graph::LeafDef;
|
use rustc_infer::traits::specialization_graph::LeafDef;
|
||||||
|
@ -391,6 +392,97 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
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.
|
/// 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)
|
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> {
|
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