Skip to content

Commit

Permalink
Rollup merge of rust-lang#107282 - BoxyUwU:erica_builtin_pointee_impl…
Browse files Browse the repository at this point in the history
…s, r=compiler-errors

erica solver: implement builtin `Pointee` trait impl candidates

r? `@compiler-errors`
  • Loading branch information
matthiaskrgr committed Jan 25, 2023
2 parents 2c432b6 + a418e39 commit 6c440bf
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
7 changes: 7 additions & 0 deletions compiler/rustc_trait_selection/src/solve/assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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)
};
Expand Down
91 changes: 91 additions & 0 deletions compiler/rustc_trait_selection/src/solve/project_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -391,6 +392,96 @@ 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(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.
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_trait_selection/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/traits/new-solver/pointee.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 6c440bf

Please sign in to comment.