1
Fork 0

Implement ~const Destruct in new solver

This commit is contained in:
Michael Goulet 2024-10-29 20:08:55 +00:00
parent a7d9ebdf08
commit 59408add4d
16 changed files with 266 additions and 74 deletions

View file

@ -12,7 +12,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use tracing::instrument;
use crate::delegate::SolverDelegate;
use crate::solve::{EvalCtxt, Goal, NoSolution};
use crate::solve::{AdtDestructorKind, EvalCtxt, Goal, NoSolution};
// Calculates the constituent types of a type for `auto trait` purposes.
#[instrument(level = "trace", skip(ecx), ret)]
@ -703,6 +703,78 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
}
}
pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
cx: I,
self_ty: I::Ty,
) -> Result<Vec<ty::TraitRef<I>>, NoSolution> {
let destruct_def_id = cx.require_lang_item(TraitSolverLangItem::Destruct);
match self_ty.kind() {
// An ADT is `~const Destruct` only if all of the fields are,
// *and* if there is a `Drop` impl, that `Drop` impl is also `~const`.
ty::Adt(adt_def, args) => {
let mut const_conditions: Vec<_> = adt_def
.all_field_tys(cx)
.iter_instantiated(cx, args)
.map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
.collect();
match adt_def.destructor(cx) {
// `Drop` impl exists, but it's not const. Type cannot be `~const Destruct`.
Some(AdtDestructorKind::NotConst) => return Err(NoSolution),
// `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
Some(AdtDestructorKind::Const) => {
let drop_def_id = cx.require_lang_item(TraitSolverLangItem::Drop);
let drop_trait_ref = ty::TraitRef::new(cx, drop_def_id, [self_ty]);
const_conditions.push(drop_trait_ref);
}
// No `Drop` impl, no need to require anything else.
None => {}
}
Ok(const_conditions)
}
ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
Ok(vec![ty::TraitRef::new(cx, destruct_def_id, [ty])])
}
ty::Tuple(tys) => Ok(tys
.iter()
.map(|field_ty| ty::TraitRef::new(cx, destruct_def_id, [field_ty]))
.collect()),
// Trivially implement `~const Destruct`
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Str
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Never
| ty::Infer(ty::InferTy::FloatVar(_) | ty::InferTy::IntVar(_))
| ty::Error(_) => Ok(vec![]),
// Coroutines and closures could implement `~const Drop`,
// but they don't really need to right now.
ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _) => Err(NoSolution),
ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
Err(NoSolution)
}
ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
panic!("unexpected type `{self_ty:?}`")
}
}
}
/// Assemble a list of predicates that would be present on a theoretical
/// user impl for an object type. These predicates must be checked any time
/// we assemble a built-in object candidate for an object type, since they

View file

@ -84,6 +84,10 @@ where
let cx = ecx.cx();
let mut candidates = vec![];
if !ecx.cx().alias_has_const_conditions(alias_ty.def_id) {
return vec![];
}
for clause in elaborate::elaborate(
cx,
cx.explicit_implied_const_bounds(alias_ty.def_id)
@ -338,10 +342,27 @@ where
}
fn consider_builtin_destruct_candidate(
_ecx: &mut EvalCtxt<'_, D>,
_goal: Goal<I, Self>,
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
Err(NoSolution)
let cx = ecx.cx();
let self_ty = goal.predicate.self_ty();
let const_conditions = structural_traits::const_conditions_for_destruct(cx, self_ty)?;
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
ecx.add_goals(
GoalSource::Misc,
const_conditions.into_iter().map(|trait_ref| {
goal.with(
cx,
ty::Binder::dummy(trait_ref)
.to_host_effect_clause(cx, goal.predicate.constness),
)
}),
);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
fn consider_builtin_transmute_candidate(