Skip to content

Commit 2c2b6c9

Browse files
committed
Auto merge of #17640 - Veykril:parse-dyn, r=Veykril
Parse contextual dyn keyword properly in edition 2015 Turns out this is more important than I thought it would be given the metrics :)
2 parents 9fd6c69 + 92f5e80 commit 2c2b6c9

File tree

15 files changed

+180
-23
lines changed

15 files changed

+180
-23
lines changed

crates/hir-expand/src/builtin_fn_macro.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
name, quote,
1919
quote::dollar_crate,
2020
tt::{self, DelimSpan},
21-
ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroFileIdExt,
21+
ExpandError, ExpandResult, HirFileIdExt, Lookup as _, MacroCallId,
2222
};
2323

2424
macro_rules! register_builtin {
@@ -687,8 +687,8 @@ fn relative_file(
687687
path_str: &str,
688688
allow_recursion: bool,
689689
) -> Result<EditionedFileId, ExpandError> {
690-
let call_site =
691-
call_id.as_macro_file().parent(db).original_file_respecting_includes(db).file_id();
690+
let lookup = call_id.lookup(db);
691+
let call_site = lookup.kind.file_id().original_file_respecting_includes(db).file_id();
692692
let path = AnchoredPath { anchor: call_site, path: path_str };
693693
let res = db
694694
.resolve_path(path)
@@ -697,7 +697,7 @@ fn relative_file(
697697
if res == call_site && !allow_recursion {
698698
Err(ExpandError::other(format!("recursive inclusion of `{path_str}`")))
699699
} else {
700-
Ok(EditionedFileId::new(res, Edition::CURRENT_FIXME))
700+
Ok(EditionedFileId::new(res, db.crate_graph()[lookup.krate].edition))
701701
}
702702
}
703703

crates/mbe/src/to_parser_input.rs

+2-3
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

+2
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

+21
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

+6-2
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 }
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

+7-4
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

+1-1
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

+1-1
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

+7
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() {
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"
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;

crates/rust-analyzer/src/cli/diagnostics.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use project_model::{CargoConfig, RustLibSource};
55
use rustc_hash::FxHashSet;
66

77
use hir::{db::HirDatabase, Crate, HirFileIdExt, Module};
8-
use ide::{AnalysisHost, AssistResolveStrategy, DiagnosticsConfig, Severity};
9-
use ide_db::base_db::SourceDatabaseExt;
8+
use ide::{AnalysisHost, AssistResolveStrategy, Diagnostic, DiagnosticsConfig, Severity};
9+
use ide_db::{base_db::SourceDatabaseExt, LineIndexDatabase};
1010
use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
1111

1212
use crate::cli::flags;
@@ -74,7 +74,11 @@ impl flags::Diagnostics {
7474
found_error = true;
7575
}
7676

77-
println!("{diagnostic:?}");
77+
let Diagnostic { code, message, range, severity, .. } = diagnostic;
78+
let line_index = db.line_index(range.file_id);
79+
let start = line_index.line_col(range.range.start());
80+
let end = line_index.line_col(range.range.end());
81+
println!("{severity:?} {code:?} from {start:?} to {end:?}: {message}");
7882
}
7983

8084
visited_files.insert(file_id);

crates/syntax/src/parsing.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub(crate) use crate::parsing::reparsing::incremental_reparse;
1212
pub(crate) fn parse_text(text: &str, edition: parser::Edition) -> (GreenNode, Vec<SyntaxError>) {
1313
let _p = tracing::info_span!("parse_text").entered();
1414
let lexed = parser::LexedStr::new(edition, text);
15-
let parser_input = lexed.to_input();
15+
let parser_input = lexed.to_input(edition);
1616
let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input, edition);
1717
let (node, errors, _eof) = build_tree(lexed, parser_output);
1818
(node, errors)
@@ -25,7 +25,7 @@ pub(crate) fn parse_text_at(
2525
) -> (GreenNode, Vec<SyntaxError>) {
2626
let _p = tracing::info_span!("parse_text_at").entered();
2727
let lexed = parser::LexedStr::new(edition, text);
28-
let parser_input = lexed.to_input();
28+
let parser_input = lexed.to_input(edition);
2929
let parser_output = entry.parse(&parser_input, edition);
3030
let (node, errors, _eof) = build_tree(lexed, parser_output);
3131
(node, errors)

crates/syntax/src/parsing/reparsing.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ fn reparse_block(
9292
let text = get_text_after_edit(node.clone().into(), edit);
9393

9494
let lexed = parser::LexedStr::new(edition, text.as_str());
95-
let parser_input = lexed.to_input();
95+
let parser_input = lexed.to_input(edition);
9696
if !is_balanced(&lexed) {
9797
return None;
9898
}

xtask/src/metrics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
time::{Instant, SystemTime, UNIX_EPOCH},
77
};
88

9-
use anyhow::{bail, format_err};
9+
use anyhow::format_err;
1010
use xshell::{cmd, Shell};
1111

1212
use crate::flags::{self, MeasurementType};
@@ -193,7 +193,7 @@ impl Metrics {
193193
impl Host {
194194
fn new(sh: &Shell) -> anyhow::Result<Host> {
195195
if cfg!(not(target_os = "linux")) {
196-
bail!("can only collect metrics on Linux ");
196+
return Ok(Host { os: "unknown".into(), cpu: "unknown".into(), mem: "unknown".into() });
197197
}
198198

199199
let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_owned();

0 commit comments

Comments
 (0)