Skip to content

Commit 76614e4

Browse files
Implement ~const Fn trait goals in the new solver
1 parent d8ea700 commit 76614e4

File tree

7 files changed

+164
-15
lines changed

7 files changed

+164
-15
lines changed

compiler/rustc_middle/src/ty/context.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
383383
self.explicit_implied_predicates_of(def_id).map_bound(|preds| preds.into_iter().copied())
384384
}
385385

386-
fn is_const_impl(self, def_id: DefId) -> bool {
386+
fn impl_is_const(self, def_id: DefId) -> bool {
387+
self.is_conditionally_const(def_id)
388+
}
389+
390+
fn fn_is_const(self, def_id: DefId) -> bool {
387391
self.is_conditionally_const(def_id)
388392
}
389393

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+108-9
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
44
use rustc_type_ir::fast_reject::DeepRejectCtxt;
55
use rustc_type_ir::inherent::*;
6-
use rustc_type_ir::{self as ty, Interner, elaborate};
6+
use rustc_type_ir::lang_items::TraitSolverLangItem;
7+
use rustc_type_ir::{self as ty, Interner, Upcast, elaborate};
78
use tracing::instrument;
89

910
use super::assembly::Candidate;
1011
use crate::delegate::SolverDelegate;
11-
use crate::solve::assembly::{self};
1212
use crate::solve::{
1313
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, NoSolution,
14-
QueryResult,
14+
QueryResult, assembly,
1515
};
1616

1717
impl<D, I> assembly::GoalKind<D> for ty::HostEffectPredicate<I>
@@ -142,7 +142,7 @@ where
142142
ty::ImplPolarity::Positive => {}
143143
};
144144

145-
if !cx.is_const_impl(impl_def_id) {
145+
if !cx.impl_is_const(impl_def_id) {
146146
return Err(NoSolution);
147147
}
148148

@@ -204,7 +204,7 @@ where
204204
_ecx: &mut EvalCtxt<'_, D>,
205205
_goal: Goal<I, Self>,
206206
) -> Result<Candidate<I>, NoSolution> {
207-
todo!("Copy/Clone is not yet const")
207+
Err(NoSolution)
208208
}
209209

210210
fn consider_builtin_pointer_like_candidate(
@@ -222,11 +222,110 @@ where
222222
}
223223

224224
fn consider_builtin_fn_trait_candidates(
225-
_ecx: &mut EvalCtxt<'_, D>,
226-
_goal: Goal<I, Self>,
225+
ecx: &mut EvalCtxt<'_, D>,
226+
goal: Goal<I, Self>,
227227
_kind: rustc_type_ir::ClosureKind,
228228
) -> Result<Candidate<I>, NoSolution> {
229-
todo!("Fn* are not yet const")
229+
let cx = ecx.cx();
230+
231+
let self_ty = goal.predicate.self_ty();
232+
let (tupled_inputs_and_output, def_id, args) = match self_ty.kind() {
233+
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
234+
ty::FnDef(def_id, args) => {
235+
let sig = cx.fn_sig(def_id);
236+
if sig.skip_binder().is_fn_trait_compatible()
237+
&& !cx.has_target_features(def_id)
238+
&& cx.fn_is_const(def_id)
239+
{
240+
(
241+
sig.instantiate(cx, args).map_bound(|sig| {
242+
(Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())
243+
}),
244+
def_id,
245+
args,
246+
)
247+
} else {
248+
return Err(NoSolution);
249+
}
250+
}
251+
// `FnPtr`s are not const for now.
252+
ty::FnPtr(..) => {
253+
return Err(NoSolution);
254+
}
255+
// `Closure`s are not const for now.
256+
ty::Closure(..) => {
257+
return Err(NoSolution);
258+
}
259+
// `CoroutineClosure`s are not const for now.
260+
ty::CoroutineClosure(..) => {
261+
return Err(NoSolution);
262+
}
263+
264+
ty::Bool
265+
| ty::Char
266+
| ty::Int(_)
267+
| ty::Uint(_)
268+
| ty::Float(_)
269+
| ty::Adt(_, _)
270+
| ty::Foreign(_)
271+
| ty::Str
272+
| ty::Array(_, _)
273+
| ty::Slice(_)
274+
| ty::RawPtr(_, _)
275+
| ty::Ref(_, _, _)
276+
| ty::Dynamic(_, _, _)
277+
| ty::Coroutine(_, _)
278+
| ty::CoroutineWitness(..)
279+
| ty::Never
280+
| ty::Tuple(_)
281+
| ty::Pat(_, _)
282+
| ty::Alias(_, _)
283+
| ty::Param(_)
284+
| ty::Placeholder(..)
285+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
286+
| ty::Error(_) => return Err(NoSolution),
287+
288+
ty::Bound(..)
289+
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
290+
panic!("unexpected type `{self_ty:?}`")
291+
}
292+
};
293+
294+
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
295+
ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output])
296+
});
297+
let requirements = cx
298+
.const_conditions(def_id)
299+
.iter_instantiated(cx, args)
300+
.map(|trait_ref| {
301+
(
302+
GoalSource::ImplWhereBound,
303+
goal.with(cx, trait_ref.to_host_effect_clause(cx, goal.predicate.host)),
304+
)
305+
})
306+
// A built-in `Fn` impl only holds if the output is sized.
307+
// (FIXME: technically we only need to check this if the type is a fn ptr...)
308+
.chain([(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))]);
309+
310+
let pred = tupled_inputs_and_output
311+
.map_bound(|(inputs, _)| {
312+
ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
313+
trait_ref: ty::TraitRef::new(cx, goal.predicate.def_id(), [
314+
goal.predicate.self_ty(),
315+
inputs,
316+
]),
317+
host: goal.predicate.host,
318+
})
319+
})
320+
.upcast(cx);
321+
322+
Self::probe_and_consider_implied_clause(
323+
ecx,
324+
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
325+
goal,
326+
pred,
327+
requirements,
328+
)
230329
}
231330

232331
fn consider_builtin_async_fn_trait_candidates(
@@ -311,7 +410,7 @@ where
311410
_ecx: &mut EvalCtxt<'_, D>,
312411
_goal: Goal<I, Self>,
313412
) -> Result<Candidate<I>, NoSolution> {
314-
unreachable!("Destruct is not const")
413+
Err(NoSolution)
315414
}
316415

317416
fn consider_builtin_transmute_candidate(

compiler/rustc_type_ir/src/interner.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ pub trait Interner:
229229
def_id: Self::DefId,
230230
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>>;
231231

232-
fn is_const_impl(self, def_id: Self::DefId) -> bool;
232+
fn impl_is_const(self, def_id: Self::DefId) -> bool;
233+
fn fn_is_const(self, def_id: Self::DefId) -> bool;
233234
fn const_conditions(
234235
self,
235236
def_id: Self::DefId,

tests/ui/traits/const-traits/const-fns-are-early-bound.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
//@ known-bug: #110395
2-
//@ failure-status: 101
3-
//@ dont-check-compiler-stderr
4-
// FIXME(effects) check-pass
1+
//@ check-pass
52
//@ compile-flags: -Znext-solver
63

74
#![crate_type = "lib"]
@@ -88,3 +85,5 @@ trait Tuple {}
8885
trait LegacyReceiver {}
8986

9087
impl<T: ?Sized> LegacyReceiver for &T {}
88+
89+
impl<T: ?Sized> LegacyReceiver for &mut T {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ aux-build:minicore.rs
2+
//@ compile-flags: --crate-type=lib -Znext-solver
3+
4+
#![feature(no_core, const_trait_impl, effects)]
5+
//~^ WARN the feature `effects` is incomplete
6+
#![no_std]
7+
#![no_core]
8+
9+
extern crate minicore;
10+
use minicore::*;
11+
12+
const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
13+
14+
#[const_trait]
15+
trait Foo {}
16+
impl Foo for () {}
17+
const fn foo<T: ~const Foo>() {}
18+
19+
const fn test() {
20+
call_indirect(&foo::<()>);
21+
//~^ ERROR the trait bound `(): ~const Foo` is not satisfied
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/minicore-fn-fail.rs:4:39
3+
|
4+
LL | #![feature(no_core, const_trait_impl, effects)]
5+
| ^^^^^^^
6+
|
7+
= note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: the trait bound `(): ~const Foo` is not satisfied
11+
--> $DIR/minicore-fn-fail.rs:20:5
12+
|
13+
LL | call_indirect(&foo::<()>);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error: aborting due to 1 previous error; 1 warning emitted
17+
18+
For more information about this error, try `rustc --explain E0277`.

tests/ui/traits/const-traits/effects/minicore-works.rs

+6
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,9 @@ const fn test_op() {
2121
let _x = Add::add(1, 2);
2222
let _y = Custom + Custom;
2323
}
24+
25+
const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
26+
27+
const fn call() {
28+
call_indirect(&call);
29+
}

0 commit comments

Comments
 (0)