Parse contextual dyn keyword properly in edition 2015

This commit is contained in:
Lukas Wirth 2024-07-19 20:20:00 +02:00
parent 9fd6c695da
commit f4199f786e
10 changed files with 164 additions and 11 deletions

View file

@ -2,6 +2,8 @@ use super::*;
pub(super) const PATH_FIRST: TokenSet =
TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
pub(super) const WEAK_DYN_PATH_FIRST: TokenSet =
TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]);
pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])

View file

@ -1,3 +1,5 @@
use crate::grammar::paths::WEAK_DYN_PATH_FIRST;
use super::*;
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) {
T![dyn] => dyn_trait_type(p),
// Some path types are not allowed to have bounds (no plus)
T![<] => path_type_bounds(p, allow_bounds),
T![ident]
if !p.edition().at_least_2018()
&& p.at_contextual_kw(T![dyn])
&& WEAK_DYN_PATH_FIRST.contains(p.nth(1)) =>
{
dyn_trait_type_weak(p)
}
_ 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),
_ => {
@ -279,6 +288,18 @@ fn dyn_trait_type(p: &mut Parser<'_>) {
m.complete(p, DYN_TRAIT_TYPE);
}
// test dyn_trait_type_weak 2015
// type A = dyn Iterator<Item=Foo<'a>> + 'a;
// type A = &dyn Iterator<Item=Foo<'a>> + 'a;
// type A = dyn::Path;
fn dyn_trait_type_weak(p: &mut Parser<'_>) {
assert!(p.at_contextual_kw(T![dyn]));
let m = p.start();
p.bump_remap(T![dyn]);
generic_params::bounds_without_colon(p);
m.complete(p, DYN_TRAIT_TYPE);
}
// test bare_dyn_types_with_leading_lifetime
// type A = 'static + Trait;
// type B = S<'static + Trait>;

View file

@ -27,14 +27,14 @@ pub(crate) struct Parser<'t> {
pos: usize,
events: Vec<Event>,
steps: Cell<u32>,
_edition: Edition,
edition: Edition,
}
static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
impl<'t> Parser<'t> {
pub(super) fn new(inp: &'t Input, edition: Edition) -> Parser<'t> {
Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0), _edition: edition }
Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0), edition: edition }
}
pub(crate) fn finish(self) -> Vec<Event> {
@ -277,6 +277,10 @@ impl<'t> Parser<'t> {
fn push_event(&mut self, event: Event) {
self.events.push(event);
}
pub(crate) fn edition(&self) -> Edition {
self.edition
}
}
/// See [`Parser::start`].

View file

@ -12,7 +12,7 @@
use std::mem;
use crate::{
LexedStr, Step,
Edition, LexedStr, Step,
SyntaxKind::{self, *},
};
@ -25,7 +25,7 @@ pub enum StrStep<'a> {
}
impl LexedStr<'_> {
pub fn to_input(&self) -> crate::Input {
pub fn to_input(&self, edition: Edition) -> crate::Input {
let _p = tracing::info_span!("LexedStr::to_input").entered();
let mut res = crate::Input::default();
let mut was_joint = false;
@ -35,8 +35,11 @@ impl LexedStr<'_> {
was_joint = false
} else if kind == SyntaxKind::IDENT {
let token_text = self.text(i);
let contextual_kw =
SyntaxKind::from_contextual_keyword(token_text).unwrap_or(SyntaxKind::IDENT);
let contextual_kw = if !edition.at_least_2018() && token_text == "dyn" {
SyntaxKind::DYN_KW
} else {
SyntaxKind::from_contextual_keyword(token_text).unwrap_or(SyntaxKind::IDENT)
};
res.push_ident(contextual_kw);
} else {
if was_joint {

View file

@ -70,7 +70,7 @@ fn parse_err() {
fn parse(entry: TopEntryPoint, text: &str, edition: Edition) -> (String, bool) {
let lexed = LexedStr::new(edition, text);
let input = lexed.to_input();
let input = lexed.to_input(edition);
let output = entry.parse(&input, edition);
let mut buf = String::new();

View file

@ -83,7 +83,7 @@ fn meta_item() {
#[track_caller]
fn check(entry: PrefixEntryPoint, input: &str, prefix: &str) {
let lexed = LexedStr::new(Edition::CURRENT, input);
let input = lexed.to_input();
let input = lexed.to_input(Edition::CURRENT);
let mut n_tokens = 0;
for step in entry.parse(&input, Edition::CURRENT).iter() {