Skip to content

Commit f4199f7

Browse files
committed
Parse contextual dyn keyword properly in edition 2015
1 parent 9fd6c69 commit f4199f7

File tree

10 files changed

+164
-11
lines changed

10 files changed

+164
-11
lines changed

crates/mbe/src/to_parser_input.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ pub(crate) fn to_parser_input<S: Copy + fmt::Debug>(
6565
i if i.starts_with('\'') => res.push(LIFETIME_IDENT),
6666
_ if ident.is_raw.yes() => res.push(IDENT),
6767
"gen" if !edition.at_least_2024() => res.push(IDENT),
68-
"async" | "await" | "dyn" | "try" if !edition.at_least_2018() => {
69-
res.push(IDENT)
70-
}
68+
"dyn" if !edition.at_least_2018() => res.push_ident(DYN_KW),
69+
"async" | "await" | "try" if !edition.at_least_2018() => res.push(IDENT),
7170
text => match SyntaxKind::from_keyword(text) {
7271
Some(kind) => res.push(kind),
7372
None => {

crates/parser/src/grammar/paths.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use super::*;
22

33
pub(super) const PATH_FIRST: TokenSet =
44
TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
5+
pub(super) const WEAK_DYN_PATH_FIRST: TokenSet =
6+
TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]);
57

68
pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
79
is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])

crates/parser/src/grammar/types.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::grammar::paths::WEAK_DYN_PATH_FIRST;
2+
13
use super::*;
24

35
pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
@@ -49,6 +51,13 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
4951
T![dyn] => dyn_trait_type(p),
5052
// Some path types are not allowed to have bounds (no plus)
5153
T![<] => path_type_bounds(p, allow_bounds),
54+
T![ident]
55+
if !p.edition().at_least_2018()
56+
&& p.at_contextual_kw(T![dyn])
57+
&& WEAK_DYN_PATH_FIRST.contains(p.nth(1)) =>
58+
{
59+
dyn_trait_type_weak(p)
60+
}
5261
_ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
5362
LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
5463
_ => {
@@ -279,6 +288,18 @@ fn dyn_trait_type(p: &mut Parser<'_>) {
279288
m.complete(p, DYN_TRAIT_TYPE);
280289
}
281290

291+
// test dyn_trait_type_weak 2015
292+
// type A = dyn Iterator<Item=Foo<'a>> + 'a;
293+
// type A = &dyn Iterator<Item=Foo<'a>> + 'a;
294+
// type A = dyn::Path;
295+
fn dyn_trait_type_weak(p: &mut Parser<'_>) {
296+
assert!(p.at_contextual_kw(T![dyn]));
297+
let m = p.start();
298+
p.bump_remap(T![dyn]);
299+
generic_params::bounds_without_colon(p);
300+
m.complete(p, DYN_TRAIT_TYPE);
301+
}
302+
282303
// test bare_dyn_types_with_leading_lifetime
283304
// type A = 'static + Trait;
284305
// type B = S<'static + Trait>;

crates/parser/src/parser.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ pub(crate) struct Parser<'t> {
2727
pos: usize,
2828
events: Vec<Event>,
2929
steps: Cell<u32>,
30-
_edition: Edition,
30+
edition: Edition,
3131
}
3232

3333
static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
3434

3535
impl<'t> Parser<'t> {
3636
pub(super) fn new(inp: &'t Input, edition: Edition) -> Parser<'t> {
37-
Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0), _edition: edition }
37+
Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0), edition: edition }
3838
}
3939

4040
pub(crate) fn finish(self) -> Vec<Event> {
@@ -277,6 +277,10 @@ impl<'t> Parser<'t> {
277277
fn push_event(&mut self, event: Event) {
278278
self.events.push(event);
279279
}
280+
281+
pub(crate) fn edition(&self) -> Edition {
282+
self.edition
283+
}
280284
}
281285

282286
/// See [`Parser::start`].

crates/parser/src/shortcuts.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use std::mem;
1313

1414
use crate::{
15-
LexedStr, Step,
15+
Edition, LexedStr, Step,
1616
SyntaxKind::{self, *},
1717
};
1818

@@ -25,7 +25,7 @@ pub enum StrStep<'a> {
2525
}
2626

2727
impl LexedStr<'_> {
28-
pub fn to_input(&self) -> crate::Input {
28+
pub fn to_input(&self, edition: Edition) -> crate::Input {
2929
let _p = tracing::info_span!("LexedStr::to_input").entered();
3030
let mut res = crate::Input::default();
3131
let mut was_joint = false;
@@ -35,8 +35,11 @@ impl LexedStr<'_> {
3535
was_joint = false
3636
} else if kind == SyntaxKind::IDENT {
3737
let token_text = self.text(i);
38-
let contextual_kw =
39-
SyntaxKind::from_contextual_keyword(token_text).unwrap_or(SyntaxKind::IDENT);
38+
let contextual_kw = if !edition.at_least_2018() && token_text == "dyn" {
39+
SyntaxKind::DYN_KW
40+
} else {
41+
SyntaxKind::from_contextual_keyword(token_text).unwrap_or(SyntaxKind::IDENT)
42+
};
4043
res.push_ident(contextual_kw);
4144
} else {
4245
if was_joint {

crates/parser/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ fn parse_err() {
7070

7171
fn parse(entry: TopEntryPoint, text: &str, edition: Edition) -> (String, bool) {
7272
let lexed = LexedStr::new(edition, text);
73-
let input = lexed.to_input();
73+
let input = lexed.to_input(edition);
7474
let output = entry.parse(&input, edition);
7575

7676
let mut buf = String::new();

crates/parser/src/tests/prefix_entries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn meta_item() {
8383
#[track_caller]
8484
fn check(entry: PrefixEntryPoint, input: &str, prefix: &str) {
8585
let lexed = LexedStr::new(Edition::CURRENT, input);
86-
let input = lexed.to_input();
86+
let input = lexed.to_input(Edition::CURRENT);
8787

8888
let mut n_tokens = 0;
8989
for step in entry.parse(&input, Edition::CURRENT).iter() {

crates/parser/test_data/generated/runner.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ mod ok {
195195
run_and_expect_no_errors("test_data/parser/inline/ok/dyn_trait_type.rs");
196196
}
197197
#[test]
198+
fn dyn_trait_type_weak() {
199+
run_and_expect_no_errors_with_edition(
200+
"test_data/parser/inline/ok/dyn_trait_type_weak.rs",
201+
crate::Edition::Edition2015,
202+
);
203+
}
204+
#[test]
198205
fn effect_blocks() { run_and_expect_no_errors("test_data/parser/inline/ok/effect_blocks.rs"); }
199206
#[test]
200207
fn exclusive_range_pat() {
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
SOURCE_FILE
2+
TYPE_ALIAS
3+
COMMENT "// 2015"
4+
WHITESPACE "\n"
5+
TYPE_KW "type"
6+
WHITESPACE " "
7+
NAME
8+
IDENT "A"
9+
WHITESPACE " "
10+
EQ "="
11+
WHITESPACE " "
12+
DYN_TRAIT_TYPE
13+
DYN_KW "dyn"
14+
WHITESPACE " "
15+
TYPE_BOUND_LIST
16+
TYPE_BOUND
17+
PATH_TYPE
18+
PATH
19+
PATH_SEGMENT
20+
NAME_REF
21+
IDENT "Iterator"
22+
GENERIC_ARG_LIST
23+
L_ANGLE "<"
24+
ASSOC_TYPE_ARG
25+
NAME_REF
26+
IDENT "Item"
27+
EQ "="
28+
PATH_TYPE
29+
PATH
30+
PATH_SEGMENT
31+
NAME_REF
32+
IDENT "Foo"
33+
GENERIC_ARG_LIST
34+
L_ANGLE "<"
35+
LIFETIME_ARG
36+
LIFETIME
37+
LIFETIME_IDENT "'a"
38+
R_ANGLE ">"
39+
R_ANGLE ">"
40+
WHITESPACE " "
41+
PLUS "+"
42+
WHITESPACE " "
43+
TYPE_BOUND
44+
LIFETIME
45+
LIFETIME_IDENT "'a"
46+
SEMICOLON ";"
47+
WHITESPACE "\n"
48+
TYPE_ALIAS
49+
TYPE_KW "type"
50+
WHITESPACE " "
51+
NAME
52+
IDENT "A"
53+
WHITESPACE " "
54+
EQ "="
55+
WHITESPACE " "
56+
REF_TYPE
57+
AMP "&"
58+
DYN_TRAIT_TYPE
59+
DYN_KW "dyn"
60+
WHITESPACE " "
61+
TYPE_BOUND_LIST
62+
TYPE_BOUND
63+
PATH_TYPE
64+
PATH
65+
PATH_SEGMENT
66+
NAME_REF
67+
IDENT "Iterator"
68+
GENERIC_ARG_LIST
69+
L_ANGLE "<"
70+
ASSOC_TYPE_ARG
71+
NAME_REF
72+
IDENT "Item"
73+
EQ "="
74+
PATH_TYPE
75+
PATH
76+
PATH_SEGMENT
77+
NAME_REF
78+
IDENT "Foo"
79+
GENERIC_ARG_LIST
80+
L_ANGLE "<"
81+
LIFETIME_ARG
82+
LIFETIME
83+
LIFETIME_IDENT "'a"
84+
R_ANGLE ">"
85+
R_ANGLE ">"
86+
WHITESPACE " "
87+
PLUS "+"
88+
WHITESPACE " "
89+
TYPE_BOUND
90+
LIFETIME
91+
LIFETIME_IDENT "'a"
92+
SEMICOLON ";"
93+
WHITESPACE "\n"
94+
TYPE_ALIAS
95+
TYPE_KW "type"
96+
WHITESPACE " "
97+
NAME
98+
IDENT "A"
99+
WHITESPACE " "
100+
EQ "="
101+
WHITESPACE " "
102+
PATH_TYPE
103+
PATH
104+
PATH
105+
PATH_SEGMENT
106+
NAME_REF
107+
IDENT "dyn"
108+
COLON2 "::"
109+
PATH_SEGMENT
110+
NAME_REF
111+
IDENT "Path"
112+
SEMICOLON ";"
113+
WHITESPACE "\n"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// 2015
2+
type A = dyn Iterator<Item=Foo<'a>> + 'a;
3+
type A = &dyn Iterator<Item=Foo<'a>> + 'a;
4+
type A = dyn::Path;

0 commit comments

Comments
 (0)