mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Auto merge of #106210 - fee1-dead-contrib:const-closure-trait-method, r=compiler-errors
Allow trait method paths to satisfy const Fn bounds r? `@oli-obk`
This commit is contained in:
commit
973a4db8d5
@ -12,8 +12,8 @@ use rustc_index::bit_set::GrowableBitSet;
|
|||||||
use rustc_infer::infer::InferOk;
|
use rustc_infer::infer::InferOk;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
|
self, Binder, GenericArg, GenericArgKind, GenericParamDefKind, InternalSubsts, SubstsRef,
|
||||||
ToPolyTraitRef, ToPredicate, Ty, TyCtxt,
|
ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt,
|
||||||
};
|
};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
|
||||||
@ -98,8 +98,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplSource::Future(vtable_future)
|
ImplSource::Future(vtable_future)
|
||||||
}
|
}
|
||||||
|
|
||||||
FnPointerCandidate { .. } => {
|
FnPointerCandidate { is_const } => {
|
||||||
let data = self.confirm_fn_pointer_candidate(obligation)?;
|
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
|
||||||
ImplSource::FnPointer(data)
|
ImplSource::FnPointer(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,17 +597,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
fn confirm_fn_pointer_candidate(
|
fn confirm_fn_pointer_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &TraitObligation<'tcx>,
|
obligation: &TraitObligation<'tcx>,
|
||||||
|
is_const: bool,
|
||||||
) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
|
||||||
{
|
{
|
||||||
debug!(?obligation, "confirm_fn_pointer_candidate");
|
debug!(?obligation, "confirm_fn_pointer_candidate");
|
||||||
|
|
||||||
|
let tcx = self.tcx();
|
||||||
let self_ty = self
|
let self_ty = self
|
||||||
.infcx
|
.infcx
|
||||||
.shallow_resolve(obligation.self_ty().no_bound_vars())
|
.shallow_resolve(obligation.self_ty().no_bound_vars())
|
||||||
.expect("fn pointer should not capture bound vars from predicate");
|
.expect("fn pointer should not capture bound vars from predicate");
|
||||||
let sig = self_ty.fn_sig(self.tcx());
|
let sig = self_ty.fn_sig(tcx);
|
||||||
let trait_ref = closure_trait_ref_and_return_type(
|
let trait_ref = closure_trait_ref_and_return_type(
|
||||||
self.tcx(),
|
tcx,
|
||||||
obligation.predicate.def_id(),
|
obligation.predicate.def_id(),
|
||||||
self_ty,
|
self_ty,
|
||||||
sig,
|
sig,
|
||||||
@ -616,9 +618,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
.map_bound(|(trait_ref, _)| trait_ref);
|
.map_bound(|(trait_ref, _)| trait_ref);
|
||||||
|
|
||||||
let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
||||||
|
let cause = obligation.derived_cause(BuiltinDerivedObligation);
|
||||||
|
|
||||||
|
if obligation.is_const() && !is_const {
|
||||||
|
// function is a trait method
|
||||||
|
if let ty::FnDef(def_id, substs) = self_ty.kind() && let Some(trait_id) = tcx.trait_of_item(*def_id) {
|
||||||
|
let trait_ref = TraitRef::from_method(tcx, trait_id, *substs);
|
||||||
|
let poly_trait_pred = Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
|
||||||
|
let obligation = Obligation::new(tcx, cause.clone(), obligation.param_env, poly_trait_pred);
|
||||||
|
nested.push(obligation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Confirm the `type Output: Sized;` bound that is present on `FnOnce`
|
// Confirm the `type Output: Sized;` bound that is present on `FnOnce`
|
||||||
let cause = obligation.derived_cause(BuiltinDerivedObligation);
|
|
||||||
let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
|
let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
|
||||||
let output_ty = normalize_with_depth_to(
|
let output_ty = normalize_with_depth_to(
|
||||||
self,
|
self,
|
||||||
|
@ -1374,6 +1374,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
FutureCandidate => {}
|
FutureCandidate => {}
|
||||||
// FnDef where the function is const
|
// FnDef where the function is const
|
||||||
FnPointerCandidate { is_const: true } => {}
|
FnPointerCandidate { is_const: true } => {}
|
||||||
|
FnPointerCandidate { is_const: false } => {
|
||||||
|
if let ty::FnDef(def_id, _) = obligation.self_ty().skip_binder().kind() && tcx.trait_of_item(*def_id).is_some() {
|
||||||
|
// Trait methods are not seen as const unless the trait is implemented as const.
|
||||||
|
// We do not filter that out in here, but nested obligations will be needed to confirm this.
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
ConstDestructCandidate(_) => {}
|
ConstDestructCandidate(_) => {}
|
||||||
_ => {
|
_ => {
|
||||||
// reject all other types of candidates
|
// reject all other types of candidates
|
||||||
|
@ -798,9 +798,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
|||||||
Self: Sized,
|
Self: Sized,
|
||||||
Self: ~const Destruct,
|
Self: ~const Destruct,
|
||||||
{
|
{
|
||||||
// HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
|
#[cfg(not(bootstrap))]
|
||||||
// when trait methods are allowed to be used when a const closure is
|
{
|
||||||
// expected.
|
max_by(self, other, Ord::cmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
match self.cmp(&other) {
|
match self.cmp(&other) {
|
||||||
Ordering::Less | Ordering::Equal => other,
|
Ordering::Less | Ordering::Equal => other,
|
||||||
Ordering::Greater => self,
|
Ordering::Greater => self,
|
||||||
@ -825,9 +828,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
|
|||||||
Self: Sized,
|
Self: Sized,
|
||||||
Self: ~const Destruct,
|
Self: ~const Destruct,
|
||||||
{
|
{
|
||||||
// HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
|
#[cfg(not(bootstrap))]
|
||||||
// when trait methods are allowed to be used when a const closure is
|
{
|
||||||
// expected.
|
min_by(self, other, Ord::cmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
match self.cmp(&other) {
|
match self.cmp(&other) {
|
||||||
Ordering::Less | Ordering::Equal => self,
|
Ordering::Less | Ordering::Equal => self,
|
||||||
Ordering::Greater => other,
|
Ordering::Greater => other,
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
|
trait Tr {
|
||||||
|
fn a(self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tr for () {
|
||||||
|
fn a(self) -> i32 { 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
|
||||||
|
x(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(need_const_closure(Tr::a) == 42);
|
||||||
|
//~^ ERROR: the trait bound
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,23 @@
|
|||||||
|
error[E0277]: the trait bound `(): ~const Tr` is not satisfied in `fn(()) -> i32 {<() as Tr>::a}`
|
||||||
|
--> $DIR/const-closure-trait-method-fail.rs:16:42
|
||||||
|
|
|
||||||
|
LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
|
||||||
|
| ------------------ ^^^^^ within `fn(()) -> i32 {<() as Tr>::a}`, the trait `~const Tr` is not implemented for `()`
|
||||||
|
| |
|
||||||
|
| required by a bound introduced by this call
|
||||||
|
|
|
||||||
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
|
||||||
|
--> $DIR/const-closure-trait-method-fail.rs:16:42
|
||||||
|
|
|
||||||
|
LL | const _: () = assert!(need_const_closure(Tr::a) == 42);
|
||||||
|
| ^^^^^
|
||||||
|
= note: required because it appears within the type `fn(()) -> i32 {<() as Tr>::a}`
|
||||||
|
note: required by a bound in `need_const_closure`
|
||||||
|
--> $DIR/const-closure-trait-method-fail.rs:12:32
|
||||||
|
|
|
||||||
|
LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `need_const_closure`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,19 @@
|
|||||||
|
// check-pass
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
#[const_trait]
|
||||||
|
trait Tr {
|
||||||
|
fn a(self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const Tr for () {
|
||||||
|
fn a(self) -> i32 { 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
|
||||||
|
x(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = assert!(need_const_closure(Tr::a) == 42);
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user