Improve "~const is not allowed here" message

This commit is contained in:
Deadbeef 2022-10-20 19:32:16 +00:00
parent 542febd2d3
commit ebf5028574
6 changed files with 85 additions and 25 deletions

View File

@ -38,6 +38,13 @@ enum SelfSemantic {
No, No,
} }
/// What is the context that prevents using `~const`?
enum DisallowTildeConstContext<'a> {
TraitObject,
ImplTrait,
Fn(FnKind<'a>),
}
struct AstValidator<'a> { struct AstValidator<'a> {
session: &'a Session, session: &'a Session,
@ -56,7 +63,7 @@ struct AstValidator<'a> {
/// e.g., `impl Iterator<Item = impl Debug>`. /// e.g., `impl Iterator<Item = impl Debug>`.
outer_impl_trait: Option<Span>, outer_impl_trait: Option<Span>,
is_tilde_const_allowed: bool, disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
/// or `Foo::Bar<impl Trait>` /// or `Foo::Bar<impl Trait>`
@ -93,18 +100,26 @@ impl<'a> AstValidator<'a> {
self.is_impl_trait_banned = old; self.is_impl_trait_banned = old;
} }
fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) { fn with_tilde_const(
let old = mem::replace(&mut self.is_tilde_const_allowed, allowed); &mut self,
disallowed: Option<DisallowTildeConstContext<'a>>,
f: impl FnOnce(&mut Self),
) {
let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
f(self); f(self);
self.is_tilde_const_allowed = old; self.disallow_tilde_const = old;
} }
fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) { fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
self.with_tilde_const(true, f) self.with_tilde_const(None, f)
} }
fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) { fn with_banned_tilde_const(
self.with_tilde_const(false, f) &mut self,
ctx: DisallowTildeConstContext<'a>,
f: impl FnOnce(&mut Self),
) {
self.with_tilde_const(Some(ctx), f)
} }
fn with_let_management( fn with_let_management(
@ -172,7 +187,7 @@ impl<'a> AstValidator<'a> {
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) { fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer); let old = mem::replace(&mut self.outer_impl_trait, outer);
if outer.is_some() { if outer.is_some() {
self.with_banned_tilde_const(f); self.with_banned_tilde_const(DisallowTildeConstContext::ImplTrait, f);
} else { } else {
f(self); f(self);
} }
@ -197,7 +212,10 @@ impl<'a> AstValidator<'a> {
TyKind::ImplTrait(..) => { TyKind::ImplTrait(..) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t)) self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
} }
TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)), TyKind::TraitObject(..) => self
.with_banned_tilde_const(DisallowTildeConstContext::TraitObject, |this| {
visit::walk_ty(this, t)
}),
TyKind::Path(ref qself, ref path) => { TyKind::Path(ref qself, ref path) => {
// We allow these: // We allow these:
// - `Option<impl Trait>` // - `Option<impl Trait>`
@ -1411,13 +1429,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
); );
err.emit(); err.emit();
} }
(_, TraitBoundModifier::MaybeConst) => { (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => {
if !self.is_tilde_const_allowed { let mut err = self.err_handler().struct_span_err(bound.span(), "`~const` is not allowed here");
self.err_handler() match reason {
.struct_span_err(bound.span(), "`~const` is not allowed here") DisallowTildeConstContext::TraitObject => err.note("trait objects cannot have `~const` trait bounds"),
.note("only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions") DisallowTildeConstContext::ImplTrait => err.note("`impl Trait`s cannot have `~const` trait bounds"),
.emit(); DisallowTildeConstContext::Fn(FnKind::Closure(..)) => err.note("closures cannot have `~const` trait bounds"),
} DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => err.span_note(ident.span, "this function is not `const`, so it cannot have `~const` trait bounds"),
};
err.emit();
} }
(_, TraitBoundModifier::MaybeConstMaybe) => { (_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler() self.err_handler()
@ -1523,10 +1543,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}); });
} }
let tilde_const_allowed = matches!(fk.header(), Some(FnHeader { .. })) let tilde_const_allowed =
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_))); matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk)); let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
} }
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@ -1770,7 +1793,7 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
in_const_trait_impl: false, in_const_trait_impl: false,
has_proc_macro_decls: false, has_proc_macro_decls: false,
outer_impl_trait: None, outer_impl_trait: None,
is_tilde_const_allowed: false, disallow_tilde_const: None,
is_impl_trait_banned: false, is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false, is_assoc_ty_bound_banned: false,
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden), forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),

View File

@ -0,0 +1,9 @@
#![feature(const_trait_impl)]
#[const_trait]
trait Bar {}
fn foo<T>() where T: ~const Bar {}
//~^ ERROR `~const` is not allowed
fn main() {}

View File

@ -0,0 +1,14 @@
error: `~const` is not allowed here
--> $DIR/issue-90052.rs:6:22
|
LL | fn foo<T>() where T: ~const Bar {}
| ^^^^^^^^^^
|
note: this function is not `const`, so it cannot have `~const` trait bounds
--> $DIR/issue-90052.rs:6:4
|
LL | fn foo<T>() where T: ~const Bar {}
| ^^^
error: aborting due to previous error

View File

@ -1,4 +1,3 @@
// check-pass
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(generic_arg_infer)] #![feature(generic_arg_infer)]
#![feature(generic_const_exprs)] #![feature(generic_const_exprs)]
@ -24,6 +23,7 @@ impl const Add42 for () {
} }
fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> { fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
//~^ ERROR `~const` is not allowed here
Foo Foo
} }

View File

@ -0,0 +1,14 @@
error: `~const` is not allowed here
--> $DIR/tilde-const-and-const-params.rs:25:11
|
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
| ^^^^^^^^^^^^
|
note: this function is not `const`, so it cannot have `~const` trait bounds
--> $DIR/tilde-const-and-const-params.rs:25:4
|
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
| ^^^
error: aborting due to previous error

View File

@ -4,7 +4,7 @@ error: `~const` is not allowed here
LL | fn rpit() -> impl ~const T { S } LL | fn rpit() -> impl ~const T { S }
| ^^^^^^^^ | ^^^^^^^^
| |
= note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions = note: `impl Trait`s cannot have `~const` trait bounds
error: `~const` is not allowed here error: `~const` is not allowed here
--> $DIR/tilde-const-invalid-places.rs:12:17 --> $DIR/tilde-const-invalid-places.rs:12:17
@ -12,7 +12,7 @@ error: `~const` is not allowed here
LL | fn apit(_: impl ~const T) {} LL | fn apit(_: impl ~const T) {}
| ^^^^^^^^ | ^^^^^^^^
| |
= note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions = note: `impl Trait`s cannot have `~const` trait bounds
error: `~const` is not allowed here error: `~const` is not allowed here
--> $DIR/tilde-const-invalid-places.rs:15:50 --> $DIR/tilde-const-invalid-places.rs:15:50
@ -20,7 +20,7 @@ error: `~const` is not allowed here
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) } LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
| ^^^^^^^^ | ^^^^^^^^
| |
= note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions = note: `impl Trait`s cannot have `~const` trait bounds
error: `~const` is not allowed here error: `~const` is not allowed here
--> $DIR/tilde-const-invalid-places.rs:18:48 --> $DIR/tilde-const-invalid-places.rs:18:48
@ -28,7 +28,7 @@ error: `~const` is not allowed here
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {} LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
| ^^^^^^^^ | ^^^^^^^^
| |
= note: only allowed on bounds on functions, traits' associated types and functions, const impls and its associated functions = note: `impl Trait`s cannot have `~const` trait bounds
error: `~const` and `?` are mutually exclusive error: `~const` and `?` are mutually exclusive
--> $DIR/tilde-const-invalid-places.rs:21:25 --> $DIR/tilde-const-invalid-places.rs:21:25