aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/publish.yml44
-rw-r--r--Cargo.lock4
-rw-r--r--crates/arena/Cargo.toml1
-rw-r--r--crates/assists/Cargo.toml17
-rw-r--r--crates/assists/src/assist_context.rs4
-rw-r--r--crates/assists/src/handlers/expand_glob_import.rs732
-rw-r--r--crates/assists/src/handlers/invert_if.rs18
-rw-r--r--crates/assists/src/utils.rs21
-rw-r--r--crates/base_db/Cargo.toml15
-rw-r--r--crates/cfg/Cargo.toml3
-rw-r--r--crates/flycheck/Cargo.toml3
-rw-r--r--crates/hir/Cargo.toml17
-rw-r--r--crates/hir_def/Cargo.toml21
-rw-r--r--crates/hir_def/src/item_tree/lower.rs4
-rw-r--r--crates/hir_def/src/nameres/tests.rs2
-rw-r--r--crates/hir_expand/Cargo.toml17
-rw-r--r--crates/hir_ty/Cargo.toml17
-rw-r--r--crates/ide/Cargo.toml23
-rw-r--r--crates/ide/src/completion.rs2
-rw-r--r--crates/ide/src/runnables.rs26
-rw-r--r--crates/ide_db/Cargo.toml15
-rw-r--r--crates/mbe/Cargo.toml7
-rw-r--r--crates/parser/Cargo.toml1
-rw-r--r--crates/paths/Cargo.toml1
-rw-r--r--crates/proc_macro_api/Cargo.toml3
-rw-r--r--crates/proc_macro_srv/Cargo.toml9
-rw-r--r--crates/proc_macro_test/Cargo.toml1
-rw-r--r--crates/profile/Cargo.toml3
-rw-r--r--crates/project_model/Cargo.toml15
-rw-r--r--crates/rust-analyzer/Cargo.toml37
-rw-r--r--crates/ssr/Cargo.toml12
-rw-r--r--crates/stdx/Cargo.toml1
-rw-r--r--crates/syntax/Cargo.toml6
-rw-r--r--crates/syntax/src/algo.rs2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs8
-rw-r--r--crates/syntax/src/ast/make.rs8
-rw-r--r--crates/test_utils/Cargo.toml3
-rw-r--r--crates/text_edit/Cargo.toml1
-rw-r--r--crates/toolchain/Cargo.toml1
-rw-r--r--crates/tt/Cargo.toml3
-rw-r--r--crates/vfs-notify/Cargo.toml5
-rw-r--r--crates/vfs/Cargo.toml3
-rw-r--r--docs/dev/style.md61
-rw-r--r--editors/code/src/net.ts8
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/codegen/rust.ungram587
46 files changed, 959 insertions, 835 deletions
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..be2c7a8ca
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,44 @@
1name: publish
2on:
3 workflow_dispatch: # We can add version input when 1.0 is released and scheduled releases are removed
4
5 schedule:
6 - cron: "0 0 * * *" # midnight UTC
7
8 push:
9 branches:
10 - release
11
12jobs:
13 publish:
14 name: publish
15 runs-on: ubuntu-16.04
16 steps:
17 - name: Checkout repository
18 uses: actions/checkout@v2
19 with:
20 fetch-depth: 0
21
22 - name: Install Rust toolchain
23 uses: actions-rs/toolchain@v1
24 with:
25 toolchain: stable
26 profile: minimal
27 override: true
28
29 - name: Install cargo-workspaces
30 uses: actions-rs/[email protected]
31 with:
32 crate: cargo-workspaces
33
34 - name: Release
35 env:
36 CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
37 PATCH: ${{ github.run_number }}
38 shell: bash
39 run: |
40 git config --global user.email "[email protected]"
41 git config --global user.name "Github Action"
42 rm Cargo.lock
43 cargo workspaces rename ra_ap_%n
44 cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
diff --git a/Cargo.lock b/Cargo.lock
index 1f8e7a29d..015f84ba8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1718,9 +1718,9 @@ dependencies = [
1718 1718
1719[[package]] 1719[[package]]
1720name = "ungrammar" 1720name = "ungrammar"
1721version = "1.1.2" 1721version = "1.1.3"
1722source = "registry+https://github.com/rust-lang/crates.io-index" 1722source = "registry+https://github.com/rust-lang/crates.io-index"
1723checksum = "bab6142ac77be714b1ea78faca6efaed5478c50724786b0fe80d8528d10692b3" 1723checksum = "ca4d39065b45f658d33013f7cc93ee050708cd543f6e07dd15b4293fcf217e12"
1724 1724
1725[[package]] 1725[[package]]
1726name = "unicase" 1726name = "unicase"
diff --git a/crates/arena/Cargo.toml b/crates/arena/Cargo.toml
index f2bb5cc45..863eedf76 100644
--- a/crates/arena/Cargo.toml
+++ b/crates/arena/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "arena" 2name = "arena"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index a560a35c7..264125651 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "assists" 2name = "assists"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,11 +14,11 @@ rustc-hash = "1.1.0"
13itertools = "0.9.0" 14itertools = "0.9.0"
14either = "1.5.3" 15either = "1.5.3"
15 16
16stdx = { path = "../stdx" } 17stdx = { path = "../stdx", version = "0.0.0" }
17syntax = { path = "../syntax" } 18syntax = { path = "../syntax", version = "0.0.0" }
18text_edit = { path = "../text_edit" } 19text_edit = { path = "../text_edit", version = "0.0.0" }
19profile = { path = "../profile" } 20profile = { path = "../profile", version = "0.0.0" }
20base_db = { path = "../base_db" } 21base_db = { path = "../base_db", version = "0.0.0" }
21ide_db = { path = "../ide_db" } 22ide_db = { path = "../ide_db", version = "0.0.0" }
22hir = { path = "../hir" } 23hir = { path = "../hir", version = "0.0.0" }
23test_utils = { path = "../test_utils" } 24test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index 11c171fc2..bf520069e 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -73,10 +73,6 @@ impl<'a> AssistContext<'a> {
73 self.sema.db 73 self.sema.db
74 } 74 }
75 75
76 pub(crate) fn source_file(&self) -> &SourceFile {
77 &self.source_file
78 }
79
80 // NB, this ignores active selection. 76 // NB, this ignores active selection.
81 pub(crate) fn offset(&self) -> TextSize { 77 pub(crate) fn offset(&self) -> TextSize {
82 self.frange.range.start() 78 self.frange.range.start()
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs
index 81d0af2f3..b39d040f6 100644
--- a/crates/assists/src/handlers/expand_glob_import.rs
+++ b/crates/assists/src/handlers/expand_glob_import.rs
@@ -1,10 +1,10 @@
1use either::Either; 1use either::Either;
2use hir::{AssocItem, MacroDef, ModuleDef, Name, PathResolution, ScopeDef, SemanticsScope}; 2use hir::{AssocItem, MacroDef, Module, ModuleDef, Name, PathResolution, ScopeDef};
3use ide_db::{ 3use ide_db::{
4 defs::{classify_name_ref, Definition, NameRefClass}, 4 defs::{classify_name_ref, Definition, NameRefClass},
5 RootDatabase, 5 search::SearchScope,
6}; 6};
7use syntax::{algo, ast, match_ast, AstNode, SyntaxNode, SyntaxToken, T}; 7use syntax::{algo, ast, AstNode, Direction, SyntaxNode, SyntaxToken, T};
8 8
9use crate::{ 9use crate::{
10 assist_context::{AssistBuilder, AssistContext, Assists}, 10 assist_context::{AssistBuilder, AssistContext, Assists},
@@ -38,140 +38,259 @@ use crate::{
38// ``` 38// ```
39pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 39pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let star = ctx.find_token_at_offset(T![*])?; 40 let star = ctx.find_token_at_offset(T![*])?;
41 let mod_path = find_mod_path(&star)?; 41 let (parent, mod_path) = find_parent_and_path(&star)?;
42 let module = match ctx.sema.resolve_path(&mod_path)? { 42 let target_module = match ctx.sema.resolve_path(&mod_path)? {
43 PathResolution::Def(ModuleDef::Module(it)) => it, 43 PathResolution::Def(ModuleDef::Module(it)) => it,
44 _ => return None, 44 _ => return None,
45 }; 45 };
46 46
47 let source_file = ctx.source_file(); 47 let current_scope = ctx.sema.scope(&star.parent());
48 let scope = ctx.sema.scope_at_offset(source_file.syntax(), ctx.offset()); 48 let current_module = current_scope.module()?;
49 49
50 let defs_in_mod = find_defs_in_mod(ctx, scope, module)?; 50 let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?;
51 let name_refs_in_source_file = 51 let imported_defs = find_imported_defs(ctx, star)?;
52 source_file.syntax().descendants().filter_map(ast::NameRef::cast).collect(); 52 let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
53 let used_names = find_used_names(ctx, defs_in_mod, name_refs_in_source_file);
54 53
55 let parent = star.parent().parent()?; 54 let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone());
56 acc.add( 55 acc.add(
57 AssistId("expand_glob_import", AssistKind::RefactorRewrite), 56 AssistId("expand_glob_import", AssistKind::RefactorRewrite),
58 "Expand glob import", 57 "Expand glob import",
59 parent.text_range(), 58 target.text_range(),
60 |builder| { 59 |builder| {
61 replace_ast(builder, &parent, mod_path, used_names); 60 replace_ast(builder, parent, mod_path, names_to_import);
62 }, 61 },
63 ) 62 )
64} 63}
65 64
66fn find_mod_path(star: &SyntaxToken) -> Option<ast::Path> { 65fn find_parent_and_path(
67 star.ancestors().find_map(|n| ast::UseTree::cast(n).and_then(|u| u.path())) 66 star: &SyntaxToken,
67) -> Option<(Either<ast::UseTree, ast::UseTreeList>, ast::Path)> {
68 return star.ancestors().find_map(|n| {
69 find_use_tree_list(n.clone())
70 .and_then(|(u, p)| Some((Either::Right(u), p)))
71 .or_else(|| find_use_tree(n).and_then(|(u, p)| Some((Either::Left(u), p))))
72 });
73
74 fn find_use_tree_list(n: SyntaxNode) -> Option<(ast::UseTreeList, ast::Path)> {
75 let use_tree_list = ast::UseTreeList::cast(n)?;
76 let path = use_tree_list.parent_use_tree().path()?;
77 Some((use_tree_list, path))
78 }
79
80 fn find_use_tree(n: SyntaxNode) -> Option<(ast::UseTree, ast::Path)> {
81 let use_tree = ast::UseTree::cast(n)?;
82 let path = use_tree.path()?;
83 Some((use_tree, path))
84 }
68} 85}
69 86
70#[derive(PartialEq)] 87#[derive(Debug, PartialEq, Clone)]
71enum Def { 88enum Def {
72 ModuleDef(ModuleDef), 89 ModuleDef(ModuleDef),
73 MacroDef(MacroDef), 90 MacroDef(MacroDef),
74} 91}
75 92
76impl Def { 93impl Def {
77 fn name(&self, db: &RootDatabase) -> Option<Name> { 94 fn is_referenced_in(&self, ctx: &AssistContext) -> bool {
78 match self { 95 let def = match self {
79 Def::ModuleDef(def) => def.name(db), 96 Def::ModuleDef(def) => Definition::ModuleDef(*def),
80 Def::MacroDef(def) => def.name(db), 97 Def::MacroDef(def) => Definition::Macro(*def),
98 };
99
100 let search_scope = SearchScope::single_file(ctx.frange.file_id);
101 def.usages(&ctx.sema).in_scope(search_scope).at_least_one()
102 }
103}
104
105#[derive(Debug, Clone)]
106struct Ref {
107 // could be alias
108 visible_name: Name,
109 def: Def,
110}
111
112impl Ref {
113 fn from_scope_def(name: Name, scope_def: ScopeDef) -> Option<Self> {
114 match scope_def {
115 ScopeDef::ModuleDef(def) => Some(Ref { visible_name: name, def: Def::ModuleDef(def) }),
116 ScopeDef::MacroDef(def) => Some(Ref { visible_name: name, def: Def::MacroDef(def) }),
117 _ => None,
81 } 118 }
82 } 119 }
83} 120}
84 121
85fn find_defs_in_mod( 122#[derive(Debug, Clone)]
123struct Refs(Vec<Ref>);
124
125impl Refs {
126 fn used_refs(&self, ctx: &AssistContext) -> Refs {
127 Refs(
128 self.0
129 .clone()
130 .into_iter()
131 .filter(|r| {
132 if let Def::ModuleDef(ModuleDef::Trait(tr)) = r.def {
133 if tr
134 .items(ctx.db())
135 .into_iter()
136 .find(|ai| {
137 if let AssocItem::Function(f) = *ai {
138 Def::ModuleDef(ModuleDef::Function(f)).is_referenced_in(ctx)
139 } else {
140 false
141 }
142 })
143 .is_some()
144 {
145 return true;
146 }
147 }
148
149 r.def.is_referenced_in(ctx)
150 })
151 .collect(),
152 )
153 }
154
155 fn filter_out_by_defs(&self, defs: Vec<Def>) -> Refs {
156 Refs(self.0.clone().into_iter().filter(|r| !defs.contains(&r.def)).collect())
157 }
158}
159
160fn find_refs_in_mod(
86 ctx: &AssistContext, 161 ctx: &AssistContext,
87 from: SemanticsScope<'_>, 162 module: Module,
88 module: hir::Module, 163 visible_from: Option<Module>,
89) -> Option<Vec<Def>> { 164) -> Option<Refs> {
90 let module_scope = module.scope(ctx.db(), from.module()); 165 if let Some(from) = visible_from {
91 166 if !is_mod_visible_from(ctx, module, from) {
92 let mut defs = vec![]; 167 return None;
93 for (_, def) in module_scope {
94 match def {
95 ScopeDef::ModuleDef(def) => defs.push(Def::ModuleDef(def)),
96 ScopeDef::MacroDef(def) => defs.push(Def::MacroDef(def)),
97 _ => continue,
98 } 168 }
99 } 169 }
100 170
101 Some(defs) 171 let module_scope = module.scope(ctx.db(), visible_from);
172 let refs = module_scope.into_iter().filter_map(|(n, d)| Ref::from_scope_def(n, d)).collect();
173 Some(Refs(refs))
102} 174}
103 175
104fn find_used_names( 176fn is_mod_visible_from(ctx: &AssistContext, module: Module, from: Module) -> bool {
105 ctx: &AssistContext, 177 match module.parent(ctx.db()) {
106 defs_in_mod: Vec<Def>, 178 Some(parent) => {
107 name_refs_in_source_file: Vec<ast::NameRef>, 179 parent.visibility_of(ctx.db(), &ModuleDef::Module(module)).map_or(true, |vis| {
108) -> Vec<Name> { 180 vis.is_visible_from(ctx.db(), from.into()) && is_mod_visible_from(ctx, parent, from)
109 let defs_in_source_file = name_refs_in_source_file 181 })
110 .iter() 182 }
111 .filter_map(|r| classify_name_ref(&ctx.sema, r)) 183 None => true,
112 .filter_map(|rc| match rc { 184 }
113 NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)), 185}
114 NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)),
115 _ => None,
116 })
117 .collect::<Vec<Def>>();
118 186
119 defs_in_mod 187// looks for name refs in parent use block's siblings
120 .iter() 188//
121 .filter(|def| { 189// mod bar {
122 if let Def::ModuleDef(ModuleDef::Trait(tr)) = def { 190// mod qux {
123 for item in tr.items(ctx.db()) { 191// struct Qux;
124 if let AssocItem::Function(f) = item { 192// }
125 if defs_in_source_file.contains(&Def::ModuleDef(ModuleDef::Function(f))) { 193//
126 return true; 194// pub use qux::Qux;
127 } 195// }
128 } 196//
129 } 197// ↓ ---------------
130 } 198// use foo::*<|>;
199// use baz::Baz;
200// ↑ ---------------
201fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>> {
202 let parent_use_item_syntax =
203 star.ancestors().find_map(|n| if ast::Use::can_cast(n.kind()) { Some(n) } else { None })?;
204
205 Some(
206 [Direction::Prev, Direction::Next]
207 .iter()
208 .map(|dir| {
209 parent_use_item_syntax
210 .siblings(dir.to_owned())
211 .filter(|n| ast::Use::can_cast(n.kind()))
212 })
213 .flatten()
214 .filter_map(|n| Some(n.descendants().filter_map(ast::NameRef::cast)))
215 .flatten()
216 .filter_map(|r| match classify_name_ref(&ctx.sema, &r)? {
217 NameRefClass::Definition(Definition::ModuleDef(def)) => Some(Def::ModuleDef(def)),
218 NameRefClass::Definition(Definition::Macro(def)) => Some(Def::MacroDef(def)),
219 _ => None,
220 })
221 .collect(),
222 )
223}
131 224
132 defs_in_source_file.contains(def) 225fn find_names_to_import(
133 }) 226 ctx: &AssistContext,
134 .filter_map(|d| d.name(ctx.db())) 227 refs_in_target: Refs,
135 .collect() 228 imported_defs: Vec<Def>,
229) -> Vec<Name> {
230 let used_refs = refs_in_target.used_refs(ctx).filter_out_by_defs(imported_defs);
231 used_refs.0.iter().map(|r| r.visible_name.clone()).collect()
136} 232}
137 233
138fn replace_ast( 234fn replace_ast(
139 builder: &mut AssistBuilder, 235 builder: &mut AssistBuilder,
140 node: &SyntaxNode, 236 parent: Either<ast::UseTree, ast::UseTreeList>,
141 path: ast::Path, 237 path: ast::Path,
142 used_names: Vec<Name>, 238 names_to_import: Vec<Name>,
143) { 239) {
144 let replacement: Either<ast::UseTree, ast::UseTreeList> = match used_names.as_slice() { 240 let existing_use_trees = match parent.clone() {
145 [name] => Either::Left(ast::make::use_tree( 241 Either::Left(_) => vec![],
146 ast::make::path_from_text(&format!("{}::{}", path, name)), 242 Either::Right(u) => u
147 None, 243 .use_trees()
148 None, 244 .filter(|n|
149 false, 245 // filter out star
150 )), 246 n.star_token().is_none())
151 names => Either::Right(ast::make::use_tree_list(names.iter().map(|n| { 247 .collect(),
152 ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false)
153 }))),
154 }; 248 };
155 249
156 let mut replace_node = |replacement: Either<ast::UseTree, ast::UseTreeList>| { 250 let new_use_trees: Vec<ast::UseTree> = names_to_import
157 algo::diff(node, &replacement.either(|u| u.syntax().clone(), |ut| ut.syntax().clone())) 251 .iter()
252 .map(|n| ast::make::use_tree(ast::make::path_from_text(&n.to_string()), None, None, false))
253 .collect();
254
255 let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat();
256
257 match use_trees.as_slice() {
258 [name] => {
259 if let Some(end_path) = name.path() {
260 let replacement = ast::make::use_tree(
261 ast::make::path_from_text(&format!("{}::{}", path, end_path)),
262 None,
263 None,
264 false,
265 );
266
267 algo::diff(
268 &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()),
269 replacement.syntax(),
270 )
271 .into_text_edit(builder.text_edit_builder());
272 }
273 }
274 names => {
275 let replacement = match parent {
276 Either::Left(_) => ast::make::use_tree(
277 path,
278 Some(ast::make::use_tree_list(names.to_owned())),
279 None,
280 false,
281 )
282 .syntax()
283 .clone(),
284 Either::Right(_) => ast::make::use_tree_list(names.to_owned()).syntax().clone(),
285 };
286
287 algo::diff(
288 &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()),
289 &replacement,
290 )
158 .into_text_edit(builder.text_edit_builder()); 291 .into_text_edit(builder.text_edit_builder());
159 };
160
161 match_ast! {
162 match node {
163 ast::UseTree(use_tree) => {
164 replace_node(replacement);
165 },
166 ast::UseTreeList(use_tree_list) => {
167 replace_node(replacement);
168 },
169 ast::Use(use_item) => {
170 builder.replace_ast(use_item, ast::make::use_(replacement.left_or_else(|ut| ast::make::use_tree(path, Some(ut), None, false))));
171 },
172 _ => {},
173 } 292 }
174 } 293 };
175} 294}
176 295
177#[cfg(test)] 296#[cfg(test)]
@@ -245,7 +364,46 @@ mod foo {
245 pub fn f() {} 364 pub fn f() {}
246} 365}
247 366
248use foo::{Baz, Bar, f}; 367use foo::{f, Baz, Bar};
368
369fn qux(bar: Bar, baz: Baz) {
370 f();
371}
372",
373 )
374 }
375
376 #[test]
377 fn expanding_glob_import_with_existing_uses_in_same_module() {
378 check_assist(
379 expand_glob_import,
380 r"
381mod foo {
382 pub struct Bar;
383 pub struct Baz;
384 pub struct Qux;
385
386 pub fn f() {}
387}
388
389use foo::Bar;
390use foo::{*<|>, f};
391
392fn qux(bar: Bar, baz: Baz) {
393 f();
394}
395",
396 r"
397mod foo {
398 pub struct Bar;
399 pub struct Baz;
400 pub struct Qux;
401
402 pub fn f() {}
403}
404
405use foo::Bar;
406use foo::{f, Baz};
249 407
250fn qux(bar: Bar, baz: Baz) { 408fn qux(bar: Bar, baz: Baz) {
251 f(); 409 f();
@@ -260,7 +418,7 @@ fn qux(bar: Bar, baz: Baz) {
260 expand_glob_import, 418 expand_glob_import,
261 r" 419 r"
262mod foo { 420mod foo {
263 mod bar { 421 pub mod bar {
264 pub struct Bar; 422 pub struct Bar;
265 pub struct Baz; 423 pub struct Baz;
266 pub struct Qux; 424 pub struct Qux;
@@ -268,7 +426,7 @@ mod foo {
268 pub fn f() {} 426 pub fn f() {}
269 } 427 }
270 428
271 mod baz { 429 pub mod baz {
272 pub fn g() {} 430 pub fn g() {}
273 } 431 }
274} 432}
@@ -282,7 +440,7 @@ fn qux(bar: Bar, baz: Baz) {
282", 440",
283 r" 441 r"
284mod foo { 442mod foo {
285 mod bar { 443 pub mod bar {
286 pub struct Bar; 444 pub struct Bar;
287 pub struct Baz; 445 pub struct Baz;
288 pub struct Qux; 446 pub struct Qux;
@@ -290,55 +448,359 @@ mod foo {
290 pub fn f() {} 448 pub fn f() {}
291 } 449 }
292 450
293 mod baz { 451 pub mod baz {
294 pub fn g() {} 452 pub fn g() {}
295 } 453 }
296} 454}
297 455
298use foo::{bar::{Baz, Bar, f}, baz::*}; 456use foo::{bar::{f, Baz, Bar}, baz::*};
299 457
300fn qux(bar: Bar, baz: Baz) { 458fn qux(bar: Bar, baz: Baz) {
301 f(); 459 f();
302 g(); 460 g();
303} 461}
304", 462",
305 ) 463 );
464
465 check_assist(
466 expand_glob_import,
467 r"
468mod foo {
469 pub mod bar {
470 pub struct Bar;
471 pub struct Baz;
472 pub struct Qux;
473
474 pub fn f() {}
475 }
476
477 pub mod baz {
478 pub fn g() {}
479 }
480}
481
482use foo::{bar::{Bar, Baz, f}, baz::*<|>};
483
484fn qux(bar: Bar, baz: Baz) {
485 f();
486 g();
487}
488",
489 r"
490mod foo {
491 pub mod bar {
492 pub struct Bar;
493 pub struct Baz;
494 pub struct Qux;
495
496 pub fn f() {}
497 }
498
499 pub mod baz {
500 pub fn g() {}
501 }
502}
503
504use foo::{bar::{Bar, Baz, f}, baz::g};
505
506fn qux(bar: Bar, baz: Baz) {
507 f();
508 g();
509}
510",
511 );
512
513 check_assist(
514 expand_glob_import,
515 r"
516mod foo {
517 pub mod bar {
518 pub struct Bar;
519 pub struct Baz;
520 pub struct Qux;
521
522 pub fn f() {}
523 }
524
525 pub mod baz {
526 pub fn g() {}
527
528 pub mod qux {
529 pub fn h() {}
530 pub fn m() {}
531
532 pub mod q {
533 pub fn j() {}
534 }
535 }
536 }
537}
538
539use foo::{
540 bar::{*, f},
541 baz::{g, qux::*<|>}
542};
543
544fn qux(bar: Bar, baz: Baz) {
545 f();
546 g();
547 h();
548 q::j();
549}
550",
551 r"
552mod foo {
553 pub mod bar {
554 pub struct Bar;
555 pub struct Baz;
556 pub struct Qux;
557
558 pub fn f() {}
559 }
560
561 pub mod baz {
562 pub fn g() {}
563
564 pub mod qux {
565 pub fn h() {}
566 pub fn m() {}
567
568 pub mod q {
569 pub fn j() {}
570 }
571 }
572 }
573}
574
575use foo::{
576 bar::{*, f},
577 baz::{g, qux::{q, h}}
578};
579
580fn qux(bar: Bar, baz: Baz) {
581 f();
582 g();
583 h();
584 q::j();
585}
586",
587 );
588
589 check_assist(
590 expand_glob_import,
591 r"
592mod foo {
593 pub mod bar {
594 pub struct Bar;
595 pub struct Baz;
596 pub struct Qux;
597
598 pub fn f() {}
599 }
600
601 pub mod baz {
602 pub fn g() {}
603
604 pub mod qux {
605 pub fn h() {}
606 pub fn m() {}
607
608 pub mod q {
609 pub fn j() {}
610 }
611 }
612 }
613}
614
615use foo::{
616 bar::{*, f},
617 baz::{g, qux::{h, q::*<|>}}
618};
619
620fn qux(bar: Bar, baz: Baz) {
621 f();
622 g();
623 h();
624 j();
625}
626",
627 r"
628mod foo {
629 pub mod bar {
630 pub struct Bar;
631 pub struct Baz;
632 pub struct Qux;
633
634 pub fn f() {}
635 }
636
637 pub mod baz {
638 pub fn g() {}
639
640 pub mod qux {
641 pub fn h() {}
642 pub fn m() {}
643
644 pub mod q {
645 pub fn j() {}
646 }
647 }
648 }
649}
650
651use foo::{
652 bar::{*, f},
653 baz::{g, qux::{h, q::j}}
654};
655
656fn qux(bar: Bar, baz: Baz) {
657 f();
658 g();
659 h();
660 j();
661}
662",
663 );
664
665 check_assist(
666 expand_glob_import,
667 r"
668mod foo {
669 pub mod bar {
670 pub struct Bar;
671 pub struct Baz;
672 pub struct Qux;
673
674 pub fn f() {}
675 }
676
677 pub mod baz {
678 pub fn g() {}
679
680 pub mod qux {
681 pub fn h() {}
682 pub fn m() {}
683
684 pub mod q {
685 pub fn j() {}
686 }
687 }
688 }
689}
690
691use foo::{
692 bar::{*, f},
693 baz::{g, qux::{q::j, *<|>}}
694};
695
696fn qux(bar: Bar, baz: Baz) {
697 f();
698 g();
699 h();
700 j();
701}
702",
703 r"
704mod foo {
705 pub mod bar {
706 pub struct Bar;
707 pub struct Baz;
708 pub struct Qux;
709
710 pub fn f() {}
711 }
712
713 pub mod baz {
714 pub fn g() {}
715
716 pub mod qux {
717 pub fn h() {}
718 pub fn m() {}
719
720 pub mod q {
721 pub fn j() {}
722 }
723 }
724 }
725}
726
727use foo::{
728 bar::{*, f},
729 baz::{g, qux::{q::j, h}}
730};
731
732fn qux(bar: Bar, baz: Baz) {
733 f();
734 g();
735 h();
736 j();
737}
738",
739 );
306 } 740 }
307 741
308 #[test] 742 #[test]
309 fn expanding_glob_import_with_macro_defs() { 743 fn expanding_glob_import_with_macro_defs() {
744 // FIXME: this is currently fails because `Definition::find_usages` ignores macros
745 // https://github.com/rust-analyzer/rust-analyzer/issues/3484
746 //
747 // check_assist(
748 // expand_glob_import,
749 // r"
750 // //- /lib.rs crate:foo
751 // #[macro_export]
752 // macro_rules! bar {
753 // () => ()
754 // }
755
756 // pub fn baz() {}
757
758 // //- /main.rs crate:main deps:foo
759 // use foo::*<|>;
760
761 // fn main() {
762 // bar!();
763 // baz();
764 // }
765 // ",
766 // r"
767 // use foo::{bar, baz};
768
769 // fn main() {
770 // bar!();
771 // baz();
772 // }
773 // ",
774 // )
775 }
776
777 #[test]
778 fn expanding_glob_import_with_trait_method_uses() {
310 check_assist( 779 check_assist(
311 expand_glob_import, 780 expand_glob_import,
312 r" 781 r"
313//- /lib.rs crate:foo 782//- /lib.rs crate:foo
314#[macro_export] 783pub trait Tr {
315macro_rules! bar { 784 fn method(&self) {}
316 () => ()
317} 785}
318 786impl Tr for () {}
319pub fn baz() {}
320 787
321//- /main.rs crate:main deps:foo 788//- /main.rs crate:main deps:foo
322use foo::*<|>; 789use foo::*<|>;
323 790
324fn main() { 791fn main() {
325 bar!(); 792 ().method();
326 baz();
327} 793}
328", 794",
329 r" 795 r"
330use foo::{bar, baz}; 796use foo::Tr;
331 797
332fn main() { 798fn main() {
333 bar!(); 799 ().method();
334 baz();
335} 800}
336", 801",
337 ) 802 );
338 }
339 803
340 #[test]
341 fn expanding_glob_import_with_trait_method_uses() {
342 check_assist( 804 check_assist(
343 expand_glob_import, 805 expand_glob_import,
344 r" 806 r"
@@ -348,6 +810,11 @@ pub trait Tr {
348} 810}
349impl Tr for () {} 811impl Tr for () {}
350 812
813pub trait Tr2 {
814 fn method2(&self) {}
815}
816impl Tr2 for () {}
817
351//- /main.rs crate:main deps:foo 818//- /main.rs crate:main deps:foo
352use foo::*<|>; 819use foo::*<|>;
353 820
@@ -362,7 +829,42 @@ fn main() {
362 ().method(); 829 ().method();
363} 830}
364", 831",
365 ) 832 );
833 }
834
835 #[test]
836 fn expanding_is_not_applicable_if_target_module_is_not_accessible_from_current_scope() {
837 check_assist_not_applicable(
838 expand_glob_import,
839 r"
840mod foo {
841 mod bar {
842 pub struct Bar;
843 }
844}
845
846use foo::bar::*<|>;
847
848fn baz(bar: Bar) {}
849",
850 );
851
852 check_assist_not_applicable(
853 expand_glob_import,
854 r"
855mod foo {
856 mod bar {
857 pub mod baz {
858 pub struct Baz;
859 }
860 }
861}
862
863use foo::bar::baz::*<|>;
864
865fn qux(baz: Baz) {}
866",
867 );
366 } 868 }
367 869
368 #[test] 870 #[test]
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs
index f0e047538..294256297 100644
--- a/crates/assists/src/handlers/invert_if.rs
+++ b/crates/assists/src/handlers/invert_if.rs
@@ -106,4 +106,22 @@ mod tests {
106 "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }", 106 "fn f() { i<|>f let Some(_) = Some(1) { 1 } else { 0 } }",
107 ) 107 )
108 } 108 }
109
110 #[test]
111 fn invert_if_option_case() {
112 check_assist(
113 invert_if,
114 "fn f() { if<|> doc_style.is_some() { Class::DocComment } else { Class::Comment } }",
115 "fn f() { if doc_style.is_none() { Class::Comment } else { Class::DocComment } }",
116 )
117 }
118
119 #[test]
120 fn invert_if_result_case() {
121 check_assist(
122 invert_if,
123 "fn f() { i<|>f doc_style.is_err() { Class::Err } else { Class::Ok } }",
124 "fn f() { if doc_style.is_ok() { Class::Ok } else { Class::Err } }",
125 )
126 }
109} 127}
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index d071d6502..e15c982e7 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -11,7 +11,7 @@ use syntax::{
11 ast::{self, make, NameOwner}, 11 ast::{self, make, NameOwner},
12 AstNode, Direction, 12 AstNode, Direction,
13 SyntaxKind::*, 13 SyntaxKind::*,
14 SyntaxNode, TextSize, T, 14 SyntaxNode, SyntaxText, TextSize, T,
15}; 15};
16 16
17use crate::assist_config::SnippetCap; 17use crate::assist_config::SnippetCap;
@@ -179,6 +179,25 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
179 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), 179 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
180 _ => None, 180 _ => None,
181 }, 181 },
182 ast::Expr::MethodCallExpr(mce) => {
183 const IS_SOME_TEXT: &str = "is_some";
184 const IS_NONE_TEXT: &str = "is_none";
185 const IS_OK_TEXT: &str = "is_ok";
186 const IS_ERR_TEXT: &str = "is_err";
187
188 let name = mce.name_ref()?;
189 let name_text = name.text();
190
191 let caller = || -> Option<SyntaxText> { Some(mce.receiver()?.syntax().text()) };
192
193 match name_text {
194 x if x == IS_SOME_TEXT => make::expr_method_call(IS_NONE_TEXT, caller),
195 x if x == IS_NONE_TEXT => make::expr_method_call(IS_SOME_TEXT, caller),
196 x if x == IS_OK_TEXT => make::expr_method_call(IS_ERR_TEXT, caller),
197 x if x == IS_ERR_TEXT => make::expr_method_call(IS_OK_TEXT, caller),
198 _ => None,
199 }
200 }
182 ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), 201 ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
183 // FIXME: 202 // FIXME:
184 // ast::Expr::Literal(true | false ) 203 // ast::Expr::Literal(true | false )
diff --git a/crates/base_db/Cargo.toml b/crates/base_db/Cargo.toml
index 7347d7528..f7bfcb0d7 100644
--- a/crates/base_db/Cargo.toml
+++ b/crates/base_db/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "base_db" 2name = "base_db"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -12,10 +13,10 @@ doctest = false
12salsa = "0.15.2" 13salsa = "0.15.2"
13rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
14 15
15syntax = { path = "../syntax" } 16syntax = { path = "../syntax", version = "0.0.0" }
16cfg = { path = "../cfg" } 17cfg = { path = "../cfg", version = "0.0.0" }
17profile = { path = "../profile" } 18profile = { path = "../profile", version = "0.0.0" }
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
19test_utils = { path = "../test_utils" } 20test_utils = { path = "../test_utils", version = "0.0.0" }
20vfs = { path = "../vfs" } 21vfs = { path = "../vfs", version = "0.0.0" }
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml
index d2ea551d1..a6785ee8e 100644
--- a/crates/cfg/Cargo.toml
+++ b/crates/cfg/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "cfg" 2name = "cfg"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -11,7 +12,7 @@ doctest = false
11[dependencies] 12[dependencies]
12rustc-hash = "1.1.0" 13rustc-hash = "1.1.0"
13 14
14tt = { path = "../tt" } 15tt = { path = "../tt", version = "0.0.0" }
15 16
16[dev-dependencies] 17[dev-dependencies]
17mbe = { path = "../mbe" } 18mbe = { path = "../mbe" }
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 262a66e4e..c230fc1e2 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "flycheck" 2name = "flycheck"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ cargo_metadata = "0.11.1"
15serde_json = "1.0.48" 16serde_json = "1.0.48"
16jod-thread = "0.1.1" 17jod-thread = "0.1.1"
17 18
18toolchain = { path = "../toolchain" } 19toolchain = { path = "../toolchain", version = "0.0.0" }
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index d0ddca27f..72f941c46 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir" 2name = "hir"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,11 +17,11 @@ arrayvec = "0.5.1"
16itertools = "0.9.0" 17itertools = "0.9.0"
17url = "2.1.1" 18url = "2.1.1"
18 19
19stdx = { path = "../stdx" } 20stdx = { path = "../stdx", version = "0.0.0" }
20syntax = { path = "../syntax" } 21syntax = { path = "../syntax", version = "0.0.0" }
21base_db = { path = "../base_db" } 22base_db = { path = "../base_db", version = "0.0.0" }
22profile = { path = "../profile" } 23profile = { path = "../profile", version = "0.0.0" }
23hir_expand = { path = "../hir_expand" } 24hir_expand = { path = "../hir_expand", version = "0.0.0" }
24hir_def = { path = "../hir_def" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
25hir_ty = { path = "../hir_ty" } 26hir_ty = { path = "../hir_ty", version = "0.0.0" }
26tt = { path = "../tt" } 27tt = { path = "../tt", version = "0.0.0" }
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 57745322f..011e4612c 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_def" 2name = "hir_def"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -20,16 +21,16 @@ itertools = "0.9.0"
20indexmap = "1.4.0" 21indexmap = "1.4.0"
21smallvec = "1.4.0" 22smallvec = "1.4.0"
22 23
23stdx = { path = "../stdx" } 24stdx = { path = "../stdx", version = "0.0.0" }
24arena = { path = "../arena" } 25arena = { path = "../arena", version = "0.0.0" }
25base_db = { path = "../base_db" } 26base_db = { path = "../base_db", version = "0.0.0" }
26syntax = { path = "../syntax" } 27syntax = { path = "../syntax", version = "0.0.0" }
27profile = { path = "../profile" } 28profile = { path = "../profile", version = "0.0.0" }
28hir_expand = { path = "../hir_expand" } 29hir_expand = { path = "../hir_expand", version = "0.0.0" }
29test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils", version = "0.0.0" }
30mbe = { path = "../mbe" } 31mbe = { path = "../mbe", version = "0.0.0" }
31cfg = { path = "../cfg" } 32cfg = { path = "../cfg", version = "0.0.0" }
32tt = { path = "../tt" } 33tt = { path = "../tt", version = "0.0.0" }
33 34
34[dev-dependencies] 35[dev-dependencies]
35expect-test = "0.1" 36expect-test = "0.1"
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 391ab5d39..6a503d785 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -557,6 +557,10 @@ impl Ctx {
557 let statik = self.lower_static(&ast)?; 557 let statik = self.lower_static(&ast)?;
558 statik.into() 558 statik.into()
559 } 559 }
560 ast::ExternItem::TypeAlias(ty) => {
561 let id = self.lower_type_alias(&ty)?;
562 id.into()
563 }
560 ast::ExternItem::MacroCall(_) => return None, 564 ast::ExternItem::MacroCall(_) => return None,
561 }; 565 };
562 self.add_attrs(id.into(), attrs); 566 self.add_attrs(id.into(), attrs);
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 8aaf7a158..5ca30dac9 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -46,6 +46,7 @@ union U { to_be: bool, not_to_be: u8 }
46enum E { V } 46enum E { V }
47 47
48extern { 48extern {
49 type Ext;
49 static EXT: u8; 50 static EXT: u8;
50 fn ext(); 51 fn ext();
51} 52}
@@ -65,6 +66,7 @@ extern {
65 Baz: t v 66 Baz: t v
66 E: t 67 E: t
67 EXT: v 68 EXT: v
69 Ext: t
68 U: t 70 U: t
69 ext: v 71 ext: v
70 "#]], 72 "#]],
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index 1c4699291..9fad2ab94 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_expand" 2name = "hir_expand"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,11 +14,11 @@ log = "0.4.8"
13either = "1.5.3" 14either = "1.5.3"
14rustc-hash = "1.0.0" 15rustc-hash = "1.0.0"
15 16
16arena = { path = "../arena" } 17arena = { path = "../arena", version = "0.0.0" }
17base_db = { path = "../base_db" } 18base_db = { path = "../base_db", version = "0.0.0" }
18syntax = { path = "../syntax" } 19syntax = { path = "../syntax", version = "0.0.0" }
19parser = { path = "../parser" } 20parser = { path = "../parser", version = "0.0.0" }
20profile = { path = "../profile" } 21profile = { path = "../profile", version = "0.0.0" }
21tt = { path = "../tt" } 22tt = { path = "../tt", version = "0.0.0" }
22mbe = { path = "../mbe" } 23mbe = { path = "../mbe", version = "0.0.0" }
23test_utils = { path = "../test_utils"} 24test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 06da0d0ec..33e155a70 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "hir_ty" 2name = "hir_ty"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -20,14 +21,14 @@ chalk-solve = { version = "0.23.0" }
20chalk-ir = { version = "0.23.0" } 21chalk-ir = { version = "0.23.0" }
21chalk-recursive = { version = "0.23.0" } 22chalk-recursive = { version = "0.23.0" }
22 23
23stdx = { path = "../stdx" } 24stdx = { path = "../stdx", version = "0.0.0" }
24hir_def = { path = "../hir_def" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
25hir_expand = { path = "../hir_expand" } 26hir_expand = { path = "../hir_expand", version = "0.0.0" }
26arena = { path = "../arena" } 27arena = { path = "../arena", version = "0.0.0" }
27base_db = { path = "../base_db" } 28base_db = { path = "../base_db", version = "0.0.0" }
28profile = { path = "../profile" } 29profile = { path = "../profile", version = "0.0.0" }
29syntax = { path = "../syntax" } 30syntax = { path = "../syntax", version = "0.0.0" }
30test_utils = { path = "../test_utils" } 31test_utils = { path = "../test_utils", version = "0.0.0" }
31 32
32[dev-dependencies] 33[dev-dependencies]
33expect-test = "0.1" 34expect-test = "0.1"
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 9ecf43e5a..e61c276df 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "ide" 2name = "ide"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -18,20 +19,20 @@ oorandom = "11.1.2"
18pulldown-cmark-to-cmark = "5.0.0" 19pulldown-cmark-to-cmark = "5.0.0"
19pulldown-cmark = {version = "0.7.2", default-features = false} 20pulldown-cmark = {version = "0.7.2", default-features = false}
20 21
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx", version = "0.0.0" }
22syntax = { path = "../syntax" } 23syntax = { path = "../syntax", version = "0.0.0" }
23text_edit = { path = "../text_edit" } 24text_edit = { path = "../text_edit", version = "0.0.0" }
24base_db = { path = "../base_db" } 25base_db = { path = "../base_db", version = "0.0.0" }
25ide_db = { path = "../ide_db" } 26ide_db = { path = "../ide_db", version = "0.0.0" }
26cfg = { path = "../cfg" } 27cfg = { path = "../cfg", version = "0.0.0" }
27profile = { path = "../profile" } 28profile = { path = "../profile", version = "0.0.0" }
28test_utils = { path = "../test_utils" } 29test_utils = { path = "../test_utils", version = "0.0.0" }
29assists = { path = "../assists" } 30assists = { path = "../assists", version = "0.0.0" }
30ssr = { path = "../ssr" } 31ssr = { path = "../ssr", version = "0.0.0" }
31 32
32# ide should depend only on the top-level `hir` package. if you need 33# ide should depend only on the top-level `hir` package. if you need
33# something from some `hir_xxx` subpackage, reexport the API via `hir`. 34# something from some `hir_xxx` subpackage, reexport the API via `hir`.
34hir = { path = "../hir" } 35hir = { path = "../hir", version = "0.0.0" }
35 36
36[dev-dependencies] 37[dev-dependencies]
37expect-test = "0.1" 38expect-test = "0.1"
diff --git a/crates/ide/src/completion.rs b/crates/ide/src/completion.rs
index 25e580d80..33bed6991 100644
--- a/crates/ide/src/completion.rs
+++ b/crates/ide/src/completion.rs
@@ -92,7 +92,7 @@ pub use crate::completion::{
92/// already present, it should give all possible variants for the identifier at 92/// already present, it should give all possible variants for the identifier at
93/// the caret. In other words, for 93/// the caret. In other words, for
94/// 94///
95/// ```no-run 95/// ```no_run
96/// fn f() { 96/// fn f() {
97/// let foo = 92; 97/// let foo = 92;
98/// let _ = bar<|> 98/// let _ = bar<|>
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 4139f329e..dd59d9e70 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -160,7 +160,7 @@ fn runnable_fn(
160 RunnableKind::Test { test_id, attr } 160 RunnableKind::Test { test_id, attr }
161 } else if fn_def.has_atom_attr("bench") { 161 } else if fn_def.has_atom_attr("bench") {
162 RunnableKind::Bench { test_id } 162 RunnableKind::Bench { test_id }
163 } else if has_doc_test(&fn_def) { 163 } else if has_runnable_doc_test(&fn_def) {
164 RunnableKind::DocTest { test_id } 164 RunnableKind::DocTest { test_id }
165 } else { 165 } else {
166 return None; 166 return None;
@@ -211,8 +211,13 @@ fn has_test_related_attribute(fn_def: &ast::Fn) -> bool {
211 .any(|attribute_text| attribute_text.contains("test")) 211 .any(|attribute_text| attribute_text.contains("test"))
212} 212}
213 213
214fn has_doc_test(fn_def: &ast::Fn) -> bool { 214fn has_runnable_doc_test(fn_def: &ast::Fn) -> bool {
215 fn_def.doc_comment_text().map_or(false, |comment| comment.contains("```")) 215 fn_def.doc_comment_text().map_or(false, |comments_text| {
216 comments_text.contains("```")
217 && !comments_text.contains("```ignore")
218 && !comments_text.contains("```no_run")
219 && !comments_text.contains("```compile_fail")
220 })
216} 221}
217 222
218fn runnable_mod( 223fn runnable_mod(
@@ -417,6 +422,21 @@ fn main() {}
417/// let x = 5; 422/// let x = 5;
418/// ``` 423/// ```
419fn foo() {} 424fn foo() {}
425
426/// ```no_run
427/// let z = 55;
428/// ```
429fn should_have_no_runnable() {}
430
431/// ```ignore
432/// let z = 55;
433/// ```
434fn should_have_no_runnable_2() {}
435
436/// ```compile_fail
437/// let z = 55;
438/// ```
439fn should_have_no_runnable_3() {}
420"#, 440"#,
421 &[&BIN, &DOCTEST], 441 &[&BIN, &DOCTEST],
422 expect![[r#" 442 expect![[r#"
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 692fb6415..320fb15e5 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "ide_db" 2name = "ide_db"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -19,12 +20,12 @@ rustc-hash = "1.1.0"
19once_cell = "1.3.1" 20once_cell = "1.3.1"
20either = "1.5.3" 21either = "1.5.3"
21 22
22stdx = { path = "../stdx" } 23stdx = { path = "../stdx", version = "0.0.0" }
23syntax = { path = "../syntax" } 24syntax = { path = "../syntax", version = "0.0.0" }
24text_edit = { path = "../text_edit" } 25text_edit = { path = "../text_edit", version = "0.0.0" }
25base_db = { path = "../base_db" } 26base_db = { path = "../base_db", version = "0.0.0" }
26profile = { path = "../profile" } 27profile = { path = "../profile", version = "0.0.0" }
27test_utils = { path = "../test_utils" } 28test_utils = { path = "../test_utils", version = "0.0.0" }
28# ide should depend only on the top-level `hir` package. if you need 29# ide should depend only on the top-level `hir` package. if you need
29# something from some `hir_xxx` subpackage, reexport the API via `hir`. 30# something from some `hir_xxx` subpackage, reexport the API via `hir`.
30hir = { path = "../hir" } 31hir = { path = "../hir", version = "0.0.0" }
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 1aba8b7c4..af80e2be3 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "mbe" 2name = "mbe"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,9 +14,9 @@ rustc-hash = "1.1.0"
13smallvec = "1.2.0" 14smallvec = "1.2.0"
14log = "0.4.8" 15log = "0.4.8"
15 16
16syntax = { path = "../syntax" } 17syntax = { path = "../syntax", version = "0.0.0" }
17parser = { path = "../parser" } 18parser = { path = "../parser", version = "0.0.0" }
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
19 20
20[dev-dependencies] 21[dev-dependencies]
21test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 358be92d1..1610e0d23 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "parser" 2name = "parser"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml
index 5ac18d63b..da26938c1 100644
--- a/crates/paths/Cargo.toml
+++ b/crates/paths/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "paths" 2name = "paths"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index a3a4c1103..75f67a22e 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "proc_macro_api" 2name = "proc_macro_api"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ log = "0.4.8"
15crossbeam-channel = "0.4.0" 16crossbeam-channel = "0.4.0"
16jod-thread = "0.1.1" 17jod-thread = "0.1.1"
17 18
18tt = { path = "../tt" } 19tt = { path = "../tt", version = "0.0.0" }
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml
index a468b5560..fb84e04ae 100644
--- a/crates/proc_macro_srv/Cargo.toml
+++ b/crates/proc_macro_srv/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "proc_macro_srv" 2name = "proc_macro_srv"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,10 +14,10 @@ goblin = "0.2.1"
13libloading = "0.6.0" 14libloading = "0.6.0"
14memmap = "0.7" 15memmap = "0.7"
15 16
16tt = { path = "../tt" } 17tt = { path = "../tt", version = "0.0.0" }
17mbe = { path = "../mbe" } 18mbe = { path = "../mbe", version = "0.0.0" }
18proc_macro_api = { path = "../proc_macro_api" } 19proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
19test_utils = { path = "../test_utils" } 20test_utils = { path = "../test_utils", version = "0.0.0" }
20 21
21[dev-dependencies] 22[dev-dependencies]
22cargo_metadata = "0.11.1" 23cargo_metadata = "0.11.1"
diff --git a/crates/proc_macro_test/Cargo.toml b/crates/proc_macro_test/Cargo.toml
index 7b0f64f31..753443be2 100644
--- a/crates/proc_macro_test/Cargo.toml
+++ b/crates/proc_macro_test/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.0"
4license = "MIT OR Apache-2.0" 4license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6edition = "2018" 6edition = "2018"
7publish = false
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml
index e271e3a56..261172d61 100644
--- a/crates/profile/Cargo.toml
+++ b/crates/profile/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "profile" 2name = "profile"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -14,7 +15,7 @@ cfg-if = "0.1.10"
14libc = "0.2.73" 15libc = "0.2.73"
15backtrace = { version = "0.3.44", optional = true } 16backtrace = { version = "0.3.44", optional = true }
16 17
17arena = { path = "../arena" } 18arena = { path = "../arena", version = "0.0.0" }
18 19
19[target.'cfg(target_os = "linux")'.dependencies] 20[target.'cfg(target_os = "linux")'.dependencies]
20perf-event = "0.4" 21perf-event = "0.4"
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml
index 386f72f41..8bee398d9 100644
--- a/crates/project_model/Cargo.toml
+++ b/crates/project_model/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "project_model" 2name = "project_model"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,10 +17,10 @@ serde = { version = "1.0.106", features = ["derive"] }
16serde_json = "1.0.48" 17serde_json = "1.0.48"
17anyhow = "1.0.26" 18anyhow = "1.0.26"
18 19
19arena = { path = "../arena" } 20arena = { path = "../arena", version = "0.0.0" }
20cfg = { path = "../cfg" } 21cfg = { path = "../cfg", version = "0.0.0" }
21base_db = { path = "../base_db" } 22base_db = { path = "../base_db", version = "0.0.0" }
22toolchain = { path = "../toolchain" } 23toolchain = { path = "../toolchain", version = "0.0.0" }
23proc_macro_api = { path = "../proc_macro_api" } 24proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
24paths = { path = "../paths" } 25paths = { path = "../paths", version = "0.0.0" }
25stdx = { path = "../stdx" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 068a961dc..044686a99 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "rust-analyzer" 2name = "rust-analyzer"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6autobins = false 7autobins = false
@@ -32,26 +33,26 @@ rayon = "1.3.1"
32mimalloc = { version = "0.1.19", default-features = false, optional = true } 33mimalloc = { version = "0.1.19", default-features = false, optional = true }
33lsp-server = "0.3.3" 34lsp-server = "0.3.3"
34 35
35stdx = { path = "../stdx" } 36stdx = { path = "../stdx", version = "0.0.0" }
36flycheck = { path = "../flycheck" } 37flycheck = { path = "../flycheck", version = "0.0.0" }
37ide = { path = "../ide" } 38ide = { path = "../ide", version = "0.0.0" }
38profile = { path = "../profile" } 39profile = { path = "../profile", version = "0.0.0" }
39project_model = { path = "../project_model" } 40project_model = { path = "../project_model", version = "0.0.0" }
40syntax = { path = "../syntax" } 41syntax = { path = "../syntax", version = "0.0.0" }
41text_edit = { path = "../text_edit" } 42text_edit = { path = "../text_edit", version = "0.0.0" }
42vfs = { path = "../vfs" } 43vfs = { path = "../vfs", version = "0.0.0" }
43vfs-notify = { path = "../vfs-notify" } 44vfs-notify = { path = "../vfs-notify", version = "0.0.0" }
44cfg = { path = "../cfg" } 45cfg = { path = "../cfg", version = "0.0.0" }
45toolchain = { path = "../toolchain" } 46toolchain = { path = "../toolchain", version = "0.0.0" }
46 47
47# This should only be used in CLI 48# This should only be used in CLI
48base_db = { path = "../base_db" } 49base_db = { path = "../base_db", version = "0.0.0" }
49ide_db = { path = "../ide_db" } 50ide_db = { path = "../ide_db", version = "0.0.0" }
50ssr = { path = "../ssr" } 51ssr = { path = "../ssr", version = "0.0.0" }
51hir = { path = "../hir" } 52hir = { path = "../hir", version = "0.0.0" }
52hir_def = { path = "../hir_def" } 53hir_def = { path = "../hir_def", version = "0.0.0" }
53hir_ty = { path = "../hir_ty" } 54hir_ty = { path = "../hir_ty", version = "0.0.0" }
54proc_macro_srv = { path = "../proc_macro_srv" } 55proc_macro_srv = { path = "../proc_macro_srv", version = "0.0.0" }
55 56
56[target.'cfg(windows)'.dependencies] 57[target.'cfg(windows)'.dependencies]
57winapi = "0.3.8" 58winapi = "0.3.8"
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml
index 22b6af0fa..6f0f53d70 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -14,12 +14,12 @@ doctest = false
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15itertools = "0.9.0" 15itertools = "0.9.0"
16 16
17text_edit = { path = "../text_edit" } 17text_edit = { path = "../text_edit", version = "0.0.0" }
18syntax = { path = "../syntax" } 18syntax = { path = "../syntax", version = "0.0.0" }
19base_db = { path = "../base_db" } 19base_db = { path = "../base_db", version = "0.0.0" }
20ide_db = { path = "../ide_db" } 20ide_db = { path = "../ide_db", version = "0.0.0" }
21hir = { path = "../hir" } 21hir = { path = "../hir", version = "0.0.0" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils", version = "0.0.0" }
23 23
24[dev-dependencies] 24[dev-dependencies]
25expect-test = "0.1" 25expect-test = "0.1"
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index b186b46f2..8d7a51156 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "stdx" 2name = "stdx"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 6818f3ad8..2c1bdb295 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -23,9 +23,9 @@ once_cell = "1.3.1"
23smol_str = { version = "0.1.15", features = ["serde"] } 23smol_str = { version = "0.1.15", features = ["serde"] }
24serde = { version = "1.0.106", features = ["derive"] } 24serde = { version = "1.0.106", features = ["derive"] }
25 25
26stdx = { path = "../stdx" } 26stdx = { path = "../stdx", version = "0.0.0" }
27text_edit = { path = "../text_edit" } 27text_edit = { path = "../text_edit", version = "0.0.0" }
28parser = { path = "../parser" } 28parser = { path = "../parser", version = "0.0.0" }
29 29
30[dev-dependencies] 30[dev-dependencies]
31walkdir = "2.3.1" 31walkdir = "2.3.1"
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 6254b38ba..ea199f9b8 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -32,7 +32,7 @@ pub fn ancestors_at_offset(
32/// imprecise: if the cursor is strictly between two nodes of the desired type, 32/// imprecise: if the cursor is strictly between two nodes of the desired type,
33/// as in 33/// as in
34/// 34///
35/// ```no-run 35/// ```no_run
36/// struct Foo {}|struct Bar; 36/// struct Foo {}|struct Bar;
37/// ``` 37/// ```
38/// 38///
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 6317407c6..d6af5755c 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1380,6 +1380,7 @@ pub enum ExternItem {
1380 Fn(Fn), 1380 Fn(Fn),
1381 MacroCall(MacroCall), 1381 MacroCall(MacroCall),
1382 Static(Static), 1382 Static(Static),
1383 TypeAlias(TypeAlias),
1383} 1384}
1384impl ast::AttrsOwner for ExternItem {} 1385impl ast::AttrsOwner for ExternItem {}
1385impl ast::NameOwner for ExternItem {} 1386impl ast::NameOwner for ExternItem {}
@@ -3339,10 +3340,13 @@ impl From<MacroCall> for ExternItem {
3339impl From<Static> for ExternItem { 3340impl From<Static> for ExternItem {
3340 fn from(node: Static) -> ExternItem { ExternItem::Static(node) } 3341 fn from(node: Static) -> ExternItem { ExternItem::Static(node) }
3341} 3342}
3343impl From<TypeAlias> for ExternItem {
3344 fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
3345}
3342impl AstNode for ExternItem { 3346impl AstNode for ExternItem {
3343 fn can_cast(kind: SyntaxKind) -> bool { 3347 fn can_cast(kind: SyntaxKind) -> bool {
3344 match kind { 3348 match kind {
3345 FN | MACRO_CALL | STATIC => true, 3349 FN | MACRO_CALL | STATIC | TYPE_ALIAS => true,
3346 _ => false, 3350 _ => false,
3347 } 3351 }
3348 } 3352 }
@@ -3351,6 +3355,7 @@ impl AstNode for ExternItem {
3351 FN => ExternItem::Fn(Fn { syntax }), 3355 FN => ExternItem::Fn(Fn { syntax }),
3352 MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }), 3356 MACRO_CALL => ExternItem::MacroCall(MacroCall { syntax }),
3353 STATIC => ExternItem::Static(Static { syntax }), 3357 STATIC => ExternItem::Static(Static { syntax }),
3358 TYPE_ALIAS => ExternItem::TypeAlias(TypeAlias { syntax }),
3354 _ => return None, 3359 _ => return None,
3355 }; 3360 };
3356 Some(res) 3361 Some(res)
@@ -3360,6 +3365,7 @@ impl AstNode for ExternItem {
3360 ExternItem::Fn(it) => &it.syntax, 3365 ExternItem::Fn(it) => &it.syntax,
3361 ExternItem::MacroCall(it) => &it.syntax, 3366 ExternItem::MacroCall(it) => &it.syntax,
3362 ExternItem::Static(it) => &it.syntax, 3367 ExternItem::Static(it) => &it.syntax,
3368 ExternItem::TypeAlias(it) => &it.syntax,
3363 } 3369 }
3364 } 3370 }
3365} 3371}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index d20c085aa..7958721e2 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -7,7 +7,7 @@
7use itertools::Itertools; 7use itertools::Itertools;
8use stdx::format_to; 8use stdx::format_to;
9 9
10use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; 10use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxText, SyntaxToken};
11 11
12pub fn name(text: &str) -> ast::Name { 12pub fn name(text: &str) -> ast::Name {
13 ast_from_text(&format!("mod {};", text)) 13 ast_from_text(&format!("mod {};", text))
@@ -137,6 +137,12 @@ pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
137pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { 137pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
138 expr_from_text(&format!("{}{}", f, arg_list)) 138 expr_from_text(&format!("{}{}", f, arg_list))
139} 139}
140pub fn expr_method_call<F>(text: &str, caller: F) -> Option<ast::Expr>
141where
142 F: FnOnce() -> Option<SyntaxText>,
143{
144 try_expr_from_text(&format!("{}.{}()", caller()?, text))
145}
140fn expr_from_text(text: &str) -> ast::Expr { 146fn expr_from_text(text: &str) -> ast::Expr {
141 ast_from_text(&format!("const C: () = {};", text)) 147 ast_from_text(&format!("const C: () = {};", text))
142} 148}
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index 45e5fb97f..93eecc678 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "test_utils" 2name = "test_utils"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -15,4 +16,4 @@ text-size = "1.0.0"
15serde_json = "1.0.48" 16serde_json = "1.0.48"
16rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
17 18
18stdx = { path = "../stdx" } 19stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/text_edit/Cargo.toml b/crates/text_edit/Cargo.toml
index a69b1ef2b..8aadc1875 100644
--- a/crates/text_edit/Cargo.toml
+++ b/crates/text_edit/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "text_edit" 2name = "text_edit"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/toolchain/Cargo.toml b/crates/toolchain/Cargo.toml
index 4856668f8..dcf0bfca0 100644
--- a/crates/toolchain/Cargo.toml
+++ b/crates/toolchain/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "toolchain" 2name = "toolchain"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml
index dfcdcf03e..5b8972ea3 100644
--- a/crates/tt/Cargo.toml
+++ b/crates/tt/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "tt" 2name = "tt"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -13,4 +14,4 @@ doctest = false
13# to reduce number of compilations 14# to reduce number of compilations
14smol_str = { version = "0.1.15", features = ["serde"] } 15smol_str = { version = "0.1.15", features = ["serde"] }
15 16
16stdx = { path = "../stdx" } 17stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml
index c1e53f4b1..54b51faab 100644
--- a/crates/vfs-notify/Cargo.toml
+++ b/crates/vfs-notify/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "vfs-notify" 2name = "vfs-notify"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -16,5 +17,5 @@ walkdir = "2.3.1"
16crossbeam-channel = "0.4.0" 17crossbeam-channel = "0.4.0"
17notify = "5.0.0-pre.3" 18notify = "5.0.0-pre.3"
18 19
19vfs = { path = "../vfs" } 20vfs = { path = "../vfs", version = "0.0.0" }
20paths = { path = "../paths" } 21paths = { path = "../paths", version = "0.0.0" }
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index 9ae8f19b6..c318a68f7 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -1,6 +1,7 @@
1[package] 1[package]
2name = "vfs" 2name = "vfs"
3version = "0.0.0" 3version = "0.0.0"
4description = "TBD"
4license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
5authors = ["rust-analyzer developers"] 6authors = ["rust-analyzer developers"]
6edition = "2018" 7edition = "2018"
@@ -12,4 +13,4 @@ doctest = false
12rustc-hash = "1.0" 13rustc-hash = "1.0"
13fst = "0.4" 14fst = "0.4"
14 15
15paths = { path = "../paths" } 16paths = { path = "../paths", version = "0.0.0" }
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 44f0956c2..bb99c4855 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -181,6 +181,30 @@ fn frobnicate(walrus: Option<Walrus>) {
181} 181}
182``` 182```
183 183
184# Early Returns
185
186Do use early returns
187
188```rust
189// Good
190fn foo() -> Option<Bar> {
191 if !condition() {
192 return None;
193 }
194
195 Some(...)
196}
197
198// Not as good
199fn foo() -> Option<Bar> {
200 if condition() {
201 Some(...)
202 } else {
203 None
204 }
205}
206```
207
184# Getters & Setters 208# Getters & Setters
185 209
186If a field can have any value without breaking invariants, make the field public. 210If a field can have any value without breaking invariants, make the field public.
@@ -189,7 +213,7 @@ Never provide setters.
189 213
190Getters should return borrowed data: 214Getters should return borrowed data:
191 215
192``` 216```rust
193struct Person { 217struct Person {
194 // Invariant: never empty 218 // Invariant: never empty
195 first_name: String, 219 first_name: String,
@@ -231,6 +255,41 @@ if words.len() != 2 {
231} 255}
232``` 256```
233 257
258# Avoid Monomorphization
259
260Rust uses monomorphization to compile generic code, meaning that for each instantiation of a generic functions with concrete types, the function is compiled afresh, *per crate*.
261This allows for exceptionally good performance, but leads to increased compile times.
262Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot.
263Compile time **does not** obey this rule -- all code has to be compiled.
264For this reason, avoid making a lot of code type parametric, *especially* on the boundaries between crates.
265
266```rust
267// Good
268fn frbonicate(f: impl FnMut()) {
269 frobnicate_impl(&mut f)
270}
271fn frobnicate_impl(f: &mut dyn FnMut()) {
272 // lots of code
273}
274
275// Not as good
276fn frbonicate(f: impl FnMut()) {
277 // lots of code
278}
279```
280
281Avoid `AsRef` polymorphism, it pays back only for widely used libraries:
282
283```rust
284// Good
285fn frbonicate(f: &Path) {
286}
287
288// Not as good
289fn frbonicate(f: impl AsRef<Path>) {
290}
291```
292
234# Documentation 293# Documentation
235 294
236For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. 295For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines.
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
index 681eaa9c9..5eba2728d 100644
--- a/editors/code/src/net.ts
+++ b/editors/code/src/net.ts
@@ -134,6 +134,14 @@ async function downloadFile(
134 134
135 await pipeline(srcStream, destFileStream); 135 await pipeline(srcStream, destFileStream);
136 136
137 // Don't apply the workaround in fixed versions of nodejs, since the process
138 // freezes on them, the process waits for no-longer emitted `close` event.
139 // The fix was applied in commit 7eed9d6bcc in v13.11.0
140 // See the nodejs changelog:
141 // https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md
142 const [, major, minor] = /v(\d+)\.(\d+)\.(\d+)/.exec(process.version)!;
143 if (+major > 13 || (+major === 13 && +minor >= 11)) return;
144
137 await new Promise<void>(resolve => { 145 await new Promise<void>(resolve => {
138 destFileStream.on("close", resolve); 146 destFileStream.on("close", resolve);
139 destFileStream.destroy(); 147 destFileStream.destroy();
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index e9edbdd10..0750b5657 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -15,7 +15,7 @@ flate2 = "1.0"
15pico-args = "0.3.1" 15pico-args = "0.3.1"
16proc-macro2 = "1.0.8" 16proc-macro2 = "1.0.8"
17quote = "1.0.2" 17quote = "1.0.2"
18ungrammar = "1.1.1" 18ungrammar = "1.1.3"
19walkdir = "2.3.1" 19walkdir = "2.3.1"
20write-json = "0.1.0" 20write-json = "0.1.0"
21# Avoid adding more dependencies to this crate 21# Avoid adding more dependencies to this crate
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
deleted file mode 100644
index aca23890c..000000000
--- a/xtask/src/codegen/rust.ungram
+++ /dev/null
@@ -1,587 +0,0 @@
1//*************************//
2// Names, Paths and Macros //
3//*************************//
4
5Name =
6 'ident'
7
8NameRef =
9 'ident' | 'int_number'
10
11Path =
12 (qualifier:Path '::')? segment:PathSegment
13
14PathSegment =
15 'crate' | 'self' | 'super'
16| '::' NameRef
17| NameRef GenericArgList?
18| NameRef ParamList RetType?
19| '<' PathType ('as' PathType)? '>'
20
21GenericArgList =
22 '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'
23
24GenericArg =
25 TypeArg
26| AssocTypeArg
27| LifetimeArg
28| ConstArg
29
30TypeArg =
31 Type
32
33AssocTypeArg =
34 NameRef (':' TypeBoundList | '=' Type)
35
36LifetimeArg =
37 'lifetime'
38
39ConstArg =
40 Expr
41
42MacroCall =
43 Attr* Path '!' Name? TokenTree ';'?
44
45TokenTree =
46 '(' ')'
47| '{' '}'
48| '[' ']'
49
50MacroItems =
51 Item*
52
53MacroStmts =
54 statements:Stmt*
55 Expr?
56
57//*************************//
58// Items //
59//*************************//
60
61SourceFile =
62 'shebang'?
63 Attr*
64 Item*
65
66Item =
67 Const
68| Enum
69| ExternBlock
70| ExternCrate
71| Fn
72| Impl
73| MacroCall
74| Module
75| Static
76| Struct
77| Trait
78| TypeAlias
79| Union
80| Use
81
82Module =
83 Attr* Visibility? 'mod' Name
84 (ItemList | ';')
85
86ItemList =
87 '{' Attr* Item* '}'
88
89ExternCrate =
90 Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
91
92Rename =
93 'as' (Name | '_')
94
95Use =
96 Attr* Visibility? 'use' UseTree ';'
97
98UseTree =
99 (Path? '::')? ('*' | UseTreeList )
100| Path Rename?
101
102UseTreeList =
103 '{' (UseTree (',' UseTree)* ','?)? '}'
104
105Fn =
106 Attr* Visibility?
107 'default'? ('async' | 'const')? 'unsafe'? Abi?
108 'fn' Name GenericParamList? ParamList RetType?
109 WhereClause?
110 (body:BlockExpr | ';')
111
112Abi =
113 'extern' 'string'?
114
115ParamList =
116 '('(
117 SelfParam
118 | (SelfParam ',')? (Param (',' Param)* ','?)?
119 )')'
120
121SelfParam =
122 Attr* (
123 ('&' 'lifetime'?)? 'mut'? 'self'
124 | 'mut'? 'self' ':' Type
125 )
126
127Param =
128 Attr* (
129 Pat (':' Type)
130 | Type
131 | '...'
132 )
133
134RetType =
135 '->' Type
136
137TypeAlias =
138 Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
139 '=' Type ';'
140
141Struct =
142 Attr* Visibility? 'struct' Name GenericParamList? (
143 WhereClause? (RecordFieldList | ';')
144 | TupleFieldList WhereClause? ';'
145 )
146
147RecordFieldList =
148 '{' fields:(RecordField (',' RecordField)* ','?)? '}'
149
150RecordField =
151 Attr* Visibility? Name ':' Type
152
153TupleFieldList =
154 '(' fields:(TupleField (',' TupleField)* ','?)? ')'
155
156TupleField =
157 Attr* Visibility? Type
158
159FieldList =
160 RecordFieldList
161| TupleFieldList
162
163Enum =
164 Attr* Visibility? 'enum' Name GenericParamList? WhereClause?
165 VariantList
166
167VariantList =
168 '{' (Variant (',' Variant)* ','?)? '}'
169
170Variant =
171 Attr* Visibility? Name FieldList ('=' Expr)?
172
173Union =
174 Attr* Visibility? 'union' Name GenericParamList? WhereClause?
175 RecordFieldList
176
177AdtDef =
178 Enum
179| Struct
180| Union
181
182Const =
183 Attr* Visibility? 'default'? 'const' (Name | '_') ':' Type
184 '=' body:Expr ';'
185
186Static =
187 Attr* Visibility? 'static'? 'mut'? Name ':' Type
188 '=' body:Expr ';'
189
190Trait =
191 Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList
192 (':' TypeBoundList?)? WhereClause
193 AssocItemList
194
195AssocItemList =
196 '{' Attr* AssocItem* '}'
197
198AssocItem =
199 Const
200| Fn
201| MacroCall
202| TypeAlias
203
204Impl =
205 Attr* Visibility?
206 'default'? 'unsafe'? 'impl' 'const'? GenericParamList?
207 ('!'? target_trait:Type 'for')? target_type:Type
208 WhereClause?
209 AssocItemList
210
211ExternBlock =
212 Attr* Abi ExternItemList
213
214ExternItemList =
215 '{' Attr* ExternItem* '}'
216
217ExternItem =
218 Fn | Static | MacroCall
219
220GenericParamList =
221 '<' (GenericParam (',' GenericParam)* ','?)? '>'
222
223GenericParam =
224 ConstParam
225| LifetimeParam
226| TypeParam
227
228TypeParam =
229 Attr* Name (':' TypeBoundList?)?
230 ('=' default_type:Type)?
231
232ConstParam =
233 Attr* 'const' Name ':' Type
234 ('=' default_val:Expr)?
235
236LifetimeParam =
237 Attr* 'lifetime' (':' TypeBoundList?)?
238
239WhereClause =
240 'where' predicates:(WherePred (',' WherePred)* ','?)
241
242WherePred =
243 ('for' GenericParamList)? ('lifetime' | Type) ':' TypeBoundList
244
245Visibility =
246 'pub' ('('
247 'super'
248 | 'self'
249 | 'crate'
250 | 'in' Path
251 ')')?
252
253Attr =
254 '#' '!'? '[' Path ('=' Literal | TokenTree)? ']'
255
256//****************************//
257// Statements and Expressions //
258//****************************//
259
260Stmt =
261 ExprStmt
262| Item
263| LetStmt
264
265LetStmt =
266 Attr* 'let' Pat (':' Type)?
267 '=' initializer:Expr ';'
268
269ExprStmt =
270 Attr* Expr ';'?
271
272Expr =
273 ArrayExpr
274| AwaitExpr
275| BinExpr
276| BlockExpr
277| BoxExpr
278| BreakExpr
279| CallExpr
280| CastExpr
281| ClosureExpr
282| ContinueExpr
283| EffectExpr
284| FieldExpr
285| ForExpr
286| IfExpr
287| IndexExpr
288| Literal
289| LoopExpr
290| MacroCall
291| MatchExpr
292| MethodCallExpr
293| ParenExpr
294| PathExpr
295| PrefixExpr
296| RangeExpr
297| RecordExpr
298| RefExpr
299| ReturnExpr
300| TryExpr
301| TupleExpr
302| WhileExpr
303
304Literal =
305 Attr* value:(
306 'int_number' | 'float_number'
307 | 'string' | 'raw_string'
308 | 'byte_string' | 'raw_byte_string'
309 | 'true' | 'false'
310 | 'char' | 'byte'
311 )
312
313PathExpr =
314 Attr* Path
315
316BlockExpr =
317 '{'
318 Attr*
319 statements:Stmt*
320 Expr?
321 '}'
322
323RefExpr =
324 Attr* '&' ('raw' |'mut' | 'const') Expr
325
326TryExpr =
327 Attr* Expr '?'
328
329EffectExpr =
330 Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr
331
332PrefixExpr =
333 Attr* op:('-' | '!' | '*') Expr
334
335BinExpr =
336 Attr*
337 lhs:Expr
338 op:(
339 '||' | '&&'
340 | '==' | '!=' | '<=' | '>=' | '<' | '>'
341 | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&'
342 | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^='
343 )
344 rhs:Expr
345
346CastExpr =
347 Attr* Expr 'as' Type
348
349ParenExpr =
350 Attr* '(' Attr* Expr ')'
351
352ArrayExpr =
353 Attr* '[' Attr* (
354 (Expr (',' Expr)* ','?)?
355 | Expr ';' Expr
356 ) ']'
357
358IndexExpr =
359 Attr* base:Expr '[' index:Expr ']'
360
361TupleExpr =
362 Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')'
363
364RecordExpr =
365 Path RecordExprFieldList
366
367RecordExprFieldList =
368 '{'
369 Attr*
370 fields:(RecordExprField (',' RecordExprField)* ','?)
371 ('..' spread:Expr)?
372 '}'
373
374RecordExprField =
375 Attr* NameRef (':' Expr)?
376
377CallExpr =
378 Attr* Expr ArgList
379
380ArgList =
381 '(' args:(Expr (',' Expr)* ','?)? ')'
382
383MethodCallExpr =
384 Attr* Expr '.' NameRef GenericArgList? ArgList
385
386FieldExpr =
387 Attr* Expr '.' NameRef
388
389ClosureExpr =
390 Attr* 'static'? 'async'? 'move'? ParamList RetType?
391 body:Expr
392
393IfExpr =
394 Attr* 'if' Condition then_branch:BlockExpr
395 ('else' else_branch:(IfExpr | BlockExpr))?
396
397Condition =
398 'let' Pat '=' Expr
399| Expr
400
401LoopExpr =
402 Attr* Label? 'loop'
403 loop_body:BlockExpr
404
405ForExpr =
406 Attr* Label? 'for' Pat 'in' iterable:Expr
407 loop_body:BlockExpr
408
409WhileExpr =
410 Attr* Label? 'while' Condition
411 loop_body:BlockExpr
412
413Label =
414 'lifetime'
415
416BreakExpr =
417 Attr* 'break' 'lifetime'? Expr?
418
419ContinueExpr =
420 Attr* 'continue' 'lifetime'?
421
422RangeExpr =
423 Attr* start:Expr? op:('..' | '..=') end:Expr?
424
425MatchExpr =
426 Attr* 'match' Expr MatchArmList
427
428MatchArmList =
429 '{'
430 Attr*
431 arms:MatchArm*
432 '}'
433
434MatchArm =
435 Attr* Pat guard:MatchGuard? '=>' Expr ','?
436
437MatchGuard =
438 'if' Expr
439
440ReturnExpr =
441 Attr* 'return' Expr?
442
443AwaitExpr =
444 Attr* Expr '.' 'await'
445
446BoxExpr =
447 Attr* 'box' Expr
448
449//*************************//
450// Types //
451//*************************//
452
453Type =
454 ArrayType
455| DynTraitType
456| FnPointerType
457| ForType
458| ImplTraitType
459| InferType
460| NeverType
461| ParenType
462| PathType
463| PointerType
464| ReferenceType
465| SliceType
466| TupleType
467
468ParenType =
469 '(' Type ')'
470
471NeverType =
472 '!'
473
474PathType =
475 Path
476
477TupleType =
478 '(' fields:(Type (',' Type)* ','?)? ')'
479
480PointerType =
481 '*' ('const' | 'mut') Type
482
483ReferenceType =
484 '&' 'lifetime'? 'mut'? Type
485
486ArrayType =
487 '[' Type ';' Expr ']'
488
489SliceType =
490 '[' Type ']'
491
492InferType =
493 '_'
494
495FnPointerType =
496 'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
497
498ForType =
499 'for' GenericParamList Type
500
501ImplTraitType =
502 'impl' TypeBoundList
503
504DynTraitType =
505 'dyn' TypeBoundList
506
507TypeBoundList =
508 bounds:(TypeBound ('+' TypeBound)* '+'?)
509
510TypeBound =
511 'lifetime'
512| '?'? Type
513
514//************************//
515// Patterns //
516//************************//
517
518Pat =
519 IdentPat
520| BoxPat
521| RestPat
522| LiteralPat
523| MacroPat
524| OrPat
525| ParenPat
526| PathPat
527| WildcardPat
528| RangePat
529| RecordPat
530| RefPat
531| SlicePat
532| TuplePat
533| TupleStructPat
534
535LiteralPat =
536 Literal
537
538IdentPat =
539 Attr* 'ref'? 'mut'? Name ('@' Pat)?
540
541WildcardPat =
542 '_'
543
544RangePat =
545 start:Pat op:('..' | '..=') end:Pat
546
547RefPat =
548 '&' 'mut'? Pat
549
550RecordPat =
551 Path RecordPatFieldList
552
553RecordPatFieldList =
554 '{'
555 fields:(RecordPatField (',' RecordPatField)* ','?)
556 '..'?
557 '}'
558
559RecordPatField =
560 Attr* (NameRef ':')? Pat
561
562TupleStructPat =
563 Path '(' fields:(Pat (',' Pat)* ','?)? ')'
564
565TuplePat =
566 '(' fields:(Pat (',' Pat)* ','?)? ')'
567
568ParenPat =
569 '(' Pat ')'
570
571SlicePat =
572 '[' (Pat (',' Pat)* ','?)? ']'
573
574PathPat =
575 Path
576
577OrPat =
578 (Pat ('|' Pat)* '|'?)
579
580BoxPat =
581 'box' Pat
582
583RestPat =
584 '..'
585
586MacroPat =
587 MacroCall