From 3879acbec090b36454c0384cd8602047b806f47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 6 Mar 2024 23:49:05 +0100 Subject: [PATCH] Suggest assoc ty bound on lifetime in eq constraint --- compiler/rustc_parse/messages.ftl | 10 ++++---- compiler/rustc_parse/src/errors.rs | 17 +++++++++---- compiler/rustc_parse/src/parser/path.rs | 24 ++++++++++++++----- .../recover-assoc-lifetime-constraint.rs | 2 +- .../recover-assoc-lifetime-constraint.stderr | 17 ++++++++----- 5 files changed, 49 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e1d26f090e0d7..960558f1ff625 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -14,10 +14,6 @@ parse_array_index_offset_of = array indexing not supported in offset_of parse_assignment_else_not_allowed = ... else {"{"} ... {"}"} is not allowed -parse_assoc_lifetime = associated lifetimes are not supported - .label = the lifetime is given here - .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime` - parse_associated_static_item_not_allowed = associated `static` items are not allowed parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later @@ -445,6 +441,12 @@ parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated wit .suggestion = remove the lifetime annotation .label = annotated with lifetime here +parse_lifetime_in_eq_constraint = lifetimes are not permitted in this context + .label = lifetime is not allowed here + .context_label = this introduces an associated item binding + .help = if you meant to specify a trait object, write `dyn /* Trait */ + {$lifetime}` + .colon_sugg = you might have meant to write a bound here + parse_lone_slash = invalid trailing slash in literal .label = {parse_lone_slash} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 5cad3a568ee2c..7c6bef0d7e4d9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2611,13 +2611,22 @@ pub(crate) struct GenericsInPath { } #[derive(Diagnostic)] -#[diag(parse_assoc_lifetime)] +#[diag(parse_lifetime_in_eq_constraint)] #[help] -pub(crate) struct AssocLifetime { +pub(crate) struct LifetimeInEqConstraint { #[primary_span] - pub span: Span, #[label] - pub lifetime: Span, + pub span: Span, + pub lifetime: Ident, + #[label(parse_context_label)] + pub binding_label: Span, + #[suggestion( + parse_colon_sugg, + style = "verbose", + applicability = "maybe-incorrect", + code = ": " + )] + pub colon_sugg: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9153f2b9d06f3..608cdd945ff94 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -718,7 +718,11 @@ impl<'a> Parser<'a> { let bounds = self.parse_generic_bounds()?; AssocConstraintKind::Bound { bounds } } else if self.eat(&token::Eq) { - self.parse_assoc_equality_term(ident, self.prev_token.span)? + self.parse_assoc_equality_term( + ident, + gen_args.as_ref(), + self.prev_token.span, + )? } else { unreachable!(); }; @@ -753,11 +757,13 @@ impl<'a> Parser<'a> { } /// Parse the term to the right of an associated item equality constraint. - /// That is, parse `` in `Item = `. - /// Right now, this only admits types in ``. + /// + /// That is, parse `$term` in `Item = $term` where `$term` is a type or + /// a const expression (wrapped in curly braces if complex). fn parse_assoc_equality_term( &mut self, ident: Ident, + gen_args: Option<&GenericArgs>, eq: Span, ) -> PResult<'a, AssocConstraintKind> { let arg = self.parse_generic_arg(None)?; @@ -769,9 +775,15 @@ impl<'a> Parser<'a> { c.into() } Some(GenericArg::Lifetime(lt)) => { - let guar = - self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); - self.mk_ty(span, ast::TyKind::Err(guar)).into() + let guar = self.dcx().emit_err(errors::LifetimeInEqConstraint { + span: lt.ident.span, + lifetime: lt.ident, + binding_label: span, + colon_sugg: gen_args + .map_or(ident.span, |args| args.span()) + .between(lt.ident.span), + }); + self.mk_ty(lt.ident.span, ast::TyKind::Err(guar)).into() } None => { let after_eq = eq.shrink_to_hi(); diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs index 558fcdfe1776f..cb65f80b08909 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs @@ -1,6 +1,6 @@ #[cfg(FALSE)] fn syntax() { - bar::(); //~ ERROR associated lifetimes are not supported + bar::(); //~ ERROR lifetimes are not permitted in this context } fn main() {} diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr index 39a6682fcaeef..606b737e72314 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr @@ -1,12 +1,17 @@ -error: associated lifetimes are not supported - --> $DIR/recover-assoc-lifetime-constraint.rs:3:11 +error: lifetimes are not permitted in this context + --> $DIR/recover-assoc-lifetime-constraint.rs:3:18 | LL | bar::(); - | ^^^^^^^-- - | | - | the lifetime is given here + | -------^^ + | | | + | | lifetime is not allowed here + | this introduces an associated item binding | - = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime` + = help: if you meant to specify a trait object, write `dyn /* Trait */ + 'a` +help: you might have meant to write a bound here + | +LL | bar::(); + | ~ error: aborting due to 1 previous error