about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-05-05 09:23:32 +0000
committerbors <bors@rust-lang.org>2023-05-05 09:23:32 +0000
commite461e53f0163fd2c7c443c5ca8335b6554b80619 (patch)
tree4a49e2c293fdada1c5b045a828ca51df7275464c
parent0dd94d3b078fa524272f942f69239a9564532fe1 (diff)
parent2a509d0eb2f17464502727797af1911b94b726f1 (diff)
downloadrust-e461e53f0163fd2c7c443c5ca8335b6554b80619.tar.gz
rust-e461e53f0163fd2c7c443c5ca8335b6554b80619.zip
Auto merge of #14739 - lowr:fix/type-with-leading-lifetime, r=Veykril
Parse bare dyn types with leading lifetime

TIL types may start with a lifetime identifier e.g. `type A = 'static + Trait;`. When parsing types, leading lifetime followed by a plus sign should be parsed as a bare dyn type rather than a generic lifetime argument or error type (which is what we produce today).

Although it's no longer accepted since Rust 2021, it wouldn't hurt to support this obsolete syntax.
-rw-r--r--crates/parser/src/grammar/generic_args.rs2
-rw-r--r--crates/parser/src/grammar/types.rs11
-rw-r--r--crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast58
-rw-r--r--crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs2
4 files changed, 72 insertions, 1 deletions
diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs
index 55794954a82..4cac04a32a4 100644
--- a/crates/parser/src/grammar/generic_args.rs
+++ b/crates/parser/src/grammar/generic_args.rs
@@ -35,7 +35,7 @@ const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
 // type T = S<i32>;
 fn generic_arg(p: &mut Parser<'_>) -> bool {
     match p.current() {
-        LIFETIME_IDENT => lifetime_arg(p),
+        LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p),
         T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
         k if k.is_literal() => const_arg(p),
         // test associated_type_bounds
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 5ae16475b65..26dac87956c 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -15,6 +15,7 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
     T![impl],
     T![dyn],
     T![Self],
+    LIFETIME_IDENT,
 ]));
 
 pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
@@ -49,6 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
         // Some path types are not allowed to have bounds (no plus)
         T![<] => path_type_(p, allow_bounds),
         _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
+        LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
         _ => {
             p.err_recover("expected type", TYPE_RECOVERY_SET);
         }
@@ -275,6 +277,15 @@ fn dyn_trait_type(p: &mut Parser<'_>) {
     m.complete(p, DYN_TRAIT_TYPE);
 }
 
+// test bare_dyn_types_with_leading_lifetime
+// type A = 'static + Trait;
+// type B = S<'static + Trait>;
+fn bare_dyn_trait_type(p: &mut Parser<'_>) {
+    let m = p.start();
+    generic_params::bounds_without_colon(p);
+    m.complete(p, DYN_TRAIT_TYPE);
+}
+
 // test path_type
 // type A = Foo;
 // type B = ::Foo;
diff --git a/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast
new file mode 100644
index 00000000000..d7e67fbcd15
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rast
@@ -0,0 +1,58 @@
+SOURCE_FILE
+  TYPE_ALIAS
+    TYPE_KW "type"
+    WHITESPACE " "
+    NAME
+      IDENT "A"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    DYN_TRAIT_TYPE
+      TYPE_BOUND_LIST
+        TYPE_BOUND
+          LIFETIME
+            LIFETIME_IDENT "'static"
+        WHITESPACE " "
+        PLUS "+"
+        WHITESPACE " "
+        TYPE_BOUND
+          PATH_TYPE
+            PATH
+              PATH_SEGMENT
+                NAME_REF
+                  IDENT "Trait"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  TYPE_ALIAS
+    TYPE_KW "type"
+    WHITESPACE " "
+    NAME
+      IDENT "B"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    PATH_TYPE
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "S"
+          GENERIC_ARG_LIST
+            L_ANGLE "<"
+            TYPE_ARG
+              DYN_TRAIT_TYPE
+                TYPE_BOUND_LIST
+                  TYPE_BOUND
+                    LIFETIME
+                      LIFETIME_IDENT "'static"
+                  WHITESPACE " "
+                  PLUS "+"
+                  WHITESPACE " "
+                  TYPE_BOUND
+                    PATH_TYPE
+                      PATH
+                        PATH_SEGMENT
+                          NAME_REF
+                            IDENT "Trait"
+            R_ANGLE ">"
+    SEMICOLON ";"
+  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs
new file mode 100644
index 00000000000..3e9a9a29ddc
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0208_bare_dyn_types_with_leading_lifetime.rs
@@ -0,0 +1,2 @@
+type A = 'static + Trait;
+type B = S<'static + Trait>;