Implement ~const Destruct in new solver
This commit is contained in:
parent
a7d9ebdf08
commit
59408add4d
16 changed files with 266 additions and 74 deletions
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue