Check FnPtr/FnDef built-in fn traits correctly with effects

This commit is contained in:
Michael Goulet
2023-12-16 19:21:43 +00:00
parent 2a7634047a
commit 69f360d00c
7 changed files with 84 additions and 24 deletions

View File

@@ -355,17 +355,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig) => {
if sig.is_fn_trait_compatible() {
candidates.vec.push(FnPointerCandidate { is_const: false });
candidates
.vec
.push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
}
}
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
ty::FnDef(def_id, _) => {
if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible()
&& self.tcx().codegen_fn_attrs(def_id).target_features.is_empty()
ty::FnDef(def_id, args) => {
let tcx = self.tcx();
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{
candidates
.vec
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
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)),
});
}
}
_ => {}

View File

@@ -103,8 +103,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
}
FnPointerCandidate { is_const } => {
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
FnPointerCandidate { fn_host_effect } => {
let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
}
@@ -653,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_fn_pointer_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
// FIXME(effects)
_is_const: bool,
fn_host_effect: ty::Const<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_fn_pointer_candidate");
@@ -675,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self_ty,
sig,
util::TupleArgumentsFlag::Yes,
fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref);
@@ -860,7 +860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bug!("closure candidate for non-closure {:?}", obligation);
};
let trait_ref = self.closure_trait_ref_unnormalized(obligation, args);
let trait_ref =
self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_);
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");

View File

@@ -1865,7 +1865,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
// Drop otherwise equivalent non-const fn pointer candidates
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes,
(FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
}
(
ParamCandidate(ref other_cand),
@@ -2660,6 +2662,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
args: GenericArgsRef<'tcx>,
fn_host_effect: ty::Const<'tcx>,
) -> ty::PolyTraitRef<'tcx> {
let closure_sig = args.as_closure().sig();
@@ -2680,6 +2683,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self_ty,
closure_sig,
util::TupleArgumentsFlag::No,
fn_host_effect,
)
.map_bound(|(trait_ref, _)| trait_ref)
}