2024-12-29 04:42:21 +00:00
|
|
|
use rustc_hir::{self as hir, LangItem};
|
2024-12-22 01:46:44 +00:00
|
|
|
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
|
2024-12-10 22:08:44 +00:00
|
|
|
use rustc_infer::traits::{
|
2025-07-03 09:14:56 +00:00
|
|
|
ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode,
|
|
|
|
|
PredicateObligation,
|
2024-12-10 22:08:44 +00:00
|
|
|
};
|
2024-10-29 17:07:32 +01:00
|
|
|
use rustc_middle::span_bug;
|
2025-04-30 16:20:32 +02:00
|
|
|
use rustc_middle::traits::query::NoSolution;
|
|
|
|
|
use rustc_middle::ty::elaborate::elaborate;
|
2024-10-22 03:22:57 +00:00
|
|
|
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
2025-10-19 01:06:56 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TypingMode};
|
2024-12-22 01:46:44 +00:00
|
|
|
use thin_vec::{ThinVec, thin_vec};
|
2024-10-22 03:22:57 +00:00
|
|
|
|
|
|
|
|
use super::SelectionContext;
|
2024-12-22 01:46:44 +00:00
|
|
|
use super::normalize::normalize_with_depth_to;
|
2024-10-22 03:22:57 +00:00
|
|
|
|
|
|
|
|
pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
|
|
|
|
|
|
|
|
|
|
pub enum EvaluationFailure {
|
|
|
|
|
Ambiguous,
|
|
|
|
|
NoSolution,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn evaluate_host_effect_obligation<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
2024-11-20 11:31:49 +01:00
|
|
|
if matches!(selcx.infcx.typing_mode(), TypingMode::Coherence) {
|
2024-10-22 03:22:57 +00:00
|
|
|
span_bug!(
|
|
|
|
|
obligation.cause.span,
|
|
|
|
|
"should not select host obligation in old solver in intercrate mode"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 08:11:02 +00:00
|
|
|
let ref obligation = selcx.infcx.resolve_vars_if_possible(obligation.clone());
|
|
|
|
|
|
2024-11-22 03:12:50 +00:00
|
|
|
// Force ambiguity for infer self ty.
|
|
|
|
|
if obligation.predicate.self_ty().is_ty_var() {
|
|
|
|
|
return Err(EvaluationFailure::Ambiguous);
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-22 03:22:57 +00:00
|
|
|
match evaluate_host_effect_from_bounds(selcx, obligation) {
|
|
|
|
|
Ok(result) => return Ok(result),
|
|
|
|
|
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(EvaluationFailure::NoSolution) => {}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-30 13:33:46 +00:00
|
|
|
match evaluate_host_effect_from_conditionally_const_item_bounds(selcx, obligation) {
|
|
|
|
|
Ok(result) => return Ok(result),
|
|
|
|
|
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(EvaluationFailure::NoSolution) => {}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
match evaluate_host_effect_from_item_bounds(selcx, obligation) {
|
|
|
|
|
Ok(result) => return Ok(result),
|
|
|
|
|
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(EvaluationFailure::NoSolution) => {}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-29 04:42:21 +00:00
|
|
|
match evaluate_host_effect_from_builtin_impls(selcx, obligation) {
|
|
|
|
|
Ok(result) => return Ok(result),
|
|
|
|
|
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(EvaluationFailure::NoSolution) => {}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-07 13:51:08 +03:00
|
|
|
match evaluate_host_effect_from_selection_candidate(selcx, obligation) {
|
2024-10-22 03:22:57 +00:00
|
|
|
Ok(result) => return Ok(result),
|
|
|
|
|
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(EvaluationFailure::NoSolution) => {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(EvaluationFailure::NoSolution)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn match_candidate<'tcx>(
|
2024-12-22 01:46:44 +00:00
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
2024-10-22 03:22:57 +00:00
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
|
2024-12-22 01:46:44 +00:00
|
|
|
candidate_is_unnormalized: bool,
|
|
|
|
|
more_nested: impl FnOnce(&mut SelectionContext<'_, 'tcx>, &mut ThinVec<PredicateObligation<'tcx>>),
|
2024-10-22 03:22:57 +00:00
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
|
2024-10-29 23:42:59 +00:00
|
|
|
if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) {
|
2024-10-22 03:22:57 +00:00
|
|
|
return Err(NoSolution);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars(
|
2024-10-22 03:22:57 +00:00
|
|
|
obligation.cause.span,
|
|
|
|
|
BoundRegionConversionTime::HigherRankedType,
|
|
|
|
|
candidate,
|
|
|
|
|
);
|
|
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
let mut nested = thin_vec![];
|
|
|
|
|
|
|
|
|
|
// Unlike param-env bounds, item bounds may not be normalized.
|
|
|
|
|
if candidate_is_unnormalized {
|
|
|
|
|
candidate = normalize_with_depth_to(
|
|
|
|
|
selcx,
|
|
|
|
|
obligation.param_env,
|
|
|
|
|
obligation.cause.clone(),
|
|
|
|
|
obligation.recursion_depth,
|
|
|
|
|
candidate,
|
|
|
|
|
&mut nested,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nested.extend(
|
|
|
|
|
selcx
|
|
|
|
|
.infcx
|
|
|
|
|
.at(&obligation.cause, obligation.param_env)
|
|
|
|
|
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
|
|
|
|
|
.into_obligations(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
more_nested(selcx, &mut nested);
|
2024-10-22 03:22:57 +00:00
|
|
|
|
|
|
|
|
Ok(nested)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn evaluate_host_effect_from_bounds<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let infcx = selcx.infcx;
|
|
|
|
|
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
|
|
|
|
let mut candidate = None;
|
|
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
for clause in obligation.param_env.caller_bounds() {
|
|
|
|
|
let bound_clause = clause.kind();
|
|
|
|
|
let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
|
|
|
|
|
continue;
|
|
|
|
|
};
|
|
|
|
|
let data = bound_clause.rebind(data);
|
|
|
|
|
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !drcx
|
|
|
|
|
.args_may_unify(obligation.predicate.trait_ref.args, data.skip_binder().trait_ref.args)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let is_match =
|
|
|
|
|
infcx.probe(|_| match_candidate(selcx, obligation, data, false, |_, _| {}).is_ok());
|
|
|
|
|
|
|
|
|
|
if is_match {
|
|
|
|
|
if candidate.is_some() {
|
|
|
|
|
return Err(EvaluationFailure::Ambiguous);
|
|
|
|
|
} else {
|
|
|
|
|
candidate = Some(data);
|
2024-10-22 03:22:57 +00:00
|
|
|
}
|
2024-12-22 01:46:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
2024-10-22 03:22:57 +00:00
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
if let Some(data) = candidate {
|
|
|
|
|
Ok(match_candidate(selcx, obligation, data, false, |_, _| {})
|
|
|
|
|
.expect("candidate matched before, so it should match again"))
|
|
|
|
|
} else {
|
|
|
|
|
Err(EvaluationFailure::NoSolution)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-30 13:33:46 +00:00
|
|
|
/// Assembles constness bounds from `~const` item bounds on alias types, which only
|
|
|
|
|
/// hold if the `~const` where bounds also hold and the parent trait is `~const`.
|
|
|
|
|
fn evaluate_host_effect_from_conditionally_const_item_bounds<'tcx>(
|
2024-12-22 01:46:44 +00:00
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let infcx = selcx.infcx;
|
|
|
|
|
let tcx = infcx.tcx;
|
|
|
|
|
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
|
|
|
|
let mut candidate = None;
|
|
|
|
|
|
|
|
|
|
let mut consider_ty = obligation.predicate.self_ty();
|
|
|
|
|
while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
|
|
|
|
|
if tcx.is_conditionally_const(alias_ty.def_id) {
|
|
|
|
|
for clause in elaborate(
|
|
|
|
|
tcx,
|
|
|
|
|
tcx.explicit_implied_const_bounds(alias_ty.def_id)
|
|
|
|
|
.iter_instantiated_copied(tcx, alias_ty.args)
|
|
|
|
|
.map(|(trait_ref, _)| {
|
|
|
|
|
trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness)
|
|
|
|
|
}),
|
2024-10-22 03:22:57 +00:00
|
|
|
) {
|
2024-12-22 01:46:44 +00:00
|
|
|
let bound_clause = clause.kind();
|
|
|
|
|
let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
|
|
|
|
|
unreachable!("should not elaborate non-HostEffect from HostEffect")
|
|
|
|
|
};
|
|
|
|
|
let data = bound_clause.rebind(data);
|
|
|
|
|
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !drcx.args_may_unify(
|
|
|
|
|
obligation.predicate.trait_ref.args,
|
|
|
|
|
data.skip_binder().trait_ref.args,
|
|
|
|
|
) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-10-22 03:22:57 +00:00
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
let is_match = infcx
|
|
|
|
|
.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
|
2024-10-22 03:22:57 +00:00
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
if is_match {
|
|
|
|
|
if candidate.is_some() {
|
|
|
|
|
return Err(EvaluationFailure::Ambiguous);
|
|
|
|
|
} else {
|
|
|
|
|
candidate = Some((data, alias_ty));
|
|
|
|
|
}
|
2024-10-22 03:22:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-22 01:46:44 +00:00
|
|
|
|
|
|
|
|
if kind != ty::Projection {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consider_ty = alias_ty.self_ty();
|
2024-10-22 03:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 01:46:44 +00:00
|
|
|
if let Some((data, alias_ty)) = candidate {
|
|
|
|
|
Ok(match_candidate(selcx, obligation, data, true, |selcx, nested| {
|
|
|
|
|
// An alias bound only holds if we also check the const conditions
|
|
|
|
|
// of the alias, so we need to register those, too.
|
|
|
|
|
let const_conditions = normalize_with_depth_to(
|
|
|
|
|
selcx,
|
|
|
|
|
obligation.param_env,
|
|
|
|
|
obligation.cause.clone(),
|
|
|
|
|
obligation.recursion_depth,
|
|
|
|
|
tcx.const_conditions(alias_ty.def_id).instantiate(tcx, alias_ty.args),
|
|
|
|
|
nested,
|
|
|
|
|
);
|
|
|
|
|
nested.extend(const_conditions.into_iter().map(|(trait_ref, _)| {
|
|
|
|
|
obligation
|
|
|
|
|
.with(tcx, trait_ref.to_host_effect_clause(tcx, obligation.predicate.constness))
|
|
|
|
|
}));
|
|
|
|
|
})
|
|
|
|
|
.expect("candidate matched before, so it should match again"))
|
2024-10-22 03:22:57 +00:00
|
|
|
} else {
|
|
|
|
|
Err(EvaluationFailure::NoSolution)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-30 13:33:46 +00:00
|
|
|
/// Assembles constness bounds "normal" item bounds on aliases, which may include
|
|
|
|
|
/// unconditionally `const` bounds that are *not* conditional and thus always hold.
|
|
|
|
|
fn evaluate_host_effect_from_item_bounds<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let infcx = selcx.infcx;
|
|
|
|
|
let tcx = infcx.tcx;
|
|
|
|
|
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
|
|
|
|
let mut candidate = None;
|
|
|
|
|
|
|
|
|
|
let mut consider_ty = obligation.predicate.self_ty();
|
|
|
|
|
while let ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) = *consider_ty.kind() {
|
|
|
|
|
for clause in tcx.item_bounds(alias_ty.def_id).iter_instantiated(tcx, alias_ty.args) {
|
|
|
|
|
let bound_clause = clause.kind();
|
|
|
|
|
let ty::ClauseKind::HostEffect(data) = bound_clause.skip_binder() else {
|
|
|
|
|
continue;
|
|
|
|
|
};
|
|
|
|
|
let data = bound_clause.rebind(data);
|
|
|
|
|
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !drcx.args_may_unify(
|
|
|
|
|
obligation.predicate.trait_ref.args,
|
|
|
|
|
data.skip_binder().trait_ref.args,
|
|
|
|
|
) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let is_match =
|
|
|
|
|
infcx.probe(|_| match_candidate(selcx, obligation, data, true, |_, _| {}).is_ok());
|
|
|
|
|
|
|
|
|
|
if is_match {
|
|
|
|
|
if candidate.is_some() {
|
|
|
|
|
return Err(EvaluationFailure::Ambiguous);
|
|
|
|
|
} else {
|
|
|
|
|
candidate = Some(data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if kind != ty::Projection {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
consider_ty = alias_ty.self_ty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(data) = candidate {
|
|
|
|
|
Ok(match_candidate(selcx, obligation, data, true, |_, _| {})
|
|
|
|
|
.expect("candidate matched before, so it should match again"))
|
|
|
|
|
} else {
|
|
|
|
|
Err(EvaluationFailure::NoSolution)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-29 04:42:21 +00:00
|
|
|
fn evaluate_host_effect_from_builtin_impls<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
|
2025-10-19 01:06:56 +00:00
|
|
|
Some(LangItem::Copy | LangItem::Clone) => {
|
|
|
|
|
evaluate_host_effect_for_copy_clone_goal(selcx, obligation)
|
|
|
|
|
}
|
2024-12-29 04:42:21 +00:00
|
|
|
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
|
2025-07-03 09:14:56 +00:00
|
|
|
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
|
|
|
|
|
evaluate_host_effect_for_fn_goal(selcx, obligation)
|
|
|
|
|
}
|
2024-12-29 04:42:21 +00:00
|
|
|
_ => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-19 01:06:56 +00:00
|
|
|
fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let tcx = selcx.tcx();
|
|
|
|
|
let self_ty = obligation.predicate.self_ty();
|
|
|
|
|
let constituent_tys = match *self_ty.kind() {
|
|
|
|
|
// impl Copy/Clone for FnDef, FnPtr
|
|
|
|
|
ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
|
|
|
|
|
|
|
|
|
|
// Implementations are provided in core
|
|
|
|
|
ty::Uint(_)
|
|
|
|
|
| ty::Int(_)
|
|
|
|
|
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
|
|
|
|
| ty::Bool
|
|
|
|
|
| ty::Float(_)
|
|
|
|
|
| ty::Char
|
|
|
|
|
| ty::RawPtr(..)
|
|
|
|
|
| ty::Never
|
|
|
|
|
| ty::Ref(_, _, ty::Mutability::Not)
|
|
|
|
|
| ty::Array(..) => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
|
|
|
|
// Cannot implement in core, as we can't be generic over patterns yet,
|
|
|
|
|
// so we'd have to list all patterns and type combinations.
|
|
|
|
|
ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
|
|
|
|
|
|
|
|
|
|
ty::Dynamic(..)
|
|
|
|
|
| ty::Str
|
|
|
|
|
| ty::Slice(_)
|
|
|
|
|
| ty::Foreign(..)
|
|
|
|
|
| ty::Ref(_, _, ty::Mutability::Mut)
|
|
|
|
|
| ty::Adt(_, _)
|
|
|
|
|
| ty::Alias(_, _)
|
|
|
|
|
| ty::Param(_)
|
|
|
|
|
| ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
|
|
|
|
ty::Bound(..)
|
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
|
panic!("unexpected type `{self_ty:?}`")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
|
|
|
|
|
ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
|
|
|
|
|
|
|
|
|
|
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
|
|
|
|
|
ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
|
|
|
|
|
|
|
|
|
|
// impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
|
|
|
|
|
ty::CoroutineClosure(_, args) => {
|
|
|
|
|
Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// only when `coroutine_clone` is enabled and the coroutine is movable
|
|
|
|
|
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
|
2025-10-26 19:57:05 +00:00
|
|
|
ty::Coroutine(def_id, args) => {
|
|
|
|
|
if selcx.should_stall_coroutine(def_id) {
|
|
|
|
|
return Err(EvaluationFailure::Ambiguous);
|
|
|
|
|
}
|
|
|
|
|
match tcx.coroutine_movability(def_id) {
|
|
|
|
|
ty::Movability::Static => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
ty::Movability::Movable => {
|
|
|
|
|
if tcx.features().coroutine_clone() {
|
|
|
|
|
Ok(ty::Binder::dummy(vec![
|
|
|
|
|
args.as_coroutine().tupled_upvars_ty(),
|
|
|
|
|
Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args),
|
|
|
|
|
]))
|
|
|
|
|
} else {
|
|
|
|
|
Err(EvaluationFailure::NoSolution)
|
|
|
|
|
}
|
2025-10-19 01:06:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-26 19:57:05 +00:00
|
|
|
}
|
2025-10-19 01:06:56 +00:00
|
|
|
|
|
|
|
|
ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
|
|
|
|
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
|
|
|
|
|
ty::CoroutineWitness(def_id, args) => Ok(tcx
|
|
|
|
|
.coroutine_hidden_types(def_id)
|
|
|
|
|
.instantiate(tcx, args)
|
|
|
|
|
.map_bound(|bound| bound.types.to_vec())),
|
|
|
|
|
}?;
|
|
|
|
|
|
|
|
|
|
Ok(constituent_tys
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|ty| {
|
|
|
|
|
obligation.with(
|
|
|
|
|
tcx,
|
|
|
|
|
ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty]))
|
|
|
|
|
.to_host_effect_clause(tcx, obligation.predicate.constness),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect())
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-29 04:42:21 +00:00
|
|
|
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
|
|
|
|
|
fn evaluate_host_effect_for_destruct_goal<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let tcx = selcx.tcx();
|
2025-06-04 06:26:56 +00:00
|
|
|
let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span);
|
2024-12-29 04:42:21 +00:00
|
|
|
let self_ty = obligation.predicate.self_ty();
|
|
|
|
|
|
|
|
|
|
let const_conditions = match *self_ty.kind() {
|
2025-03-11 12:08:45 +00:00
|
|
|
// `ManuallyDrop` is trivially `[const] Destruct` as we do not run any drop glue on it.
|
2025-04-29 10:20:16 +00:00
|
|
|
ty::Adt(adt_def, _) if adt_def.is_manually_drop() => thin_vec![],
|
|
|
|
|
|
2025-03-11 12:08:45 +00:00
|
|
|
// 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]`.
|
2024-12-29 04:42:21 +00:00
|
|
|
ty::Adt(adt_def, args) => {
|
|
|
|
|
let mut const_conditions: ThinVec<_> = adt_def
|
|
|
|
|
.all_fields()
|
|
|
|
|
.map(|field| ty::TraitRef::new(tcx, destruct_def_id, [field.ty(tcx, args)]))
|
|
|
|
|
.collect();
|
2025-04-01 09:28:46 +00:00
|
|
|
match adt_def.destructor(tcx).map(|dtor| tcx.constness(dtor.did)) {
|
2025-03-11 12:08:45 +00:00
|
|
|
// `Drop` impl exists, but it's not const. Type cannot be `[const] Destruct`.
|
2024-12-29 04:42:21 +00:00
|
|
|
Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
|
2025-03-11 12:08:45 +00:00
|
|
|
// `Drop` impl exists, and it's const. Require `Ty: [const] Drop` to hold.
|
2024-12-29 04:42:21 +00:00
|
|
|
Some(hir::Constness::Const) => {
|
2025-06-04 06:26:56 +00:00
|
|
|
let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span);
|
2024-12-29 04:42:21 +00:00
|
|
|
let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
|
|
|
|
|
const_conditions.push(drop_trait_ref);
|
|
|
|
|
}
|
|
|
|
|
// No `Drop` impl, no need to require anything else.
|
|
|
|
|
None => {}
|
|
|
|
|
}
|
|
|
|
|
const_conditions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ty::Array(ty, _) | ty::Pat(ty, _) | ty::Slice(ty) => {
|
|
|
|
|
thin_vec![ty::TraitRef::new(tcx, destruct_def_id, [ty])]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ty::Tuple(tys) => {
|
|
|
|
|
tys.iter().map(|field_ty| ty::TraitRef::new(tcx, destruct_def_id, [field_ty])).collect()
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-11 12:08:45 +00:00
|
|
|
// Trivially implement `[const] Destruct`
|
2024-12-29 04:42:21 +00:00
|
|
|
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(_) => thin_vec![],
|
|
|
|
|
|
2025-03-11 12:08:45 +00:00
|
|
|
// Coroutines and closures could implement `[const] Drop`,
|
2024-12-29 04:42:21 +00:00
|
|
|
// but they don't really need to right now.
|
|
|
|
|
ty::Closure(_, _)
|
|
|
|
|
| ty::CoroutineClosure(_, _)
|
|
|
|
|
| ty::Coroutine(_, _)
|
|
|
|
|
| ty::CoroutineWitness(_, _) => return Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
2025-03-11 12:08:45 +00:00
|
|
|
// FIXME(unsafe_binders): Unsafe binders could implement `[const] Drop`
|
2024-12-29 04:42:21 +00:00
|
|
|
// if their inner type implements it.
|
|
|
|
|
ty::UnsafeBinder(_) => return Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
|
|
|
|
ty::Dynamic(..) | ty::Param(_) | ty::Alias(..) | ty::Placeholder(_) | ty::Foreign(_) => {
|
|
|
|
|
return Err(EvaluationFailure::NoSolution);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ty::Bound(..)
|
|
|
|
|
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
|
|
|
|
panic!("unexpected type `{self_ty:?}`")
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(const_conditions
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|trait_ref| {
|
|
|
|
|
obligation.with(
|
|
|
|
|
tcx,
|
|
|
|
|
ty::Binder::dummy(trait_ref)
|
|
|
|
|
.to_host_effect_clause(tcx, obligation.predicate.constness),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect())
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-03 09:14:56 +00:00
|
|
|
// NOTE: Keep this in sync with `extract_fn_def_from_const_callable` in the new solver.
|
|
|
|
|
fn evaluate_host_effect_for_fn_goal<'tcx>(
|
|
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let tcx = selcx.tcx();
|
|
|
|
|
let self_ty = obligation.predicate.self_ty();
|
|
|
|
|
|
|
|
|
|
let (def, args) = match *self_ty.kind() {
|
|
|
|
|
ty::FnDef(def, args) => (def, args),
|
|
|
|
|
|
|
|
|
|
// We may support function pointers at some point in the future
|
|
|
|
|
ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution),
|
|
|
|
|
|
2025-07-08 15:41:13 +00:00
|
|
|
// Closures could implement `[const] Fn`,
|
2025-07-03 09:14:56 +00:00
|
|
|
// but they don't really need to right now.
|
2025-07-08 15:41:13 +00:00
|
|
|
ty::Closure(..) | ty::CoroutineClosure(_, _) => {
|
2025-07-03 09:14:56 +00:00
|
|
|
return Err(EvaluationFailure::NoSolution);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Everything else needs explicit impls or cannot have an impl
|
|
|
|
|
_ => return Err(EvaluationFailure::NoSolution),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match tcx.constness(def) {
|
|
|
|
|
hir::Constness::Const => Ok(tcx
|
|
|
|
|
.const_conditions(def)
|
|
|
|
|
.instantiate(tcx, args)
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(c, span)| {
|
|
|
|
|
let code = ObligationCauseCode::WhereClause(def, span);
|
|
|
|
|
let cause =
|
|
|
|
|
ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code);
|
|
|
|
|
Obligation::new(
|
|
|
|
|
tcx,
|
|
|
|
|
cause,
|
|
|
|
|
obligation.param_env,
|
|
|
|
|
c.to_host_effect_clause(tcx, obligation.predicate.constness),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.collect()),
|
|
|
|
|
hir::Constness::NotConst => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-07 13:51:08 +03:00
|
|
|
fn evaluate_host_effect_from_selection_candidate<'tcx>(
|
2024-10-22 03:22:57 +00:00
|
|
|
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
|
|
|
obligation: &HostEffectObligation<'tcx>,
|
|
|
|
|
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
|
|
|
|
let tcx = selcx.tcx();
|
|
|
|
|
selcx.infcx.commit_if_ok(|_| {
|
|
|
|
|
match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
|
|
|
|
|
Ok(None) => Err(EvaluationFailure::Ambiguous),
|
|
|
|
|
Err(_) => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
Ok(Some(source)) => match source {
|
|
|
|
|
ImplSource::UserDefined(impl_) => {
|
2025-07-22 17:05:45 -05:00
|
|
|
if tcx.impl_trait_header(impl_.impl_def_id).constness != hir::Constness::Const {
|
2024-10-22 03:22:57 +00:00
|
|
|
return Err(EvaluationFailure::NoSolution);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut nested = impl_.nested;
|
|
|
|
|
nested.extend(
|
|
|
|
|
tcx.const_conditions(impl_.impl_def_id)
|
|
|
|
|
.instantiate(tcx, impl_.args)
|
|
|
|
|
.into_iter()
|
2024-12-10 22:08:44 +00:00
|
|
|
.map(|(trait_ref, span)| {
|
|
|
|
|
Obligation::new(
|
2024-10-22 03:22:57 +00:00
|
|
|
tcx,
|
2024-12-10 22:08:44 +00:00
|
|
|
obligation.cause.clone().derived_host_cause(
|
|
|
|
|
ty::Binder::dummy(obligation.predicate),
|
|
|
|
|
|derived| {
|
|
|
|
|
ObligationCauseCode::ImplDerivedHost(Box::new(
|
|
|
|
|
ImplDerivedHostCause {
|
|
|
|
|
derived,
|
|
|
|
|
impl_def_id: impl_.impl_def_id,
|
|
|
|
|
span,
|
|
|
|
|
},
|
|
|
|
|
))
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
obligation.param_env,
|
2024-10-29 23:42:59 +00:00
|
|
|
trait_ref
|
|
|
|
|
.to_host_effect_clause(tcx, obligation.predicate.constness),
|
2024-10-22 03:22:57 +00:00
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Ok(nested)
|
|
|
|
|
}
|
|
|
|
|
_ => Err(EvaluationFailure::NoSolution),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|