Rip out old effects var handling code from traits

This commit is contained in:
Michael Goulet 2024-10-20 13:39:52 +00:00
parent bfab34af4c
commit 6f6f91ab82
14 changed files with 34 additions and 491 deletions

View File

@ -6,13 +6,10 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem; use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
use rustc_middle::{bug, mir}; use rustc_middle::{bug, mir};
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, use tracing::instrument;
};
use tracing::{instrument, trace};
use super::ConstCx; use super::ConstCx;
@ -195,50 +192,8 @@ impl Qualif for NeedsNonConstDrop {
return false; return false;
} }
// FIXME(effects): If `destruct` is not a `const_trait`, // FIXME(effects): Reimplement const drop checking.
// or effects are disabled in this crate, then give up. NeedsDrop::in_any_value_of_ty(cx, ty)
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
return NeedsDrop::in_any_value_of_ty(cx, ty);
}
let obligation = Obligation::new(
cx.tcx,
ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
ty::TraitRef::new(cx.tcx, destruct_def_id, [
ty::GenericArg::from(ty),
ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
]),
);
let infcx = cx.tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
// If we couldn't select a const destruct candidate, then it's bad
return true;
};
trace!(?impl_src);
if !matches!(
impl_src,
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
) {
// If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad
return true;
}
if impl_src.borrow_nested_obligations().is_empty() {
return false;
}
// If we had any errors, then it's bad
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(impl_src.nested_obligations());
let errors = ocx.select_all_or_error();
!errors.is_empty()
} }
fn in_adt_inherently<'tcx>( fn in_adt_inherently<'tcx>(

View File

@ -537,40 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// //
// This check is here because there is currently no way to express a trait bound for `FnDef` types only. // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
if let ty::FnDef(def_id, _args) = *arg_ty.kind() { if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
let fn_once_def_id = if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
let fn_once_output_def_id =
self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
if self.tcx.has_host_param(fn_once_def_id) {
let const_param: ty::GenericArg<'tcx> =
([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
self.register_predicate(traits::Obligation::new(
self.tcx,
self.misc(span),
self.param_env,
ty::TraitRef::new(self.tcx, fn_once_def_id, [
arg_ty.into(),
fn_sig.inputs()[0].into(),
const_param,
]),
));
self.register_predicate(traits::Obligation::new(
self.tcx,
self.misc(span),
self.param_env,
ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new(
self.tcx,
fn_once_output_def_id,
[arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
),
term: fn_sig.output().into(),
},
));
self.select_obligations_where_possible(|_| {});
} else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
} }
} else { } else {

View File

@ -161,9 +161,7 @@ pub enum SelectionCandidate<'tcx> {
/// Implementation of a `Fn`-family trait by one of the anonymous /// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int) -> int`) /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate { FnPointerCandidate,
fn_host_effect: ty::Const<'tcx>,
},
TraitAliasCandidate, TraitAliasCandidate,
@ -180,9 +178,6 @@ pub enum SelectionCandidate<'tcx> {
BuiltinObjectCandidate, BuiltinObjectCandidate,
BuiltinUnsizeCandidate, BuiltinUnsizeCandidate,
/// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
ConstDestructCandidate(Option<DefId>),
} }
/// The result of trait evaluation. The order is important /// The result of trait evaluation. The order is important

View File

@ -907,24 +907,6 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
/// Constructs generic args for an item, optionally appending a const effect param type
pub fn with_opt_host_effect_param(
self,
caller_def_id: LocalDefId,
callee_def_id: DefId,
args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
) -> ty::GenericArgsRef<'tcx> {
let generics = self.generics_of(callee_def_id);
assert_eq!(generics.parent, None);
let opt_const_param = generics
.host_effect_index
.is_some()
.then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id)));
self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
}
/// Expand any [weak alias types][weak] contained within the given `value`. /// Expand any [weak alias types][weak] contained within the given `value`.
/// ///
/// This should be used over other normalization routines in situations where /// This should be used over other normalization routines in situations where

View File

@ -454,12 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}; };
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
let method = trait_method( let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
self.tcx,
eq_def_id,
sym::eq,
self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]),
);
let bool_ty = self.tcx.types.bool; let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span); let eq_result = self.temp(bool_ty, source_info.span);

View File

@ -43,7 +43,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
} }
struct ConstToPat<'tcx> { struct ConstToPat<'tcx> {
id: hir::HirId,
span: Span, span: Span,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
@ -62,7 +61,6 @@ impl<'tcx> ConstToPat<'tcx> {
) -> Self { ) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner); trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat { ConstToPat {
id,
span, span,
infcx, infcx,
param_env: pat_ctxt.param_env, param_env: pat_ctxt.param_env,
@ -149,15 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
tcx, tcx,
ObligationCause::dummy(), ObligationCause::dummy(),
self.param_env, self.param_env,
ty::TraitRef::new_from_args( ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
tcx,
partial_eq_trait_id,
tcx.with_opt_host_effect_param(
tcx.hir().enclosing_body_owner(self.id),
partial_eq_trait_id,
[ty, ty],
),
),
); );
// This *could* accept a type that isn't actually `PartialEq`, because region bounds get // This *could* accept a type that isn't actually `PartialEq`, because region bounds get

View File

@ -3701,12 +3701,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
} }
_ => None, _ => None,
}; };
// Also add host param, if present
let host = self.tcx.generics_of(trait_pred.def_id()).host_effect_index.map(|idx| trait_pred.skip_binder().trait_ref.args[idx]);
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
trait_ref: ty::TraitRef::new(self.tcx, trait_ref: ty::TraitRef::new(self.tcx,
trait_pred.def_id(), trait_pred.def_id(),
[field_ty].into_iter().chain(trait_args).chain(host), [field_ty].into_iter().chain(trait_args),
), ),
..*tr ..*tr
}); });

View File

@ -1642,24 +1642,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
sig, sig,
); );
let host_effect_param = match *fn_type.kind() { confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
ty::FnDef(def_id, args) => tcx .with_addl_obligations(nested)
.generics_of(def_id) .with_addl_obligations(obligations)
.host_effect_index
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
ty::FnPtr(..) => tcx.consts.true_,
_ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
};
confirm_callable_candidate(
selcx,
obligation,
sig,
util::TupleArgumentsFlag::Yes,
host_effect_param,
)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
} }
fn confirm_closure_candidate<'cx, 'tcx>( fn confirm_closure_candidate<'cx, 'tcx>(
@ -1739,16 +1724,9 @@ fn confirm_closure_candidate<'cx, 'tcx>(
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
confirm_callable_candidate( confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
selcx, .with_addl_obligations(nested)
obligation, .with_addl_obligations(obligations)
closure_sig,
util::TupleArgumentsFlag::No,
// FIXME(effects): This doesn't handle const closures correctly!
selcx.tcx().consts.true_,
)
.with_addl_obligations(nested)
.with_addl_obligations(obligations)
} }
fn confirm_callable_candidate<'cx, 'tcx>( fn confirm_callable_candidate<'cx, 'tcx>(
@ -1756,7 +1734,6 @@ fn confirm_callable_candidate<'cx, 'tcx>(
obligation: &ProjectionTermObligation<'tcx>, obligation: &ProjectionTermObligation<'tcx>,
fn_sig: ty::PolyFnSig<'tcx>, fn_sig: ty::PolyFnSig<'tcx>,
flag: util::TupleArgumentsFlag, flag: util::TupleArgumentsFlag,
fn_host_effect: ty::Const<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
let tcx = selcx.tcx(); let tcx = selcx.tcx();
@ -1771,7 +1748,6 @@ fn confirm_callable_candidate<'cx, 'tcx>(
obligation.predicate.self_ty(), obligation.predicate.self_ty(),
fn_sig, fn_sig,
flag, flag,
fn_host_effect,
) )
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(tcx, fn_once_output_def_id, trait_ref.args), projection_term: ty::AliasTerm::new_from_args(tcx, fn_once_output_def_id, trait_ref.args),

View File

@ -543,23 +543,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Provide an impl, but only for suitable `fn` pointers. // Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig_tys, hdr) => { ty::FnPtr(sig_tys, hdr) => {
if sig_tys.with(hdr).is_fn_trait_compatible() { if sig_tys.with(hdr).is_fn_trait_compatible() {
candidates candidates.vec.push(FnPointerCandidate);
.vec
.push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
} }
} }
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
ty::FnDef(def_id, args) => { ty::FnDef(def_id, _args) => {
let tcx = self.tcx(); let tcx = self.tcx();
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty() && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{ {
candidates.vec.push(FnPointerCandidate { candidates.vec.push(FnPointerCandidate);
fn_host_effect: tcx
.generics_of(def_id)
.host_effect_index
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
});
} }
} }
_ => {} _ => {}
@ -1170,103 +1163,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn assemble_const_destruct_candidates( fn assemble_const_destruct_candidates(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, _obligation: &PolyTraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>,
) { ) {
// If the predicate is `~const Destruct` in a non-const environment, we don't actually need // FIXME(effects): Destruct is not const yet, and it is implemented
// to check anything. We'll short-circuit checking any obligations in confirmation, too. // by all types today in non-const setting.
let Some(host_effect_index) = candidates.vec.push(BuiltinCandidate { has_nested: false });
self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
else {
candidates.vec.push(BuiltinCandidate { has_nested: false });
return;
};
// If the obligation has `host = true`, then the obligation is non-const and it's always
// trivially implemented.
if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index)
== self.tcx().consts.true_
{
candidates.vec.push(BuiltinCandidate { has_nested: false });
return;
}
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
match self_ty.kind() {
ty::Alias(..)
| ty::Dynamic(..)
| ty::Error(_)
| ty::Bound(..)
| ty::Param(_)
| ty::Placeholder(_) => {
// We don't know if these are `~const Destruct`, at least
// not structurally... so don't push a candidate.
}
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Infer(ty::IntVar(_))
| ty::Infer(ty::FloatVar(_))
| ty::Str
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Never
| ty::Foreign(_)
| ty::Array(..)
| ty::Pat(..)
| ty::Slice(_)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::Tuple(_)
| ty::CoroutineWitness(..) => {
// These are built-in, and cannot have a custom `impl const Destruct`.
candidates.vec.push(ConstDestructCandidate(None));
}
ty::Adt(..) => {
let mut relevant_impl = None;
self.tcx().for_each_relevant_impl(
self.tcx().require_lang_item(LangItem::Drop, None),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
if let Some(old_impl_def_id) = relevant_impl {
self.tcx()
.dcx()
.struct_span_err(
self.tcx().def_span(impl_def_id),
"multiple drop impls found",
)
.with_span_note(
self.tcx().def_span(old_impl_def_id),
"other impl here",
)
.delay_as_bug();
}
relevant_impl = Some(impl_def_id);
},
);
if let Some(impl_def_id) = relevant_impl {
// Check that `impl Drop` is actually const, if there is a custom impl
if self.tcx().constness(impl_def_id) == hir::Constness::Const {
candidates.vec.push(ConstDestructCandidate(Some(impl_def_id)));
}
} else {
// Otherwise check the ADT like a built-in type (structurally)
candidates.vec.push(ConstDestructCandidate(None));
}
}
ty::Infer(_) => {
candidates.ambiguous = true;
}
}
} }
fn assemble_candidate_for_tuple( fn assemble_candidate_for_tuple(

View File

@ -28,9 +28,9 @@ use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::{ use crate::traits::{
ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch,
SignatureMismatch, TraitDynIncompatible, TraitObligation, Unimplemented, TraitDynIncompatible, TraitObligation, Unimplemented,
}; };
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@ -109,8 +109,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
} }
FnPointerCandidate { fn_host_effect } => { FnPointerCandidate => {
let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?; let data = self.confirm_fn_pointer_candidate(obligation)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
@ -131,11 +131,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
TraitUpcastingUnsizeCandidate(idx) => { TraitUpcastingUnsizeCandidate(idx) => {
self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
} }
ConstDestructCandidate(def_id) => {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
}; };
// The obligations returned by confirmation are recursively evaluated // The obligations returned by confirmation are recursively evaluated
@ -708,7 +703,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_fn_pointer_candidate( fn confirm_fn_pointer_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
fn_host_effect: ty::Const<'tcx>,
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate"); debug!(?obligation, "confirm_fn_pointer_candidate");
let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
@ -722,7 +716,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self_ty, self_ty,
sig, sig,
util::TupleArgumentsFlag::Yes, util::TupleArgumentsFlag::Yes,
fn_host_effect,
) )
.map_bound(|(trait_ref, _)| trait_ref); .map_bound(|(trait_ref, _)| trait_ref);
@ -904,11 +897,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
let trait_ref = match *self_ty.kind() { let trait_ref = match *self_ty.kind() {
ty::Closure(..) => self.closure_trait_ref_unnormalized( ty::Closure(..) => {
self_ty, self.closure_trait_ref_unnormalized(self_ty, obligation.predicate.def_id())
obligation.predicate.def_id(), }
self.tcx().consts.true_,
),
ty::CoroutineClosure(_, args) => { ty::CoroutineClosure(_, args) => {
args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
ty::TraitRef::new(self.tcx(), obligation.predicate.def_id(), [ ty::TraitRef::new(self.tcx(), obligation.predicate.def_id(), [
@ -1341,170 +1332,4 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => bug!("source: {source}, target: {target}"), _ => bug!("source: {source}, target: {target}"),
}) })
} }
fn confirm_const_destruct_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
impl_def_id: Option<DefId>,
) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
let Some(host_effect_index) =
self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
else {
bug!()
};
let host_effect_param: ty::GenericArg<'tcx> =
obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into();
let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
let tcx = self.tcx();
let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
let mut nested = PredicateObligations::new();
let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
// If we have a custom `impl const Drop`, then
// first check it like a regular impl candidate.
// This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
if let Some(impl_def_id) = impl_def_id {
let mut new_obligation = obligation.clone();
new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
trait_pred.trait_ref.def_id = drop_trait;
trait_pred
});
let args = self.rematch_impl(impl_def_id, &new_obligation);
debug!(?args, "impl args");
let cause = obligation.derived_cause(|derived| {
ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause {
derived,
impl_or_alias_def_id: impl_def_id,
impl_def_predicate_index: None,
span: obligation.cause.span,
}))
});
let obligations = ensure_sufficient_stack(|| {
self.vtable_impl(
impl_def_id,
args,
&cause,
new_obligation.recursion_depth + 1,
new_obligation.param_env,
obligation.predicate,
)
});
nested.extend(obligations.nested);
}
// We want to confirm the ADT's fields if we have an ADT
let mut stack = match *self_ty.skip_binder().kind() {
ty::Adt(def, args) => def.all_fields().map(|f| f.ty(tcx, args)).collect(),
_ => vec![self_ty.skip_binder()],
};
while let Some(nested_ty) = stack.pop() {
match *nested_ty.kind() {
// We know these types are trivially drop
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Infer(ty::IntVar(_))
| ty::Infer(ty::FloatVar(_))
| ty::Str
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Never
| ty::Foreign(_) => {}
// `ManuallyDrop` is trivially drop
ty::Adt(def, _) if def.is_manually_drop() => {}
// These types are built-in, so we can fast-track by registering
// nested predicates for their constituent type(s)
ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
stack.push(ty);
}
ty::Tuple(tys) => {
stack.extend(tys.iter());
}
ty::Closure(_, args) => {
stack.push(args.as_closure().tupled_upvars_ty());
}
ty::Coroutine(_, args) => {
let coroutine = args.as_coroutine();
stack.extend([coroutine.tupled_upvars_ty(), coroutine.witness()]);
}
ty::CoroutineWitness(def_id, args) => {
let tcx = self.tcx();
stack.extend(tcx.bound_coroutine_hidden_types(def_id).map(|bty| {
self.infcx.enter_forall_and_leak_universe(bty.instantiate(tcx, args))
}))
}
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
ty::Alias(ty::Projection | ty::Inherent, ..) => {
let predicate = normalize_with_depth_to(
self,
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
self_ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::new(
self.tcx(),
self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
[nested_ty.into(), host_effect_param],
),
polarity: ty::PredicatePolarity::Positive,
}),
&mut nested,
);
nested.push(Obligation::with_depth(
tcx,
cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate,
));
}
// If we have any other type (e.g. an ADT), just register a nested obligation
// since it's either not `const Drop` (and we raise an error during selection),
// or it's an ADT (and we need to check for a custom impl during selection)
ty::Error(_)
| ty::Dynamic(..)
| ty::CoroutineClosure(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Adt(..)
| ty::Alias(ty::Opaque | ty::Weak, _)
| ty::Infer(_)
| ty::Placeholder(_) => {
let predicate = self_ty.rebind(ty::TraitPredicate {
trait_ref: ty::TraitRef::new(
self.tcx(),
self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
[nested_ty.into(), host_effect_param],
),
polarity: ty::PredicatePolarity::Positive,
});
nested.push(Obligation::with_depth(
tcx,
cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate,
));
}
}
}
Ok(nested)
}
} }

View File

@ -1831,12 +1831,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
// (*) // (*)
(BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => { (BuiltinCandidate { has_nested: false }, _) => DropVictim::Yes,
DropVictim::Yes (_, BuiltinCandidate { has_nested: false }) => DropVictim::No,
}
(_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
DropVictim::No
}
(ParamCandidate(other), ParamCandidate(victim)) => { (ParamCandidate(other), ParamCandidate(victim)) => {
let same_except_bound_vars = other.skip_binder().trait_ref let same_except_bound_vars = other.skip_binder().trait_ref
@ -1855,11 +1851,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
} }
} }
// Drop otherwise equivalent non-const fn pointer candidates
(FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
}
( (
ParamCandidate(other_cand), ParamCandidate(other_cand),
ImplCandidate(..) ImplCandidate(..)
@ -2766,7 +2757,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self, &mut self,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
fn_trait_def_id: DefId, fn_trait_def_id: DefId,
fn_host_effect: ty::Const<'tcx>,
) -> ty::PolyTraitRef<'tcx> { ) -> ty::PolyTraitRef<'tcx> {
let ty::Closure(_, args) = *self_ty.kind() else { let ty::Closure(_, args) = *self_ty.kind() else {
bug!("expected closure, found {self_ty}"); bug!("expected closure, found {self_ty}");
@ -2779,7 +2769,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self_ty, self_ty,
closure_sig, closure_sig,
util::TupleArgumentsFlag::No, util::TupleArgumentsFlag::No,
fn_host_effect,
) )
.map_bound(|(trait_ref, _)| trait_ref) .map_bound(|(trait_ref, _)| trait_ref)
} }

View File

@ -215,22 +215,13 @@ pub(crate) fn closure_trait_ref_and_return_type<'tcx>(
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
sig: ty::PolyFnSig<'tcx>, sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag, tuple_arguments: TupleArgumentsFlag,
fn_host_effect: ty::Const<'tcx>,
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
assert!(!self_ty.has_escaping_bound_vars()); assert!(!self_ty.has_escaping_bound_vars());
let arguments_tuple = match tuple_arguments { let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()), TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
}; };
let trait_ref = if tcx.has_host_param(fn_trait_def_id) { let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
ty::TraitRef::new(tcx, fn_trait_def_id, [
ty::GenericArg::from(self_ty),
ty::GenericArg::from(arguments_tuple),
ty::GenericArg::from(fn_host_effect),
])
} else {
ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple])
};
sig.map_bound(|sig| (trait_ref, sig.output())) sig.map_bound(|sig| (trait_ref, sig.output()))
} }

View File

@ -190,15 +190,6 @@ fn is_same_generics<'tcx>(
.enumerate() .enumerate()
.skip(1) // skip `Self` implicit arg .skip(1) // skip `Self` implicit arg
.all(|(arg_index, arg)| { .all(|(arg_index, arg)| {
if [
implied_by_generics.host_effect_index,
implied_generics.host_effect_index,
]
.contains(&Some(arg_index))
{
// skip host effect params in determining whether generics are same
return true;
}
if let Some(ty) = arg.as_type() { if let Some(ty) = arg.as_type() {
if let &ty::Param(ty::ParamTy { index, .. }) = ty.kind() if let &ty::Param(ty::ParamTy { index, .. }) = ty.kind()
// `index == 0` means that it's referring to `Self`, // `index == 0` means that it's referring to `Self`,

View File

@ -274,23 +274,10 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
.map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// If an effect arg was not specified, we need to specify it.
let effect_arg = if tcx
.generics_of(trait_id)
.host_effect_index
.is_some_and(|x| args.get(x - 1).is_none())
{
Some(GenericArg::from(callee_id.map_or(tcx.consts.true_, |def_id| {
tcx.expected_host_effect_param_for_body(def_id)
})))
} else {
None
};
let trait_ref = TraitRef::new( let trait_ref = TraitRef::new(
tcx, tcx,
trait_id, trait_id,
[GenericArg::from(ty)].into_iter().chain(args).chain(effect_arg), [GenericArg::from(ty)].into_iter().chain(args),
); );
debug_assert_matches!( debug_assert_matches!(