Rollup merge of #107282 - BoxyUwU:erica_builtin_pointee_impls, r=compiler-errors

erica solver: implement builtin `Pointee` trait impl candidates

r? ```@compiler-errors```
This commit is contained in:
Matthias Krüger 2023-01-25 22:19:56 +01:00 committed by GitHub
commit a20b86f881
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 128 additions and 0 deletions

View File

@ -133,6 +133,11 @@ fn consider_builtin_tuple_candidate(
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 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'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)
};

View File

@ -7,6 +7,7 @@
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,96 @@ fn consider_builtin_tuple_candidate(
) -> 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(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())],
));
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.

View File

@ -185,6 +185,13 @@ fn consider_builtin_tuple_candidate(
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> {

View 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() {}