Allow calling const closures in const items

This commit is contained in:
Oli Scherer
2026-03-11 07:37:29 +00:00
parent e8a4611779
commit 1867653c81
8 changed files with 29 additions and 22 deletions
@@ -1069,6 +1069,9 @@ pub(super) fn const_conditions<'tcx>(
},
// N.B. Tuple ctors are unconditionally constant.
Node::Ctor(hir::VariantData::Tuple { .. }) => return Default::default(),
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_), .. }) => {
(hir::Generics::empty(), None, tcx.is_conditionally_const(tcx.local_parent(def_id)))
}
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
};
@@ -402,6 +402,11 @@ fn fn_is_const(self, def_id: DefId) -> bool {
self.is_conditionally_const(def_id)
}
fn closure_is_const(self, def_id: DefId) -> bool {
debug_assert_matches!(self.def_kind(def_id), DefKind::Closure);
self.constness(def_id) == hir::Constness::Const
}
fn alias_has_const_conditions(self, def_id: DefId) -> bool {
debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::OpaqueTy);
self.is_conditionally_const(def_id)
+1 -5
View File
@@ -2118,11 +2118,7 @@ pub fn is_conditionally_const(self, def_id: impl Into<DefId>) -> bool {
// FIXME(const_trait_impl): ATPITs could be conditionally const?
hir::OpaqueTyOrigin::TyAlias { .. } => false,
},
DefKind::Closure => {
// Closures and RPITs will eventually have const conditions
// for `[const]` bounds.
false
}
DefKind::Closure => self.constness(def_id) == hir::Constness::Const,
DefKind::Ctor(_, CtorKind::Const)
| DefKind::Mod
| DefKind::Struct
@@ -661,10 +661,11 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>(
///
/// Doing so on all calls to `extract_tupled_inputs_and_output_from_callable`
/// would be wasteful.
#[instrument(level = "trace", skip(cx), ret)]
pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
cx: I,
self_ty: I::Ty,
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> {
) -> Result<(ty::Binder<I, (I::Ty, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> {
match self_ty.kind() {
ty::FnDef(def_id, args) => {
let sig = cx.fn_sig(def_id);
@@ -675,7 +676,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
Ok((
sig.instantiate(cx, args)
.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())),
def_id,
def_id.into(),
args,
))
} else {
@@ -686,9 +687,19 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
ty::FnPtr(..) => {
return Err(NoSolution);
}
// `Closure`s are not const for now.
ty::Closure(..) => {
return Err(NoSolution);
ty::Closure(def, args) => {
if cx.closure_is_const(def) {
let closure_args = args.as_closure();
Ok((
closure_args
.sig()
.map_bound(|sig| (sig.inputs().get(0).unwrap(), sig.output())),
def.into(),
args,
))
} else {
return Err(NoSolution);
}
}
// `CoroutineClosure`s are not const for now.
ty::CoroutineClosure(..) => {
@@ -272,6 +272,7 @@ fn consider_builtin_fn_ptr_trait_candidate(
todo!("Fn* are not yet const")
}
#[instrument(level = "trace", skip_all, ret)]
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
@@ -289,7 +290,7 @@ fn consider_builtin_fn_trait_candidates(
let output_is_sized_pred =
ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]);
let requirements = cx
.const_conditions(def_id.into())
.const_conditions(def_id)
.iter_instantiated(cx, args)
.map(|trait_ref| {
(
+1
View File
@@ -308,6 +308,7 @@ fn impl_super_outlives(
fn impl_is_const(self, def_id: Self::ImplId) -> bool;
fn fn_is_const(self, def_id: Self::FunctionId) -> bool;
fn closure_is_const(self, def_id: Self::ClosureId) -> bool;
fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool;
fn const_conditions(
self,
+1 -2
View File
@@ -1,11 +1,10 @@
// FIXME(const_trait_impl) check-pass
//@ check-pass
//@ compile-flags: -Znext-solver
#![feature(const_closures, const_trait_impl)]
#![allow(incomplete_features)]
const _: () = {
assert!((const || true)());
//~^ ERROR }: const Fn()` is not satisfied
};
fn main() {}
-9
View File
@@ -1,9 +0,0 @@
error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: const Fn()` is not satisfied
--> $DIR/call.rs:7:13
|
LL | assert!((const || true)());
| ^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.