Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// process any deferred resolutions.
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
for deferred_call_resolution in deferred_call_resolutions {
deferred_call_resolution.resolve(self);
deferred_call_resolution.resolve(&mut FnCtxt::new(
self,
self.param_env,
closure_def_id,
));
Comment on lines -532 to +536
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was necessary, as otherwise

const FOO: impl Fn() = || {
    let x = || ();
    x()
};

would have performed some checks in the outer closure's body as if it were const, causing the x() invocation to fail because x is not a const closure

}
}

Expand Down
54 changes: 53 additions & 1 deletion compiler/rustc_trait_selection/src/traits/effects.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use rustc_hir::{self as hir, LangItem};
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
use rustc_infer::traits::{
ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode,
PredicateObligation,
};
use rustc_middle::span_bug;
use rustc_middle::traits::query::NoSolution;
Expand Down Expand Up @@ -303,6 +304,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
evaluate_host_effect_for_fn_goal(selcx, obligation)
}
_ => Err(EvaluationFailure::NoSolution),
}
}
Expand Down Expand Up @@ -398,6 +402,54 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
.collect())
}

// 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),

// Coroutines could implement `[const] Fn`,
// but they don't really need to right now.
ty::Closure(..)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _) => {
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),
}
}

fn evaluate_host_effect_from_selection_candidate<'tcx>(
selcx: &mut SelectionContext<'_, 'tcx>,
obligation: &HostEffectObligation<'tcx>,
Expand Down
34 changes: 21 additions & 13 deletions library/core/src/ops/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ use crate::marker::Tuple;
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
// FIXME(const_trait_impl) #[const_trait]
#[const_trait]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we have a proper lib feature and tracking issue here, rather than slapping everything into a 5-year-old issue that was created for an entirely different generation of the const trait RFC evolution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lang feature is not very useful without the lib feature, requiring separate lib features for different traits is just going to require one to add many features when using any somewhat large feature.

We could pick a new tracking issue, but that also just feels like shuffling things around for no good reason.

I have no idea what the process will be for stabilizing any of these, a lot of them are entangled. We'll likely want to stabilize many traits as const together with stabilizing the lang feature to not cause weird ecosystem churn

pub trait Fn<Args: Tuple>: FnMut<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
Expand Down Expand Up @@ -159,7 +160,8 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
// FIXME(const_trait_impl) #[const_trait]
#[const_trait]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
pub trait FnMut<Args: Tuple>: FnOnce<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
Expand Down Expand Up @@ -238,7 +240,8 @@ pub trait FnMut<Args: Tuple>: FnOnce<Args> {
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
// FIXME(const_trait_impl) #[const_trait]
#[const_trait]
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
pub trait FnOnce<Args: Tuple> {
/// The returned type after the call operator is used.
#[lang = "fn_once_output"]
Expand All @@ -254,29 +257,32 @@ mod impls {
use crate::marker::Tuple;

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Tuple, F: ?Sized> Fn<A> for &F
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl<A: Tuple, F: ?Sized> const Fn<A> for &F
where
F: Fn<A>,
F: ~const Fn<A>,
{
extern "rust-call" fn call(&self, args: A) -> F::Output {
(**self).call(args)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Tuple, F: ?Sized> FnMut<A> for &F
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl<A: Tuple, F: ?Sized> const FnMut<A> for &F
where
F: Fn<A>,
F: ~const Fn<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(**self).call(args)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Tuple, F: ?Sized> FnOnce<A> for &F
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F
where
F: Fn<A>,
F: ~const Fn<A>,
{
type Output = F::Output;

Expand All @@ -286,19 +292,21 @@ mod impls {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Tuple, F: ?Sized> FnMut<A> for &mut F
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F
where
F: FnMut<A>,
F: ~const FnMut<A>,
{
extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
(*self).call_mut(args)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Tuple, F: ?Sized> FnOnce<A> for &mut F
#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")]
impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F
where
F: FnMut<A>,
F: ~const FnMut<A>,
{
type Output = F::Output;
extern "rust-call" fn call_once(self, args: A) -> F::Output {
Expand Down
175 changes: 3 additions & 172 deletions tests/ui/consts/fn_trait_refs.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,151 +4,6 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls`
LL | #![feature(const_fn_trait_ref_impls)]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:14:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:21:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
LL | T: [const] FnOnce<()>,
| ^^^^^^^ can't be applied to `FnOnce`
|
note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
LL | T: [const] FnOnce<()>,
| ^^^^^^^ can't be applied to `FnOnce`
|
note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:28:8
|
LL | T: [const] FnOnce<()>,
| ^^^^^^^ can't be applied to `FnOnce`
|
note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:35:8
|
LL | T: [const] Fn<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `Fn`
|
note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: `[const]` can only be applied to `#[const_trait]` traits
--> $DIR/fn_trait_refs.rs:49:8
|
LL | T: [const] FnMut<()> + [const] Destruct,
| ^^^^^^^ can't be applied to `FnMut`
|
note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied
--> $DIR/fn_trait_refs.rs:71:17
|
Expand All @@ -161,31 +16,7 @@ error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied
LL | assert!(test_two == (2, 2));
| ^^^^^^^^^^^^^^^^^^

error[E0015]: cannot call non-const closure in constant functions
--> $DIR/fn_trait_refs.rs:16:5
|
LL | f()
| ^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0015]: cannot call non-const closure in constant functions
--> $DIR/fn_trait_refs.rs:23:5
|
LL | f()
| ^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0015]: cannot call non-const closure in constant functions
--> $DIR/fn_trait_refs.rs:30:5
|
LL | f()
| ^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 21 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0015, E0277, E0635.
For more information about an error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0277, E0635.
For more information about an error, try `rustc --explain E0277`.
Loading
Loading