diff options
Diffstat (limited to 'crates')
42 files changed, 1384 insertions, 961 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index 205dd223b..d42ac3ad4 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"] | |||
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [dependencies] | 8 | [dependencies] |
9 | clap = { version = "2.32.0", default-features = false } | 9 | pico-args = "0.2.0" |
10 | flexi_logger = "0.14.0" | 10 | flexi_logger = "0.14.0" |
11 | indicatif = "0.11.0" | 11 | indicatif = "0.11.0" |
12 | 12 | ||
diff --git a/crates/ra_cli/src/help.rs b/crates/ra_cli/src/help.rs new file mode 100644 index 000000000..5171578f0 --- /dev/null +++ b/crates/ra_cli/src/help.rs | |||
@@ -0,0 +1,72 @@ | |||
1 | pub const GLOBAL_HELP: &str = "ra-cli | ||
2 | |||
3 | USAGE: | ||
4 | ra_cli <SUBCOMMAND> | ||
5 | |||
6 | FLAGS: | ||
7 | -h, --help Prints help information | ||
8 | |||
9 | SUBCOMMANDS: | ||
10 | analysis-bench | ||
11 | analysis-stats | ||
12 | highlight | ||
13 | parse | ||
14 | symbols"; | ||
15 | |||
16 | pub const ANALYSIS_BENCH_HELP: &str = "ra_cli-analysis-bench | ||
17 | |||
18 | USAGE: | ||
19 | ra_cli analysis-bench [FLAGS] [OPTIONS] [PATH] | ||
20 | |||
21 | FLAGS: | ||
22 | -h, --help Prints help information | ||
23 | -v, --verbose | ||
24 | |||
25 | OPTIONS: | ||
26 | --complete <PATH:LINE:COLUMN> Compute completions at this location | ||
27 | --highlight <PATH> Hightlight this file | ||
28 | |||
29 | ARGS: | ||
30 | <PATH> Project to analyse"; | ||
31 | |||
32 | pub const ANALYSIS_STATS_HELP: &str = "ra-cli-analysis-stats | ||
33 | |||
34 | USAGE: | ||
35 | ra_cli analysis-stats [FLAGS] [OPTIONS] [PATH] | ||
36 | |||
37 | FLAGS: | ||
38 | -h, --help Prints help information | ||
39 | --memory-usage | ||
40 | -v, --verbose | ||
41 | |||
42 | OPTIONS: | ||
43 | -o <ONLY> | ||
44 | |||
45 | ARGS: | ||
46 | <PATH>"; | ||
47 | |||
48 | pub const HIGHLIGHT_HELP: &str = "ra-cli-highlight | ||
49 | |||
50 | USAGE: | ||
51 | ra_cli highlight [FLAGS] | ||
52 | |||
53 | FLAGS: | ||
54 | -h, --help Prints help information | ||
55 | -r, --rainbow"; | ||
56 | |||
57 | pub const SYMBOLS_HELP: &str = "ra-cli-symbols | ||
58 | |||
59 | USAGE: | ||
60 | ra_cli highlight [FLAGS] | ||
61 | |||
62 | FLAGS: | ||
63 | -h, --help Prints help inforamtion"; | ||
64 | |||
65 | pub const PARSE_HELP: &str = "ra-cli-parse | ||
66 | |||
67 | USAGE: | ||
68 | ra_cli parse [FLAGS] | ||
69 | |||
70 | FLAGS: | ||
71 | -h, --help Prints help inforamtion | ||
72 | --no-dump"; | ||
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index de8191ca3..e6334cf56 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | mod analysis_stats; | 1 | mod analysis_stats; |
2 | mod analysis_bench; | 2 | mod analysis_bench; |
3 | mod help; | ||
3 | 4 | ||
4 | use std::{error::Error, io::Read}; | 5 | use std::{error::Error, fmt::Write, io::Read}; |
5 | 6 | ||
6 | use clap::{App, Arg, SubCommand}; | ||
7 | use flexi_logger::Logger; | 7 | use flexi_logger::Logger; |
8 | use pico_args::Arguments; | ||
8 | use ra_ide_api::{file_structure, Analysis}; | 9 | use ra_ide_api::{file_structure, Analysis}; |
9 | use ra_prof::profile; | 10 | use ra_prof::profile; |
10 | use ra_syntax::{AstNode, SourceFile}; | 11 | use ra_syntax::{AstNode, SourceFile}; |
@@ -13,77 +14,89 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; | |||
13 | 14 | ||
14 | fn main() -> Result<()> { | 15 | fn main() -> Result<()> { |
15 | Logger::with_env().start()?; | 16 | Logger::with_env().start()?; |
16 | let matches = App::new("ra-cli") | 17 | |
17 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | 18 | let subcommand = match std::env::args_os().nth(1) { |
18 | .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) | 19 | None => { |
19 | .subcommand(SubCommand::with_name("symbols")) | 20 | eprintln!("{}", help::GLOBAL_HELP); |
20 | .subcommand( | 21 | return Ok(()); |
21 | SubCommand::with_name("highlight") | 22 | } |
22 | .arg(Arg::with_name("rainbow").short("r").long("rainbow")), | 23 | Some(s) => s, |
23 | ) | 24 | }; |
24 | .subcommand( | 25 | let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect()); |
25 | SubCommand::with_name("analysis-stats") | 26 | |
26 | .arg(Arg::with_name("verbose").short("v").long("verbose")) | 27 | match &*subcommand.to_string_lossy() { |
27 | .arg(Arg::with_name("memory-usage").long("memory-usage")) | 28 | "parse" => { |
28 | .arg(Arg::with_name("only").short("o").takes_value(true)) | 29 | if matches.contains(["-h", "--help"]) { |
29 | .arg(Arg::with_name("path")), | 30 | eprintln!("{}", help::PARSE_HELP); |
30 | ) | 31 | return Ok(()); |
31 | .subcommand( | 32 | } |
32 | SubCommand::with_name("analysis-bench") | 33 | let no_dump = matches.contains("--no-dump"); |
33 | .arg(Arg::with_name("verbose").short("v").long("verbose")) | 34 | matches.finish().or_else(handle_extra_flags)?; |
34 | .arg( | 35 | |
35 | Arg::with_name("highlight") | ||
36 | .long("highlight") | ||
37 | .takes_value(true) | ||
38 | .conflicts_with("complete") | ||
39 | .value_name("PATH") | ||
40 | .help("highlight this file"), | ||
41 | ) | ||
42 | .arg( | ||
43 | Arg::with_name("complete") | ||
44 | .long("complete") | ||
45 | .takes_value(true) | ||
46 | .conflicts_with("highlight") | ||
47 | .value_name("PATH:LINE:COLUMN") | ||
48 | .help("compute completions at this location"), | ||
49 | ) | ||
50 | .arg(Arg::with_name("path").value_name("PATH").help("project to analyze")), | ||
51 | ) | ||
52 | .get_matches(); | ||
53 | match matches.subcommand() { | ||
54 | ("parse", Some(matches)) => { | ||
55 | let _p = profile("parsing"); | 36 | let _p = profile("parsing"); |
56 | let file = file()?; | 37 | let file = file()?; |
57 | if !matches.is_present("no-dump") { | 38 | if !no_dump { |
58 | println!("{:#?}", file.syntax()); | 39 | println!("{:#?}", file.syntax()); |
59 | } | 40 | } |
60 | std::mem::forget(file); | 41 | std::mem::forget(file); |
61 | } | 42 | } |
62 | ("symbols", _) => { | 43 | "symbols" => { |
44 | if matches.contains(["-h", "--help"]) { | ||
45 | eprintln!("{}", help::SYMBOLS_HELP); | ||
46 | return Ok(()); | ||
47 | } | ||
48 | matches.finish().or_else(handle_extra_flags)?; | ||
63 | let file = file()?; | 49 | let file = file()?; |
64 | for s in file_structure(&file) { | 50 | for s in file_structure(&file) { |
65 | println!("{:?}", s); | 51 | println!("{:?}", s); |
66 | } | 52 | } |
67 | } | 53 | } |
68 | ("highlight", Some(matches)) => { | 54 | "highlight" => { |
55 | if matches.contains(["-h", "--help"]) { | ||
56 | eprintln!("{}", help::HIGHLIGHT_HELP); | ||
57 | return Ok(()); | ||
58 | } | ||
59 | let rainbow_opt = matches.contains(["-r", "--rainbow"]); | ||
60 | matches.finish().or_else(handle_extra_flags)?; | ||
69 | let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); | 61 | let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); |
70 | let html = analysis.highlight_as_html(file_id, matches.is_present("rainbow")).unwrap(); | 62 | let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap(); |
71 | println!("{}", html); | 63 | println!("{}", html); |
72 | } | 64 | } |
73 | ("analysis-stats", Some(matches)) => { | 65 | "analysis-stats" => { |
74 | let verbose = matches.is_present("verbose"); | 66 | if matches.contains(["-h", "--help"]) { |
75 | let memory_usage = matches.is_present("memory-usage"); | 67 | eprintln!("{}", help::ANALYSIS_STATS_HELP); |
76 | let path = matches.value_of("path").unwrap_or(""); | 68 | return Ok(()); |
77 | let only = matches.value_of("only"); | 69 | } |
78 | analysis_stats::run(verbose, memory_usage, path.as_ref(), only)?; | 70 | let verbose = matches.contains(["-v", "--verbose"]); |
71 | let memory_usage = matches.contains("--memory-usage"); | ||
72 | let path: String = matches.value_from_str("--path")?.unwrap_or_default(); | ||
73 | let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned()); | ||
74 | matches.finish().or_else(handle_extra_flags)?; | ||
75 | analysis_stats::run( | ||
76 | verbose, | ||
77 | memory_usage, | ||
78 | path.as_ref(), | ||
79 | only.as_ref().map(String::as_ref), | ||
80 | )?; | ||
79 | } | 81 | } |
80 | ("analysis-bench", Some(matches)) => { | 82 | "analysis-bench" => { |
81 | let verbose = matches.is_present("verbose"); | 83 | if matches.contains(["-h", "--help"]) { |
82 | let path = matches.value_of("path").unwrap_or(""); | 84 | eprintln!("{}", help::ANALYSIS_BENCH_HELP); |
83 | let op = if let Some(path) = matches.value_of("highlight") { | 85 | return Ok(()); |
86 | } | ||
87 | let verbose = matches.contains(["-v", "--verbose"]); | ||
88 | let path: String = matches.value_from_str("--path")?.unwrap_or_default(); | ||
89 | let highlight_path = matches.value_from_str("--highlight")?; | ||
90 | let complete_path = matches.value_from_str("--complete")?; | ||
91 | if highlight_path.is_some() && complete_path.is_some() { | ||
92 | panic!("either --highlight or --complete must be set, not both") | ||
93 | } | ||
94 | let op = if let Some(path) = highlight_path { | ||
95 | let path: String = path; | ||
84 | analysis_bench::Op::Highlight { path: path.into() } | 96 | analysis_bench::Op::Highlight { path: path.into() } |
85 | } else if let Some(path_line_col) = matches.value_of("complete") { | 97 | } else if let Some(path_line_col) = complete_path { |
86 | let (path_line, column) = rsplit_at_char(path_line_col, ':')?; | 98 | let path_line_col: String = path_line_col; |
99 | let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?; | ||
87 | let (path, line) = rsplit_at_char(path_line, ':')?; | 100 | let (path, line) = rsplit_at_char(path_line, ':')?; |
88 | analysis_bench::Op::Complete { | 101 | analysis_bench::Op::Complete { |
89 | path: path.into(), | 102 | path: path.into(), |
@@ -93,13 +106,27 @@ fn main() -> Result<()> { | |||
93 | } else { | 106 | } else { |
94 | panic!("either --highlight or --complete must be set") | 107 | panic!("either --highlight or --complete must be set") |
95 | }; | 108 | }; |
109 | matches.finish().or_else(handle_extra_flags)?; | ||
96 | analysis_bench::run(verbose, path.as_ref(), op)?; | 110 | analysis_bench::run(verbose, path.as_ref(), op)?; |
97 | } | 111 | } |
98 | _ => unreachable!(), | 112 | _ => eprintln!("{}", help::GLOBAL_HELP), |
99 | } | 113 | } |
100 | Ok(()) | 114 | Ok(()) |
101 | } | 115 | } |
102 | 116 | ||
117 | fn handle_extra_flags(e: pico_args::Error) -> Result<()> { | ||
118 | if let pico_args::Error::UnusedArgsLeft(flags) = e { | ||
119 | let mut invalid_flags = String::new(); | ||
120 | for flag in flags { | ||
121 | write!(&mut invalid_flags, "{}, ", flag)?; | ||
122 | } | ||
123 | let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); | ||
124 | Err(format!("Invalid flags: {}", invalid_flags).into()) | ||
125 | } else { | ||
126 | Err(e.to_string().into()) | ||
127 | } | ||
128 | } | ||
129 | |||
103 | fn file() -> Result<SourceFile> { | 130 | fn file() -> Result<SourceFile> { |
104 | let text = read_stdin()?; | 131 | let text = read_stdin()?; |
105 | Ok(SourceFile::parse(&text).tree()) | 132 | Ok(SourceFile::parse(&text).tree()) |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index e0d0d4209..9ea4e695d 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -90,7 +90,7 @@ impl HirFileId { | |||
90 | }) | 90 | }) |
91 | .ok()?; | 91 | .ok()?; |
92 | match macro_file.macro_file_kind { | 92 | match macro_file.macro_file_kind { |
93 | MacroFileKind::Items => Some(Parse::to_syntax(mbe::token_tree_to_ast_item_list(&tt))), | 93 | MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax), |
94 | MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), | 94 | MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax), |
95 | } | 95 | } |
96 | } | 96 | } |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 74546e5e2..7488d75a5 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -67,7 +67,6 @@ use test_utils::tested_by; | |||
67 | use crate::{ | 67 | use crate::{ |
68 | db::{AstDatabase, DefDatabase}, | 68 | db::{AstDatabase, DefDatabase}, |
69 | diagnostics::DiagnosticSink, | 69 | diagnostics::DiagnosticSink, |
70 | either::Either, | ||
71 | ids::MacroDefId, | 70 | ids::MacroDefId, |
72 | nameres::diagnostics::DefDiagnostic, | 71 | nameres::diagnostics::DefDiagnostic, |
73 | AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, | 72 | AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, |
@@ -105,8 +104,6 @@ pub struct CrateDefMap { | |||
105 | /// However, do we want to put it as a global variable? | 104 | /// However, do we want to put it as a global variable? |
106 | poison_macros: FxHashSet<MacroDefId>, | 105 | poison_macros: FxHashSet<MacroDefId>, |
107 | 106 | ||
108 | exported_macros: FxHashMap<Name, MacroDefId>, | ||
109 | |||
110 | diagnostics: Vec<DefDiagnostic>, | 107 | diagnostics: Vec<DefDiagnostic>, |
111 | } | 108 | } |
112 | 109 | ||
@@ -138,12 +135,6 @@ pub(crate) struct ModuleData { | |||
138 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 135 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
139 | pub struct ModuleScope { | 136 | pub struct ModuleScope { |
140 | items: FxHashMap<Name, Resolution>, | 137 | items: FxHashMap<Name, Resolution>, |
141 | /// Macros in current module scoped | ||
142 | /// | ||
143 | /// This scope works exactly the same way that item scoping does. | ||
144 | /// Macro invocation with quantified path will search in it. | ||
145 | /// See details below. | ||
146 | macros: FxHashMap<Name, MacroDef>, | ||
147 | /// Macros visable in current module in legacy textual scope | 138 | /// Macros visable in current module in legacy textual scope |
148 | /// | 139 | /// |
149 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. | 140 | /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. |
@@ -152,6 +143,10 @@ pub struct ModuleScope { | |||
152 | /// and only normal scoped `macros` will be searched in. | 143 | /// and only normal scoped `macros` will be searched in. |
153 | /// | 144 | /// |
154 | /// Note that this automatically inherit macros defined textually before the definition of module itself. | 145 | /// Note that this automatically inherit macros defined textually before the definition of module itself. |
146 | /// | ||
147 | /// Module scoped macros will be inserted into `items` instead of here. | ||
148 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will | ||
149 | // be all resolved to the last one defined if shadowing happens. | ||
155 | legacy_macros: FxHashMap<Name, MacroDef>, | 150 | legacy_macros: FxHashMap<Name, MacroDef>, |
156 | } | 151 | } |
157 | 152 | ||
@@ -164,35 +159,43 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { | |||
164 | .collect() | 159 | .collect() |
165 | }); | 160 | }); |
166 | 161 | ||
162 | /// Legacy macros can only be accessed through special methods like `get_legacy_macros`. | ||
163 | /// Other methods will only resolve values, types and module scoped macros only. | ||
167 | impl ModuleScope { | 164 | impl ModuleScope { |
168 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a { | 165 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a { |
169 | //FIXME: shadowing | 166 | //FIXME: shadowing |
170 | self.items.iter().chain(BUILTIN_SCOPE.iter()) | 167 | self.items.iter().chain(BUILTIN_SCOPE.iter()) |
171 | } | 168 | } |
169 | |||
170 | /// Iterate over all module scoped macros | ||
171 | pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a { | ||
172 | self.items | ||
173 | .iter() | ||
174 | .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_))) | ||
175 | } | ||
176 | |||
177 | /// Iterate over all legacy textual scoped macros visable at the end of the module | ||
178 | pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a { | ||
179 | self.legacy_macros.iter().map(|(name, def)| (name, *def)) | ||
180 | } | ||
181 | |||
182 | /// Get a name from current module scope, legacy macros are not included | ||
172 | pub fn get(&self, name: &Name) -> Option<&Resolution> { | 183 | pub fn get(&self, name: &Name) -> Option<&Resolution> { |
173 | self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) | 184 | self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) |
174 | } | 185 | } |
186 | |||
175 | pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { | 187 | pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { |
176 | self.items.values().filter_map(|r| match r.def.take_types() { | 188 | self.items.values().filter_map(|r| match r.def.take_types() { |
177 | Some(ModuleDef::Trait(t)) => Some(t), | 189 | Some(ModuleDef::Trait(t)) => Some(t), |
178 | _ => None, | 190 | _ => None, |
179 | }) | 191 | }) |
180 | } | 192 | } |
181 | /// It resolves in module scope. Textual scoped macros are ignored here. | 193 | |
182 | fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> { | ||
183 | match (self.get(name), self.macros.get(name)) { | ||
184 | (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)), | ||
185 | (_, Some(macro_)) => Some(Either::B(*macro_)), | ||
186 | _ => None, | ||
187 | } | ||
188 | } | ||
189 | fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> { | 194 | fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> { |
190 | self.legacy_macros.get(name).copied() | 195 | self.legacy_macros.get(name).copied() |
191 | } | 196 | } |
192 | } | 197 | } |
193 | 198 | ||
194 | type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; | ||
195 | |||
196 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 199 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
197 | pub struct Resolution { | 200 | pub struct Resolution { |
198 | /// None for unresolved | 201 | /// None for unresolved |
@@ -201,20 +204,26 @@ pub struct Resolution { | |||
201 | pub import: Option<ImportId>, | 204 | pub import: Option<ImportId>, |
202 | } | 205 | } |
203 | 206 | ||
207 | impl Resolution { | ||
208 | pub(crate) fn from_macro(macro_: MacroDef) -> Self { | ||
209 | Resolution { def: PerNs::macros(macro_), import: None } | ||
210 | } | ||
211 | } | ||
212 | |||
204 | #[derive(Debug, Clone)] | 213 | #[derive(Debug, Clone)] |
205 | struct ResolvePathResult { | 214 | struct ResolvePathResult { |
206 | resolved_def: ItemOrMacro, | 215 | resolved_def: PerNs<ModuleDef>, |
207 | segment_index: Option<usize>, | 216 | segment_index: Option<usize>, |
208 | reached_fixedpoint: ReachedFixedPoint, | 217 | reached_fixedpoint: ReachedFixedPoint, |
209 | } | 218 | } |
210 | 219 | ||
211 | impl ResolvePathResult { | 220 | impl ResolvePathResult { |
212 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | 221 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
213 | ResolvePathResult::with(Either::A(PerNs::none()), reached_fixedpoint, None) | 222 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) |
214 | } | 223 | } |
215 | 224 | ||
216 | fn with( | 225 | fn with( |
217 | resolved_def: ItemOrMacro, | 226 | resolved_def: PerNs<ModuleDef>, |
218 | reached_fixedpoint: ReachedFixedPoint, | 227 | reached_fixedpoint: ReachedFixedPoint, |
219 | segment_index: Option<usize>, | 228 | segment_index: Option<usize>, |
220 | ) -> ResolvePathResult { | 229 | ) -> ResolvePathResult { |
@@ -234,21 +243,6 @@ enum ReachedFixedPoint { | |||
234 | No, | 243 | No, |
235 | } | 244 | } |
236 | 245 | ||
237 | /// helper function for select item or macro to use | ||
238 | fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro { | ||
239 | match (left, right) { | ||
240 | (Either::A(s), Either::A(o)) => Either::A(s.or(o)), | ||
241 | (Either::B(s), _) => Either::B(s), | ||
242 | (Either::A(s), Either::B(o)) => { | ||
243 | if !s.is_none() { | ||
244 | Either::A(s) | ||
245 | } else { | ||
246 | Either::B(o) | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | impl CrateDefMap { | 246 | impl CrateDefMap { |
253 | pub(crate) fn crate_def_map_query( | 247 | pub(crate) fn crate_def_map_query( |
254 | // Note that this doesn't have `+ AstDatabase`! | 248 | // Note that this doesn't have `+ AstDatabase`! |
@@ -269,7 +263,6 @@ impl CrateDefMap { | |||
269 | root, | 263 | root, |
270 | modules, | 264 | modules, |
271 | poison_macros: FxHashSet::default(), | 265 | poison_macros: FxHashSet::default(), |
272 | exported_macros: FxHashMap::default(), | ||
273 | diagnostics: Vec::new(), | 266 | diagnostics: Vec::new(), |
274 | } | 267 | } |
275 | }; | 268 | }; |
@@ -328,16 +321,6 @@ impl CrateDefMap { | |||
328 | path: &Path, | 321 | path: &Path, |
329 | ) -> (PerNs<ModuleDef>, Option<usize>) { | 322 | ) -> (PerNs<ModuleDef>, Option<usize>) { |
330 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | 323 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); |
331 | (res.resolved_def.a().unwrap_or_else(PerNs::none), res.segment_index) | ||
332 | } | ||
333 | |||
334 | pub(crate) fn resolve_path_with_macro( | ||
335 | &self, | ||
336 | db: &impl DefDatabase, | ||
337 | original_module: CrateModuleId, | ||
338 | path: &Path, | ||
339 | ) -> (ItemOrMacro, Option<usize>) { | ||
340 | let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); | ||
341 | (res.resolved_def, res.segment_index) | 324 | (res.resolved_def, res.segment_index) |
342 | } | 325 | } |
343 | 326 | ||
@@ -351,13 +334,13 @@ impl CrateDefMap { | |||
351 | path: &Path, | 334 | path: &Path, |
352 | ) -> ResolvePathResult { | 335 | ) -> ResolvePathResult { |
353 | let mut segments = path.segments.iter().enumerate(); | 336 | let mut segments = path.segments.iter().enumerate(); |
354 | let mut curr_per_ns: ItemOrMacro = match path.kind { | 337 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { |
355 | PathKind::Crate => { | 338 | PathKind::Crate => { |
356 | Either::A(PerNs::types(Module { krate: self.krate, module_id: self.root }.into())) | 339 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) |
340 | } | ||
341 | PathKind::Self_ => { | ||
342 | PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) | ||
357 | } | 343 | } |
358 | PathKind::Self_ => Either::A(PerNs::types( | ||
359 | Module { krate: self.krate, module_id: original_module }.into(), | ||
360 | )), | ||
361 | // plain import or absolute path in 2015: crate-relative with | 344 | // plain import or absolute path in 2015: crate-relative with |
362 | // fallback to extern prelude (with the simplification in | 345 | // fallback to extern prelude (with the simplification in |
363 | // rust-lang/rust#57745) | 346 | // rust-lang/rust#57745) |
@@ -379,11 +362,11 @@ impl CrateDefMap { | |||
379 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 362 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
380 | }; | 363 | }; |
381 | log::debug!("resolving {:?} in module", segment); | 364 | log::debug!("resolving {:?} in module", segment); |
382 | self.resolve_name_in_module_with_macro(db, original_module, &segment.name) | 365 | self.resolve_name_in_module(db, original_module, &segment.name) |
383 | } | 366 | } |
384 | PathKind::Super => { | 367 | PathKind::Super => { |
385 | if let Some(p) = self.modules[original_module].parent { | 368 | if let Some(p) = self.modules[original_module].parent { |
386 | Either::A(PerNs::types(Module { krate: self.krate, module_id: p }.into())) | 369 | PerNs::types(Module { krate: self.krate, module_id: p }.into()) |
387 | } else { | 370 | } else { |
388 | log::debug!("super path in root module"); | 371 | log::debug!("super path in root module"); |
389 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 372 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
@@ -397,7 +380,7 @@ impl CrateDefMap { | |||
397 | }; | 380 | }; |
398 | if let Some(def) = self.extern_prelude.get(&segment.name) { | 381 | if let Some(def) = self.extern_prelude.get(&segment.name) { |
399 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | 382 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); |
400 | Either::A(PerNs::types(*def)) | 383 | PerNs::types(*def) |
401 | } else { | 384 | } else { |
402 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 385 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
403 | } | 386 | } |
@@ -405,7 +388,7 @@ impl CrateDefMap { | |||
405 | }; | 388 | }; |
406 | 389 | ||
407 | for (i, segment) in segments { | 390 | for (i, segment) in segments { |
408 | let curr = match curr_per_ns.as_ref().a().and_then(|m| m.as_ref().take_types()) { | 391 | let curr = match curr_per_ns.as_ref().take_types() { |
409 | Some(r) => r, | 392 | Some(r) => r, |
410 | None => { | 393 | None => { |
411 | // we still have path segments left, but the path so far | 394 | // we still have path segments left, but the path so far |
@@ -425,8 +408,7 @@ impl CrateDefMap { | |||
425 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | 408 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; |
426 | log::debug!("resolving {:?} in other crate", path); | 409 | log::debug!("resolving {:?} in other crate", path); |
427 | let defp_map = db.crate_def_map(module.krate); | 410 | let defp_map = db.crate_def_map(module.krate); |
428 | let (def, s) = | 411 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); |
429 | defp_map.resolve_path_with_macro(db, module.module_id, &path); | ||
430 | return ResolvePathResult::with( | 412 | return ResolvePathResult::with( |
431 | def, | 413 | def, |
432 | ReachedFixedPoint::Yes, | 414 | ReachedFixedPoint::Yes, |
@@ -434,8 +416,9 @@ impl CrateDefMap { | |||
434 | ); | 416 | ); |
435 | } | 417 | } |
436 | 418 | ||
437 | match self[module.module_id].scope.get_item_or_macro(&segment.name) { | 419 | // Since it is a quantified path here, it should not contains legacy macros |
438 | Some(res) => res, | 420 | match self[module.module_id].scope.get(&segment.name) { |
421 | Some(res) => res.def, | ||
439 | _ => { | 422 | _ => { |
440 | log::debug!("path segment {:?} not found", segment.name); | 423 | log::debug!("path segment {:?} not found", segment.name); |
441 | return ResolvePathResult::empty(ReachedFixedPoint::No); | 424 | return ResolvePathResult::empty(ReachedFixedPoint::No); |
@@ -446,10 +429,10 @@ impl CrateDefMap { | |||
446 | // enum variant | 429 | // enum variant |
447 | tested_by!(can_import_enum_variant); | 430 | tested_by!(can_import_enum_variant); |
448 | match e.variant(db, &segment.name) { | 431 | match e.variant(db, &segment.name) { |
449 | Some(variant) => Either::A(PerNs::both(variant.into(), variant.into())), | 432 | Some(variant) => PerNs::both(variant.into(), variant.into()), |
450 | None => { | 433 | None => { |
451 | return ResolvePathResult::with( | 434 | return ResolvePathResult::with( |
452 | Either::A(PerNs::types((*e).into())), | 435 | PerNs::types((*e).into()), |
453 | ReachedFixedPoint::Yes, | 436 | ReachedFixedPoint::Yes, |
454 | Some(i), | 437 | Some(i), |
455 | ); | 438 | ); |
@@ -466,7 +449,7 @@ impl CrateDefMap { | |||
466 | ); | 449 | ); |
467 | 450 | ||
468 | return ResolvePathResult::with( | 451 | return ResolvePathResult::with( |
469 | Either::A(PerNs::types(*s)), | 452 | PerNs::types(*s), |
470 | ReachedFixedPoint::Yes, | 453 | ReachedFixedPoint::Yes, |
471 | Some(i), | 454 | Some(i), |
472 | ); | 455 | ); |
@@ -476,14 +459,12 @@ impl CrateDefMap { | |||
476 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | 459 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) |
477 | } | 460 | } |
478 | 461 | ||
479 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> ItemOrMacro { | 462 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
480 | let from_crate_root = self[self.root] | 463 | let from_crate_root = |
481 | .scope | 464 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); |
482 | .get_item_or_macro(name) | ||
483 | .unwrap_or_else(|| Either::A(PerNs::none())); | ||
484 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 465 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
485 | 466 | ||
486 | or(from_crate_root, Either::A(from_extern_prelude)) | 467 | from_crate_root.or(from_extern_prelude) |
487 | } | 468 | } |
488 | 469 | ||
489 | pub(crate) fn resolve_name_in_module( | 470 | pub(crate) fn resolve_name_in_module( |
@@ -492,47 +473,38 @@ impl CrateDefMap { | |||
492 | module: CrateModuleId, | 473 | module: CrateModuleId, |
493 | name: &Name, | 474 | name: &Name, |
494 | ) -> PerNs<ModuleDef> { | 475 | ) -> PerNs<ModuleDef> { |
495 | self.resolve_name_in_module_with_macro(db, module, name).a().unwrap_or_else(PerNs::none) | ||
496 | } | ||
497 | |||
498 | fn resolve_name_in_module_with_macro( | ||
499 | &self, | ||
500 | db: &impl DefDatabase, | ||
501 | module: CrateModuleId, | ||
502 | name: &Name, | ||
503 | ) -> ItemOrMacro { | ||
504 | // Resolve in: | 476 | // Resolve in: |
505 | // - legacy scope | 477 | // - legacy scope of macro |
506 | // - current module / scope | 478 | // - current module / scope |
507 | // - extern prelude | 479 | // - extern prelude |
508 | // - std prelude | 480 | // - std prelude |
509 | let from_legacy_macro = self[module] | 481 | let from_legacy_macro = |
510 | .scope | 482 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); |
511 | .get_legacy_macro(name) | 483 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); |
512 | .map_or_else(|| Either::A(PerNs::none()), Either::B); | ||
513 | let from_scope = | ||
514 | self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); | ||
515 | let from_extern_prelude = | 484 | let from_extern_prelude = |
516 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 485 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
517 | let from_prelude = self.resolve_in_prelude(db, name); | 486 | let from_prelude = self.resolve_in_prelude(db, name); |
518 | 487 | ||
519 | or(from_legacy_macro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude))) | 488 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) |
520 | } | 489 | } |
521 | 490 | ||
522 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | 491 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
523 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | 492 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) |
524 | } | 493 | } |
525 | 494 | ||
526 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> ItemOrMacro { | 495 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs<ModuleDef> { |
527 | if let Some(prelude) = self.prelude { | 496 | if let Some(prelude) = self.prelude { |
528 | let resolution = if prelude.krate == self.krate { | 497 | let keep; |
529 | self[prelude.module_id].scope.get_item_or_macro(name) | 498 | let def_map = if prelude.krate == self.krate { |
499 | self | ||
530 | } else { | 500 | } else { |
531 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.get_item_or_macro(name) | 501 | // Extend lifetime |
502 | keep = db.crate_def_map(prelude.krate); | ||
503 | &keep | ||
532 | }; | 504 | }; |
533 | resolution.unwrap_or_else(|| Either::A(PerNs::none())) | 505 | def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) |
534 | } else { | 506 | } else { |
535 | Either::A(PerNs::none()) | 507 | PerNs::none() |
536 | } | 508 | } |
537 | } | 509 | } |
538 | } | 510 | } |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 09cda7656..03fbbd33f 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -5,14 +5,13 @@ use test_utils::tested_by; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | either::Either, | ||
9 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 8 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
10 | name::MACRO_RULES, | 9 | name::MACRO_RULES, |
11 | nameres::{ | 10 | nameres::{ |
12 | diagnostics::DefDiagnostic, | 11 | diagnostics::DefDiagnostic, |
13 | mod_resolution::{resolve_submodule, ParentModule}, | 12 | mod_resolution::{resolve_submodule, ParentModule}, |
14 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | 13 | raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, |
15 | ReachedFixedPoint, Resolution, ResolveMode, | 14 | Resolution, ResolveMode, |
16 | }, | 15 | }, |
17 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, | 16 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, |
18 | Struct, Trait, TypeAlias, Union, | 17 | Struct, Trait, TypeAlias, Union, |
@@ -123,30 +122,51 @@ where | |||
123 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 122 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
124 | // show unresolved imports in completion, etc | 123 | // show unresolved imports in completion, etc |
125 | for (module_id, import, import_data) in unresolved_imports { | 124 | for (module_id, import, import_data) in unresolved_imports { |
126 | self.record_resolved_import(module_id, Either::A(PerNs::none()), import, &import_data) | 125 | self.record_resolved_import(module_id, PerNs::none(), import, &import_data) |
127 | } | 126 | } |
128 | } | 127 | } |
129 | 128 | ||
129 | /// Define a macro with `macro_rules`. | ||
130 | /// | ||
131 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, | ||
132 | /// then it is also defined in the root module scope. | ||
133 | /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition. | ||
134 | /// | ||
135 | /// It is surprising that the macro will never be in the current module scope. | ||
136 | /// These code fails with "unresolved import/macro", | ||
137 | /// ```rust,compile_fail | ||
138 | /// mod m { macro_rules! foo { () => {} } } | ||
139 | /// use m::foo as bar; | ||
140 | /// ``` | ||
141 | /// | ||
142 | /// ```rust,compile_fail | ||
143 | /// macro_rules! foo { () => {} } | ||
144 | /// self::foo!(); | ||
145 | /// crate::foo!(); | ||
146 | /// ``` | ||
147 | /// | ||
148 | /// Well, this code compiles, bacause the plain path `foo` in `use` is searched | ||
149 | /// in the legacy textual scope only. | ||
150 | /// ```rust | ||
151 | /// macro_rules! foo { () => {} } | ||
152 | /// use foo as bar; | ||
153 | /// ``` | ||
130 | fn define_macro( | 154 | fn define_macro( |
131 | &mut self, | 155 | &mut self, |
132 | module_id: CrateModuleId, | 156 | module_id: CrateModuleId, |
133 | name: Name, | 157 | name: Name, |
134 | macro_id: MacroDefId, | 158 | macro_: MacroDef, |
135 | export: bool, | 159 | export: bool, |
136 | ) { | 160 | ) { |
137 | let def = Either::B(MacroDef { id: macro_id }); | 161 | // Textual scoping |
162 | self.define_legacy_macro(module_id, name.clone(), macro_); | ||
138 | 163 | ||
164 | // Module scoping | ||
139 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 165 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
140 | // crate root, even if the parent modules is **not** visible. | 166 | // crate root, even if the parent modules is **not** visible. |
141 | if export { | 167 | if export { |
142 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 168 | self.update(self.def_map.root, None, &[(name.clone(), Resolution::from_macro(macro_))]); |
143 | |||
144 | // Exported macros are collected in crate level ready for | ||
145 | // glob import with `#[macro_use]`. | ||
146 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
147 | } | 169 | } |
148 | self.update(module_id, None, &[(name.clone(), def)]); | ||
149 | self.define_legacy_macro(module_id, name.clone(), macro_id); | ||
150 | } | 170 | } |
151 | 171 | ||
152 | /// Define a legacy textual scoped macro in module | 172 | /// Define a legacy textual scoped macro in module |
@@ -156,14 +176,12 @@ where | |||
156 | /// the definition of current module. | 176 | /// the definition of current module. |
157 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | 177 | /// And also, `macro_use` on a module will import all legacy macros visable inside to |
158 | /// current legacy scope, with possible shadowing. | 178 | /// current legacy scope, with possible shadowing. |
159 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | 179 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) { |
160 | // Always shadowing | 180 | // Always shadowing |
161 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); | 181 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); |
162 | } | 182 | } |
163 | 183 | ||
164 | /// Import macros from `#[macro_use] extern crate`. | 184 | /// Import macros from `#[macro_use] extern crate`. |
165 | /// | ||
166 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
167 | fn import_macros_from_extern_crate( | 185 | fn import_macros_from_extern_crate( |
168 | &mut self, | 186 | &mut self, |
169 | current_module_id: CrateModuleId, | 187 | current_module_id: CrateModuleId, |
@@ -184,14 +202,20 @@ where | |||
184 | 202 | ||
185 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 203 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 204 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
187 | self.import_all_macros_exported(current_module_id, m); | 205 | self.import_all_macros_exported(current_module_id, m.krate); |
188 | } | 206 | } |
189 | } | 207 | } |
190 | 208 | ||
191 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { | 209 | /// Import all exported macros from another crate |
192 | let item_map = self.db.crate_def_map(module.krate); | 210 | /// |
193 | for (name, ¯o_id) in &item_map.exported_macros { | 211 | /// Exported macros are just all macros in the root module scope. |
194 | self.define_legacy_macro(current_module_id, name.clone(), macro_id); | 212 | /// Note that it contains not only all `#[macro_export]` macros, but also all aliases |
213 | /// created by `use` in the root module, ignoring the visibility of `use`. | ||
214 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) { | ||
215 | let def_map = self.db.crate_def_map(krate); | ||
216 | for (name, def) in def_map[def_map.root].scope.macros() { | ||
217 | // `macro_use` only bring things into legacy scope. | ||
218 | self.define_legacy_macro(current_module_id, name.clone(), def); | ||
195 | } | 219 | } |
196 | } | 220 | } |
197 | 221 | ||
@@ -219,7 +243,7 @@ where | |||
219 | &self, | 243 | &self, |
220 | module_id: CrateModuleId, | 244 | module_id: CrateModuleId, |
221 | import: &raw::ImportData, | 245 | import: &raw::ImportData, |
222 | ) -> (ItemOrMacro, ReachedFixedPoint) { | 246 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { |
223 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 247 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
224 | if import.is_extern_crate { | 248 | if import.is_extern_crate { |
225 | let res = self.def_map.resolve_name_in_extern_prelude( | 249 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -228,7 +252,7 @@ where | |||
228 | .as_ident() | 252 | .as_ident() |
229 | .expect("extern crate should have been desugared to one-element path"), | 253 | .expect("extern crate should have been desugared to one-element path"), |
230 | ); | 254 | ); |
231 | (Either::A(res), ReachedFixedPoint::Yes) | 255 | (res, ReachedFixedPoint::Yes) |
232 | } else { | 256 | } else { |
233 | let res = self.def_map.resolve_path_fp_with_macro( | 257 | let res = self.def_map.resolve_path_fp_with_macro( |
234 | self.db, | 258 | self.db, |
@@ -244,13 +268,13 @@ where | |||
244 | fn record_resolved_import( | 268 | fn record_resolved_import( |
245 | &mut self, | 269 | &mut self, |
246 | module_id: CrateModuleId, | 270 | module_id: CrateModuleId, |
247 | def: ItemOrMacro, | 271 | def: PerNs<ModuleDef>, |
248 | import_id: raw::ImportId, | 272 | import_id: raw::ImportId, |
249 | import: &raw::ImportData, | 273 | import: &raw::ImportData, |
250 | ) { | 274 | ) { |
251 | if import.is_glob { | 275 | if import.is_glob { |
252 | log::debug!("glob import: {:?}", import); | 276 | log::debug!("glob import: {:?}", import); |
253 | match def.a().and_then(|item| item.take_types()) { | 277 | match def.take_types() { |
254 | Some(ModuleDef::Module(m)) => { | 278 | Some(ModuleDef::Module(m)) => { |
255 | if import.is_prelude { | 279 | if import.is_prelude { |
256 | tested_by!(std_prelude); | 280 | tested_by!(std_prelude); |
@@ -260,30 +284,29 @@ where | |||
260 | // glob import from other crate => we can just import everything once | 284 | // glob import from other crate => we can just import everything once |
261 | let item_map = self.db.crate_def_map(m.krate); | 285 | let item_map = self.db.crate_def_map(m.krate); |
262 | let scope = &item_map[m.module_id].scope; | 286 | let scope = &item_map[m.module_id].scope; |
287 | |||
288 | // Module scoped macros is included | ||
263 | let items = scope | 289 | let items = scope |
264 | .items | 290 | .items |
265 | .iter() | 291 | .iter() |
266 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 292 | .map(|(name, res)| (name.clone(), res.clone())) |
267 | let macros = | 293 | .collect::<Vec<_>>(); |
268 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
269 | 294 | ||
270 | let all = items.chain(macros).collect::<Vec<_>>(); | 295 | self.update(module_id, Some(import_id), &items); |
271 | self.update(module_id, Some(import_id), &all); | ||
272 | } else { | 296 | } else { |
273 | // glob import from same crate => we do an initial | 297 | // glob import from same crate => we do an initial |
274 | // import, and then need to propagate any further | 298 | // import, and then need to propagate any further |
275 | // additions | 299 | // additions |
276 | let scope = &self.def_map[m.module_id].scope; | 300 | let scope = &self.def_map[m.module_id].scope; |
301 | |||
302 | // Module scoped macros is included | ||
277 | let items = scope | 303 | let items = scope |
278 | .items | 304 | .items |
279 | .iter() | 305 | .iter() |
280 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 306 | .map(|(name, res)| (name.clone(), res.clone())) |
281 | let macros = | 307 | .collect::<Vec<_>>(); |
282 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
283 | 308 | ||
284 | let all = items.chain(macros).collect::<Vec<_>>(); | 309 | self.update(module_id, Some(import_id), &items); |
285 | |||
286 | self.update(module_id, Some(import_id), &all); | ||
287 | // record the glob import in case we add further items | 310 | // record the glob import in case we add further items |
288 | self.glob_imports | 311 | self.glob_imports |
289 | .entry(m.module_id) | 312 | .entry(m.module_id) |
@@ -303,7 +326,7 @@ where | |||
303 | import: Some(import_id), | 326 | import: Some(import_id), |
304 | }; | 327 | }; |
305 | let name = variant.name(self.db)?; | 328 | let name = variant.name(self.db)?; |
306 | Some((name, Either::A(res))) | 329 | Some((name, res)) |
307 | }) | 330 | }) |
308 | .collect::<Vec<_>>(); | 331 | .collect::<Vec<_>>(); |
309 | self.update(module_id, Some(import_id), &resolutions); | 332 | self.update(module_id, Some(import_id), &resolutions); |
@@ -323,18 +346,12 @@ where | |||
323 | 346 | ||
324 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 347 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
325 | if import.is_extern_crate && module_id == self.def_map.root { | 348 | if import.is_extern_crate && module_id == self.def_map.root { |
326 | if let Some(def) = def.a().and_then(|item| item.take_types()) { | 349 | if let Some(def) = def.take_types() { |
327 | self.def_map.extern_prelude.insert(name.clone(), def); | 350 | self.def_map.extern_prelude.insert(name.clone(), def); |
328 | } | 351 | } |
329 | } | 352 | } |
330 | 353 | ||
331 | let resolution = match def { | 354 | let resolution = Resolution { def, import: Some(import_id) }; |
332 | Either::A(item) => { | ||
333 | Either::A(Resolution { def: item, import: Some(import_id) }) | ||
334 | } | ||
335 | Either::B(macro_) => Either::B(macro_), | ||
336 | }; | ||
337 | |||
338 | self.update(module_id, Some(import_id), &[(name, resolution)]); | 355 | self.update(module_id, Some(import_id), &[(name, resolution)]); |
339 | } | 356 | } |
340 | None => tested_by!(bogus_paths), | 357 | None => tested_by!(bogus_paths), |
@@ -346,7 +363,7 @@ where | |||
346 | &mut self, | 363 | &mut self, |
347 | module_id: CrateModuleId, | 364 | module_id: CrateModuleId, |
348 | import: Option<raw::ImportId>, | 365 | import: Option<raw::ImportId>, |
349 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 366 | resolutions: &[(Name, Resolution)], |
350 | ) { | 367 | ) { |
351 | self.update_recursive(module_id, import, resolutions, 0) | 368 | self.update_recursive(module_id, import, resolutions, 0) |
352 | } | 369 | } |
@@ -355,7 +372,7 @@ where | |||
355 | &mut self, | 372 | &mut self, |
356 | module_id: CrateModuleId, | 373 | module_id: CrateModuleId, |
357 | import: Option<raw::ImportId>, | 374 | import: Option<raw::ImportId>, |
358 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 375 | resolutions: &[(Name, Resolution)], |
359 | depth: usize, | 376 | depth: usize, |
360 | ) { | 377 | ) { |
361 | if depth > 100 { | 378 | if depth > 100 { |
@@ -365,35 +382,30 @@ where | |||
365 | let module_items = &mut self.def_map.modules[module_id].scope; | 382 | let module_items = &mut self.def_map.modules[module_id].scope; |
366 | let mut changed = false; | 383 | let mut changed = false; |
367 | for (name, res) in resolutions { | 384 | for (name, res) in resolutions { |
368 | match res { | 385 | let existing = module_items.items.entry(name.clone()).or_default(); |
369 | // item | ||
370 | Either::A(res) => { | ||
371 | let existing = module_items.items.entry(name.clone()).or_default(); | ||
372 | |||
373 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
374 | existing.def.types = res.def.types; | ||
375 | existing.import = import.or(res.import); | ||
376 | changed = true; | ||
377 | } | ||
378 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
379 | existing.def.values = res.def.values; | ||
380 | existing.import = import.or(res.import); | ||
381 | changed = true; | ||
382 | } | ||
383 | 386 | ||
384 | if existing.def.is_none() | 387 | if existing.def.types.is_none() && res.def.types.is_some() { |
385 | && res.def.is_none() | 388 | existing.def.types = res.def.types; |
386 | && existing.import.is_none() | 389 | existing.import = import.or(res.import); |
387 | && res.import.is_some() | 390 | changed = true; |
388 | { | 391 | } |
389 | existing.import = res.import; | 392 | if existing.def.values.is_none() && res.def.values.is_some() { |
390 | } | 393 | existing.def.values = res.def.values; |
391 | } | 394 | existing.import = import.or(res.import); |
392 | // macro | 395 | changed = true; |
393 | Either::B(res) => { | 396 | } |
394 | // Always shadowing | 397 | if existing.def.macros.is_none() && res.def.macros.is_some() { |
395 | module_items.macros.insert(name.clone(), *res); | 398 | existing.def.macros = res.def.macros; |
396 | } | 399 | existing.import = import.or(res.import); |
400 | changed = true; | ||
401 | } | ||
402 | |||
403 | if existing.def.is_none() | ||
404 | && res.def.is_none() | ||
405 | && existing.import.is_none() | ||
406 | && res.import.is_some() | ||
407 | { | ||
408 | existing.import = res.import; | ||
397 | } | 409 | } |
398 | } | 410 | } |
399 | 411 | ||
@@ -425,7 +437,7 @@ where | |||
425 | path, | 437 | path, |
426 | ); | 438 | ); |
427 | 439 | ||
428 | if let Some(def) = resolved_res.resolved_def.b() { | 440 | if let Some(def) = resolved_res.resolved_def.get_macros() { |
429 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); | 441 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); |
430 | resolved.push((*module_id, call_id, def.id)); | 442 | resolved.push((*module_id, call_id, def.id)); |
431 | res = ReachedFixedPoint::No; | 443 | res = ReachedFixedPoint::No; |
@@ -528,7 +540,7 @@ where | |||
528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 540 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
529 | if prelude_module.krate != self.def_collector.def_map.krate { | 541 | if prelude_module.krate != self.def_collector.def_map.krate { |
530 | tested_by!(prelude_is_macro_use); | 542 | tested_by!(prelude_is_macro_use); |
531 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module); | 543 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); |
532 | } | 544 | } |
533 | } | 545 | } |
534 | 546 | ||
@@ -636,7 +648,7 @@ where | |||
636 | ), | 648 | ), |
637 | import: None, | 649 | import: None, |
638 | }; | 650 | }; |
639 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]); | 651 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); |
640 | res | 652 | res |
641 | } | 653 | } |
642 | 654 | ||
@@ -667,7 +679,7 @@ where | |||
667 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), | 679 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), |
668 | }; | 680 | }; |
669 | let resolution = Resolution { def, import: None }; | 681 | let resolution = Resolution { def, import: None }; |
670 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]) | 682 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) |
671 | } | 683 | } |
672 | 684 | ||
673 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 685 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
@@ -675,7 +687,8 @@ where | |||
675 | if is_macro_rules(&mac.path) { | 687 | if is_macro_rules(&mac.path) { |
676 | if let Some(name) = &mac.name { | 688 | if let Some(name) = &mac.name { |
677 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); | 689 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); |
678 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export) | 690 | let macro_ = MacroDef { id: macro_id }; |
691 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); | ||
679 | } | 692 | } |
680 | return; | 693 | return; |
681 | } | 694 | } |
@@ -706,7 +719,7 @@ where | |||
706 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { | 719 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { |
707 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | 720 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); |
708 | for (name, macro_) in macros { | 721 | for (name, macro_) in macros { |
709 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); | 722 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
710 | } | 723 | } |
711 | } | 724 | } |
712 | } | 725 | } |
@@ -758,7 +771,6 @@ mod tests { | |||
758 | root, | 771 | root, |
759 | modules, | 772 | modules, |
760 | poison_macros: FxHashSet::default(), | 773 | poison_macros: FxHashSet::default(), |
761 | exported_macros: FxHashMap::default(), | ||
762 | diagnostics: Vec::new(), | 774 | diagnostics: Vec::new(), |
763 | } | 775 | } |
764 | }; | 776 | }; |
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs index c40a3ff9d..d07cc08f4 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -1,78 +1,87 @@ | |||
1 | use crate::MacroDef; | ||
2 | |||
1 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 3 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
2 | pub enum Namespace { | 4 | pub enum Namespace { |
3 | Types, | 5 | Types, |
4 | Values, | 6 | Values, |
7 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
8 | // Macro, | ||
5 | } | 9 | } |
6 | 10 | ||
7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
8 | pub struct PerNs<T> { | 12 | pub struct PerNs<T> { |
9 | pub types: Option<T>, | 13 | pub types: Option<T>, |
10 | pub values: Option<T>, | 14 | pub values: Option<T>, |
15 | /// Since macros has different type, many methods simply ignore it. | ||
16 | /// We can only use special method like `get_macros` to access it. | ||
17 | pub macros: Option<MacroDef>, | ||
11 | } | 18 | } |
12 | 19 | ||
13 | impl<T> Default for PerNs<T> { | 20 | impl<T> Default for PerNs<T> { |
14 | fn default() -> Self { | 21 | fn default() -> Self { |
15 | PerNs { types: None, values: None } | 22 | PerNs { types: None, values: None, macros: None } |
16 | } | 23 | } |
17 | } | 24 | } |
18 | 25 | ||
19 | impl<T> PerNs<T> { | 26 | impl<T> PerNs<T> { |
20 | pub fn none() -> PerNs<T> { | 27 | pub fn none() -> PerNs<T> { |
21 | PerNs { types: None, values: None } | 28 | PerNs { types: None, values: None, macros: None } |
22 | } | 29 | } |
23 | 30 | ||
24 | pub fn values(t: T) -> PerNs<T> { | 31 | pub fn values(t: T) -> PerNs<T> { |
25 | PerNs { types: None, values: Some(t) } | 32 | PerNs { types: None, values: Some(t), macros: None } |
26 | } | 33 | } |
27 | 34 | ||
28 | pub fn types(t: T) -> PerNs<T> { | 35 | pub fn types(t: T) -> PerNs<T> { |
29 | PerNs { types: Some(t), values: None } | 36 | PerNs { types: Some(t), values: None, macros: None } |
30 | } | 37 | } |
31 | 38 | ||
32 | pub fn both(types: T, values: T) -> PerNs<T> { | 39 | pub fn both(types: T, values: T) -> PerNs<T> { |
33 | PerNs { types: Some(types), values: Some(values) } | 40 | PerNs { types: Some(types), values: Some(values), macros: None } |
34 | } | 41 | } |
35 | 42 | ||
36 | pub fn is_none(&self) -> bool { | 43 | pub fn macros(macro_: MacroDef) -> PerNs<T> { |
37 | self.types.is_none() && self.values.is_none() | 44 | PerNs { types: None, values: None, macros: Some(macro_) } |
38 | } | 45 | } |
39 | 46 | ||
40 | pub fn is_both(&self) -> bool { | 47 | pub fn is_none(&self) -> bool { |
41 | self.types.is_some() && self.values.is_some() | 48 | self.types.is_none() && self.values.is_none() && self.macros.is_none() |
42 | } | 49 | } |
43 | 50 | ||
44 | pub fn take(self, namespace: Namespace) -> Option<T> { | 51 | pub fn is_all(&self) -> bool { |
45 | match namespace { | 52 | self.types.is_some() && self.values.is_some() && self.macros.is_some() |
46 | Namespace::Types => self.types, | ||
47 | Namespace::Values => self.values, | ||
48 | } | ||
49 | } | 53 | } |
50 | 54 | ||
51 | pub fn take_types(self) -> Option<T> { | 55 | pub fn take_types(self) -> Option<T> { |
52 | self.take(Namespace::Types) | 56 | self.types |
53 | } | 57 | } |
54 | 58 | ||
55 | pub fn take_values(self) -> Option<T> { | 59 | pub fn take_values(self) -> Option<T> { |
56 | self.take(Namespace::Values) | 60 | self.values |
57 | } | 61 | } |
58 | 62 | ||
59 | pub fn get(&self, namespace: Namespace) -> Option<&T> { | 63 | pub fn get_macros(&self) -> Option<MacroDef> { |
60 | self.as_ref().take(namespace) | 64 | self.macros |
61 | } | 65 | } |
62 | 66 | ||
63 | pub fn as_ref(&self) -> PerNs<&T> { | 67 | pub fn only_macros(&self) -> PerNs<T> { |
64 | PerNs { types: self.types.as_ref(), values: self.values.as_ref() } | 68 | PerNs { types: None, values: None, macros: self.macros } |
65 | } | 69 | } |
66 | 70 | ||
67 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | 71 | pub fn as_ref(&self) -> PerNs<&T> { |
68 | PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } | 72 | PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros } |
69 | } | 73 | } |
70 | 74 | ||
71 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | 75 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { |
72 | PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } | 76 | PerNs { |
77 | types: self.types.or(other.types), | ||
78 | values: self.values.or(other.values), | ||
79 | macros: self.macros.or(other.macros), | ||
80 | } | ||
73 | } | 81 | } |
74 | 82 | ||
83 | /// Map types and values. Leave macros unchanged. | ||
75 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | 84 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { |
76 | PerNs { types: self.types.map(&f), values: self.values.map(&f) } | 85 | PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros } |
77 | } | 86 | } |
78 | } | 87 | } |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index c646d3d00..04b97cb90 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -76,8 +76,10 @@ impl RawItems { | |||
76 | source_map: ImportSourceMap::default(), | 76 | source_map: ImportSourceMap::default(), |
77 | }; | 77 | }; |
78 | if let Some(node) = db.parse_or_expand(file_id) { | 78 | if let Some(node) = db.parse_or_expand(file_id) { |
79 | if let Some(source_file) = ast::SourceFile::cast(node) { | 79 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { |
80 | collector.process_module(None, source_file); | 80 | collector.process_module(None, source_file); |
81 | } else if let Some(item_list) = ast::MacroItems::cast(node) { | ||
82 | collector.process_module(None, item_list); | ||
81 | } | 83 | } |
82 | } | 84 | } |
83 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) | 85 | (Arc::new(collector.raw_items), Arc::new(collector.source_map)) |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 4ff897ca5..bc4b47b70 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -12,8 +12,7 @@ use test_utils::covers; | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | mock::{CrateGraphFixture, MockDatabase}, | 14 | mock::{CrateGraphFixture, MockDatabase}, |
15 | nameres::Resolution, | 15 | Crate, |
16 | Crate, Either, | ||
17 | }; | 16 | }; |
18 | 17 | ||
19 | use super::*; | 18 | use super::*; |
@@ -37,35 +36,38 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
37 | *buf += path; | 36 | *buf += path; |
38 | *buf += "\n"; | 37 | *buf += "\n"; |
39 | 38 | ||
40 | let items = map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::A(it))); | 39 | let mut entries = map.modules[module] |
41 | let macros = map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::B(m))); | 40 | .scope |
42 | let mut entries = items.chain(macros).collect::<Vec<_>>(); | 41 | .items |
43 | 42 | .iter() | |
43 | .map(|(name, res)| (name, res.def)) | ||
44 | .collect::<Vec<_>>(); | ||
44 | entries.sort_by_key(|(name, _)| *name); | 45 | entries.sort_by_key(|(name, _)| *name); |
46 | |||
45 | for (name, res) in entries { | 47 | for (name, res) in entries { |
46 | match res { | 48 | *buf += &format!("{}:", name); |
47 | Either::A(it) => { | 49 | |
48 | *buf += &format!("{}: {}\n", name, dump_resolution(it)); | 50 | if res.types.is_some() { |
49 | } | 51 | *buf += " t"; |
50 | Either::B(_) => { | 52 | } |
51 | *buf += &format!("{}: m\n", name); | 53 | if res.values.is_some() { |
52 | } | 54 | *buf += " v"; |
55 | } | ||
56 | if res.macros.is_some() { | ||
57 | *buf += " m"; | ||
58 | } | ||
59 | if res.is_none() { | ||
60 | *buf += " _"; | ||
53 | } | 61 | } |
62 | |||
63 | *buf += "\n"; | ||
54 | } | 64 | } |
65 | |||
55 | for (name, child) in map.modules[module].children.iter() { | 66 | for (name, child) in map.modules[module].children.iter() { |
56 | let path = path.to_string() + &format!("::{}", name); | 67 | let path = path.to_string() + &format!("::{}", name); |
57 | go(buf, map, &path, *child); | 68 | go(buf, map, &path, *child); |
58 | } | 69 | } |
59 | } | 70 | } |
60 | |||
61 | fn dump_resolution(resolution: &Resolution) -> &'static str { | ||
62 | match (resolution.def.types.is_some(), resolution.def.values.is_some()) { | ||
63 | (true, true) => "t v", | ||
64 | (true, false) => "t", | ||
65 | (false, true) => "v", | ||
66 | (false, false) => "_", | ||
67 | } | ||
68 | } | ||
69 | } | 71 | } |
70 | 72 | ||
71 | fn def_map(fixtute: &str) -> String { | 73 | fn def_map(fixtute: &str) -> String { |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index ebc4d6890..20ee63c67 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -21,7 +21,6 @@ fn macro_rules_are_globally_visible() { | |||
21 | â‹®crate | 21 | â‹®crate |
22 | â‹®Foo: t v | 22 | â‹®Foo: t v |
23 | â‹®nested: t | 23 | â‹®nested: t |
24 | â‹®structs: m | ||
25 | â‹® | 24 | â‹® |
26 | â‹®crate::nested | 25 | â‹®crate::nested |
27 | â‹®Bar: t v | 26 | â‹®Bar: t v |
@@ -47,7 +46,6 @@ fn macro_rules_can_define_modules() { | |||
47 | ); | 46 | ); |
48 | assert_snapshot!(map, @r###" | 47 | assert_snapshot!(map, @r###" |
49 | â‹®crate | 48 | â‹®crate |
50 | â‹®m: m | ||
51 | â‹®n1: t | 49 | â‹®n1: t |
52 | â‹® | 50 | â‹® |
53 | â‹®crate::n1 | 51 | â‹®crate::n1 |
@@ -133,7 +131,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
133 | â‹®crate | 131 | â‹®crate |
134 | â‹®Foo: t v | 132 | â‹®Foo: t v |
135 | â‹®bar: m | 133 | â‹®bar: m |
136 | â‹®baz: m | ||
137 | â‹®foo: m | 134 | â‹®foo: m |
138 | "###); | 135 | "###); |
139 | } | 136 | } |
@@ -271,7 +268,6 @@ fn prelude_cycle() { | |||
271 | â‹®prelude: t | 268 | â‹®prelude: t |
272 | â‹® | 269 | â‹® |
273 | â‹®crate::prelude | 270 | â‹®crate::prelude |
274 | â‹®declare_mod: m | ||
275 | "###); | 271 | "###); |
276 | } | 272 | } |
277 | 273 | ||
@@ -345,7 +341,6 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
345 | â‹®Ok: t v | 341 | â‹®Ok: t v |
346 | â‹®OkAfter: t v | 342 | â‹®OkAfter: t v |
347 | â‹®OkShadowStop: t v | 343 | â‹®OkShadowStop: t v |
348 | â‹®foo: m | ||
349 | â‹®m1: t | 344 | â‹®m1: t |
350 | â‹®m2: t | 345 | â‹®m2: t |
351 | â‹®m3: t | 346 | â‹®m3: t |
@@ -354,28 +349,132 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
354 | â‹®ok_double_macro_use_shadow: v | 349 | â‹®ok_double_macro_use_shadow: v |
355 | â‹® | 350 | â‹® |
356 | â‹®crate::m7 | 351 | â‹®crate::m7 |
357 | â‹®baz: m | ||
358 | â‹® | 352 | â‹® |
359 | â‹®crate::m1 | 353 | â‹®crate::m1 |
360 | â‹®bar: m | ||
361 | â‹® | 354 | â‹® |
362 | â‹®crate::m5 | 355 | â‹®crate::m5 |
363 | â‹®m6: t | 356 | â‹®m6: t |
364 | â‹® | 357 | â‹® |
365 | â‹®crate::m5::m6 | 358 | â‹®crate::m5::m6 |
366 | â‹®foo: m | ||
367 | â‹® | 359 | â‹® |
368 | â‹®crate::m2 | 360 | â‹®crate::m2 |
369 | â‹® | 361 | â‹® |
370 | â‹®crate::m3 | 362 | â‹®crate::m3 |
371 | â‹®OkAfterInside: t v | 363 | â‹®OkAfterInside: t v |
372 | â‹®OkMacroUse: t v | 364 | â‹®OkMacroUse: t v |
373 | â‹®foo: m | ||
374 | â‹®m4: t | 365 | â‹®m4: t |
375 | â‹®ok_shadow: v | 366 | â‹®ok_shadow: v |
376 | â‹® | 367 | â‹® |
377 | â‹®crate::m3::m4 | 368 | â‹®crate::m3::m4 |
378 | â‹®bar: m | ||
379 | â‹®ok_shadow_deep: v | 369 | â‹®ok_shadow_deep: v |
380 | "###); | 370 | "###); |
381 | } | 371 | } |
372 | |||
373 | #[test] | ||
374 | fn type_value_macro_live_in_different_scopes() { | ||
375 | let map = def_map( | ||
376 | " | ||
377 | //- /main.rs | ||
378 | #[macro_export] | ||
379 | macro_rules! foo { | ||
380 | ($x:ident) => { type $x = (); } | ||
381 | } | ||
382 | |||
383 | foo!(foo); | ||
384 | use foo as bar; | ||
385 | |||
386 | use self::foo as baz; | ||
387 | fn baz() {} | ||
388 | ", | ||
389 | ); | ||
390 | assert_snapshot!(map, @r###" | ||
391 | â‹®crate | ||
392 | â‹®bar: t m | ||
393 | â‹®baz: t v m | ||
394 | â‹®foo: t m | ||
395 | "###); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn macro_use_can_be_aliased() { | ||
400 | let map = def_map_with_crate_graph( | ||
401 | " | ||
402 | //- /main.rs | ||
403 | #[macro_use] | ||
404 | extern crate foo; | ||
405 | |||
406 | foo!(Direct); | ||
407 | bar!(Alias); | ||
408 | |||
409 | //- /lib.rs | ||
410 | use crate::foo as bar; | ||
411 | |||
412 | mod m { | ||
413 | #[macro_export] | ||
414 | macro_rules! foo { | ||
415 | ($x:ident) => { struct $x; } | ||
416 | } | ||
417 | } | ||
418 | ", | ||
419 | crate_graph! { | ||
420 | "main": ("/main.rs", ["foo"]), | ||
421 | "foo": ("/lib.rs", []), | ||
422 | }, | ||
423 | ); | ||
424 | assert_snapshot!(map, @r###" | ||
425 | â‹®crate | ||
426 | â‹®Alias: t v | ||
427 | â‹®Direct: t v | ||
428 | â‹®foo: t | ||
429 | "###); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn path_quantified_macros() { | ||
434 | let map = def_map( | ||
435 | " | ||
436 | //- /main.rs | ||
437 | macro_rules! foo { | ||
438 | ($x:ident) => { struct $x; } | ||
439 | } | ||
440 | |||
441 | crate::foo!(NotResolved); | ||
442 | |||
443 | crate::bar!(OkCrate); | ||
444 | bar!(OkPlain); | ||
445 | alias1!(NotHere); | ||
446 | m::alias1!(OkAliasPlain); | ||
447 | m::alias2!(OkAliasSuper); | ||
448 | m::alias3!(OkAliasCrate); | ||
449 | not_found!(NotFound); | ||
450 | |||
451 | mod m { | ||
452 | #[macro_export] | ||
453 | macro_rules! bar { | ||
454 | ($x:ident) => { struct $x; } | ||
455 | } | ||
456 | |||
457 | pub use bar as alias1; | ||
458 | pub use super::bar as alias2; | ||
459 | pub use crate::bar as alias3; | ||
460 | pub use self::bar as not_found; | ||
461 | } | ||
462 | ", | ||
463 | ); | ||
464 | assert_snapshot!(map, @r###" | ||
465 | â‹®crate | ||
466 | â‹®OkAliasCrate: t v | ||
467 | â‹®OkAliasPlain: t v | ||
468 | â‹®OkAliasSuper: t v | ||
469 | â‹®OkCrate: t v | ||
470 | â‹®OkPlain: t v | ||
471 | â‹®bar: m | ||
472 | â‹®m: t | ||
473 | â‹® | ||
474 | â‹®crate::m | ||
475 | â‹®alias1: m | ||
476 | â‹®alias2: m | ||
477 | â‹®alias3: m | ||
478 | â‹®not_found: _ | ||
479 | "###); | ||
480 | } | ||
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index ef75308f6..d9bdd0e22 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -6,7 +6,6 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | code_model::Crate, | 7 | code_model::Crate, |
8 | db::HirDatabase, | 8 | db::HirDatabase, |
9 | either::Either, | ||
10 | expr::{ | 9 | expr::{ |
11 | scope::{ExprScopes, ScopeId}, | 10 | scope::{ExprScopes, ScopeId}, |
12 | PatId, | 11 | PatId, |
@@ -126,7 +125,7 @@ impl Resolver { | |||
126 | let mut resolution = PerNs::none(); | 125 | let mut resolution = PerNs::none(); |
127 | for scope in self.scopes.iter().rev() { | 126 | for scope in self.scopes.iter().rev() { |
128 | resolution = resolution.or(scope.resolve_name(db, name)); | 127 | resolution = resolution.or(scope.resolve_name(db, name)); |
129 | if resolution.is_both() { | 128 | if resolution.is_all() { |
130 | return resolution; | 129 | return resolution; |
131 | } | 130 | } |
132 | } | 131 | } |
@@ -139,10 +138,7 @@ impl Resolver { | |||
139 | path: &Path, | 138 | path: &Path, |
140 | ) -> Option<MacroDef> { | 139 | ) -> Option<MacroDef> { |
141 | let (item_map, module) = self.module()?; | 140 | let (item_map, module) = self.module()?; |
142 | match item_map.resolve_path_with_macro(db, module, path) { | 141 | item_map.resolve_path(db, module, path).0.get_macros() |
143 | (Either::B(macro_def), None) => Some(macro_def), | ||
144 | _ => None, | ||
145 | } | ||
146 | } | 142 | } |
147 | 143 | ||
148 | /// Returns the resolved path segments | 144 | /// Returns the resolved path segments |
@@ -191,6 +187,9 @@ impl Resolver { | |||
191 | if current.values.is_none() { | 187 | if current.values.is_none() { |
192 | current.values = res.values; | 188 | current.values = res.values; |
193 | } | 189 | } |
190 | if current.macros.is_none() { | ||
191 | current.macros = res.macros; | ||
192 | } | ||
194 | }); | 193 | }); |
195 | } | 194 | } |
196 | names | 195 | names |
@@ -313,6 +312,9 @@ impl Scope { | |||
313 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { | 312 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { |
314 | f(name.clone(), res.def.map(Resolution::Def)); | 313 | f(name.clone(), res.def.map(Resolution::Def)); |
315 | }); | 314 | }); |
315 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { | ||
316 | f(name.clone(), PerNs::macros(macro_)); | ||
317 | }); | ||
316 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { | 318 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { |
317 | f(name.clone(), PerNs::types(Resolution::Def(*def))); | 319 | f(name.clone(), PerNs::types(Resolution::Def(*def))); |
318 | }); | 320 | }); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 25716fe8c..c60e72abf 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2838,6 +2838,64 @@ fn main() { | |||
2838 | ); | 2838 | ); |
2839 | } | 2839 | } |
2840 | 2840 | ||
2841 | #[test] | ||
2842 | fn infer_path_quantified_macros_expanded() { | ||
2843 | assert_snapshot!( | ||
2844 | infer(r#" | ||
2845 | #[macro_export] | ||
2846 | macro_rules! foo { | ||
2847 | () => { 42i32 } | ||
2848 | } | ||
2849 | |||
2850 | mod m { | ||
2851 | pub use super::foo as bar; | ||
2852 | } | ||
2853 | |||
2854 | fn main() { | ||
2855 | let x = crate::foo!(); | ||
2856 | let y = m::bar!(); | ||
2857 | } | ||
2858 | "#), | ||
2859 | @r###" | ||
2860 | ![0; 5) '42i32': i32 | ||
2861 | ![0; 5) '42i32': i32 | ||
2862 | [111; 164) '{ ...!(); }': () | ||
2863 | [121; 122) 'x': i32 | ||
2864 | [148; 149) 'y': i32 | ||
2865 | "### | ||
2866 | ); | ||
2867 | } | ||
2868 | |||
2869 | #[test] | ||
2870 | fn infer_type_value_macro_having_same_name() { | ||
2871 | assert_snapshot!( | ||
2872 | infer(r#" | ||
2873 | #[macro_export] | ||
2874 | macro_rules! foo { | ||
2875 | () => { | ||
2876 | mod foo { | ||
2877 | pub use super::foo; | ||
2878 | } | ||
2879 | }; | ||
2880 | ($x:tt) => { | ||
2881 | $x | ||
2882 | }; | ||
2883 | } | ||
2884 | |||
2885 | foo!(); | ||
2886 | |||
2887 | fn foo() { | ||
2888 | let foo = foo::foo!(42i32); | ||
2889 | } | ||
2890 | "#), | ||
2891 | @r###" | ||
2892 | ![0; 5) '42i32': i32 | ||
2893 | [171; 206) '{ ...32); }': () | ||
2894 | [181; 184) 'foo': i32 | ||
2895 | "### | ||
2896 | ); | ||
2897 | } | ||
2898 | |||
2841 | #[ignore] | 2899 | #[ignore] |
2842 | #[test] | 2900 | #[test] |
2843 | fn method_resolution_trait_before_autoref() { | 2901 | fn method_resolution_trait_before_autoref() { |
@@ -3007,7 +3065,7 @@ impl<T, U> Into<U> for T where U: From<T> {} | |||
3007 | fn test() { S2.into()<|>; } | 3065 | fn test() { S2.into()<|>; } |
3008 | "#, | 3066 | "#, |
3009 | ); | 3067 | ); |
3010 | assert_eq!(t, "S1"); | 3068 | assert_eq!(t, "{unknown}"); |
3011 | } | 3069 | } |
3012 | 3070 | ||
3013 | #[test] | 3071 | #[test] |
@@ -3024,7 +3082,7 @@ impl<T, U: From<T>> Into<U> for T {} | |||
3024 | fn test() { S2.into()<|>; } | 3082 | fn test() { S2.into()<|>; } |
3025 | "#, | 3083 | "#, |
3026 | ); | 3084 | ); |
3027 | assert_eq!(t, "S1"); | 3085 | assert_eq!(t, "{unknown}"); |
3028 | } | 3086 | } |
3029 | 3087 | ||
3030 | #[test] | 3088 | #[test] |
@@ -3066,7 +3124,7 @@ impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} | |||
3066 | fn test() { (S {}).method()<|>; } | 3124 | fn test() { (S {}).method()<|>; } |
3067 | "#, | 3125 | "#, |
3068 | ); | 3126 | ); |
3069 | assert_eq!(t, "{unknown}"); | 3127 | assert_eq!(t, "()"); |
3070 | } | 3128 | } |
3071 | 3129 | ||
3072 | #[test] | 3130 | #[test] |
@@ -3546,11 +3604,11 @@ fn test(x: Trait, y: &Trait) -> u64 { | |||
3546 | [129; 132) 'bar': fn bar() -> {unknown} | 3604 | [129; 132) 'bar': fn bar() -> {unknown} |
3547 | [129; 134) 'bar()': {unknown} | 3605 | [129; 134) 'bar()': {unknown} |
3548 | [140; 141) 'x': {unknown} | 3606 | [140; 141) 'x': {unknown} |
3549 | [140; 147) 'x.foo()': {unknown} | 3607 | [140; 147) 'x.foo()': u64 |
3550 | [153; 154) 'y': &{unknown} | 3608 | [153; 154) 'y': &{unknown} |
3551 | [153; 160) 'y.foo()': {unknown} | 3609 | [153; 160) 'y.foo()': u64 |
3552 | [166; 167) 'z': {unknown} | 3610 | [166; 167) 'z': {unknown} |
3553 | [166; 173) 'z.foo()': {unknown} | 3611 | [166; 173) 'z.foo()': u64 |
3554 | "### | 3612 | "### |
3555 | ); | 3613 | ); |
3556 | } | 3614 | } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 8a127efa1..0367c6560 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -356,14 +356,6 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | |||
356 | } | 356 | } |
357 | } | 357 | } |
358 | 358 | ||
359 | fn is_non_enumerable_trait(db: &impl HirDatabase, trait_: Trait) -> bool { | ||
360 | let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string(); | ||
361 | match &*name { | ||
362 | "Sized" => true, | ||
363 | _ => false, | ||
364 | } | ||
365 | } | ||
366 | |||
367 | fn convert_where_clauses( | 359 | fn convert_where_clauses( |
368 | db: &impl HirDatabase, | 360 | db: &impl HirDatabase, |
369 | def: GenericDef, | 361 | def: GenericDef, |
@@ -486,7 +478,7 @@ pub(crate) fn trait_datum_query( | |||
486 | associated_ty_ids: Vec::new(), | 478 | associated_ty_ids: Vec::new(), |
487 | where_clauses: Vec::new(), | 479 | where_clauses: Vec::new(), |
488 | flags: chalk_rust_ir::TraitFlags { | 480 | flags: chalk_rust_ir::TraitFlags { |
489 | non_enumerable: false, | 481 | non_enumerable: true, |
490 | auto: false, | 482 | auto: false, |
491 | marker: false, | 483 | marker: false, |
492 | upstream: true, | 484 | upstream: true, |
@@ -503,7 +495,7 @@ pub(crate) fn trait_datum_query( | |||
503 | let flags = chalk_rust_ir::TraitFlags { | 495 | let flags = chalk_rust_ir::TraitFlags { |
504 | auto: trait_.is_auto(db), | 496 | auto: trait_.is_auto(db), |
505 | upstream: trait_.module(db).krate(db) != Some(krate), | 497 | upstream: trait_.module(db).krate(db) != Some(krate), |
506 | non_enumerable: is_non_enumerable_trait(db, trait_), | 498 | non_enumerable: true, |
507 | // FIXME set these flags correctly | 499 | // FIXME set these flags correctly |
508 | marker: false, | 500 | marker: false, |
509 | fundamental: false, | 501 | fundamental: false, |
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml index 68f559295..b058dde91 100644 --- a/crates/ra_mbe/Cargo.toml +++ b/crates/ra_mbe/Cargo.toml | |||
@@ -12,3 +12,7 @@ itertools = "0.8.0" | |||
12 | rustc-hash = "1.0.0" | 12 | rustc-hash = "1.0.0" |
13 | smallvec = "0.6.9" | 13 | smallvec = "0.6.9" |
14 | log = "0.4.5" | 14 | log = "0.4.5" |
15 | |||
16 | [dev-dependencies] | ||
17 | test_utils = { path = "../test_utils" } | ||
18 | |||
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 52c3d03b5..f07f000ff 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -41,8 +41,8 @@ pub enum ExpandError { | |||
41 | } | 41 | } |
42 | 42 | ||
43 | pub use crate::syntax_bridge::{ | 43 | pub use crate::syntax_bridge::{ |
44 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_ast_item_list, token_tree_to_expr, | 44 | ast_to_token_tree, syntax_node_to_token_tree, token_tree_to_expr, token_tree_to_items, |
45 | token_tree_to_macro_items, token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, | 45 | token_tree_to_macro_stmts, token_tree_to_pat, token_tree_to_ty, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /// This struct contains AST for a single `macro_rules` definition. What might | 48 | /// This struct contains AST for a single `macro_rules` definition. What might |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 01641fdee..78df96880 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -81,21 +81,26 @@ struct Bindings { | |||
81 | 81 | ||
82 | #[derive(Debug)] | 82 | #[derive(Debug)] |
83 | enum Binding { | 83 | enum Binding { |
84 | Simple(tt::TokenTree), | 84 | Fragment(Fragment), |
85 | Nested(Vec<Binding>), | 85 | Nested(Vec<Binding>), |
86 | Empty, | 86 | Empty, |
87 | } | 87 | } |
88 | 88 | ||
89 | #[derive(Debug, Clone)] | ||
90 | enum Fragment { | ||
91 | /// token fragments are just copy-pasted into the output | ||
92 | Tokens(tt::TokenTree), | ||
93 | /// Ast fragments are inserted with fake delimiters, so as to make things | ||
94 | /// like `$i * 2` where `$i = 1 + 1` work as expectd. | ||
95 | Ast(tt::TokenTree), | ||
96 | } | ||
97 | |||
89 | impl Bindings { | 98 | impl Bindings { |
90 | fn push_optional(&mut self, name: &SmolStr) { | 99 | fn push_optional(&mut self, name: &SmolStr) { |
91 | // FIXME: Do we have a better way to represent an empty token ? | 100 | // FIXME: Do we have a better way to represent an empty token ? |
92 | // Insert an empty subtree for empty token | 101 | // Insert an empty subtree for empty token |
93 | self.inner.insert( | 102 | let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(); |
94 | name.clone(), | 103 | self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); |
95 | Binding::Simple( | ||
96 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(), | ||
97 | ), | ||
98 | ); | ||
99 | } | 104 | } |
100 | 105 | ||
101 | fn push_empty(&mut self, name: &SmolStr) { | 106 | fn push_empty(&mut self, name: &SmolStr) { |
@@ -106,13 +111,13 @@ impl Bindings { | |||
106 | self.inner.contains_key(name) | 111 | self.inner.contains_key(name) |
107 | } | 112 | } |
108 | 113 | ||
109 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&tt::TokenTree, ExpandError> { | 114 | fn get(&self, name: &SmolStr, nesting: &[usize]) -> Result<&Fragment, ExpandError> { |
110 | let mut b = self.inner.get(name).ok_or_else(|| { | 115 | let mut b = self.inner.get(name).ok_or_else(|| { |
111 | ExpandError::BindingError(format!("could not find binding `{}`", name)) | 116 | ExpandError::BindingError(format!("could not find binding `{}`", name)) |
112 | })?; | 117 | })?; |
113 | for &idx in nesting.iter() { | 118 | for &idx in nesting.iter() { |
114 | b = match b { | 119 | b = match b { |
115 | Binding::Simple(_) => break, | 120 | Binding::Fragment(_) => break, |
116 | Binding::Nested(bs) => bs.get(idx).ok_or_else(|| { | 121 | Binding::Nested(bs) => bs.get(idx).ok_or_else(|| { |
117 | ExpandError::BindingError(format!("could not find nested binding `{}`", name)) | 122 | ExpandError::BindingError(format!("could not find nested binding `{}`", name)) |
118 | })?, | 123 | })?, |
@@ -125,7 +130,7 @@ impl Bindings { | |||
125 | }; | 130 | }; |
126 | } | 131 | } |
127 | match b { | 132 | match b { |
128 | Binding::Simple(it) => Ok(it), | 133 | Binding::Fragment(it) => Ok(it), |
129 | Binding::Nested(_) => Err(ExpandError::BindingError(format!( | 134 | Binding::Nested(_) => Err(ExpandError::BindingError(format!( |
130 | "expected simple binding, found nested binding `{}`", | 135 | "expected simple binding, found nested binding `{}`", |
131 | name | 136 | name |
@@ -195,8 +200,8 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
195 | crate::Leaf::Var(crate::Var { text, kind }) => { | 200 | crate::Leaf::Var(crate::Var { text, kind }) => { |
196 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; | 201 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; |
197 | match match_meta_var(kind.as_str(), input)? { | 202 | match match_meta_var(kind.as_str(), input)? { |
198 | Some(tt) => { | 203 | Some(fragment) => { |
199 | res.inner.insert(text.clone(), Binding::Simple(tt)); | 204 | res.inner.insert(text.clone(), Binding::Fragment(fragment)); |
200 | } | 205 | } |
201 | None => res.push_optional(text), | 206 | None => res.push_optional(text), |
202 | } | 207 | } |
@@ -292,7 +297,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
292 | Ok(res) | 297 | Ok(res) |
293 | } | 298 | } |
294 | 299 | ||
295 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTree>, ExpandError> { | 300 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> { |
296 | let fragment = match kind { | 301 | let fragment = match kind { |
297 | "path" => Path, | 302 | "path" => Path, |
298 | "expr" => Expr, | 303 | "expr" => Expr, |
@@ -303,7 +308,7 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr | |||
303 | "meta" => MetaItem, | 308 | "meta" => MetaItem, |
304 | "item" => Item, | 309 | "item" => Item, |
305 | _ => { | 310 | _ => { |
306 | let binding = match kind { | 311 | let tt = match kind { |
307 | "ident" => { | 312 | "ident" => { |
308 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | 313 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); |
309 | tt::Leaf::from(ident).into() | 314 | tt::Leaf::from(ident).into() |
@@ -321,11 +326,12 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<tt::TokenTr | |||
321 | }, | 326 | }, |
322 | _ => return Err(ExpandError::UnexpectedToken), | 327 | _ => return Err(ExpandError::UnexpectedToken), |
323 | }; | 328 | }; |
324 | return Ok(Some(binding)); | 329 | return Ok(Some(Fragment::Tokens(tt))); |
325 | } | 330 | } |
326 | }; | 331 | }; |
327 | let binding = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; | 332 | let tt = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; |
328 | Ok(Some(binding)) | 333 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; |
334 | Ok(Some(fragment)) | ||
329 | } | 335 | } |
330 | 336 | ||
331 | #[derive(Debug)] | 337 | #[derive(Debug)] |
@@ -339,45 +345,20 @@ fn expand_subtree( | |||
339 | template: &crate::Subtree, | 345 | template: &crate::Subtree, |
340 | ctx: &mut ExpandCtx, | 346 | ctx: &mut ExpandCtx, |
341 | ) -> Result<tt::Subtree, ExpandError> { | 347 | ) -> Result<tt::Subtree, ExpandError> { |
342 | let token_trees = template | 348 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
343 | .token_trees | 349 | for tt in template.token_trees.iter() { |
344 | .iter() | 350 | let tt = expand_tt(tt, ctx)?; |
345 | .map(|it| expand_tt(it, ctx)) | 351 | push_fragment(&mut buf, tt); |
346 | .filter(|it| { | ||
347 | // Filter empty subtree | ||
348 | if let Ok(tt::TokenTree::Subtree(subtree)) = it { | ||
349 | subtree.delimiter != tt::Delimiter::None || !subtree.token_trees.is_empty() | ||
350 | } else { | ||
351 | true | ||
352 | } | ||
353 | }) | ||
354 | .collect::<Result<Vec<_>, ExpandError>>()?; | ||
355 | |||
356 | Ok(tt::Subtree { token_trees, delimiter: template.delimiter }) | ||
357 | } | ||
358 | |||
359 | /// Reduce single token subtree to single token | ||
360 | /// In `tt` matcher case, all tt tokens will be braced by a Delimiter::None | ||
361 | /// which makes all sort of problems. | ||
362 | fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree { | ||
363 | if subtree.delimiter != tt::Delimiter::None || subtree.token_trees.len() != 1 { | ||
364 | return subtree.into(); | ||
365 | } | 352 | } |
366 | 353 | ||
367 | match subtree.token_trees.pop().unwrap() { | 354 | Ok(tt::Subtree { delimiter: template.delimiter, token_trees: buf }) |
368 | tt::TokenTree::Subtree(subtree) => reduce_single_token(subtree), | ||
369 | tt::TokenTree::Leaf(token) => token.into(), | ||
370 | } | ||
371 | } | 355 | } |
372 | 356 | ||
373 | fn expand_tt( | 357 | fn expand_tt(template: &crate::TokenTree, ctx: &mut ExpandCtx) -> Result<Fragment, ExpandError> { |
374 | template: &crate::TokenTree, | ||
375 | ctx: &mut ExpandCtx, | ||
376 | ) -> Result<tt::TokenTree, ExpandError> { | ||
377 | let res: tt::TokenTree = match template { | 358 | let res: tt::TokenTree = match template { |
378 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), | 359 | crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(), |
379 | crate::TokenTree::Repeat(repeat) => { | 360 | crate::TokenTree::Repeat(repeat) => { |
380 | let mut token_trees: Vec<tt::TokenTree> = Vec::new(); | 361 | let mut buf: Vec<tt::TokenTree> = Vec::new(); |
381 | ctx.nesting.push(0); | 362 | ctx.nesting.push(0); |
382 | // Dirty hack to make macro-expansion terminate. | 363 | // Dirty hack to make macro-expansion terminate. |
383 | // This should be replaced by a propper macro-by-example implementation | 364 | // This should be replaced by a propper macro-by-example implementation |
@@ -418,23 +399,23 @@ fn expand_tt( | |||
418 | 399 | ||
419 | let idx = ctx.nesting.pop().unwrap(); | 400 | let idx = ctx.nesting.pop().unwrap(); |
420 | ctx.nesting.push(idx + 1); | 401 | ctx.nesting.push(idx + 1); |
421 | token_trees.push(reduce_single_token(t)); | 402 | push_subtree(&mut buf, t); |
422 | 403 | ||
423 | if let Some(ref sep) = repeat.separator { | 404 | if let Some(ref sep) = repeat.separator { |
424 | match sep { | 405 | match sep { |
425 | crate::Separator::Ident(ident) => { | 406 | crate::Separator::Ident(ident) => { |
426 | has_seps = 1; | 407 | has_seps = 1; |
427 | token_trees.push(tt::Leaf::from(ident.clone()).into()); | 408 | buf.push(tt::Leaf::from(ident.clone()).into()); |
428 | } | 409 | } |
429 | crate::Separator::Literal(lit) => { | 410 | crate::Separator::Literal(lit) => { |
430 | has_seps = 1; | 411 | has_seps = 1; |
431 | token_trees.push(tt::Leaf::from(lit.clone()).into()); | 412 | buf.push(tt::Leaf::from(lit.clone()).into()); |
432 | } | 413 | } |
433 | 414 | ||
434 | crate::Separator::Puncts(puncts) => { | 415 | crate::Separator::Puncts(puncts) => { |
435 | has_seps = puncts.len(); | 416 | has_seps = puncts.len(); |
436 | for punct in puncts { | 417 | for punct in puncts { |
437 | token_trees.push(tt::Leaf::from(*punct).into()); | 418 | buf.push(tt::Leaf::from(*punct).into()); |
438 | } | 419 | } |
439 | } | 420 | } |
440 | } | 421 | } |
@@ -450,16 +431,16 @@ fn expand_tt( | |||
450 | 431 | ||
451 | ctx.nesting.pop().unwrap(); | 432 | ctx.nesting.pop().unwrap(); |
452 | for _ in 0..has_seps { | 433 | for _ in 0..has_seps { |
453 | token_trees.pop(); | 434 | buf.pop(); |
454 | } | 435 | } |
455 | 436 | ||
456 | if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { | 437 | if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 { |
457 | return Err(ExpandError::UnexpectedToken); | 438 | return Err(ExpandError::UnexpectedToken); |
458 | } | 439 | } |
459 | 440 | ||
460 | // Check if it is a singel token subtree without any delimiter | 441 | // Check if it is a single token subtree without any delimiter |
461 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} | 442 | // e.g {Delimiter:None> ['>'] /Delimiter:None>} |
462 | reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None }) | 443 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into() |
463 | } | 444 | } |
464 | crate::TokenTree::Leaf(leaf) => match leaf { | 445 | crate::TokenTree::Leaf(leaf) => match leaf { |
465 | crate::Leaf::Ident(ident) => { | 446 | crate::Leaf::Ident(ident) => { |
@@ -500,20 +481,15 @@ fn expand_tt( | |||
500 | } | 481 | } |
501 | .into() | 482 | .into() |
502 | } else { | 483 | } else { |
503 | let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); | 484 | let fragment = ctx.bindings.get(&v.text, &ctx.nesting)?.clone(); |
504 | ctx.var_expanded = true; | 485 | ctx.var_expanded = true; |
505 | 486 | return Ok(fragment); | |
506 | if let tt::TokenTree::Subtree(subtree) = tkn { | ||
507 | reduce_single_token(subtree) | ||
508 | } else { | ||
509 | tkn | ||
510 | } | ||
511 | } | 487 | } |
512 | } | 488 | } |
513 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), | 489 | crate::Leaf::Literal(l) => tt::Leaf::from(tt::Literal { text: l.text.clone() }).into(), |
514 | }, | 490 | }, |
515 | }; | 491 | }; |
516 | Ok(res) | 492 | Ok(Fragment::Tokens(res)) |
517 | } | 493 | } |
518 | 494 | ||
519 | #[cfg(test)] | 495 | #[cfg(test)] |
@@ -586,3 +562,17 @@ mod tests { | |||
586 | expand_rule(&rules.rules[0], &invocation_tt) | 562 | expand_rule(&rules.rules[0], &invocation_tt) |
587 | } | 563 | } |
588 | } | 564 | } |
565 | |||
566 | fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) { | ||
567 | match fragment { | ||
568 | Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt), | ||
569 | Fragment::Tokens(tt) | Fragment::Ast(tt) => buf.push(tt), | ||
570 | } | ||
571 | } | ||
572 | |||
573 | fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { | ||
574 | match tt.delimiter { | ||
575 | tt::Delimiter::None => buf.extend(tt.token_trees), | ||
576 | _ => buf.push(tt.into()), | ||
577 | } | ||
578 | } | ||
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index a380b1cfd..2d035307b 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -46,31 +46,19 @@ pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, Toke | |||
46 | // * TraitItems(SmallVec<[ast::TraitItem; 1]>) | 46 | // * TraitItems(SmallVec<[ast::TraitItem; 1]>) |
47 | // * ImplItems(SmallVec<[ast::ImplItem; 1]>) | 47 | // * ImplItems(SmallVec<[ast::ImplItem; 1]>) |
48 | // * ForeignItems(SmallVec<[ast::ForeignItem; 1]> | 48 | // * ForeignItems(SmallVec<[ast::ForeignItem; 1]> |
49 | // | ||
50 | // | ||
51 | |||
52 | fn token_tree_to_syntax_node<F>(tt: &tt::Subtree, f: F) -> Result<Parse<SyntaxNode>, ExpandError> | ||
53 | where | ||
54 | F: Fn(&mut dyn ra_parser::TokenSource, &mut dyn ra_parser::TreeSink), | ||
55 | { | ||
56 | let tokens = [tt.clone().into()]; | ||
57 | let buffer = TokenBuffer::new(&tokens); | ||
58 | let mut token_source = SubtreeTokenSource::new(&buffer); | ||
59 | let mut tree_sink = TtTreeSink::new(buffer.begin()); | ||
60 | f(&mut token_source, &mut tree_sink); | ||
61 | if tree_sink.roots.len() != 1 { | ||
62 | return Err(ExpandError::ConversionError); | ||
63 | } | ||
64 | //FIXME: would be cool to report errors | ||
65 | let parse = tree_sink.inner.finish(); | ||
66 | Ok(parse) | ||
67 | } | ||
68 | 49 | ||
69 | fn fragment_to_syntax_node( | 50 | fn fragment_to_syntax_node( |
70 | tt: &tt::Subtree, | 51 | tt: &tt::Subtree, |
71 | fragment_kind: FragmentKind, | 52 | fragment_kind: FragmentKind, |
72 | ) -> Result<Parse<SyntaxNode>, ExpandError> { | 53 | ) -> Result<Parse<SyntaxNode>, ExpandError> { |
73 | let tokens = [tt.clone().into()]; | 54 | let tmp; |
55 | let tokens = match tt { | ||
56 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), | ||
57 | _ => { | ||
58 | tmp = [tt.clone().into()]; | ||
59 | &tmp[..] | ||
60 | } | ||
61 | }; | ||
74 | let buffer = TokenBuffer::new(&tokens); | 62 | let buffer = TokenBuffer::new(&tokens); |
75 | let mut token_source = SubtreeTokenSource::new(&buffer); | 63 | let mut token_source = SubtreeTokenSource::new(&buffer); |
76 | let mut tree_sink = TtTreeSink::new(buffer.begin()); | 64 | let mut tree_sink = TtTreeSink::new(buffer.begin()); |
@@ -108,17 +96,11 @@ pub fn token_tree_to_macro_stmts(tt: &tt::Subtree) -> Result<Parse<ast::MacroStm | |||
108 | } | 96 | } |
109 | 97 | ||
110 | /// Parses the token tree (result of macro expansion) as a sequence of items | 98 | /// Parses the token tree (result of macro expansion) as a sequence of items |
111 | pub fn token_tree_to_macro_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { | 99 | pub fn token_tree_to_items(tt: &tt::Subtree) -> Result<Parse<ast::MacroItems>, ExpandError> { |
112 | let parse = fragment_to_syntax_node(tt, Items)?; | 100 | let parse = fragment_to_syntax_node(tt, Items)?; |
113 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) | 101 | parse.cast().ok_or_else(|| crate::ExpandError::ConversionError) |
114 | } | 102 | } |
115 | 103 | ||
116 | /// Parses the token tree (result of macro expansion) as a sequence of items | ||
117 | pub fn token_tree_to_ast_item_list(tt: &tt::Subtree) -> Parse<ast::SourceFile> { | ||
118 | let parse = token_tree_to_syntax_node(tt, ra_parser::parse).unwrap(); | ||
119 | parse.cast().unwrap() | ||
120 | } | ||
121 | |||
122 | impl TokenMap { | 104 | impl TokenMap { |
123 | pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { | 105 | pub fn relative_range_of(&self, tt: tt::TokenId) -> Option<TextRange> { |
124 | let idx = tt.0 as usize; | 106 | let idx = tt.0 as usize; |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 034ea639b..312fa4626 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use ra_syntax::{ast, AstNode, NodeOrToken}; | 1 | use ra_syntax::{ast, AstNode, NodeOrToken}; |
2 | use test_utils::assert_eq_text; | ||
2 | 3 | ||
3 | use super::*; | 4 | use super::*; |
4 | 5 | ||
@@ -69,7 +70,7 @@ pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { | |||
69 | 70 | ||
70 | pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems { | 71 | pub(crate) fn expand_to_items(rules: &MacroRules, invocation: &str) -> ast::MacroItems { |
71 | let expanded = expand(rules, invocation); | 72 | let expanded = expand(rules, invocation); |
72 | token_tree_to_macro_items(&expanded).unwrap().tree() | 73 | token_tree_to_items(&expanded).unwrap().tree() |
73 | } | 74 | } |
74 | 75 | ||
75 | #[allow(unused)] | 76 | #[allow(unused)] |
@@ -152,11 +153,10 @@ pub(crate) fn assert_expansion( | |||
152 | 153 | ||
153 | // wrap the given text to a macro call | 154 | // wrap the given text to a macro call |
154 | let expected = text_to_tokentree(&expected); | 155 | let expected = text_to_tokentree(&expected); |
155 | |||
156 | let (expanded_tree, expected_tree) = match kind { | 156 | let (expanded_tree, expected_tree) = match kind { |
157 | MacroKind::Items => { | 157 | MacroKind::Items => { |
158 | let expanded_tree = token_tree_to_macro_items(&expanded).unwrap().tree(); | 158 | let expanded_tree = token_tree_to_items(&expanded).unwrap().tree(); |
159 | let expected_tree = token_tree_to_macro_items(&expected).unwrap().tree(); | 159 | let expected_tree = token_tree_to_items(&expected).unwrap().tree(); |
160 | 160 | ||
161 | ( | 161 | ( |
162 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), | 162 | debug_dump_ignore_spaces(expanded_tree.syntax()).trim().to_string(), |
@@ -178,7 +178,7 @@ pub(crate) fn assert_expansion( | |||
178 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | 178 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); |
179 | assert_eq!( | 179 | assert_eq!( |
180 | expanded_tree, expected_tree, | 180 | expanded_tree, expected_tree, |
181 | "left => {}\nright => {}", | 181 | "\nleft:\n{}\nright:\n{}", |
182 | expanded_tree, expected_tree, | 182 | expanded_tree, expected_tree, |
183 | ); | 183 | ); |
184 | 184 | ||
@@ -410,7 +410,7 @@ fn test_expand_to_item_list() { | |||
410 | ", | 410 | ", |
411 | ); | 411 | ); |
412 | let expansion = expand(&rules, "structs!(Foo, Bar);"); | 412 | let expansion = expand(&rules, "structs!(Foo, Bar);"); |
413 | let tree = token_tree_to_macro_items(&expansion).unwrap().tree(); | 413 | let tree = token_tree_to_items(&expansion).unwrap().tree(); |
414 | assert_eq!( | 414 | assert_eq!( |
415 | format!("{:#?}", tree.syntax()).trim(), | 415 | format!("{:#?}", tree.syntax()).trim(), |
416 | r#" | 416 | r#" |
@@ -667,9 +667,9 @@ fn test_expr_order() { | |||
667 | } | 667 | } |
668 | "#, | 668 | "#, |
669 | ); | 669 | ); |
670 | 670 | let dump = format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()); | |
671 | assert_eq!( | 671 | assert_eq_text!( |
672 | format!("{:#?}", expand_to_items(&rules, "foo! { 1 + 1 }").syntax()).trim(), | 672 | dump.trim(), |
673 | r#"MACRO_ITEMS@[0; 15) | 673 | r#"MACRO_ITEMS@[0; 15) |
674 | FN_DEF@[0; 15) | 674 | FN_DEF@[0; 15) |
675 | FN_KW@[0; 2) "fn" | 675 | FN_KW@[0; 2) "fn" |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index a2ad580bc..0158f9b8a 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -93,12 +93,12 @@ pub(crate) mod fragments { | |||
93 | // https://doc.rust-lang.org/reference/paths.html#simple-paths | 93 | // https://doc.rust-lang.org/reference/paths.html#simple-paths |
94 | // The start of an meta must be a simple path | 94 | // The start of an meta must be a simple path |
95 | match p.current() { | 95 | match p.current() { |
96 | IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump(), | 96 | IDENT | T![::] | T![super] | T![self] | T![crate] => p.bump_any(), |
97 | T![=] => { | 97 | T![=] => { |
98 | p.bump(); | 98 | p.bump_any(); |
99 | match p.current() { | 99 | match p.current() { |
100 | c if c.is_literal() => p.bump(), | 100 | c if c.is_literal() => p.bump_any(), |
101 | T![true] | T![false] => p.bump(), | 101 | T![true] | T![false] => p.bump_any(), |
102 | _ => {} | 102 | _ => {} |
103 | } | 103 | } |
104 | break; | 104 | break; |
@@ -126,7 +126,7 @@ pub(crate) mod fragments { | |||
126 | 126 | ||
127 | while !p.at(EOF) { | 127 | while !p.at(EOF) { |
128 | if p.at(T![;]) { | 128 | if p.at(T![;]) { |
129 | p.bump(); | 129 | p.bump(T![;]); |
130 | continue; | 130 | continue; |
131 | } | 131 | } |
132 | 132 | ||
@@ -179,7 +179,7 @@ fn opt_visibility(p: &mut Parser) -> bool { | |||
179 | match p.current() { | 179 | match p.current() { |
180 | T![pub] => { | 180 | T![pub] => { |
181 | let m = p.start(); | 181 | let m = p.start(); |
182 | p.bump(); | 182 | p.bump(T![pub]); |
183 | if p.at(T!['(']) { | 183 | if p.at(T!['(']) { |
184 | match p.nth(1) { | 184 | match p.nth(1) { |
185 | // test crate_visibility | 185 | // test crate_visibility |
@@ -188,13 +188,13 @@ fn opt_visibility(p: &mut Parser) -> bool { | |||
188 | // pub(self) struct S; | 188 | // pub(self) struct S; |
189 | // pub(self) struct S; | 189 | // pub(self) struct S; |
190 | T![crate] | T![self] | T![super] => { | 190 | T![crate] | T![self] | T![super] => { |
191 | p.bump(); | 191 | p.bump_any(); |
192 | p.bump(); | 192 | p.bump_any(); |
193 | p.expect(T![')']); | 193 | p.expect(T![')']); |
194 | } | 194 | } |
195 | T![in] => { | 195 | T![in] => { |
196 | p.bump(); | 196 | p.bump_any(); |
197 | p.bump(); | 197 | p.bump_any(); |
198 | paths::use_path(p); | 198 | paths::use_path(p); |
199 | p.expect(T![')']); | 199 | p.expect(T![')']); |
200 | } | 200 | } |
@@ -210,9 +210,9 @@ fn opt_visibility(p: &mut Parser) -> bool { | |||
210 | // | 210 | // |
211 | // test crate_keyword_path | 211 | // test crate_keyword_path |
212 | // fn foo() { crate::foo(); } | 212 | // fn foo() { crate::foo(); } |
213 | T![crate] if p.nth(1) != T![::] => { | 213 | T![crate] if !p.nth_at(1, T![::]) => { |
214 | let m = p.start(); | 214 | let m = p.start(); |
215 | p.bump(); | 215 | p.bump_any(); |
216 | m.complete(p, VISIBILITY); | 216 | m.complete(p, VISIBILITY); |
217 | } | 217 | } |
218 | _ => return false, | 218 | _ => return false, |
@@ -223,7 +223,7 @@ fn opt_visibility(p: &mut Parser) -> bool { | |||
223 | fn opt_alias(p: &mut Parser) { | 223 | fn opt_alias(p: &mut Parser) { |
224 | if p.at(T![as]) { | 224 | if p.at(T![as]) { |
225 | let m = p.start(); | 225 | let m = p.start(); |
226 | p.bump(); | 226 | p.bump_any(); |
227 | if !p.eat(T![_]) { | 227 | if !p.eat(T![_]) { |
228 | name(p); | 228 | name(p); |
229 | } | 229 | } |
@@ -234,9 +234,9 @@ fn opt_alias(p: &mut Parser) { | |||
234 | fn abi(p: &mut Parser) { | 234 | fn abi(p: &mut Parser) { |
235 | assert!(p.at(T![extern])); | 235 | assert!(p.at(T![extern])); |
236 | let abi = p.start(); | 236 | let abi = p.start(); |
237 | p.bump(); | 237 | p.bump_any(); |
238 | match p.current() { | 238 | match p.current() { |
239 | STRING | RAW_STRING => p.bump(), | 239 | STRING | RAW_STRING => p.bump_any(), |
240 | _ => (), | 240 | _ => (), |
241 | } | 241 | } |
242 | abi.complete(p, ABI); | 242 | abi.complete(p, ABI); |
@@ -245,7 +245,7 @@ fn abi(p: &mut Parser) { | |||
245 | fn opt_fn_ret_type(p: &mut Parser) -> bool { | 245 | fn opt_fn_ret_type(p: &mut Parser) -> bool { |
246 | if p.at(T![->]) { | 246 | if p.at(T![->]) { |
247 | let m = p.start(); | 247 | let m = p.start(); |
248 | p.bump(); | 248 | p.bump(T![->]); |
249 | types::type_(p); | 249 | types::type_(p); |
250 | m.complete(p, RET_TYPE); | 250 | m.complete(p, RET_TYPE); |
251 | true | 251 | true |
@@ -257,7 +257,7 @@ fn opt_fn_ret_type(p: &mut Parser) -> bool { | |||
257 | fn name_r(p: &mut Parser, recovery: TokenSet) { | 257 | fn name_r(p: &mut Parser, recovery: TokenSet) { |
258 | if p.at(IDENT) { | 258 | if p.at(IDENT) { |
259 | let m = p.start(); | 259 | let m = p.start(); |
260 | p.bump(); | 260 | p.bump_any(); |
261 | m.complete(p, NAME); | 261 | m.complete(p, NAME); |
262 | } else { | 262 | } else { |
263 | p.err_recover("expected a name", recovery); | 263 | p.err_recover("expected a name", recovery); |
@@ -271,11 +271,11 @@ fn name(p: &mut Parser) { | |||
271 | fn name_ref(p: &mut Parser) { | 271 | fn name_ref(p: &mut Parser) { |
272 | if p.at(IDENT) { | 272 | if p.at(IDENT) { |
273 | let m = p.start(); | 273 | let m = p.start(); |
274 | p.bump(); | 274 | p.bump_any(); |
275 | m.complete(p, NAME_REF); | 275 | m.complete(p, NAME_REF); |
276 | } else if p.at(T![self]) { | 276 | } else if p.at(T![self]) { |
277 | let m = p.start(); | 277 | let m = p.start(); |
278 | p.bump(); | 278 | p.bump_any(); |
279 | m.complete(p, T![self]); | 279 | m.complete(p, T![self]); |
280 | } else { | 280 | } else { |
281 | p.err_and_bump("expected identifier"); | 281 | p.err_and_bump("expected identifier"); |
@@ -285,7 +285,7 @@ fn name_ref(p: &mut Parser) { | |||
285 | fn name_ref_or_index(p: &mut Parser) { | 285 | fn name_ref_or_index(p: &mut Parser) { |
286 | if p.at(IDENT) || p.at(INT_NUMBER) { | 286 | if p.at(IDENT) || p.at(INT_NUMBER) { |
287 | let m = p.start(); | 287 | let m = p.start(); |
288 | p.bump(); | 288 | p.bump_any(); |
289 | m.complete(p, NAME_REF); | 289 | m.complete(p, NAME_REF); |
290 | } else { | 290 | } else { |
291 | p.err_and_bump("expected identifier"); | 291 | p.err_and_bump("expected identifier"); |
@@ -296,7 +296,7 @@ fn error_block(p: &mut Parser, message: &str) { | |||
296 | assert!(p.at(T!['{'])); | 296 | assert!(p.at(T!['{'])); |
297 | let m = p.start(); | 297 | let m = p.start(); |
298 | p.error(message); | 298 | p.error(message); |
299 | p.bump(); | 299 | p.bump_any(); |
300 | expressions::expr_block_contents(p); | 300 | expressions::expr_block_contents(p); |
301 | p.eat(T!['}']); | 301 | p.eat(T!['}']); |
302 | m.complete(p, ERROR); | 302 | m.complete(p, ERROR); |
diff --git a/crates/ra_parser/src/grammar/attributes.rs b/crates/ra_parser/src/grammar/attributes.rs index e97170203..81a363a57 100644 --- a/crates/ra_parser/src/grammar/attributes.rs +++ b/crates/ra_parser/src/grammar/attributes.rs | |||
@@ -15,11 +15,11 @@ pub(super) fn outer_attributes(p: &mut Parser) { | |||
15 | fn attribute(p: &mut Parser, inner: bool) { | 15 | fn attribute(p: &mut Parser, inner: bool) { |
16 | let attr = p.start(); | 16 | let attr = p.start(); |
17 | assert!(p.at(T![#])); | 17 | assert!(p.at(T![#])); |
18 | p.bump(); | 18 | p.bump_any(); |
19 | 19 | ||
20 | if inner { | 20 | if inner { |
21 | assert!(p.at(T![!])); | 21 | assert!(p.at(T![!])); |
22 | p.bump(); | 22 | p.bump_any(); |
23 | } | 23 | } |
24 | 24 | ||
25 | if p.at(T!['[']) { | 25 | if p.at(T!['[']) { |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 855418f1c..1dd9a586c 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -14,20 +14,17 @@ const EXPR_FIRST: TokenSet = LHS_FIRST; | |||
14 | 14 | ||
15 | pub(super) fn expr(p: &mut Parser) -> BlockLike { | 15 | pub(super) fn expr(p: &mut Parser) -> BlockLike { |
16 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; | 16 | let r = Restrictions { forbid_structs: false, prefer_stmt: false }; |
17 | let mut dollar_lvl = 0; | 17 | expr_bp(p, r, 1).1 |
18 | expr_bp(p, r, 1, &mut dollar_lvl).1 | ||
19 | } | 18 | } |
20 | 19 | ||
21 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { | 20 | pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) { |
22 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; | 21 | let r = Restrictions { forbid_structs: false, prefer_stmt: true }; |
23 | let mut dollar_lvl = 0; | 22 | expr_bp(p, r, 1) |
24 | expr_bp(p, r, 1, &mut dollar_lvl) | ||
25 | } | 23 | } |
26 | 24 | ||
27 | fn expr_no_struct(p: &mut Parser) { | 25 | fn expr_no_struct(p: &mut Parser) { |
28 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; | 26 | let r = Restrictions { forbid_structs: true, prefer_stmt: false }; |
29 | let mut dollar_lvl = 0; | 27 | expr_bp(p, r, 1); |
30 | expr_bp(p, r, 1, &mut dollar_lvl); | ||
31 | } | 28 | } |
32 | 29 | ||
33 | // test block | 30 | // test block |
@@ -46,7 +43,7 @@ pub(crate) fn block(p: &mut Parser) { | |||
46 | pub(crate) fn naked_block(p: &mut Parser) { | 43 | pub(crate) fn naked_block(p: &mut Parser) { |
47 | assert!(p.at(T!['{'])); | 44 | assert!(p.at(T!['{'])); |
48 | let m = p.start(); | 45 | let m = p.start(); |
49 | p.bump(); | 46 | p.bump_any(); |
50 | expr_block_contents(p); | 47 | expr_block_contents(p); |
51 | p.expect(T!['}']); | 48 | p.expect(T!['}']); |
52 | m.complete(p, BLOCK); | 49 | m.complete(p, BLOCK); |
@@ -153,7 +150,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { | |||
153 | // } | 150 | // } |
154 | fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) { | 151 | fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) { |
155 | assert!(p.at(T![let])); | 152 | assert!(p.at(T![let])); |
156 | p.bump(); | 153 | p.bump_any(); |
157 | patterns::pattern(p); | 154 | patterns::pattern(p); |
158 | if p.at(T![:]) { | 155 | if p.at(T![:]) { |
159 | types::ascription(p); | 156 | types::ascription(p); |
@@ -198,7 +195,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
198 | // } | 195 | // } |
199 | 196 | ||
200 | if p.at(T![;]) { | 197 | if p.at(T![;]) { |
201 | p.bump(); | 198 | p.bump_any(); |
202 | continue; | 199 | continue; |
203 | } | 200 | } |
204 | 201 | ||
@@ -212,72 +209,53 @@ struct Restrictions { | |||
212 | prefer_stmt: bool, | 209 | prefer_stmt: bool, |
213 | } | 210 | } |
214 | 211 | ||
215 | enum Op { | 212 | /// Binding powers of operators for a Pratt parser. |
216 | Simple, | 213 | /// |
217 | Composite(SyntaxKind, u8), | 214 | /// See https://www.oilshell.org/blog/2016/11/03.html |
218 | } | 215 | #[rustfmt::skip] |
219 | 216 | fn current_op(p: &Parser) -> (u8, SyntaxKind) { | |
220 | fn current_op(p: &Parser) -> (u8, Op) { | 217 | const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]); |
221 | if let Some(t) = p.current3() { | 218 | match p.current() { |
222 | match t { | 219 | T![|] if p.at(T![||]) => (3, T![||]), |
223 | (T![<], T![<], T![=]) => return (1, Op::Composite(T![<<=], 3)), | 220 | T![|] if p.at(T![|=]) => (1, T![|=]), |
224 | (T![>], T![>], T![=]) => return (1, Op::Composite(T![>>=], 3)), | 221 | T![|] => (6, T![|]), |
225 | _ => (), | 222 | T![>] if p.at(T![>>=]) => (1, T![>>=]), |
226 | } | 223 | T![>] if p.at(T![>>]) => (9, T![>>]), |
227 | } | 224 | T![>] if p.at(T![>=]) => (5, T![>=]), |
228 | 225 | T![>] => (5, T![>]), | |
229 | if let Some(t) = p.current2() { | 226 | T![=] if p.at(T![=>]) => NOT_AN_OP, |
230 | match t { | 227 | T![=] if p.at(T![==]) => (5, T![==]), |
231 | (T![+], T![=]) => return (1, Op::Composite(T![+=], 2)), | 228 | T![=] => (1, T![=]), |
232 | (T![-], T![=]) => return (1, Op::Composite(T![-=], 2)), | 229 | T![<] if p.at(T![<=]) => (5, T![<=]), |
233 | (T![*], T![=]) => return (1, Op::Composite(T![*=], 2)), | 230 | T![<] if p.at(T![<<=]) => (1, T![<<=]), |
234 | (T![%], T![=]) => return (1, Op::Composite(T![%=], 2)), | 231 | T![<] if p.at(T![<<]) => (9, T![<<]), |
235 | (T![/], T![=]) => return (1, Op::Composite(T![/=], 2)), | 232 | T![<] => (5, T![<]), |
236 | (T![|], T![=]) => return (1, Op::Composite(T![|=], 2)), | 233 | T![+] if p.at(T![+=]) => (1, T![+=]), |
237 | (T![&], T![=]) => return (1, Op::Composite(T![&=], 2)), | 234 | T![+] => (10, T![+]), |
238 | (T![^], T![=]) => return (1, Op::Composite(T![^=], 2)), | 235 | T![^] if p.at(T![^=]) => (1, T![^=]), |
239 | (T![|], T![|]) => return (3, Op::Composite(T![||], 2)), | 236 | T![^] => (7, T![^]), |
240 | (T![&], T![&]) => return (4, Op::Composite(T![&&], 2)), | 237 | T![%] if p.at(T![%=]) => (1, T![%=]), |
241 | (T![<], T![=]) => return (5, Op::Composite(T![<=], 2)), | 238 | T![%] => (11, T![%]), |
242 | (T![>], T![=]) => return (5, Op::Composite(T![>=], 2)), | 239 | T![&] if p.at(T![&=]) => (1, T![&=]), |
243 | (T![<], T![<]) => return (9, Op::Composite(T![<<], 2)), | 240 | T![&] if p.at(T![&&]) => (4, T![&&]), |
244 | (T![>], T![>]) => return (9, Op::Composite(T![>>], 2)), | 241 | T![&] => (8, T![&]), |
245 | _ => (), | 242 | T![/] if p.at(T![/=]) => (1, T![/=]), |
246 | } | 243 | T![/] => (11, T![/]), |
244 | T![*] if p.at(T![*=]) => (1, T![*=]), | ||
245 | T![*] => (11, T![*]), | ||
246 | T![.] if p.at(T![..=]) => (2, T![..=]), | ||
247 | T![.] if p.at(T![..]) => (2, T![..]), | ||
248 | T![!] if p.at(T![!=]) => (5, T![!=]), | ||
249 | T![-] if p.at(T![-=]) => (1, T![-=]), | ||
250 | T![-] => (10, T![-]), | ||
251 | |||
252 | _ => NOT_AN_OP | ||
247 | } | 253 | } |
248 | |||
249 | let bp = match p.current() { | ||
250 | T![=] => 1, | ||
251 | T![..] | T![..=] => 2, | ||
252 | T![==] | T![!=] | T![<] | T![>] => 5, | ||
253 | T![|] => 6, | ||
254 | T![^] => 7, | ||
255 | T![&] => 8, | ||
256 | T![-] | T![+] => 10, | ||
257 | T![*] | T![/] | T![%] => 11, | ||
258 | _ => 0, | ||
259 | }; | ||
260 | (bp, Op::Simple) | ||
261 | } | 254 | } |
262 | 255 | ||
263 | // Parses expression with binding power of at least bp. | 256 | // Parses expression with binding power of at least bp. |
264 | fn expr_bp( | 257 | fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) { |
265 | p: &mut Parser, | 258 | let mut lhs = match lhs(p, r) { |
266 | r: Restrictions, | ||
267 | mut bp: u8, | ||
268 | dollar_lvl: &mut usize, | ||
269 | ) -> (Option<CompletedMarker>, BlockLike) { | ||
270 | // `newly_dollar_open` is a flag indicated that dollar is just closed after lhs, e.g. | ||
271 | // `$1$ + a` | ||
272 | // We use this flag to skip handling it. | ||
273 | let mut newly_dollar_open = if p.at_l_dollar() { | ||
274 | *dollar_lvl += p.eat_l_dollars(); | ||
275 | true | ||
276 | } else { | ||
277 | false | ||
278 | }; | ||
279 | |||
280 | let mut lhs = match lhs(p, r, dollar_lvl) { | ||
281 | Some((lhs, blocklike)) => { | 259 | Some((lhs, blocklike)) => { |
282 | // test stmt_bin_expr_ambiguity | 260 | // test stmt_bin_expr_ambiguity |
283 | // fn foo() { | 261 | // fn foo() { |
@@ -293,42 +271,23 @@ fn expr_bp( | |||
293 | }; | 271 | }; |
294 | 272 | ||
295 | loop { | 273 | loop { |
296 | if *dollar_lvl > 0 && p.at_r_dollar() { | ||
297 | *dollar_lvl -= p.eat_r_dollars(*dollar_lvl); | ||
298 | if !newly_dollar_open { | ||
299 | // We "pump" bp for make it highest priority | ||
300 | bp = 255; | ||
301 | } | ||
302 | newly_dollar_open = false; | ||
303 | } | ||
304 | |||
305 | let is_range = p.at(T![..]) || p.at(T![..=]); | 274 | let is_range = p.at(T![..]) || p.at(T![..=]); |
306 | let (op_bp, op) = current_op(p); | 275 | let (op_bp, op) = current_op(p); |
307 | if op_bp < bp { | 276 | if op_bp < bp { |
308 | break; | 277 | break; |
309 | } | 278 | } |
310 | let m = lhs.precede(p); | 279 | let m = lhs.precede(p); |
311 | match op { | 280 | p.bump(op); |
312 | Op::Simple => p.bump(), | ||
313 | Op::Composite(kind, n) => { | ||
314 | p.bump_compound(kind, n); | ||
315 | } | ||
316 | } | ||
317 | 281 | ||
318 | expr_bp(p, r, op_bp + 1, dollar_lvl); | 282 | expr_bp(p, r, op_bp + 1); |
319 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); | 283 | lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); |
320 | } | 284 | } |
321 | (Some(lhs), BlockLike::NotBlock) | 285 | (Some(lhs), BlockLike::NotBlock) |
322 | } | 286 | } |
323 | 287 | ||
324 | const LHS_FIRST: TokenSet = | 288 | const LHS_FIRST: TokenSet = atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOT, MINUS]); |
325 | atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOTDOT, DOTDOTEQ, MINUS]); | ||
326 | 289 | ||
327 | fn lhs( | 290 | fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { |
328 | p: &mut Parser, | ||
329 | r: Restrictions, | ||
330 | dollar_lvl: &mut usize, | ||
331 | ) -> Option<(CompletedMarker, BlockLike)> { | ||
332 | let m; | 291 | let m; |
333 | let kind = match p.current() { | 292 | let kind = match p.current() { |
334 | // test ref_expr | 293 | // test ref_expr |
@@ -338,7 +297,7 @@ fn lhs( | |||
338 | // } | 297 | // } |
339 | T![&] => { | 298 | T![&] => { |
340 | m = p.start(); | 299 | m = p.start(); |
341 | p.bump(); | 300 | p.bump_any(); |
342 | p.eat(T![mut]); | 301 | p.eat(T![mut]); |
343 | REF_EXPR | 302 | REF_EXPR |
344 | } | 303 | } |
@@ -350,20 +309,23 @@ fn lhs( | |||
350 | // } | 309 | // } |
351 | T![*] | T![!] | T![-] => { | 310 | T![*] | T![!] | T![-] => { |
352 | m = p.start(); | 311 | m = p.start(); |
353 | p.bump(); | 312 | p.bump_any(); |
354 | PREFIX_EXPR | 313 | PREFIX_EXPR |
355 | } | 314 | } |
356 | // test full_range_expr | ||
357 | // fn foo() { xs[..]; } | ||
358 | T![..] | T![..=] => { | ||
359 | m = p.start(); | ||
360 | p.bump(); | ||
361 | if p.at_ts(EXPR_FIRST) { | ||
362 | expr_bp(p, r, 2, dollar_lvl); | ||
363 | } | ||
364 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | ||
365 | } | ||
366 | _ => { | 315 | _ => { |
316 | // test full_range_expr | ||
317 | // fn foo() { xs[..]; } | ||
318 | for &op in [T![..=], T![..]].iter() { | ||
319 | if p.at(op) { | ||
320 | m = p.start(); | ||
321 | p.bump(op); | ||
322 | if p.at_ts(EXPR_FIRST) { | ||
323 | expr_bp(p, r, 2); | ||
324 | } | ||
325 | return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock)); | ||
326 | } | ||
327 | } | ||
328 | |||
367 | // test expression_after_block | 329 | // test expression_after_block |
368 | // fn foo() { | 330 | // fn foo() { |
369 | // let mut p = F{x: 5}; | 331 | // let mut p = F{x: 5}; |
@@ -374,7 +336,7 @@ fn lhs( | |||
374 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); | 336 | return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()))); |
375 | } | 337 | } |
376 | }; | 338 | }; |
377 | expr_bp(p, r, 255, dollar_lvl); | 339 | expr_bp(p, r, 255); |
378 | Some((m.complete(p, kind), BlockLike::NotBlock)) | 340 | Some((m.complete(p, kind), BlockLike::NotBlock)) |
379 | } | 341 | } |
380 | 342 | ||
@@ -399,29 +361,13 @@ fn postfix_expr( | |||
399 | // } | 361 | // } |
400 | T!['('] if allow_calls => call_expr(p, lhs), | 362 | T!['('] if allow_calls => call_expr(p, lhs), |
401 | T!['['] if allow_calls => index_expr(p, lhs), | 363 | T!['['] if allow_calls => index_expr(p, lhs), |
402 | T![.] if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::]) => { | 364 | T![.] => match postfix_dot_expr(p, lhs) { |
403 | method_call_expr(p, lhs) | 365 | Ok(it) => it, |
404 | } | 366 | Err(it) => { |
405 | T![.] if p.nth(1) == AWAIT_KW => { | 367 | lhs = it; |
406 | // test await_expr | 368 | break; |
407 | // fn foo() { | 369 | } |
408 | // x.await; | 370 | }, |
409 | // x.0.await; | ||
410 | // x.0().await?.hello(); | ||
411 | // } | ||
412 | let m = lhs.precede(p); | ||
413 | p.bump(); | ||
414 | p.bump(); | ||
415 | m.complete(p, AWAIT_EXPR) | ||
416 | } | ||
417 | T![.] => field_expr(p, lhs), | ||
418 | // test postfix_range | ||
419 | // fn foo() { let x = 1..; } | ||
420 | T![..] | T![..=] if !EXPR_FIRST.contains(p.nth(1)) => { | ||
421 | let m = lhs.precede(p); | ||
422 | p.bump(); | ||
423 | m.complete(p, RANGE_EXPR) | ||
424 | } | ||
425 | T![?] => try_expr(p, lhs), | 371 | T![?] => try_expr(p, lhs), |
426 | T![as] => cast_expr(p, lhs), | 372 | T![as] => cast_expr(p, lhs), |
427 | _ => break, | 373 | _ => break, |
@@ -429,7 +375,46 @@ fn postfix_expr( | |||
429 | allow_calls = true; | 375 | allow_calls = true; |
430 | block_like = BlockLike::NotBlock; | 376 | block_like = BlockLike::NotBlock; |
431 | } | 377 | } |
432 | (lhs, block_like) | 378 | return (lhs, block_like); |
379 | |||
380 | fn postfix_dot_expr( | ||
381 | p: &mut Parser, | ||
382 | lhs: CompletedMarker, | ||
383 | ) -> Result<CompletedMarker, CompletedMarker> { | ||
384 | assert!(p.at(T![.])); | ||
385 | if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) { | ||
386 | return Ok(method_call_expr(p, lhs)); | ||
387 | } | ||
388 | |||
389 | // test await_expr | ||
390 | // fn foo() { | ||
391 | // x.await; | ||
392 | // x.0.await; | ||
393 | // x.0().await?.hello(); | ||
394 | // } | ||
395 | if p.nth(1) == T![await] { | ||
396 | let m = lhs.precede(p); | ||
397 | p.bump(T![.]); | ||
398 | p.bump(T![await]); | ||
399 | return Ok(m.complete(p, AWAIT_EXPR)); | ||
400 | } | ||
401 | |||
402 | // test postfix_range | ||
403 | // fn foo() { let x = 1..; } | ||
404 | for &(op, la) in [(T![..=], 3), (T![..], 2)].iter() { | ||
405 | if p.at(op) { | ||
406 | return if EXPR_FIRST.contains(p.nth(la)) { | ||
407 | Err(lhs) | ||
408 | } else { | ||
409 | let m = lhs.precede(p); | ||
410 | p.bump(op); | ||
411 | Ok(m.complete(p, RANGE_EXPR)) | ||
412 | }; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | Ok(field_expr(p, lhs)) | ||
417 | } | ||
433 | } | 418 | } |
434 | 419 | ||
435 | // test call_expr | 420 | // test call_expr |
@@ -453,7 +438,7 @@ fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
453 | fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 438 | fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
454 | assert!(p.at(T!['['])); | 439 | assert!(p.at(T!['['])); |
455 | let m = lhs.precede(p); | 440 | let m = lhs.precede(p); |
456 | p.bump(); | 441 | p.bump_any(); |
457 | expr(p); | 442 | expr(p); |
458 | p.expect(T![']']); | 443 | p.expect(T![']']); |
459 | m.complete(p, INDEX_EXPR) | 444 | m.complete(p, INDEX_EXPR) |
@@ -465,9 +450,9 @@ fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
465 | // y.bar::<T>(1, 2,); | 450 | // y.bar::<T>(1, 2,); |
466 | // } | 451 | // } |
467 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 452 | fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
468 | assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth(2) == T![::])); | 453 | assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); |
469 | let m = lhs.precede(p); | 454 | let m = lhs.precede(p); |
470 | p.bump(); | 455 | p.bump_any(); |
471 | name_ref(p); | 456 | name_ref(p); |
472 | type_args::opt_type_arg_list(p, true); | 457 | type_args::opt_type_arg_list(p, true); |
473 | if p.at(T!['(']) { | 458 | if p.at(T!['(']) { |
@@ -493,12 +478,12 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
493 | fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 478 | fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
494 | assert!(p.at(T![.])); | 479 | assert!(p.at(T![.])); |
495 | let m = lhs.precede(p); | 480 | let m = lhs.precede(p); |
496 | p.bump(); | 481 | p.bump_any(); |
497 | if p.at(IDENT) || p.at(INT_NUMBER) { | 482 | if p.at(IDENT) || p.at(INT_NUMBER) { |
498 | name_ref_or_index(p) | 483 | name_ref_or_index(p) |
499 | } else if p.at(FLOAT_NUMBER) { | 484 | } else if p.at(FLOAT_NUMBER) { |
500 | // FIXME: How to recover and instead parse INT + T![.]? | 485 | // FIXME: How to recover and instead parse INT + T![.]? |
501 | p.bump(); | 486 | p.bump_any(); |
502 | } else { | 487 | } else { |
503 | p.error("expected field name or number") | 488 | p.error("expected field name or number") |
504 | } | 489 | } |
@@ -512,7 +497,7 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
512 | fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 497 | fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
513 | assert!(p.at(T![?])); | 498 | assert!(p.at(T![?])); |
514 | let m = lhs.precede(p); | 499 | let m = lhs.precede(p); |
515 | p.bump(); | 500 | p.bump_any(); |
516 | m.complete(p, TRY_EXPR) | 501 | m.complete(p, TRY_EXPR) |
517 | } | 502 | } |
518 | 503 | ||
@@ -526,7 +511,7 @@ fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
526 | fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 511 | fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
527 | assert!(p.at(T![as])); | 512 | assert!(p.at(T![as])); |
528 | let m = lhs.precede(p); | 513 | let m = lhs.precede(p); |
529 | p.bump(); | 514 | p.bump_any(); |
530 | // Use type_no_bounds(), because cast expressions are not | 515 | // Use type_no_bounds(), because cast expressions are not |
531 | // allowed to have bounds. | 516 | // allowed to have bounds. |
532 | types::type_no_bounds(p); | 517 | types::type_no_bounds(p); |
@@ -536,7 +521,7 @@ fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
536 | fn arg_list(p: &mut Parser) { | 521 | fn arg_list(p: &mut Parser) { |
537 | assert!(p.at(T!['('])); | 522 | assert!(p.at(T!['('])); |
538 | let m = p.start(); | 523 | let m = p.start(); |
539 | p.bump(); | 524 | p.bump_any(); |
540 | while !p.at(T![')']) && !p.at(EOF) { | 525 | while !p.at(T![')']) && !p.at(EOF) { |
541 | if !p.at_ts(EXPR_FIRST) { | 526 | if !p.at_ts(EXPR_FIRST) { |
542 | p.error("expected expression"); | 527 | p.error("expected expression"); |
@@ -567,7 +552,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { | |||
567 | record_field_list(p); | 552 | record_field_list(p); |
568 | (m.complete(p, RECORD_LIT), BlockLike::NotBlock) | 553 | (m.complete(p, RECORD_LIT), BlockLike::NotBlock) |
569 | } | 554 | } |
570 | T![!] => { | 555 | T![!] if !p.at(T![!=]) => { |
571 | let block_like = items::macro_call_after_excl(p); | 556 | let block_like = items::macro_call_after_excl(p); |
572 | (m.complete(p, MACRO_CALL), block_like) | 557 | (m.complete(p, MACRO_CALL), block_like) |
573 | } | 558 | } |
@@ -585,7 +570,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { | |||
585 | pub(crate) fn record_field_list(p: &mut Parser) { | 570 | pub(crate) fn record_field_list(p: &mut Parser) { |
586 | assert!(p.at(T!['{'])); | 571 | assert!(p.at(T!['{'])); |
587 | let m = p.start(); | 572 | let m = p.start(); |
588 | p.bump(); | 573 | p.bump_any(); |
589 | while !p.at(EOF) && !p.at(T!['}']) { | 574 | while !p.at(EOF) && !p.at(T!['}']) { |
590 | match p.current() { | 575 | match p.current() { |
591 | // test record_literal_field_with_attr | 576 | // test record_literal_field_with_attr |
@@ -601,8 +586,8 @@ pub(crate) fn record_field_list(p: &mut Parser) { | |||
601 | } | 586 | } |
602 | m.complete(p, RECORD_FIELD); | 587 | m.complete(p, RECORD_FIELD); |
603 | } | 588 | } |
604 | T![..] => { | 589 | T![.] if p.at(T![..]) => { |
605 | p.bump(); | 590 | p.bump(T![..]); |
606 | expr(p); | 591 | expr(p); |
607 | } | 592 | } |
608 | T!['{'] => error_block(p, "expected a field"), | 593 | T!['{'] => error_block(p, "expected a field"), |
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index ec7f2441d..6e295fbf9 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs | |||
@@ -31,7 +31,7 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> { | |||
31 | return None; | 31 | return None; |
32 | } | 32 | } |
33 | let m = p.start(); | 33 | let m = p.start(); |
34 | p.bump(); | 34 | p.bump_any(); |
35 | Some(m.complete(p, LITERAL)) | 35 | Some(m.complete(p, LITERAL)) |
36 | } | 36 | } |
37 | 37 | ||
@@ -69,6 +69,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar | |||
69 | let done = match p.current() { | 69 | let done = match p.current() { |
70 | T!['('] => tuple_expr(p), | 70 | T!['('] => tuple_expr(p), |
71 | T!['['] => array_expr(p), | 71 | T!['['] => array_expr(p), |
72 | L_DOLLAR => meta_var_expr(p), | ||
72 | T![|] => lambda_expr(p), | 73 | T![|] => lambda_expr(p), |
73 | T![move] if la == T![|] => lambda_expr(p), | 74 | T![move] if la == T![|] => lambda_expr(p), |
74 | T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => lambda_expr(p), | 75 | T![async] if la == T![|] || (la == T![move] && p.nth(2) == T![|]) => lambda_expr(p), |
@@ -100,14 +101,14 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar | |||
100 | } | 101 | } |
101 | T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => { | 102 | T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => { |
102 | let m = p.start(); | 103 | let m = p.start(); |
103 | p.bump(); | 104 | p.bump_any(); |
104 | p.eat(T![move]); | 105 | p.eat(T![move]); |
105 | block_expr(p, Some(m)) | 106 | block_expr(p, Some(m)) |
106 | } | 107 | } |
107 | T![match] => match_expr(p), | 108 | T![match] => match_expr(p), |
108 | T![unsafe] if la == T!['{'] => { | 109 | T![unsafe] if la == T!['{'] => { |
109 | let m = p.start(); | 110 | let m = p.start(); |
110 | p.bump(); | 111 | p.bump_any(); |
111 | block_expr(p, Some(m)) | 112 | block_expr(p, Some(m)) |
112 | } | 113 | } |
113 | T!['{'] => { | 114 | T!['{'] => { |
@@ -179,7 +180,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { | |||
179 | fn array_expr(p: &mut Parser) -> CompletedMarker { | 180 | fn array_expr(p: &mut Parser) -> CompletedMarker { |
180 | assert!(p.at(T!['['])); | 181 | assert!(p.at(T!['['])); |
181 | let m = p.start(); | 182 | let m = p.start(); |
182 | p.bump(); | 183 | p.bump_any(); |
183 | if p.eat(T![']']) { | 184 | if p.eat(T![']']) { |
184 | return m.complete(p, ARRAY_EXPR); | 185 | return m.complete(p, ARRAY_EXPR); |
185 | } | 186 | } |
@@ -261,11 +262,11 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker { | |||
261 | fn if_expr(p: &mut Parser) -> CompletedMarker { | 262 | fn if_expr(p: &mut Parser) -> CompletedMarker { |
262 | assert!(p.at(T![if])); | 263 | assert!(p.at(T![if])); |
263 | let m = p.start(); | 264 | let m = p.start(); |
264 | p.bump(); | 265 | p.bump_any(); |
265 | cond(p); | 266 | cond(p); |
266 | block(p); | 267 | block(p); |
267 | if p.at(T![else]) { | 268 | if p.at(T![else]) { |
268 | p.bump(); | 269 | p.bump_any(); |
269 | if p.at(T![if]) { | 270 | if p.at(T![if]) { |
270 | if_expr(p); | 271 | if_expr(p); |
271 | } else { | 272 | } else { |
@@ -284,8 +285,8 @@ fn if_expr(p: &mut Parser) -> CompletedMarker { | |||
284 | fn label(p: &mut Parser) { | 285 | fn label(p: &mut Parser) { |
285 | assert!(p.at(LIFETIME) && p.nth(1) == T![:]); | 286 | assert!(p.at(LIFETIME) && p.nth(1) == T![:]); |
286 | let m = p.start(); | 287 | let m = p.start(); |
287 | p.bump(); | 288 | p.bump_any(); |
288 | p.bump(); | 289 | p.bump_any(); |
289 | m.complete(p, LABEL); | 290 | m.complete(p, LABEL); |
290 | } | 291 | } |
291 | 292 | ||
@@ -296,7 +297,7 @@ fn label(p: &mut Parser) { | |||
296 | fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | 297 | fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { |
297 | assert!(p.at(T![loop])); | 298 | assert!(p.at(T![loop])); |
298 | let m = m.unwrap_or_else(|| p.start()); | 299 | let m = m.unwrap_or_else(|| p.start()); |
299 | p.bump(); | 300 | p.bump_any(); |
300 | block(p); | 301 | block(p); |
301 | m.complete(p, LOOP_EXPR) | 302 | m.complete(p, LOOP_EXPR) |
302 | } | 303 | } |
@@ -309,7 +310,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | |||
309 | fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | 310 | fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { |
310 | assert!(p.at(T![while])); | 311 | assert!(p.at(T![while])); |
311 | let m = m.unwrap_or_else(|| p.start()); | 312 | let m = m.unwrap_or_else(|| p.start()); |
312 | p.bump(); | 313 | p.bump_any(); |
313 | cond(p); | 314 | cond(p); |
314 | block(p); | 315 | block(p); |
315 | m.complete(p, WHILE_EXPR) | 316 | m.complete(p, WHILE_EXPR) |
@@ -322,7 +323,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | |||
322 | fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | 323 | fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { |
323 | assert!(p.at(T![for])); | 324 | assert!(p.at(T![for])); |
324 | let m = m.unwrap_or_else(|| p.start()); | 325 | let m = m.unwrap_or_else(|| p.start()); |
325 | p.bump(); | 326 | p.bump_any(); |
326 | patterns::pattern(p); | 327 | patterns::pattern(p); |
327 | p.expect(T![in]); | 328 | p.expect(T![in]); |
328 | expr_no_struct(p); | 329 | expr_no_struct(p); |
@@ -356,7 +357,7 @@ fn cond(p: &mut Parser) { | |||
356 | fn match_expr(p: &mut Parser) -> CompletedMarker { | 357 | fn match_expr(p: &mut Parser) -> CompletedMarker { |
357 | assert!(p.at(T![match])); | 358 | assert!(p.at(T![match])); |
358 | let m = p.start(); | 359 | let m = p.start(); |
359 | p.bump(); | 360 | p.bump_any(); |
360 | expr_no_struct(p); | 361 | expr_no_struct(p); |
361 | if p.at(T!['{']) { | 362 | if p.at(T!['{']) { |
362 | match_arm_list(p); | 363 | match_arm_list(p); |
@@ -452,7 +453,7 @@ fn match_arm(p: &mut Parser) -> BlockLike { | |||
452 | fn match_guard(p: &mut Parser) -> CompletedMarker { | 453 | fn match_guard(p: &mut Parser) -> CompletedMarker { |
453 | assert!(p.at(T![if])); | 454 | assert!(p.at(T![if])); |
454 | let m = p.start(); | 455 | let m = p.start(); |
455 | p.bump(); | 456 | p.bump_any(); |
456 | expr(p); | 457 | expr(p); |
457 | m.complete(p, MATCH_GUARD) | 458 | m.complete(p, MATCH_GUARD) |
458 | } | 459 | } |
@@ -478,7 +479,7 @@ pub(super) fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | |||
478 | fn return_expr(p: &mut Parser) -> CompletedMarker { | 479 | fn return_expr(p: &mut Parser) -> CompletedMarker { |
479 | assert!(p.at(T![return])); | 480 | assert!(p.at(T![return])); |
480 | let m = p.start(); | 481 | let m = p.start(); |
481 | p.bump(); | 482 | p.bump_any(); |
482 | if p.at_ts(EXPR_FIRST) { | 483 | if p.at_ts(EXPR_FIRST) { |
483 | expr(p); | 484 | expr(p); |
484 | } | 485 | } |
@@ -495,7 +496,7 @@ fn return_expr(p: &mut Parser) -> CompletedMarker { | |||
495 | fn continue_expr(p: &mut Parser) -> CompletedMarker { | 496 | fn continue_expr(p: &mut Parser) -> CompletedMarker { |
496 | assert!(p.at(T![continue])); | 497 | assert!(p.at(T![continue])); |
497 | let m = p.start(); | 498 | let m = p.start(); |
498 | p.bump(); | 499 | p.bump_any(); |
499 | p.eat(LIFETIME); | 500 | p.eat(LIFETIME); |
500 | m.complete(p, CONTINUE_EXPR) | 501 | m.complete(p, CONTINUE_EXPR) |
501 | } | 502 | } |
@@ -512,7 +513,7 @@ fn continue_expr(p: &mut Parser) -> CompletedMarker { | |||
512 | fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { | 513 | fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { |
513 | assert!(p.at(T![break])); | 514 | assert!(p.at(T![break])); |
514 | let m = p.start(); | 515 | let m = p.start(); |
515 | p.bump(); | 516 | p.bump_any(); |
516 | p.eat(LIFETIME); | 517 | p.eat(LIFETIME); |
517 | // test break_ambiguity | 518 | // test break_ambiguity |
518 | // fn foo(){ | 519 | // fn foo(){ |
@@ -534,7 +535,7 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { | |||
534 | fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | 535 | fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { |
535 | assert!(p.at(T![try])); | 536 | assert!(p.at(T![try])); |
536 | let m = m.unwrap_or_else(|| p.start()); | 537 | let m = m.unwrap_or_else(|| p.start()); |
537 | p.bump(); | 538 | p.bump_any(); |
538 | block(p); | 539 | block(p); |
539 | m.complete(p, TRY_EXPR) | 540 | m.complete(p, TRY_EXPR) |
540 | } | 541 | } |
@@ -548,9 +549,33 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | |||
548 | fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { | 549 | fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { |
549 | assert!(p.at(T![box])); | 550 | assert!(p.at(T![box])); |
550 | let m = m.unwrap_or_else(|| p.start()); | 551 | let m = m.unwrap_or_else(|| p.start()); |
551 | p.bump(); | 552 | p.bump_any(); |
552 | if p.at_ts(EXPR_FIRST) { | 553 | if p.at_ts(EXPR_FIRST) { |
553 | expr(p); | 554 | expr(p); |
554 | } | 555 | } |
555 | m.complete(p, BOX_EXPR) | 556 | m.complete(p, BOX_EXPR) |
556 | } | 557 | } |
558 | |||
559 | /// Expression from `$var` macro expansion, wrapped in dollars | ||
560 | fn meta_var_expr(p: &mut Parser) -> CompletedMarker { | ||
561 | assert!(p.at(L_DOLLAR)); | ||
562 | let m = p.start(); | ||
563 | p.bump(L_DOLLAR); | ||
564 | let (completed, _is_block) = | ||
565 | expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1); | ||
566 | |||
567 | match (completed, p.current()) { | ||
568 | (Some(it), R_DOLLAR) => { | ||
569 | p.bump(R_DOLLAR); | ||
570 | m.abandon(p); | ||
571 | it | ||
572 | } | ||
573 | _ => { | ||
574 | while !p.at(R_DOLLAR) { | ||
575 | p.bump_any() | ||
576 | } | ||
577 | p.bump(R_DOLLAR); | ||
578 | m.complete(p, ERROR) | ||
579 | } | ||
580 | } | ||
581 | } | ||
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index b4327b78f..eff9d67e4 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs | |||
@@ -64,7 +64,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF | |||
64 | } else if p.at(T!['}']) && !stop_on_r_curly { | 64 | } else if p.at(T!['}']) && !stop_on_r_curly { |
65 | let e = p.start(); | 65 | let e = p.start(); |
66 | p.error("unmatched `}`"); | 66 | p.error("unmatched `}`"); |
67 | p.bump(); | 67 | p.bump_any(); |
68 | e.complete(p, ERROR); | 68 | e.complete(p, ERROR); |
69 | } else if !p.at(EOF) && !p.at(T!['}']) { | 69 | } else if !p.at(EOF) && !p.at(T!['}']) { |
70 | p.err_and_bump("expected an item"); | 70 | p.err_and_bump("expected an item"); |
@@ -276,9 +276,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { | |||
276 | 276 | ||
277 | fn extern_crate_item(p: &mut Parser, m: Marker) { | 277 | fn extern_crate_item(p: &mut Parser, m: Marker) { |
278 | assert!(p.at(T![extern])); | 278 | assert!(p.at(T![extern])); |
279 | p.bump(); | 279 | p.bump_any(); |
280 | assert!(p.at(T![crate])); | 280 | assert!(p.at(T![crate])); |
281 | p.bump(); | 281 | p.bump_any(); |
282 | name_ref(p); | 282 | name_ref(p); |
283 | opt_alias(p); | 283 | opt_alias(p); |
284 | p.expect(T![;]); | 284 | p.expect(T![;]); |
@@ -288,7 +288,7 @@ fn extern_crate_item(p: &mut Parser, m: Marker) { | |||
288 | pub(crate) fn extern_item_list(p: &mut Parser) { | 288 | pub(crate) fn extern_item_list(p: &mut Parser) { |
289 | assert!(p.at(T!['{'])); | 289 | assert!(p.at(T!['{'])); |
290 | let m = p.start(); | 290 | let m = p.start(); |
291 | p.bump(); | 291 | p.bump_any(); |
292 | mod_contents(p, true); | 292 | mod_contents(p, true); |
293 | p.expect(T!['}']); | 293 | p.expect(T!['}']); |
294 | m.complete(p, EXTERN_ITEM_LIST); | 294 | m.complete(p, EXTERN_ITEM_LIST); |
@@ -296,7 +296,7 @@ pub(crate) fn extern_item_list(p: &mut Parser) { | |||
296 | 296 | ||
297 | fn fn_def(p: &mut Parser, flavor: ItemFlavor) { | 297 | fn fn_def(p: &mut Parser, flavor: ItemFlavor) { |
298 | assert!(p.at(T![fn])); | 298 | assert!(p.at(T![fn])); |
299 | p.bump(); | 299 | p.bump_any(); |
300 | 300 | ||
301 | name_r(p, ITEM_RECOVERY_SET); | 301 | name_r(p, ITEM_RECOVERY_SET); |
302 | // test function_type_params | 302 | // test function_type_params |
@@ -323,7 +323,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) { | |||
323 | // test fn_decl | 323 | // test fn_decl |
324 | // trait T { fn foo(); } | 324 | // trait T { fn foo(); } |
325 | if p.at(T![;]) { | 325 | if p.at(T![;]) { |
326 | p.bump(); | 326 | p.bump_any(); |
327 | } else { | 327 | } else { |
328 | expressions::block(p) | 328 | expressions::block(p) |
329 | } | 329 | } |
@@ -333,7 +333,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) { | |||
333 | // type Foo = Bar; | 333 | // type Foo = Bar; |
334 | fn type_def(p: &mut Parser, m: Marker) { | 334 | fn type_def(p: &mut Parser, m: Marker) { |
335 | assert!(p.at(T![type])); | 335 | assert!(p.at(T![type])); |
336 | p.bump(); | 336 | p.bump_any(); |
337 | 337 | ||
338 | name(p); | 338 | name(p); |
339 | 339 | ||
@@ -357,7 +357,7 @@ fn type_def(p: &mut Parser, m: Marker) { | |||
357 | 357 | ||
358 | pub(crate) fn mod_item(p: &mut Parser, m: Marker) { | 358 | pub(crate) fn mod_item(p: &mut Parser, m: Marker) { |
359 | assert!(p.at(T![mod])); | 359 | assert!(p.at(T![mod])); |
360 | p.bump(); | 360 | p.bump_any(); |
361 | 361 | ||
362 | name(p); | 362 | name(p); |
363 | if p.at(T!['{']) { | 363 | if p.at(T!['{']) { |
@@ -371,7 +371,7 @@ pub(crate) fn mod_item(p: &mut Parser, m: Marker) { | |||
371 | pub(crate) fn mod_item_list(p: &mut Parser) { | 371 | pub(crate) fn mod_item_list(p: &mut Parser) { |
372 | assert!(p.at(T!['{'])); | 372 | assert!(p.at(T!['{'])); |
373 | let m = p.start(); | 373 | let m = p.start(); |
374 | p.bump(); | 374 | p.bump_any(); |
375 | mod_contents(p, true); | 375 | mod_contents(p, true); |
376 | p.expect(T!['}']); | 376 | p.expect(T!['}']); |
377 | m.complete(p, ITEM_LIST); | 377 | m.complete(p, ITEM_LIST); |
@@ -412,7 +412,7 @@ pub(crate) fn token_tree(p: &mut Parser) { | |||
412 | _ => unreachable!(), | 412 | _ => unreachable!(), |
413 | }; | 413 | }; |
414 | let m = p.start(); | 414 | let m = p.start(); |
415 | p.bump(); | 415 | p.bump_any(); |
416 | while !p.at(EOF) && !p.at(closing_paren_kind) { | 416 | while !p.at(EOF) && !p.at(closing_paren_kind) { |
417 | match p.current() { | 417 | match p.current() { |
418 | T!['{'] | T!['('] | T!['['] => token_tree(p), | 418 | T!['{'] | T!['('] | T!['['] => token_tree(p), |
@@ -422,7 +422,7 @@ pub(crate) fn token_tree(p: &mut Parser) { | |||
422 | return; | 422 | return; |
423 | } | 423 | } |
424 | T![')'] | T![']'] => p.err_and_bump("unmatched brace"), | 424 | T![')'] | T![']'] => p.err_and_bump("unmatched brace"), |
425 | _ => p.bump_raw(), | 425 | _ => p.bump_any(), |
426 | } | 426 | } |
427 | } | 427 | } |
428 | p.expect(closing_paren_kind); | 428 | p.expect(closing_paren_kind); |
diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs index b4908ebba..e11546333 100644 --- a/crates/ra_parser/src/grammar/items/consts.rs +++ b/crates/ra_parser/src/grammar/items/consts.rs | |||
@@ -10,7 +10,7 @@ pub(super) fn const_def(p: &mut Parser, m: Marker) { | |||
10 | 10 | ||
11 | fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { | 11 | fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { |
12 | assert!(p.at(kw)); | 12 | assert!(p.at(kw)); |
13 | p.bump(); | 13 | p.bump_any(); |
14 | p.eat(T![mut]); // FIXME: validator to forbid const mut | 14 | p.eat(T![mut]); // FIXME: validator to forbid const mut |
15 | name(p); | 15 | name(p); |
16 | types::ascription(p); | 16 | types::ascription(p); |
diff --git a/crates/ra_parser/src/grammar/items/nominal.rs b/crates/ra_parser/src/grammar/items/nominal.rs index 54f02c7c9..460acd65e 100644 --- a/crates/ra_parser/src/grammar/items/nominal.rs +++ b/crates/ra_parser/src/grammar/items/nominal.rs | |||
@@ -11,7 +11,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) { | |||
11 | type_params::opt_where_clause(p); | 11 | type_params::opt_where_clause(p); |
12 | match p.current() { | 12 | match p.current() { |
13 | T![;] => { | 13 | T![;] => { |
14 | p.bump(); | 14 | p.bump_any(); |
15 | } | 15 | } |
16 | T!['{'] => record_field_def_list(p), | 16 | T!['{'] => record_field_def_list(p), |
17 | _ => { | 17 | _ => { |
@@ -21,7 +21,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) { | |||
21 | } | 21 | } |
22 | } | 22 | } |
23 | T![;] if kind == T![struct] => { | 23 | T![;] if kind == T![struct] => { |
24 | p.bump(); | 24 | p.bump_any(); |
25 | } | 25 | } |
26 | T!['{'] => record_field_def_list(p), | 26 | T!['{'] => record_field_def_list(p), |
27 | T!['('] if kind == T![struct] => { | 27 | T!['('] if kind == T![struct] => { |
@@ -44,7 +44,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) { | |||
44 | 44 | ||
45 | pub(super) fn enum_def(p: &mut Parser, m: Marker) { | 45 | pub(super) fn enum_def(p: &mut Parser, m: Marker) { |
46 | assert!(p.at(T![enum])); | 46 | assert!(p.at(T![enum])); |
47 | p.bump(); | 47 | p.bump_any(); |
48 | name_r(p, ITEM_RECOVERY_SET); | 48 | name_r(p, ITEM_RECOVERY_SET); |
49 | type_params::opt_type_param_list(p); | 49 | type_params::opt_type_param_list(p); |
50 | type_params::opt_where_clause(p); | 50 | type_params::opt_where_clause(p); |
@@ -59,7 +59,7 @@ pub(super) fn enum_def(p: &mut Parser, m: Marker) { | |||
59 | pub(crate) fn enum_variant_list(p: &mut Parser) { | 59 | pub(crate) fn enum_variant_list(p: &mut Parser) { |
60 | assert!(p.at(T!['{'])); | 60 | assert!(p.at(T!['{'])); |
61 | let m = p.start(); | 61 | let m = p.start(); |
62 | p.bump(); | 62 | p.bump_any(); |
63 | while !p.at(EOF) && !p.at(T!['}']) { | 63 | while !p.at(EOF) && !p.at(T!['}']) { |
64 | if p.at(T!['{']) { | 64 | if p.at(T!['{']) { |
65 | error_block(p, "expected enum variant"); | 65 | error_block(p, "expected enum variant"); |
@@ -73,7 +73,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) { | |||
73 | T!['{'] => record_field_def_list(p), | 73 | T!['{'] => record_field_def_list(p), |
74 | T!['('] => tuple_field_def_list(p), | 74 | T!['('] => tuple_field_def_list(p), |
75 | T![=] => { | 75 | T![=] => { |
76 | p.bump(); | 76 | p.bump_any(); |
77 | expressions::expr(p); | 77 | expressions::expr(p); |
78 | } | 78 | } |
79 | _ => (), | 79 | _ => (), |
@@ -94,7 +94,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) { | |||
94 | pub(crate) fn record_field_def_list(p: &mut Parser) { | 94 | pub(crate) fn record_field_def_list(p: &mut Parser) { |
95 | assert!(p.at(T!['{'])); | 95 | assert!(p.at(T!['{'])); |
96 | let m = p.start(); | 96 | let m = p.start(); |
97 | p.bump(); | 97 | p.bump_any(); |
98 | while !p.at(T!['}']) && !p.at(EOF) { | 98 | while !p.at(T!['}']) && !p.at(EOF) { |
99 | if p.at(T!['{']) { | 99 | if p.at(T!['{']) { |
100 | error_block(p, "expected field"); | 100 | error_block(p, "expected field"); |
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs index 5fcacfbff..b49221a4b 100644 --- a/crates/ra_parser/src/grammar/items/traits.rs +++ b/crates/ra_parser/src/grammar/items/traits.rs | |||
@@ -5,7 +5,7 @@ use super::*; | |||
5 | // trait X<U: Debug + Display>: Hash + Clone where U: Copy {} | 5 | // trait X<U: Debug + Display>: Hash + Clone where U: Copy {} |
6 | pub(super) fn trait_def(p: &mut Parser) { | 6 | pub(super) fn trait_def(p: &mut Parser) { |
7 | assert!(p.at(T![trait])); | 7 | assert!(p.at(T![trait])); |
8 | p.bump(); | 8 | p.bump_any(); |
9 | name_r(p, ITEM_RECOVERY_SET); | 9 | name_r(p, ITEM_RECOVERY_SET); |
10 | type_params::opt_type_param_list(p); | 10 | type_params::opt_type_param_list(p); |
11 | if p.at(T![:]) { | 11 | if p.at(T![:]) { |
@@ -29,7 +29,7 @@ pub(super) fn trait_def(p: &mut Parser) { | |||
29 | pub(crate) fn trait_item_list(p: &mut Parser) { | 29 | pub(crate) fn trait_item_list(p: &mut Parser) { |
30 | assert!(p.at(T!['{'])); | 30 | assert!(p.at(T!['{'])); |
31 | let m = p.start(); | 31 | let m = p.start(); |
32 | p.bump(); | 32 | p.bump_any(); |
33 | while !p.at(EOF) && !p.at(T!['}']) { | 33 | while !p.at(EOF) && !p.at(T!['}']) { |
34 | if p.at(T!['{']) { | 34 | if p.at(T!['{']) { |
35 | error_block(p, "expected an item"); | 35 | error_block(p, "expected an item"); |
@@ -45,7 +45,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) { | |||
45 | // impl Foo {} | 45 | // impl Foo {} |
46 | pub(super) fn impl_block(p: &mut Parser) { | 46 | pub(super) fn impl_block(p: &mut Parser) { |
47 | assert!(p.at(T![impl])); | 47 | assert!(p.at(T![impl])); |
48 | p.bump(); | 48 | p.bump_any(); |
49 | if choose_type_params_over_qpath(p) { | 49 | if choose_type_params_over_qpath(p) { |
50 | type_params::opt_type_param_list(p); | 50 | type_params::opt_type_param_list(p); |
51 | } | 51 | } |
@@ -78,7 +78,7 @@ pub(super) fn impl_block(p: &mut Parser) { | |||
78 | pub(crate) fn impl_item_list(p: &mut Parser) { | 78 | pub(crate) fn impl_item_list(p: &mut Parser) { |
79 | assert!(p.at(T!['{'])); | 79 | assert!(p.at(T!['{'])); |
80 | let m = p.start(); | 80 | let m = p.start(); |
81 | p.bump(); | 81 | p.bump_any(); |
82 | // test impl_inner_attributes | 82 | // test impl_inner_attributes |
83 | // enum F{} | 83 | // enum F{} |
84 | // impl F { | 84 | // impl F { |
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs index 83a65e226..f28f522b8 100644 --- a/crates/ra_parser/src/grammar/items/use_item.rs +++ b/crates/ra_parser/src/grammar/items/use_item.rs | |||
@@ -2,7 +2,7 @@ use super::*; | |||
2 | 2 | ||
3 | pub(super) fn use_item(p: &mut Parser, m: Marker) { | 3 | pub(super) fn use_item(p: &mut Parser, m: Marker) { |
4 | assert!(p.at(T![use])); | 4 | assert!(p.at(T![use])); |
5 | p.bump(); | 5 | p.bump_any(); |
6 | use_tree(p); | 6 | use_tree(p); |
7 | p.expect(T![;]); | 7 | p.expect(T![;]); |
8 | m.complete(p, USE_ITEM); | 8 | m.complete(p, USE_ITEM); |
@@ -13,9 +13,8 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) { | |||
13 | /// so handles both `some::path::{inner::path}` and `inner::path` in | 13 | /// so handles both `some::path::{inner::path}` and `inner::path` in |
14 | /// `use some::path::{inner::path};` | 14 | /// `use some::path::{inner::path};` |
15 | fn use_tree(p: &mut Parser) { | 15 | fn use_tree(p: &mut Parser) { |
16 | let la = p.nth(1); | ||
17 | let m = p.start(); | 16 | let m = p.start(); |
18 | match (p.current(), la) { | 17 | match p.current() { |
19 | // Finish the use_tree for cases of e.g. | 18 | // Finish the use_tree for cases of e.g. |
20 | // `use some::path::{self, *};` or `use *;` | 19 | // `use some::path::{self, *};` or `use *;` |
21 | // This does not handle cases such as `use some::path::*` | 20 | // This does not handle cases such as `use some::path::*` |
@@ -28,15 +27,15 @@ fn use_tree(p: &mut Parser) { | |||
28 | // use ::*; | 27 | // use ::*; |
29 | // use some::path::{*}; | 28 | // use some::path::{*}; |
30 | // use some::path::{::*}; | 29 | // use some::path::{::*}; |
31 | (T![*], _) => p.bump(), | 30 | T![*] => p.bump(T![*]), |
32 | (T![::], T![*]) => { | 31 | T![:] if p.at(T![::]) && p.nth(2) == T![*] => { |
33 | // Parse `use ::*;`, which imports all from the crate root in Rust 2015 | 32 | // Parse `use ::*;`, which imports all from the crate root in Rust 2015 |
34 | // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`) | 33 | // This is invalid inside a use_tree_list, (e.g. `use some::path::{::*}`) |
35 | // but still parses and errors later: ('crate root in paths can only be used in start position') | 34 | // but still parses and errors later: ('crate root in paths can only be used in start position') |
36 | // FIXME: Add this error (if not out of scope) | 35 | // FIXME: Add this error (if not out of scope) |
37 | // In Rust 2018, it is always invalid (see above) | 36 | // In Rust 2018, it is always invalid (see above) |
38 | p.bump(); | 37 | p.bump(T![::]); |
39 | p.bump(); | 38 | p.bump(T![*]); |
40 | } | 39 | } |
41 | // Open a use tree list | 40 | // Open a use tree list |
42 | // Handles cases such as `use {some::path};` or `{inner::path}` in | 41 | // Handles cases such as `use {some::path};` or `{inner::path}` in |
@@ -47,10 +46,11 @@ fn use_tree(p: &mut Parser) { | |||
47 | // use {path::from::root}; // Rust 2015 | 46 | // use {path::from::root}; // Rust 2015 |
48 | // use ::{some::arbritrary::path}; // Rust 2015 | 47 | // use ::{some::arbritrary::path}; // Rust 2015 |
49 | // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig | 48 | // use ::{{{crate::export}}}; // Nonsensical but perfectly legal nestnig |
50 | (T!['{'], _) | (T![::], T!['{']) => { | 49 | T!['{'] => { |
51 | if p.at(T![::]) { | 50 | use_tree_list(p); |
52 | p.bump(); | 51 | } |
53 | } | 52 | T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => { |
53 | p.bump(T![::]); | ||
54 | use_tree_list(p); | 54 | use_tree_list(p); |
55 | } | 55 | } |
56 | // Parse a 'standard' path. | 56 | // Parse a 'standard' path. |
@@ -80,11 +80,11 @@ fn use_tree(p: &mut Parser) { | |||
80 | // use Trait as _; | 80 | // use Trait as _; |
81 | opt_alias(p); | 81 | opt_alias(p); |
82 | } | 82 | } |
83 | T![::] => { | 83 | T![:] if p.at(T![::]) => { |
84 | p.bump(); | 84 | p.bump(T![::]); |
85 | match p.current() { | 85 | match p.current() { |
86 | T![*] => { | 86 | T![*] => { |
87 | p.bump(); | 87 | p.bump_any(); |
88 | } | 88 | } |
89 | // test use_tree_list_after_path | 89 | // test use_tree_list_after_path |
90 | // use crate::{Item}; | 90 | // use crate::{Item}; |
@@ -114,7 +114,7 @@ fn use_tree(p: &mut Parser) { | |||
114 | pub(crate) fn use_tree_list(p: &mut Parser) { | 114 | pub(crate) fn use_tree_list(p: &mut Parser) { |
115 | assert!(p.at(T!['{'])); | 115 | assert!(p.at(T!['{'])); |
116 | let m = p.start(); | 116 | let m = p.start(); |
117 | p.bump(); | 117 | p.bump_any(); |
118 | while !p.at(EOF) && !p.at(T!['}']) { | 118 | while !p.at(EOF) && !p.at(T!['}']) { |
119 | use_tree(p); | 119 | use_tree(p); |
120 | if !p.at(T!['}']) { | 120 | if !p.at(T!['}']) { |
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs index 0b09f1874..5893b22fd 100644 --- a/crates/ra_parser/src/grammar/params.rs +++ b/crates/ra_parser/src/grammar/params.rs | |||
@@ -39,7 +39,7 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
39 | let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) }; | 39 | let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) }; |
40 | assert!(p.at(bra)); | 40 | assert!(p.at(bra)); |
41 | let m = p.start(); | 41 | let m = p.start(); |
42 | p.bump(); | 42 | p.bump_any(); |
43 | if flavor.type_required() { | 43 | if flavor.type_required() { |
44 | // test self_param_outer_attr | 44 | // test self_param_outer_attr |
45 | // fn f(#[must_use] self) {} | 45 | // fn f(#[must_use] self) {} |
@@ -80,7 +80,7 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
80 | match flavor { | 80 | match flavor { |
81 | Flavor::OptionalType | Flavor::Normal => { | 81 | Flavor::OptionalType | Flavor::Normal => { |
82 | patterns::pattern(p); | 82 | patterns::pattern(p); |
83 | if p.at(T![:]) || flavor.type_required() { | 83 | if p.at(T![:]) && !p.at(T![::]) || flavor.type_required() { |
84 | types::ascription(p) | 84 | types::ascription(p) |
85 | } | 85 | } |
86 | } | 86 | } |
@@ -96,10 +96,11 @@ fn value_parameter(p: &mut Parser, flavor: Flavor) { | |||
96 | // trait Foo { | 96 | // trait Foo { |
97 | // fn bar(_: u64, mut x: i32); | 97 | // fn bar(_: u64, mut x: i32); |
98 | // } | 98 | // } |
99 | if (la0 == IDENT || la0 == T![_]) && la1 == T![:] | 99 | if (la0 == IDENT || la0 == T![_]) && la1 == T![:] && !p.nth_at(1, T![::]) |
100 | || la0 == T![mut] && la1 == IDENT && la2 == T![:] | 100 | || la0 == T![mut] && la1 == IDENT && la2 == T![:] |
101 | || la0 == T![&] && la1 == IDENT && la2 == T![:] | 101 | || la0 == T![&] |
102 | || la0 == T![&] && la1 == T![mut] && la2 == IDENT && la3 == T![:] | 102 | && (la1 == IDENT && la2 == T![:] && !p.nth_at(2, T![::]) |
103 | || la1 == T![mut] && la2 == IDENT && la3 == T![:] && !p.nth_at(3, T![::])) | ||
103 | { | 104 | { |
104 | patterns::pattern(p); | 105 | patterns::pattern(p); |
105 | types::ascription(p); | 106 | types::ascription(p); |
@@ -146,7 +147,7 @@ fn opt_self_param(p: &mut Parser) { | |||
146 | }; | 147 | }; |
147 | m = p.start(); | 148 | m = p.start(); |
148 | for _ in 0..n_toks { | 149 | for _ in 0..n_toks { |
149 | p.bump(); | 150 | p.bump_any(); |
150 | } | 151 | } |
151 | } | 152 | } |
152 | m.complete(p, SELF_PARAM); | 153 | m.complete(p, SELF_PARAM); |
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs index 28c35a67d..24b65128e 100644 --- a/crates/ra_parser/src/grammar/paths.rs +++ b/crates/ra_parser/src/grammar/paths.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use super::*; | 1 | use super::*; |
2 | 2 | ||
3 | pub(super) const PATH_FIRST: TokenSet = | 3 | pub(super) const PATH_FIRST: TokenSet = |
4 | token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLONCOLON, L_ANGLE]; | 4 | token_set![IDENT, SELF_KW, SUPER_KW, CRATE_KW, COLON, L_ANGLE]; |
5 | 5 | ||
6 | pub(super) fn is_path_start(p: &Parser) -> bool { | 6 | pub(super) fn is_path_start(p: &Parser) -> bool { |
7 | is_use_path_start(p) || p.at(T![<]) | 7 | is_use_path_start(p) || p.at(T![<]) |
@@ -9,7 +9,8 @@ pub(super) fn is_path_start(p: &Parser) -> bool { | |||
9 | 9 | ||
10 | pub(super) fn is_use_path_start(p: &Parser) -> bool { | 10 | pub(super) fn is_use_path_start(p: &Parser) -> bool { |
11 | match p.current() { | 11 | match p.current() { |
12 | IDENT | T![self] | T![super] | T![crate] | T![::] => true, | 12 | IDENT | T![self] | T![super] | T![crate] => true, |
13 | T![:] if p.at(T![::]) => true, | ||
13 | _ => false, | 14 | _ => false, |
14 | } | 15 | } |
15 | } | 16 | } |
@@ -38,13 +39,13 @@ fn path(p: &mut Parser, mode: Mode) { | |||
38 | path_segment(p, mode, true); | 39 | path_segment(p, mode, true); |
39 | let mut qual = path.complete(p, PATH); | 40 | let mut qual = path.complete(p, PATH); |
40 | loop { | 41 | loop { |
41 | let use_tree = match p.nth(1) { | 42 | let use_tree = match p.nth(2) { |
42 | T![*] | T!['{'] => true, | 43 | T![*] | T!['{'] => true, |
43 | _ => false, | 44 | _ => false, |
44 | }; | 45 | }; |
45 | if p.at(T![::]) && !use_tree { | 46 | if p.at(T![::]) && !use_tree { |
46 | let path = qual.precede(p); | 47 | let path = qual.precede(p); |
47 | p.bump(); | 48 | p.bump(T![::]); |
48 | path_segment(p, mode, false); | 49 | path_segment(p, mode, false); |
49 | let path = path.complete(p, PATH); | 50 | let path = path.complete(p, PATH); |
50 | qual = path; | 51 | qual = path; |
@@ -80,7 +81,7 @@ fn path_segment(p: &mut Parser, mode: Mode, first: bool) { | |||
80 | } | 81 | } |
81 | // test crate_path | 82 | // test crate_path |
82 | // use crate::foo; | 83 | // use crate::foo; |
83 | T![self] | T![super] | T![crate] => p.bump(), | 84 | T![self] | T![super] | T![crate] => p.bump_any(), |
84 | _ => { | 85 | _ => { |
85 | p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); | 86 | p.err_recover("expected identifier", items::ITEM_RECOVERY_SET); |
86 | } | 87 | } |
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs index 32cde7de6..dd1d25b07 100644 --- a/crates/ra_parser/src/grammar/patterns.rs +++ b/crates/ra_parser/src/grammar/patterns.rs | |||
@@ -34,17 +34,20 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) { | |||
34 | // 200 .. 301=> (), | 34 | // 200 .. 301=> (), |
35 | // } | 35 | // } |
36 | // } | 36 | // } |
37 | if p.at(T![...]) || p.at(T![..=]) || p.at(T![..]) { | 37 | for &range_op in [T![...], T![..=], T![..]].iter() { |
38 | let m = lhs.precede(p); | 38 | if p.at(range_op) { |
39 | p.bump(); | 39 | let m = lhs.precede(p); |
40 | atom_pat(p, recovery_set); | 40 | p.bump(range_op); |
41 | m.complete(p, RANGE_PAT); | 41 | atom_pat(p, recovery_set); |
42 | m.complete(p, RANGE_PAT); | ||
43 | return; | ||
44 | } | ||
42 | } | 45 | } |
43 | // test marco_pat | 46 | // test marco_pat |
44 | // fn main() { | 47 | // fn main() { |
45 | // let m!(x) = 0; | 48 | // let m!(x) = 0; |
46 | // } | 49 | // } |
47 | else if lhs.kind() == PATH_PAT && p.at(T![!]) { | 50 | if lhs.kind() == PATH_PAT && p.at(T![!]) { |
48 | let m = lhs.precede(p); | 51 | let m = lhs.precede(p); |
49 | items::macro_call_after_excl(p); | 52 | items::macro_call_after_excl(p); |
50 | m.complete(p, MACRO_CALL); | 53 | m.complete(p, MACRO_CALL); |
@@ -56,14 +59,16 @@ const PAT_RECOVERY_SET: TokenSet = | |||
56 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; | 59 | token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA]; |
57 | 60 | ||
58 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | 61 | fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { |
59 | // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro | ||
60 | // (T![x]). | ||
61 | let is_path_or_macro_pat = | ||
62 | |la1| la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!]; | ||
63 | |||
64 | let m = match p.nth(0) { | 62 | let m = match p.nth(0) { |
65 | T![box] => box_pat(p), | 63 | T![box] => box_pat(p), |
66 | T![ref] | T![mut] | IDENT if !is_path_or_macro_pat(p.nth(1)) => bind_pat(p, true), | 64 | T![ref] | T![mut] => bind_pat(p, true), |
65 | IDENT => match p.nth(1) { | ||
66 | // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro | ||
67 | // (T![x]). | ||
68 | T!['('] | T!['{'] | T![!] => path_pat(p), | ||
69 | T![:] if p.nth_at(1, T![::]) => path_pat(p), | ||
70 | _ => bind_pat(p, true), | ||
71 | }, | ||
67 | 72 | ||
68 | _ if paths::is_use_path_start(p) => path_pat(p), | 73 | _ if paths::is_use_path_start(p) => path_pat(p), |
69 | _ if is_literal_pat_start(p) => literal_pat(p), | 74 | _ if is_literal_pat_start(p) => literal_pat(p), |
@@ -100,7 +105,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker { | |||
100 | assert!(is_literal_pat_start(p)); | 105 | assert!(is_literal_pat_start(p)); |
101 | let m = p.start(); | 106 | let m = p.start(); |
102 | if p.at(T![-]) { | 107 | if p.at(T![-]) { |
103 | p.bump(); | 108 | p.bump_any(); |
104 | } | 109 | } |
105 | expressions::literal(p); | 110 | expressions::literal(p); |
106 | m.complete(p, LITERAL_PAT) | 111 | m.complete(p, LITERAL_PAT) |
@@ -140,7 +145,7 @@ fn path_pat(p: &mut Parser) -> CompletedMarker { | |||
140 | // } | 145 | // } |
141 | fn tuple_pat_fields(p: &mut Parser) { | 146 | fn tuple_pat_fields(p: &mut Parser) { |
142 | assert!(p.at(T!['('])); | 147 | assert!(p.at(T!['('])); |
143 | p.bump(); | 148 | p.bump_any(); |
144 | pat_list(p, T![')']); | 149 | pat_list(p, T![')']); |
145 | p.expect(T![')']); | 150 | p.expect(T![')']); |
146 | } | 151 | } |
@@ -155,10 +160,10 @@ fn tuple_pat_fields(p: &mut Parser) { | |||
155 | fn record_field_pat_list(p: &mut Parser) { | 160 | fn record_field_pat_list(p: &mut Parser) { |
156 | assert!(p.at(T!['{'])); | 161 | assert!(p.at(T!['{'])); |
157 | let m = p.start(); | 162 | let m = p.start(); |
158 | p.bump(); | 163 | p.bump_any(); |
159 | while !p.at(EOF) && !p.at(T!['}']) { | 164 | while !p.at(EOF) && !p.at(T!['}']) { |
160 | match p.current() { | 165 | match p.current() { |
161 | T![..] => p.bump(), | 166 | T![.] if p.at(T![..]) => p.bump(T![..]), |
162 | IDENT if p.nth(1) == T![:] => record_field_pat(p), | 167 | IDENT if p.nth(1) == T![:] => record_field_pat(p), |
163 | T!['{'] => error_block(p, "expected ident"), | 168 | T!['{'] => error_block(p, "expected ident"), |
164 | T![box] => { | 169 | T![box] => { |
@@ -182,7 +187,7 @@ fn record_field_pat(p: &mut Parser) { | |||
182 | 187 | ||
183 | let m = p.start(); | 188 | let m = p.start(); |
184 | name(p); | 189 | name(p); |
185 | p.bump(); | 190 | p.bump_any(); |
186 | pattern(p); | 191 | pattern(p); |
187 | m.complete(p, RECORD_FIELD_PAT); | 192 | m.complete(p, RECORD_FIELD_PAT); |
188 | } | 193 | } |
@@ -192,7 +197,7 @@ fn record_field_pat(p: &mut Parser) { | |||
192 | fn placeholder_pat(p: &mut Parser) -> CompletedMarker { | 197 | fn placeholder_pat(p: &mut Parser) -> CompletedMarker { |
193 | assert!(p.at(T![_])); | 198 | assert!(p.at(T![_])); |
194 | let m = p.start(); | 199 | let m = p.start(); |
195 | p.bump(); | 200 | p.bump_any(); |
196 | m.complete(p, PLACEHOLDER_PAT) | 201 | m.complete(p, PLACEHOLDER_PAT) |
197 | } | 202 | } |
198 | 203 | ||
@@ -204,7 +209,7 @@ fn placeholder_pat(p: &mut Parser) -> CompletedMarker { | |||
204 | fn ref_pat(p: &mut Parser) -> CompletedMarker { | 209 | fn ref_pat(p: &mut Parser) -> CompletedMarker { |
205 | assert!(p.at(T![&])); | 210 | assert!(p.at(T![&])); |
206 | let m = p.start(); | 211 | let m = p.start(); |
207 | p.bump(); | 212 | p.bump_any(); |
208 | p.eat(T![mut]); | 213 | p.eat(T![mut]); |
209 | pattern(p); | 214 | pattern(p); |
210 | m.complete(p, REF_PAT) | 215 | m.complete(p, REF_PAT) |
@@ -228,7 +233,7 @@ fn tuple_pat(p: &mut Parser) -> CompletedMarker { | |||
228 | fn slice_pat(p: &mut Parser) -> CompletedMarker { | 233 | fn slice_pat(p: &mut Parser) -> CompletedMarker { |
229 | assert!(p.at(T!['['])); | 234 | assert!(p.at(T!['['])); |
230 | let m = p.start(); | 235 | let m = p.start(); |
231 | p.bump(); | 236 | p.bump_any(); |
232 | pat_list(p, T![']']); | 237 | pat_list(p, T![']']); |
233 | p.expect(T![']']); | 238 | p.expect(T![']']); |
234 | m.complete(p, SLICE_PAT) | 239 | m.complete(p, SLICE_PAT) |
@@ -237,7 +242,7 @@ fn slice_pat(p: &mut Parser) -> CompletedMarker { | |||
237 | fn pat_list(p: &mut Parser, ket: SyntaxKind) { | 242 | fn pat_list(p: &mut Parser, ket: SyntaxKind) { |
238 | while !p.at(EOF) && !p.at(ket) { | 243 | while !p.at(EOF) && !p.at(ket) { |
239 | match p.current() { | 244 | match p.current() { |
240 | T![..] => p.bump(), | 245 | T![.] if p.at(T![..]) => p.bump(T![..]), |
241 | _ => { | 246 | _ => { |
242 | if !p.at_ts(PATTERN_FIRST) { | 247 | if !p.at_ts(PATTERN_FIRST) { |
243 | p.error("expected a pattern"); | 248 | p.error("expected a pattern"); |
@@ -281,7 +286,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker { | |||
281 | fn box_pat(p: &mut Parser) -> CompletedMarker { | 286 | fn box_pat(p: &mut Parser) -> CompletedMarker { |
282 | assert!(p.at(T![box])); | 287 | assert!(p.at(T![box])); |
283 | let m = p.start(); | 288 | let m = p.start(); |
284 | p.bump(); | 289 | p.bump_any(); |
285 | pattern(p); | 290 | pattern(p); |
286 | m.complete(p, BOX_PAT) | 291 | m.complete(p, BOX_PAT) |
287 | } | 292 | } |
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs index 3db08b280..edc7d4ff2 100644 --- a/crates/ra_parser/src/grammar/type_args.rs +++ b/crates/ra_parser/src/grammar/type_args.rs | |||
@@ -2,19 +2,16 @@ use super::*; | |||
2 | 2 | ||
3 | pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) { | 3 | pub(super) fn opt_type_arg_list(p: &mut Parser, colon_colon_required: bool) { |
4 | let m; | 4 | let m; |
5 | match (colon_colon_required, p.nth(0), p.nth(1)) { | 5 | if p.at(T![::]) && p.nth(2) == T![<] { |
6 | (_, T![::], T![<]) => { | 6 | m = p.start(); |
7 | m = p.start(); | 7 | p.bump(T![::]); |
8 | p.bump(); | 8 | p.bump(T![<]); |
9 | p.bump(); | 9 | } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] { |
10 | } | 10 | m = p.start(); |
11 | (false, T![<], T![=]) => return, | 11 | p.bump(T![<]); |
12 | (false, T![<], _) => { | 12 | } else { |
13 | m = p.start(); | 13 | return; |
14 | p.bump(); | 14 | } |
15 | } | ||
16 | _ => return, | ||
17 | }; | ||
18 | 15 | ||
19 | while !p.at(EOF) && !p.at(T![>]) { | 16 | while !p.at(EOF) && !p.at(T![>]) { |
20 | type_arg(p); | 17 | type_arg(p); |
@@ -32,19 +29,19 @@ fn type_arg(p: &mut Parser) { | |||
32 | let m = p.start(); | 29 | let m = p.start(); |
33 | match p.current() { | 30 | match p.current() { |
34 | LIFETIME => { | 31 | LIFETIME => { |
35 | p.bump(); | 32 | p.bump_any(); |
36 | m.complete(p, LIFETIME_ARG); | 33 | m.complete(p, LIFETIME_ARG); |
37 | } | 34 | } |
38 | // test associated_type_bounds | 35 | // test associated_type_bounds |
39 | // fn print_all<T: Iterator<Item: Display>>(printables: T) {} | 36 | // fn print_all<T: Iterator<Item: Display>>(printables: T) {} |
40 | IDENT if p.nth(1) == T![:] => { | 37 | IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => { |
41 | name_ref(p); | 38 | name_ref(p); |
42 | type_params::bounds(p); | 39 | type_params::bounds(p); |
43 | m.complete(p, ASSOC_TYPE_ARG); | 40 | m.complete(p, ASSOC_TYPE_ARG); |
44 | } | 41 | } |
45 | IDENT if p.nth(1) == T![=] => { | 42 | IDENT if p.nth(1) == T![=] => { |
46 | name_ref(p); | 43 | name_ref(p); |
47 | p.bump(); | 44 | p.bump_any(); |
48 | types::type_(p); | 45 | types::type_(p); |
49 | m.complete(p, ASSOC_TYPE_ARG); | 46 | m.complete(p, ASSOC_TYPE_ARG); |
50 | } | 47 | } |
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs index cf54344c6..31d709d81 100644 --- a/crates/ra_parser/src/grammar/type_params.rs +++ b/crates/ra_parser/src/grammar/type_params.rs | |||
@@ -10,7 +10,7 @@ pub(super) fn opt_type_param_list(p: &mut Parser) { | |||
10 | fn type_param_list(p: &mut Parser) { | 10 | fn type_param_list(p: &mut Parser) { |
11 | assert!(p.at(T![<])); | 11 | assert!(p.at(T![<])); |
12 | let m = p.start(); | 12 | let m = p.start(); |
13 | p.bump(); | 13 | p.bump_any(); |
14 | 14 | ||
15 | while !p.at(EOF) && !p.at(T![>]) { | 15 | while !p.at(EOF) && !p.at(T![>]) { |
16 | let m = p.start(); | 16 | let m = p.start(); |
@@ -38,7 +38,7 @@ fn type_param_list(p: &mut Parser) { | |||
38 | 38 | ||
39 | fn lifetime_param(p: &mut Parser, m: Marker) { | 39 | fn lifetime_param(p: &mut Parser, m: Marker) { |
40 | assert!(p.at(LIFETIME)); | 40 | assert!(p.at(LIFETIME)); |
41 | p.bump(); | 41 | p.bump_any(); |
42 | if p.at(T![:]) { | 42 | if p.at(T![:]) { |
43 | lifetime_bounds(p); | 43 | lifetime_bounds(p); |
44 | } | 44 | } |
@@ -54,7 +54,7 @@ fn type_param(p: &mut Parser, m: Marker) { | |||
54 | // test type_param_default | 54 | // test type_param_default |
55 | // struct S<T = i32>; | 55 | // struct S<T = i32>; |
56 | if p.at(T![=]) { | 56 | if p.at(T![=]) { |
57 | p.bump(); | 57 | p.bump_any(); |
58 | types::type_(p) | 58 | types::type_(p) |
59 | } | 59 | } |
60 | m.complete(p, TYPE_PARAM); | 60 | m.complete(p, TYPE_PARAM); |
@@ -64,15 +64,15 @@ fn type_param(p: &mut Parser, m: Marker) { | |||
64 | // struct S<T: 'a + ?Sized + (Copy)>; | 64 | // struct S<T: 'a + ?Sized + (Copy)>; |
65 | pub(super) fn bounds(p: &mut Parser) { | 65 | pub(super) fn bounds(p: &mut Parser) { |
66 | assert!(p.at(T![:])); | 66 | assert!(p.at(T![:])); |
67 | p.bump(); | 67 | p.bump_any(); |
68 | bounds_without_colon(p); | 68 | bounds_without_colon(p); |
69 | } | 69 | } |
70 | 70 | ||
71 | fn lifetime_bounds(p: &mut Parser) { | 71 | fn lifetime_bounds(p: &mut Parser) { |
72 | assert!(p.at(T![:])); | 72 | assert!(p.at(T![:])); |
73 | p.bump(); | 73 | p.bump_any(); |
74 | while p.at(LIFETIME) { | 74 | while p.at(LIFETIME) { |
75 | p.bump(); | 75 | p.bump_any(); |
76 | if !p.eat(T![+]) { | 76 | if !p.eat(T![+]) { |
77 | break; | 77 | break; |
78 | } | 78 | } |
@@ -99,7 +99,7 @@ fn type_bound(p: &mut Parser) -> bool { | |||
99 | let has_paren = p.eat(T!['(']); | 99 | let has_paren = p.eat(T!['(']); |
100 | p.eat(T![?]); | 100 | p.eat(T![?]); |
101 | match p.current() { | 101 | match p.current() { |
102 | LIFETIME => p.bump(), | 102 | LIFETIME => p.bump_any(), |
103 | T![for] => types::for_type(p), | 103 | T![for] => types::for_type(p), |
104 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), | 104 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), |
105 | _ => { | 105 | _ => { |
@@ -128,7 +128,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) { | |||
128 | return; | 128 | return; |
129 | } | 129 | } |
130 | let m = p.start(); | 130 | let m = p.start(); |
131 | p.bump(); | 131 | p.bump_any(); |
132 | 132 | ||
133 | while is_where_predicate(p) { | 133 | while is_where_predicate(p) { |
134 | where_predicate(p); | 134 | where_predicate(p); |
@@ -166,7 +166,7 @@ fn where_predicate(p: &mut Parser) { | |||
166 | let m = p.start(); | 166 | let m = p.start(); |
167 | match p.current() { | 167 | match p.current() { |
168 | LIFETIME => { | 168 | LIFETIME => { |
169 | p.bump(); | 169 | p.bump_any(); |
170 | if p.at(T![:]) { | 170 | if p.at(T![:]) { |
171 | bounds(p); | 171 | bounds(p); |
172 | } else { | 172 | } else { |
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs index 9e321b2a6..0eb28ef09 100644 --- a/crates/ra_parser/src/grammar/types.rs +++ b/crates/ra_parser/src/grammar/types.rs | |||
@@ -44,7 +44,7 @@ pub(super) fn ascription(p: &mut Parser) { | |||
44 | fn paren_or_tuple_type(p: &mut Parser) { | 44 | fn paren_or_tuple_type(p: &mut Parser) { |
45 | assert!(p.at(T!['('])); | 45 | assert!(p.at(T!['('])); |
46 | let m = p.start(); | 46 | let m = p.start(); |
47 | p.bump(); | 47 | p.bump_any(); |
48 | let mut n_types: u32 = 0; | 48 | let mut n_types: u32 = 0; |
49 | let mut trailing_comma: bool = false; | 49 | let mut trailing_comma: bool = false; |
50 | while !p.at(EOF) && !p.at(T![')']) { | 50 | while !p.at(EOF) && !p.at(T![')']) { |
@@ -79,20 +79,20 @@ fn paren_or_tuple_type(p: &mut Parser) { | |||
79 | fn never_type(p: &mut Parser) { | 79 | fn never_type(p: &mut Parser) { |
80 | assert!(p.at(T![!])); | 80 | assert!(p.at(T![!])); |
81 | let m = p.start(); | 81 | let m = p.start(); |
82 | p.bump(); | 82 | p.bump_any(); |
83 | m.complete(p, NEVER_TYPE); | 83 | m.complete(p, NEVER_TYPE); |
84 | } | 84 | } |
85 | 85 | ||
86 | fn pointer_type(p: &mut Parser) { | 86 | fn pointer_type(p: &mut Parser) { |
87 | assert!(p.at(T![*])); | 87 | assert!(p.at(T![*])); |
88 | let m = p.start(); | 88 | let m = p.start(); |
89 | p.bump(); | 89 | p.bump_any(); |
90 | 90 | ||
91 | match p.current() { | 91 | match p.current() { |
92 | // test pointer_type_mut | 92 | // test pointer_type_mut |
93 | // type M = *mut (); | 93 | // type M = *mut (); |
94 | // type C = *mut (); | 94 | // type C = *mut (); |
95 | T![mut] | T![const] => p.bump(), | 95 | T![mut] | T![const] => p.bump_any(), |
96 | _ => { | 96 | _ => { |
97 | // test_err pointer_type_no_mutability | 97 | // test_err pointer_type_no_mutability |
98 | // type T = *(); | 98 | // type T = *(); |
@@ -110,21 +110,21 @@ fn pointer_type(p: &mut Parser) { | |||
110 | fn array_or_slice_type(p: &mut Parser) { | 110 | fn array_or_slice_type(p: &mut Parser) { |
111 | assert!(p.at(T!['['])); | 111 | assert!(p.at(T!['['])); |
112 | let m = p.start(); | 112 | let m = p.start(); |
113 | p.bump(); | 113 | p.bump_any(); |
114 | 114 | ||
115 | type_(p); | 115 | type_(p); |
116 | let kind = match p.current() { | 116 | let kind = match p.current() { |
117 | // test slice_type | 117 | // test slice_type |
118 | // type T = [()]; | 118 | // type T = [()]; |
119 | T![']'] => { | 119 | T![']'] => { |
120 | p.bump(); | 120 | p.bump_any(); |
121 | SLICE_TYPE | 121 | SLICE_TYPE |
122 | } | 122 | } |
123 | 123 | ||
124 | // test array_type | 124 | // test array_type |
125 | // type T = [(); 92]; | 125 | // type T = [(); 92]; |
126 | T![;] => { | 126 | T![;] => { |
127 | p.bump(); | 127 | p.bump_any(); |
128 | expressions::expr(p); | 128 | expressions::expr(p); |
129 | p.expect(T![']']); | 129 | p.expect(T![']']); |
130 | ARRAY_TYPE | 130 | ARRAY_TYPE |
@@ -146,7 +146,7 @@ fn array_or_slice_type(p: &mut Parser) { | |||
146 | fn reference_type(p: &mut Parser) { | 146 | fn reference_type(p: &mut Parser) { |
147 | assert!(p.at(T![&])); | 147 | assert!(p.at(T![&])); |
148 | let m = p.start(); | 148 | let m = p.start(); |
149 | p.bump(); | 149 | p.bump_any(); |
150 | p.eat(LIFETIME); | 150 | p.eat(LIFETIME); |
151 | p.eat(T![mut]); | 151 | p.eat(T![mut]); |
152 | type_no_bounds(p); | 152 | type_no_bounds(p); |
@@ -158,7 +158,7 @@ fn reference_type(p: &mut Parser) { | |||
158 | fn placeholder_type(p: &mut Parser) { | 158 | fn placeholder_type(p: &mut Parser) { |
159 | assert!(p.at(T![_])); | 159 | assert!(p.at(T![_])); |
160 | let m = p.start(); | 160 | let m = p.start(); |
161 | p.bump(); | 161 | p.bump_any(); |
162 | m.complete(p, PLACEHOLDER_TYPE); | 162 | m.complete(p, PLACEHOLDER_TYPE); |
163 | } | 163 | } |
164 | 164 | ||
@@ -193,7 +193,7 @@ fn fn_pointer_type(p: &mut Parser) { | |||
193 | 193 | ||
194 | pub(super) fn for_binder(p: &mut Parser) { | 194 | pub(super) fn for_binder(p: &mut Parser) { |
195 | assert!(p.at(T![for])); | 195 | assert!(p.at(T![for])); |
196 | p.bump(); | 196 | p.bump_any(); |
197 | if p.at(T![<]) { | 197 | if p.at(T![<]) { |
198 | type_params::opt_type_param_list(p); | 198 | type_params::opt_type_param_list(p); |
199 | } else { | 199 | } else { |
@@ -224,7 +224,7 @@ pub(super) fn for_type(p: &mut Parser) { | |||
224 | fn impl_trait_type(p: &mut Parser) { | 224 | fn impl_trait_type(p: &mut Parser) { |
225 | assert!(p.at(T![impl])); | 225 | assert!(p.at(T![impl])); |
226 | let m = p.start(); | 226 | let m = p.start(); |
227 | p.bump(); | 227 | p.bump_any(); |
228 | type_params::bounds_without_colon(p); | 228 | type_params::bounds_without_colon(p); |
229 | m.complete(p, IMPL_TRAIT_TYPE); | 229 | m.complete(p, IMPL_TRAIT_TYPE); |
230 | } | 230 | } |
@@ -234,7 +234,7 @@ fn impl_trait_type(p: &mut Parser) { | |||
234 | fn dyn_trait_type(p: &mut Parser) { | 234 | fn dyn_trait_type(p: &mut Parser) { |
235 | assert!(p.at(T![dyn ])); | 235 | assert!(p.at(T![dyn ])); |
236 | let m = p.start(); | 236 | let m = p.start(); |
237 | p.bump(); | 237 | p.bump_any(); |
238 | type_params::bounds_without_colon(p); | 238 | type_params::bounds_without_colon(p); |
239 | m.complete(p, DYN_TRAIT_TYPE); | 239 | m.complete(p, DYN_TRAIT_TYPE); |
240 | } | 240 | } |
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index 393586561..a2ac363fb 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs | |||
@@ -5,8 +5,8 @@ use drop_bomb::DropBomb; | |||
5 | use crate::{ | 5 | use crate::{ |
6 | event::Event, | 6 | event::Event, |
7 | ParseError, | 7 | ParseError, |
8 | SyntaxKind::{self, EOF, ERROR, TOMBSTONE}, | 8 | SyntaxKind::{self, EOF, ERROR, L_DOLLAR, R_DOLLAR, TOMBSTONE}, |
9 | Token, TokenSet, TokenSource, T, | 9 | TokenSet, TokenSource, T, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// `Parser` struct provides the low-level API for | 12 | /// `Parser` struct provides the low-level API for |
@@ -40,38 +40,6 @@ impl<'t> Parser<'t> { | |||
40 | self.nth(0) | 40 | self.nth(0) |
41 | } | 41 | } |
42 | 42 | ||
43 | /// Returns the kinds of the current two tokens, if they are not separated | ||
44 | /// by trivia. | ||
45 | /// | ||
46 | /// Useful for parsing things like `>>`. | ||
47 | pub(crate) fn current2(&self) -> Option<(SyntaxKind, SyntaxKind)> { | ||
48 | let c1 = self.nth(0); | ||
49 | let c2 = self.nth(1); | ||
50 | |||
51 | if self.token_source.current().is_jointed_to_next { | ||
52 | Some((c1, c2)) | ||
53 | } else { | ||
54 | None | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /// Returns the kinds of the current three tokens, if they are not separated | ||
59 | /// by trivia. | ||
60 | /// | ||
61 | /// Useful for parsing things like `=>>`. | ||
62 | pub(crate) fn current3(&self) -> Option<(SyntaxKind, SyntaxKind, SyntaxKind)> { | ||
63 | let c1 = self.nth(0); | ||
64 | let c2 = self.nth(1); | ||
65 | let c3 = self.nth(2); | ||
66 | if self.token_source.current().is_jointed_to_next | ||
67 | && self.token_source.lookahead_nth(1).is_jointed_to_next | ||
68 | { | ||
69 | Some((c1, c2, c3)) | ||
70 | } else { | ||
71 | None | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /// Lookahead operation: returns the kind of the next nth | 43 | /// Lookahead operation: returns the kind of the next nth |
76 | /// token. | 44 | /// token. |
77 | pub(crate) fn nth(&self, n: usize) -> SyntaxKind { | 45 | pub(crate) fn nth(&self, n: usize) -> SyntaxKind { |
@@ -81,33 +49,93 @@ impl<'t> Parser<'t> { | |||
81 | assert!(steps <= 10_000_000, "the parser seems stuck"); | 49 | assert!(steps <= 10_000_000, "the parser seems stuck"); |
82 | self.steps.set(steps + 1); | 50 | self.steps.set(steps + 1); |
83 | 51 | ||
84 | // It is beecause the Dollar will appear between nth | 52 | self.token_source.lookahead_nth(n).kind |
85 | // Following code skips through it | ||
86 | let mut non_dollars_count = 0; | ||
87 | let mut i = 0; | ||
88 | |||
89 | loop { | ||
90 | let token = self.token_source.lookahead_nth(i); | ||
91 | let mut kind = token.kind; | ||
92 | if let Some((composited, step)) = self.is_composite(token, i) { | ||
93 | kind = composited; | ||
94 | i += step; | ||
95 | } else { | ||
96 | i += 1; | ||
97 | } | ||
98 | |||
99 | match kind { | ||
100 | EOF => return EOF, | ||
101 | SyntaxKind::L_DOLLAR | SyntaxKind::R_DOLLAR => {} | ||
102 | _ if non_dollars_count == n => return kind, | ||
103 | _ => non_dollars_count += 1, | ||
104 | } | ||
105 | } | ||
106 | } | 53 | } |
107 | 54 | ||
108 | /// Checks if the current token is `kind`. | 55 | /// Checks if the current token is `kind`. |
109 | pub(crate) fn at(&self, kind: SyntaxKind) -> bool { | 56 | pub(crate) fn at(&self, kind: SyntaxKind) -> bool { |
110 | self.current() == kind | 57 | self.nth_at(0, kind) |
58 | } | ||
59 | |||
60 | pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool { | ||
61 | match kind { | ||
62 | T![-=] => self.at_composite2(n, T![-], T![=]), | ||
63 | T![->] => self.at_composite2(n, T![-], T![>]), | ||
64 | T![::] => self.at_composite2(n, T![:], T![:]), | ||
65 | T![!=] => self.at_composite2(n, T![!], T![=]), | ||
66 | T![..] => self.at_composite2(n, T![.], T![.]), | ||
67 | T![*=] => self.at_composite2(n, T![*], T![=]), | ||
68 | T![/=] => self.at_composite2(n, T![/], T![=]), | ||
69 | T![&&] => self.at_composite2(n, T![&], T![&]), | ||
70 | T![&=] => self.at_composite2(n, T![&], T![=]), | ||
71 | T![%=] => self.at_composite2(n, T![%], T![=]), | ||
72 | T![^=] => self.at_composite2(n, T![^], T![=]), | ||
73 | T![+=] => self.at_composite2(n, T![+], T![=]), | ||
74 | T![<<] => self.at_composite2(n, T![<], T![<]), | ||
75 | T![<=] => self.at_composite2(n, T![<], T![=]), | ||
76 | T![==] => self.at_composite2(n, T![=], T![=]), | ||
77 | T![=>] => self.at_composite2(n, T![=], T![>]), | ||
78 | T![>=] => self.at_composite2(n, T![>], T![=]), | ||
79 | T![>>] => self.at_composite2(n, T![>], T![>]), | ||
80 | T![|=] => self.at_composite2(n, T![|], T![=]), | ||
81 | T![||] => self.at_composite2(n, T![|], T![|]), | ||
82 | |||
83 | T![...] => self.at_composite3(n, T![.], T![.], T![.]), | ||
84 | T![..=] => self.at_composite3(n, T![.], T![.], T![=]), | ||
85 | T![<<=] => self.at_composite3(n, T![<], T![<], T![=]), | ||
86 | T![>>=] => self.at_composite3(n, T![>], T![>], T![=]), | ||
87 | |||
88 | _ => self.token_source.lookahead_nth(n).kind == kind, | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /// Consume the next token if `kind` matches. | ||
93 | pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool { | ||
94 | if !self.at(kind) { | ||
95 | return false; | ||
96 | } | ||
97 | let n_raw_tokens = match kind { | ||
98 | T![-=] | ||
99 | | T![->] | ||
100 | | T![::] | ||
101 | | T![!=] | ||
102 | | T![..] | ||
103 | | T![*=] | ||
104 | | T![/=] | ||
105 | | T![&&] | ||
106 | | T![&=] | ||
107 | | T![%=] | ||
108 | | T![^=] | ||
109 | | T![+=] | ||
110 | | T![<<] | ||
111 | | T![<=] | ||
112 | | T![==] | ||
113 | | T![=>] | ||
114 | | T![>=] | ||
115 | | T![>>] | ||
116 | | T![|=] | ||
117 | | T![||] => 2, | ||
118 | |||
119 | T![...] | T![..=] | T![<<=] | T![>>=] => 3, | ||
120 | _ => 1, | ||
121 | }; | ||
122 | self.do_bump(kind, n_raw_tokens); | ||
123 | true | ||
124 | } | ||
125 | |||
126 | fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool { | ||
127 | let t1 = self.token_source.lookahead_nth(n + 0); | ||
128 | let t2 = self.token_source.lookahead_nth(n + 1); | ||
129 | t1.kind == k1 && t1.is_jointed_to_next && t2.kind == k2 | ||
130 | } | ||
131 | |||
132 | fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool { | ||
133 | let t1 = self.token_source.lookahead_nth(n + 0); | ||
134 | let t2 = self.token_source.lookahead_nth(n + 1); | ||
135 | let t3 = self.token_source.lookahead_nth(n + 2); | ||
136 | (t1.kind == k1 && t1.is_jointed_to_next) | ||
137 | && (t2.kind == k2 && t2.is_jointed_to_next) | ||
138 | && t3.kind == k3 | ||
111 | } | 139 | } |
112 | 140 | ||
113 | /// Checks if the current token is in `kinds`. | 141 | /// Checks if the current token is in `kinds`. |
@@ -129,45 +157,18 @@ impl<'t> Parser<'t> { | |||
129 | Marker::new(pos) | 157 | Marker::new(pos) |
130 | } | 158 | } |
131 | 159 | ||
132 | /// Advances the parser by one token unconditionally | 160 | /// Consume the next token if `kind` matches. |
133 | /// Mainly use in `token_tree` parsing | 161 | pub(crate) fn bump(&mut self, kind: SyntaxKind) { |
134 | pub(crate) fn bump_raw(&mut self) { | 162 | assert!(self.eat(kind)); |
135 | let mut kind = self.token_source.current().kind; | ||
136 | |||
137 | // Skip dollars, do_bump will eat these later | ||
138 | let mut i = 0; | ||
139 | while kind == SyntaxKind::L_DOLLAR || kind == SyntaxKind::R_DOLLAR { | ||
140 | kind = self.token_source.lookahead_nth(i).kind; | ||
141 | i += 1; | ||
142 | } | ||
143 | |||
144 | if kind == EOF { | ||
145 | return; | ||
146 | } | ||
147 | self.do_bump(kind, 1); | ||
148 | } | 163 | } |
149 | 164 | ||
150 | /// Advances the parser by one token with composite puncts handled | 165 | /// Advances the parser by one token with composite puncts handled |
151 | pub(crate) fn bump(&mut self) { | 166 | pub(crate) fn bump_any(&mut self) { |
152 | let kind = self.nth(0); | 167 | let kind = self.nth(0); |
153 | if kind == EOF { | 168 | if kind == EOF { |
154 | return; | 169 | return; |
155 | } | 170 | } |
156 | 171 | self.do_bump(kind, 1) | |
157 | use SyntaxKind::*; | ||
158 | |||
159 | // Handle parser composites | ||
160 | match kind { | ||
161 | T![...] | T![..=] => { | ||
162 | self.bump_compound(kind, 3); | ||
163 | } | ||
164 | T![..] | T![::] | T![==] | T![=>] | T![!=] | T![->] => { | ||
165 | self.bump_compound(kind, 2); | ||
166 | } | ||
167 | _ => { | ||
168 | self.do_bump(kind, 1); | ||
169 | } | ||
170 | } | ||
171 | } | 172 | } |
172 | 173 | ||
173 | /// Advances the parser by one token, remapping its kind. | 174 | /// Advances the parser by one token, remapping its kind. |
@@ -184,13 +185,6 @@ impl<'t> Parser<'t> { | |||
184 | self.do_bump(kind, 1); | 185 | self.do_bump(kind, 1); |
185 | } | 186 | } |
186 | 187 | ||
187 | /// Advances the parser by `n` tokens, remapping its kind. | ||
188 | /// This is useful to create compound tokens from parts. For | ||
189 | /// example, an `<<` token is two consecutive remapped `<` tokens | ||
190 | pub(crate) fn bump_compound(&mut self, kind: SyntaxKind, n: u8) { | ||
191 | self.do_bump(kind, n); | ||
192 | } | ||
193 | |||
194 | /// Emit error with the `message` | 188 | /// Emit error with the `message` |
195 | /// FIXME: this should be much more fancy and support | 189 | /// FIXME: this should be much more fancy and support |
196 | /// structured errors with spans and notes, like rustc | 190 | /// structured errors with spans and notes, like rustc |
@@ -200,15 +194,6 @@ impl<'t> Parser<'t> { | |||
200 | self.push_event(Event::Error { msg }) | 194 | self.push_event(Event::Error { msg }) |
201 | } | 195 | } |
202 | 196 | ||
203 | /// Consume the next token if `kind` matches. | ||
204 | pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool { | ||
205 | if !self.at(kind) { | ||
206 | return false; | ||
207 | } | ||
208 | self.bump(); | ||
209 | true | ||
210 | } | ||
211 | |||
212 | /// Consume the next token if it is `kind` or emit an error | 197 | /// Consume the next token if it is `kind` or emit an error |
213 | /// otherwise. | 198 | /// otherwise. |
214 | pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { | 199 | pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { |
@@ -226,19 +211,26 @@ impl<'t> Parser<'t> { | |||
226 | 211 | ||
227 | /// Create an error node and consume the next token. | 212 | /// Create an error node and consume the next token. |
228 | pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { | 213 | pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { |
229 | if self.at(T!['{']) || self.at(T!['}']) || self.at_ts(recovery) { | 214 | match self.current() { |
230 | self.error(message); | 215 | T!['{'] | T!['}'] | L_DOLLAR | R_DOLLAR => { |
231 | } else { | 216 | self.error(message); |
232 | let m = self.start(); | 217 | return; |
218 | } | ||
219 | _ => (), | ||
220 | } | ||
221 | |||
222 | if self.at_ts(recovery) { | ||
233 | self.error(message); | 223 | self.error(message); |
234 | self.bump(); | 224 | return; |
235 | m.complete(self, ERROR); | 225 | } |
236 | }; | 226 | |
227 | let m = self.start(); | ||
228 | self.error(message); | ||
229 | self.bump_any(); | ||
230 | m.complete(self, ERROR); | ||
237 | } | 231 | } |
238 | 232 | ||
239 | fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { | 233 | fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { |
240 | self.eat_dollars(); | ||
241 | |||
242 | for _ in 0..n_raw_tokens { | 234 | for _ in 0..n_raw_tokens { |
243 | self.token_source.bump(); | 235 | self.token_source.bump(); |
244 | } | 236 | } |
@@ -249,110 +241,6 @@ impl<'t> Parser<'t> { | |||
249 | fn push_event(&mut self, event: Event) { | 241 | fn push_event(&mut self, event: Event) { |
250 | self.events.push(event) | 242 | self.events.push(event) |
251 | } | 243 | } |
252 | |||
253 | /// helper function for check if it is composite. | ||
254 | fn is_composite(&self, first: Token, n: usize) -> Option<(SyntaxKind, usize)> { | ||
255 | // We assume the dollars will not occuried between | ||
256 | // mult-byte tokens | ||
257 | |||
258 | let jn1 = first.is_jointed_to_next; | ||
259 | if !jn1 && first.kind != T![-] { | ||
260 | return None; | ||
261 | } | ||
262 | |||
263 | let second = self.token_source.lookahead_nth(n + 1); | ||
264 | if first.kind == T![-] && second.kind == T![>] { | ||
265 | return Some((T![->], 2)); | ||
266 | } | ||
267 | if !jn1 { | ||
268 | return None; | ||
269 | } | ||
270 | |||
271 | match (first.kind, second.kind) { | ||
272 | (T![:], T![:]) => return Some((T![::], 2)), | ||
273 | (T![=], T![=]) => return Some((T![==], 2)), | ||
274 | (T![=], T![>]) => return Some((T![=>], 2)), | ||
275 | (T![!], T![=]) => return Some((T![!=], 2)), | ||
276 | _ => {} | ||
277 | } | ||
278 | |||
279 | if first.kind != T![.] || second.kind != T![.] { | ||
280 | return None; | ||
281 | } | ||
282 | |||
283 | let third = self.token_source.lookahead_nth(n + 2); | ||
284 | |||
285 | let jn2 = second.is_jointed_to_next; | ||
286 | let la3 = third.kind; | ||
287 | |||
288 | if jn2 && la3 == T![.] { | ||
289 | return Some((T![...], 3)); | ||
290 | } | ||
291 | if la3 == T![=] { | ||
292 | return Some((T![..=], 3)); | ||
293 | } | ||
294 | return Some((T![..], 2)); | ||
295 | } | ||
296 | |||
297 | fn eat_dollars(&mut self) { | ||
298 | loop { | ||
299 | match self.token_source.current().kind { | ||
300 | k @ SyntaxKind::L_DOLLAR | k @ SyntaxKind::R_DOLLAR => { | ||
301 | self.token_source.bump(); | ||
302 | self.push_event(Event::Token { kind: k, n_raw_tokens: 1 }); | ||
303 | } | ||
304 | _ => { | ||
305 | return; | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | |||
311 | pub(crate) fn eat_l_dollars(&mut self) -> usize { | ||
312 | let mut ate_count = 0; | ||
313 | loop { | ||
314 | match self.token_source.current().kind { | ||
315 | k @ SyntaxKind::L_DOLLAR => { | ||
316 | self.token_source.bump(); | ||
317 | self.push_event(Event::Token { kind: k, n_raw_tokens: 1 }); | ||
318 | ate_count += 1; | ||
319 | } | ||
320 | _ => { | ||
321 | return ate_count; | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | |||
327 | pub(crate) fn eat_r_dollars(&mut self, max_count: usize) -> usize { | ||
328 | let mut ate_count = 0; | ||
329 | loop { | ||
330 | match self.token_source.current().kind { | ||
331 | k @ SyntaxKind::R_DOLLAR => { | ||
332 | self.token_source.bump(); | ||
333 | self.push_event(Event::Token { kind: k, n_raw_tokens: 1 }); | ||
334 | ate_count += 1; | ||
335 | |||
336 | if max_count >= ate_count { | ||
337 | return ate_count; | ||
338 | } | ||
339 | } | ||
340 | _ => { | ||
341 | return ate_count; | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | pub(crate) fn at_l_dollar(&self) -> bool { | ||
348 | let kind = self.token_source.current().kind; | ||
349 | (kind == SyntaxKind::L_DOLLAR) | ||
350 | } | ||
351 | |||
352 | pub(crate) fn at_r_dollar(&self) -> bool { | ||
353 | let kind = self.token_source.current().kind; | ||
354 | (kind == SyntaxKind::R_DOLLAR) | ||
355 | } | ||
356 | } | 244 | } |
357 | 245 | ||
358 | /// See `Parser::start`. | 246 | /// See `Parser::start`. |
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs index fa5d2d5d8..458920607 100644 --- a/crates/ra_syntax/src/tests.rs +++ b/crates/ra_syntax/src/tests.rs | |||
@@ -16,6 +16,18 @@ fn lexer_tests() { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | #[test] | 18 | #[test] |
19 | fn parse_smoke_test() { | ||
20 | let code = r##" | ||
21 | fn main() { | ||
22 | println!("Hello, world!") | ||
23 | } | ||
24 | "##; | ||
25 | |||
26 | let parse = SourceFile::parse(code); | ||
27 | assert!(parse.ok().is_ok()); | ||
28 | } | ||
29 | |||
30 | #[test] | ||
19 | fn parser_tests() { | 31 | fn parser_tests() { |
20 | dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { | 32 | dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { |
21 | let parse = SourceFile::parse(text); | 33 | let parse = SourceFile::parse(text); |
@@ -75,7 +87,9 @@ fn self_hosting_parsing() { | |||
75 | { | 87 | { |
76 | count += 1; | 88 | count += 1; |
77 | let text = read_text(entry.path()); | 89 | let text = read_text(entry.path()); |
78 | SourceFile::parse(&text).ok().expect("There should be no errors in the file"); | 90 | if let Err(errors) = SourceFile::parse(&text).ok() { |
91 | panic!("Parsing errors:\n{:?}\n{}\n", errors, entry.path().display()); | ||
92 | } | ||
79 | } | 93 | } |
80 | assert!( | 94 | assert!( |
81 | count > 30, | 95 | count > 30, |
diff --git a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs new file mode 100644 index 000000000..0d3f5722a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | fn a() -> Foo<bar::Baz> {} | ||
2 | |||
3 | fn b(_: impl FnMut(x::Y)) {} | ||
4 | |||
5 | fn c(_: impl FnMut(&x::Y)) {} | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt new file mode 100644 index 000000000..7e1af254c --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt | |||
@@ -0,0 +1,126 @@ | |||
1 | SOURCE_FILE@[0; 88) | ||
2 | FN_DEF@[0; 26) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 4) | ||
6 | IDENT@[3; 4) "a" | ||
7 | PARAM_LIST@[4; 6) | ||
8 | L_PAREN@[4; 5) "(" | ||
9 | R_PAREN@[5; 6) ")" | ||
10 | WHITESPACE@[6; 7) " " | ||
11 | RET_TYPE@[7; 23) | ||
12 | THIN_ARROW@[7; 9) "->" | ||
13 | WHITESPACE@[9; 10) " " | ||
14 | PATH_TYPE@[10; 23) | ||
15 | PATH@[10; 23) | ||
16 | PATH_SEGMENT@[10; 23) | ||
17 | NAME_REF@[10; 13) | ||
18 | IDENT@[10; 13) "Foo" | ||
19 | TYPE_ARG_LIST@[13; 23) | ||
20 | L_ANGLE@[13; 14) "<" | ||
21 | TYPE_ARG@[14; 22) | ||
22 | PATH_TYPE@[14; 22) | ||
23 | PATH@[14; 22) | ||
24 | PATH@[14; 17) | ||
25 | PATH_SEGMENT@[14; 17) | ||
26 | NAME_REF@[14; 17) | ||
27 | IDENT@[14; 17) "bar" | ||
28 | COLONCOLON@[17; 19) "::" | ||
29 | PATH_SEGMENT@[19; 22) | ||
30 | NAME_REF@[19; 22) | ||
31 | IDENT@[19; 22) "Baz" | ||
32 | R_ANGLE@[22; 23) ">" | ||
33 | WHITESPACE@[23; 24) " " | ||
34 | BLOCK_EXPR@[24; 26) | ||
35 | BLOCK@[24; 26) | ||
36 | L_CURLY@[24; 25) "{" | ||
37 | R_CURLY@[25; 26) "}" | ||
38 | WHITESPACE@[26; 28) "\n\n" | ||
39 | FN_DEF@[28; 56) | ||
40 | FN_KW@[28; 30) "fn" | ||
41 | WHITESPACE@[30; 31) " " | ||
42 | NAME@[31; 32) | ||
43 | IDENT@[31; 32) "b" | ||
44 | PARAM_LIST@[32; 53) | ||
45 | L_PAREN@[32; 33) "(" | ||
46 | PARAM@[33; 52) | ||
47 | PLACEHOLDER_PAT@[33; 34) | ||
48 | UNDERSCORE@[33; 34) "_" | ||
49 | COLON@[34; 35) ":" | ||
50 | WHITESPACE@[35; 36) " " | ||
51 | IMPL_TRAIT_TYPE@[36; 52) | ||
52 | IMPL_KW@[36; 40) "impl" | ||
53 | WHITESPACE@[40; 41) " " | ||
54 | TYPE_BOUND_LIST@[41; 52) | ||
55 | TYPE_BOUND@[41; 52) | ||
56 | PATH_TYPE@[41; 52) | ||
57 | PATH@[41; 52) | ||
58 | PATH_SEGMENT@[41; 52) | ||
59 | NAME_REF@[41; 46) | ||
60 | IDENT@[41; 46) "FnMut" | ||
61 | PARAM_LIST@[46; 52) | ||
62 | L_PAREN@[46; 47) "(" | ||
63 | PARAM@[47; 51) | ||
64 | PATH_TYPE@[47; 51) | ||
65 | PATH@[47; 51) | ||
66 | PATH@[47; 48) | ||
67 | PATH_SEGMENT@[47; 48) | ||
68 | NAME_REF@[47; 48) | ||
69 | IDENT@[47; 48) "x" | ||
70 | COLONCOLON@[48; 50) "::" | ||
71 | PATH_SEGMENT@[50; 51) | ||
72 | NAME_REF@[50; 51) | ||
73 | IDENT@[50; 51) "Y" | ||
74 | R_PAREN@[51; 52) ")" | ||
75 | R_PAREN@[52; 53) ")" | ||
76 | WHITESPACE@[53; 54) " " | ||
77 | BLOCK_EXPR@[54; 56) | ||
78 | BLOCK@[54; 56) | ||
79 | L_CURLY@[54; 55) "{" | ||
80 | R_CURLY@[55; 56) "}" | ||
81 | WHITESPACE@[56; 58) "\n\n" | ||
82 | FN_DEF@[58; 87) | ||
83 | FN_KW@[58; 60) "fn" | ||
84 | WHITESPACE@[60; 61) " " | ||
85 | NAME@[61; 62) | ||
86 | IDENT@[61; 62) "c" | ||
87 | PARAM_LIST@[62; 84) | ||
88 | L_PAREN@[62; 63) "(" | ||
89 | PARAM@[63; 83) | ||
90 | PLACEHOLDER_PAT@[63; 64) | ||
91 | UNDERSCORE@[63; 64) "_" | ||
92 | COLON@[64; 65) ":" | ||
93 | WHITESPACE@[65; 66) " " | ||
94 | IMPL_TRAIT_TYPE@[66; 83) | ||
95 | IMPL_KW@[66; 70) "impl" | ||
96 | WHITESPACE@[70; 71) " " | ||
97 | TYPE_BOUND_LIST@[71; 83) | ||
98 | TYPE_BOUND@[71; 83) | ||
99 | PATH_TYPE@[71; 83) | ||
100 | PATH@[71; 83) | ||
101 | PATH_SEGMENT@[71; 83) | ||
102 | NAME_REF@[71; 76) | ||
103 | IDENT@[71; 76) "FnMut" | ||
104 | PARAM_LIST@[76; 83) | ||
105 | L_PAREN@[76; 77) "(" | ||
106 | PARAM@[77; 82) | ||
107 | REFERENCE_TYPE@[77; 82) | ||
108 | AMP@[77; 78) "&" | ||
109 | PATH_TYPE@[78; 82) | ||
110 | PATH@[78; 82) | ||
111 | PATH@[78; 79) | ||
112 | PATH_SEGMENT@[78; 79) | ||
113 | NAME_REF@[78; 79) | ||
114 | IDENT@[78; 79) "x" | ||
115 | COLONCOLON@[79; 81) "::" | ||
116 | PATH_SEGMENT@[81; 82) | ||
117 | NAME_REF@[81; 82) | ||
118 | IDENT@[81; 82) "Y" | ||
119 | R_PAREN@[82; 83) ")" | ||
120 | R_PAREN@[83; 84) ")" | ||
121 | WHITESPACE@[84; 85) " " | ||
122 | BLOCK_EXPR@[85; 87) | ||
123 | BLOCK@[85; 87) | ||
124 | L_CURLY@[85; 86) "{" | ||
125 | R_CURLY@[86; 87) "}" | ||
126 | WHITESPACE@[87; 88) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs new file mode 100644 index 000000000..cd204f65e --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | type X = (); | ||
2 | |||
3 | fn main() { | ||
4 | let ():::X = (); | ||
5 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt new file mode 100644 index 000000000..d656e74b1 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt | |||
@@ -0,0 +1,50 @@ | |||
1 | SOURCE_FILE@[0; 49) | ||
2 | TYPE_ALIAS_DEF@[0; 12) | ||
3 | TYPE_KW@[0; 4) "type" | ||
4 | WHITESPACE@[4; 5) " " | ||
5 | NAME@[5; 6) | ||
6 | IDENT@[5; 6) "X" | ||
7 | WHITESPACE@[6; 7) " " | ||
8 | EQ@[7; 8) "=" | ||
9 | WHITESPACE@[8; 9) " " | ||
10 | TUPLE_TYPE@[9; 11) | ||
11 | L_PAREN@[9; 10) "(" | ||
12 | R_PAREN@[10; 11) ")" | ||
13 | SEMI@[11; 12) ";" | ||
14 | WHITESPACE@[12; 14) "\n\n" | ||
15 | FN_DEF@[14; 48) | ||
16 | FN_KW@[14; 16) "fn" | ||
17 | WHITESPACE@[16; 17) " " | ||
18 | NAME@[17; 21) | ||
19 | IDENT@[17; 21) "main" | ||
20 | PARAM_LIST@[21; 23) | ||
21 | L_PAREN@[21; 22) "(" | ||
22 | R_PAREN@[22; 23) ")" | ||
23 | WHITESPACE@[23; 24) " " | ||
24 | BLOCK_EXPR@[24; 48) | ||
25 | BLOCK@[24; 48) | ||
26 | L_CURLY@[24; 25) "{" | ||
27 | WHITESPACE@[25; 30) "\n " | ||
28 | LET_STMT@[30; 46) | ||
29 | LET_KW@[30; 33) "let" | ||
30 | WHITESPACE@[33; 34) " " | ||
31 | TUPLE_PAT@[34; 36) | ||
32 | L_PAREN@[34; 35) "(" | ||
33 | R_PAREN@[35; 36) ")" | ||
34 | COLON@[36; 37) ":" | ||
35 | PATH_TYPE@[37; 40) | ||
36 | PATH@[37; 40) | ||
37 | PATH_SEGMENT@[37; 40) | ||
38 | COLONCOLON@[37; 39) "::" | ||
39 | NAME_REF@[39; 40) | ||
40 | IDENT@[39; 40) "X" | ||
41 | WHITESPACE@[40; 41) " " | ||
42 | EQ@[41; 42) "=" | ||
43 | WHITESPACE@[42; 43) " " | ||
44 | TUPLE_EXPR@[43; 45) | ||
45 | L_PAREN@[43; 44) "(" | ||
46 | R_PAREN@[44; 45) ")" | ||
47 | SEMI@[45; 46) ";" | ||
48 | WHITESPACE@[46; 47) "\n" | ||
49 | R_CURLY@[47; 48) "}" | ||
50 | WHITESPACE@[48; 49) "\n" | ||
diff --git a/crates/ra_tools/Cargo.toml b/crates/ra_tools/Cargo.toml index b94a0b18d..848ca408d 100644 --- a/crates/ra_tools/Cargo.toml +++ b/crates/ra_tools/Cargo.toml | |||
@@ -8,7 +8,7 @@ publish = false | |||
8 | [dependencies] | 8 | [dependencies] |
9 | walkdir = "2.1.3" | 9 | walkdir = "2.1.3" |
10 | itertools = "0.8.0" | 10 | itertools = "0.8.0" |
11 | clap = { version = "2.32.0", default-features = false } | 11 | pico-args = "0.2.0" |
12 | quote = "1.0.2" | 12 | quote = "1.0.2" |
13 | proc-macro2 = "1.0.1" | 13 | proc-macro2 = "1.0.1" |
14 | ron = "0.5.1" | 14 | ron = "0.5.1" |
diff --git a/crates/ra_tools/src/help.rs b/crates/ra_tools/src/help.rs new file mode 100644 index 000000000..6dde6c2d2 --- /dev/null +++ b/crates/ra_tools/src/help.rs | |||
@@ -0,0 +1,45 @@ | |||
1 | pub const GLOBAL_HELP: &str = "tasks | ||
2 | |||
3 | USAGE: | ||
4 | ra_tools <SUBCOMMAND> | ||
5 | |||
6 | FLAGS: | ||
7 | -h, --help Prints help information | ||
8 | |||
9 | SUBCOMMANDS: | ||
10 | format | ||
11 | format-hook | ||
12 | fuzz-tests | ||
13 | gen-syntax | ||
14 | gen-tests | ||
15 | install-ra | ||
16 | lint"; | ||
17 | |||
18 | pub const INSTALL_RA_HELP: &str = "ra_tools-install-ra | ||
19 | |||
20 | USAGE: | ||
21 | ra_tools.exe install-ra [FLAGS] | ||
22 | |||
23 | FLAGS: | ||
24 | --client-code | ||
25 | -h, --help Prints help information | ||
26 | --jemalloc | ||
27 | --server"; | ||
28 | |||
29 | pub fn print_no_param_subcommand_help(subcommand: &str) { | ||
30 | eprintln!( | ||
31 | "ra_tools-{} | ||
32 | |||
33 | USAGE: | ||
34 | ra_tools {} | ||
35 | |||
36 | FLAGS: | ||
37 | -h, --help Prints help information", | ||
38 | subcommand, subcommand | ||
39 | ); | ||
40 | } | ||
41 | |||
42 | pub const INSTALL_RA_CONFLICT: &str = | ||
43 | "error: The argument `--server` cannot be used with `--client-code` | ||
44 | |||
45 | For more information try --help"; | ||
diff --git a/crates/ra_tools/src/main.rs b/crates/ra_tools/src/main.rs index 33badf290..f96f1875f 100644 --- a/crates/ra_tools/src/main.rs +++ b/crates/ra_tools/src/main.rs | |||
@@ -1,5 +1,8 @@ | |||
1 | use clap::{App, Arg, SubCommand}; | 1 | mod help; |
2 | |||
3 | use core::fmt::Write; | ||
2 | use core::str; | 4 | use core::str; |
5 | use pico_args::Arguments; | ||
3 | use ra_tools::{ | 6 | use ra_tools::{ |
4 | gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, | 7 | gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, |
5 | Cmd, Overwrite, Result, | 8 | Cmd, Overwrite, Result, |
@@ -20,45 +23,95 @@ struct ServerOpt { | |||
20 | } | 23 | } |
21 | 24 | ||
22 | fn main() -> Result<()> { | 25 | fn main() -> Result<()> { |
23 | let matches = App::new("tasks") | 26 | let subcommand = match std::env::args_os().nth(1) { |
24 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | 27 | None => { |
25 | .subcommand(SubCommand::with_name("gen-syntax")) | 28 | eprintln!("{}", help::GLOBAL_HELP); |
26 | .subcommand(SubCommand::with_name("gen-tests")) | 29 | return Ok(()); |
27 | .subcommand( | 30 | } |
28 | SubCommand::with_name("install-ra") | 31 | Some(s) => s, |
29 | .arg(Arg::with_name("server").long("--server")) | 32 | }; |
30 | .arg(Arg::with_name("jemalloc").long("jemalloc")) | 33 | let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect()); |
31 | .arg(Arg::with_name("client-code").long("client-code").conflicts_with("server")), | 34 | let subcommand = &*subcommand.to_string_lossy(); |
32 | ) | 35 | match subcommand { |
33 | .alias("install-code") | 36 | "install-ra" | "install-code" => { |
34 | .subcommand(SubCommand::with_name("format")) | 37 | if matches.contains(["-h", "--help"]) { |
35 | .subcommand(SubCommand::with_name("format-hook")) | 38 | eprintln!("{}", help::INSTALL_RA_HELP); |
36 | .subcommand(SubCommand::with_name("fuzz-tests")) | 39 | return Ok(()); |
37 | .subcommand(SubCommand::with_name("lint")) | 40 | } |
38 | .get_matches(); | 41 | let server = matches.contains("--server"); |
39 | match matches.subcommand() { | 42 | let client_code = matches.contains("--client-code"); |
40 | ("install-ra", Some(matches)) => { | 43 | if server && client_code { |
44 | eprintln!("{}", help::INSTALL_RA_CONFLICT); | ||
45 | return Ok(()); | ||
46 | } | ||
47 | let jemalloc = matches.contains("--jemalloc"); | ||
48 | matches.finish().or_else(handle_extra_flags)?; | ||
41 | let opts = InstallOpt { | 49 | let opts = InstallOpt { |
42 | client: if matches.is_present("server") { None } else { Some(ClientOpt::VsCode) }, | 50 | client: if server { None } else { Some(ClientOpt::VsCode) }, |
43 | server: if matches.is_present("client-code") { | 51 | server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) }, |
44 | None | ||
45 | } else { | ||
46 | Some(ServerOpt { jemalloc: matches.is_present("jemalloc") }) | ||
47 | }, | ||
48 | }; | 52 | }; |
49 | install(opts)? | 53 | install(opts)? |
50 | } | 54 | } |
51 | ("gen-tests", _) => gen_tests(Overwrite)?, | 55 | "gen-tests" => { |
52 | ("gen-syntax", _) => generate_boilerplate(Overwrite)?, | 56 | if matches.contains(["-h", "--help"]) { |
53 | ("format", _) => run_rustfmt(Overwrite)?, | 57 | help::print_no_param_subcommand_help(&subcommand); |
54 | ("format-hook", _) => install_format_hook()?, | 58 | return Ok(()); |
55 | ("lint", _) => run_clippy()?, | 59 | } |
56 | ("fuzz-tests", _) => run_fuzzer()?, | 60 | gen_tests(Overwrite)? |
57 | _ => unreachable!(), | 61 | } |
62 | "gen-syntax" => { | ||
63 | if matches.contains(["-h", "--help"]) { | ||
64 | help::print_no_param_subcommand_help(&subcommand); | ||
65 | return Ok(()); | ||
66 | } | ||
67 | generate_boilerplate(Overwrite)? | ||
68 | } | ||
69 | "format" => { | ||
70 | if matches.contains(["-h", "--help"]) { | ||
71 | help::print_no_param_subcommand_help(&subcommand); | ||
72 | return Ok(()); | ||
73 | } | ||
74 | run_rustfmt(Overwrite)? | ||
75 | } | ||
76 | "format-hook" => { | ||
77 | if matches.contains(["-h", "--help"]) { | ||
78 | help::print_no_param_subcommand_help(&subcommand); | ||
79 | return Ok(()); | ||
80 | } | ||
81 | install_format_hook()? | ||
82 | } | ||
83 | "lint" => { | ||
84 | if matches.contains(["-h", "--help"]) { | ||
85 | help::print_no_param_subcommand_help(&subcommand); | ||
86 | return Ok(()); | ||
87 | } | ||
88 | run_clippy()? | ||
89 | } | ||
90 | "fuzz-tests" => { | ||
91 | if matches.contains(["-h", "--help"]) { | ||
92 | help::print_no_param_subcommand_help(&subcommand); | ||
93 | return Ok(()); | ||
94 | } | ||
95 | run_fuzzer()? | ||
96 | } | ||
97 | _ => eprintln!("{}", help::GLOBAL_HELP), | ||
58 | } | 98 | } |
59 | Ok(()) | 99 | Ok(()) |
60 | } | 100 | } |
61 | 101 | ||
102 | fn handle_extra_flags(e: pico_args::Error) -> Result<()> { | ||
103 | if let pico_args::Error::UnusedArgsLeft(flags) = e { | ||
104 | let mut invalid_flags = String::new(); | ||
105 | for flag in flags { | ||
106 | write!(&mut invalid_flags, "{}, ", flag)?; | ||
107 | } | ||
108 | let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); | ||
109 | Err(format!("Invalid flags: {}", invalid_flags).into()) | ||
110 | } else { | ||
111 | Err(e.to_string().into()) | ||
112 | } | ||
113 | } | ||
114 | |||
62 | fn install(opts: InstallOpt) -> Result<()> { | 115 | fn install(opts: InstallOpt) -> Result<()> { |
63 | if cfg!(target_os = "macos") { | 116 | if cfg!(target_os = "macos") { |
64 | fix_path_for_mac()? | 117 | fix_path_for_mac()? |