Const stability on impls doesn't make sense
Closed this issue · 8 comments
Const stability on impls makes no sense in the same way that stability on impls makes no sense, since you can always put a const call behind some generic type parameter and only see the impl after substitution/monomorphization.
We currently have code in the MIR const validation to handle const impls, and we shouldn't.
The dilemma here is that we allow unstable on impls, so I guess we should keep allowing rustc_const_unstable on impls, too. We just obviously shouldn't enforce anything about them.
Notice how, on 1.65:
#![feature(const_trait_impl)]
use std::ops::Add;
use std::marker::Destruct;
const fn foo(t: i32, t2: i32) {
Add::add(t, t2);
}
const fn test() {
foo(1, 2);
}errors with:
error: `<i32 as Add>::add` is not yet stable as a const fn
--> <source>:7:5
|
7 | Add::add(t, t2);
| ^^^^^^^^^^^^^^^
|
= help: add `#![feature(const_ops)]` to the crate attributes to enable
But I can write:
#![feature(const_trait_impl)]
use std::ops::Add;
use std::marker::Destruct;
const fn foo<T: ~const Add<Output = T> + ~const Destruct>(t: T, t2: T) {
Add::add(t, t2);
}
const fn test() {
foo(1, 2);
}and it works totally fine.
The dilemma here is that we allow unstable on impls, so I guess we should keep allowing rustc_const_unstable on impls, too. We just obviously shouldn't enforce anything about them.
Why should we repeat the mistake? We should disallow both, since they can't reasonably have an effect with the current solver.
Regarding the examples -- we can stage the rollout of const trait in various ways:
- All at once, i.e. once const_trait_impl is stable all
const implfor stable traits are immediately available on stable - Trait-for-trait, i.e. a stable trait has to be separately marked as
#[rustc_const_stable]to allow~const Traitbounds and trait method calls inconst fn - Trait-fn-trait-fn, i.e. even in a const-stable trait we can separately control which functions can be const-called on stable.
It's hard for me to say how much granularity we will need.
I think (2.) makes sense.
Thinking about what additional stability guarantees should be imposed to fix this:
- Traits need to have their own const stability. Probably with the same rules as @RalfJung's const stability rework, i.e. either marked const-stable/const-unstable if theyre stable (idk if we want to allow them to be marked const-indirect-stable?), or unmarked/const-unstable if they're unstable.
- I think we should additionally validate that all const impls of a const-stable trait are marked const-stable (or perhaps const-indirect-stable if the impl is unstable?), and probably that all const impls of an const-unstable trait remain marked const-unstable, unless we want to make it so that calls to specific const impls are stable before the trait, for example, becomes stable.
For now, I guess we can just always require const traits and impls to be const-unstable (either explicitly, or implicitly via #[unstable], like regular const fn)