mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Check FnPtr/FnDef built-in fn traits correctly with effects
This commit is contained in:
parent
2a7634047a
commit
69f360d00c
@ -153,7 +153,7 @@ pub enum SelectionCandidate<'tcx> {
|
||||
/// Implementation of a `Fn`-family trait by one of the anonymous
|
||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||
FnPointerCandidate {
|
||||
is_const: bool,
|
||||
fn_host_effect: ty::Const<'tcx>,
|
||||
},
|
||||
|
||||
TraitAliasCandidate,
|
||||
|
@ -2327,8 +2327,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
nested: Vec<PredicateObligation<'tcx>>,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
let sig = fn_type.fn_sig(selcx.tcx());
|
||||
let sig = fn_type.fn_sig(tcx);
|
||||
let Normalized { value: sig, obligations } = normalize_with_depth(
|
||||
selcx,
|
||||
obligation.param_env,
|
||||
@ -2337,9 +2338,24 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
|
||||
sig,
|
||||
);
|
||||
|
||||
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
let host_effect_param = match *fn_type.kind() {
|
||||
ty::FnDef(def_id, args) => tcx
|
||||
.generics_of(def_id)
|
||||
.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>(
|
||||
@ -2362,9 +2378,16 @@ fn confirm_closure_candidate<'cx, 'tcx>(
|
||||
|
||||
debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
|
||||
|
||||
confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
|
||||
.with_addl_obligations(nested)
|
||||
.with_addl_obligations(obligations)
|
||||
confirm_callable_candidate(
|
||||
selcx,
|
||||
obligation,
|
||||
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>(
|
||||
@ -2372,6 +2395,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
obligation: &ProjectionTyObligation<'tcx>,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
flag: util::TupleArgumentsFlag,
|
||||
fn_host_effect: ty::Const<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
|
||||
@ -2386,6 +2410,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
obligation.predicate.self_ty(),
|
||||
fn_sig,
|
||||
flag,
|
||||
fn_host_effect,
|
||||
)
|
||||
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
|
||||
projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
|
||||
|
@ -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)),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -264,13 +264,26 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
|
||||
self_ty: Ty<'tcx>,
|
||||
sig: ty::PolyFnSig<'tcx>,
|
||||
tuple_arguments: TupleArgumentsFlag,
|
||||
fn_host_effect: ty::Const<'tcx>,
|
||||
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
|
||||
assert!(!self_ty.has_escaping_bound_vars());
|
||||
let arguments_tuple = match tuple_arguments {
|
||||
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
|
||||
TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
|
||||
};
|
||||
let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
|
||||
let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() {
|
||||
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()))
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
// check-pass
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)]
|
||||
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs, staged_api)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(const_trait_impl, effects, const_mut_refs)]
|
||||
#![allow(internal_features)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
#![stable(feature = "minicore", since = "1.0.0")]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
@ -82,6 +83,7 @@ trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
|
||||
#[lang = "fn_once"]
|
||||
#[rustc_paren_sugar]
|
||||
trait FnOnce<Args: Tuple> {
|
||||
#[lang = "fn_once_output"]
|
||||
type Output;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
@ -93,7 +95,7 @@ struct ConstFnMutClosure<CapturedData, Function> {
|
||||
}
|
||||
|
||||
#[lang = "tuple_trait"]
|
||||
pub trait Tuple {}
|
||||
trait Tuple {}
|
||||
|
||||
macro_rules! impl_fn_mut_tuple {
|
||||
($($var:ident)*) => {
|
||||
@ -509,3 +511,12 @@ trait StructuralPartialEq {}
|
||||
trait StructuralEq {}
|
||||
|
||||
const fn drop<T: ~const Destruct>(_: T) {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
||||
fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||
arg: ARG,
|
||||
called_in_const: F,
|
||||
called_at_rt: G,
|
||||
) -> RET;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user