diff options
43 files changed, 409 insertions, 260 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0ca0b7b63..c378014f0 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1319,9 +1319,9 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" | |||
1319 | 1319 | ||
1320 | [[package]] | 1320 | [[package]] |
1321 | name = "rowan" | 1321 | name = "rowan" |
1322 | version = "0.13.0-pre.3" | 1322 | version = "0.13.0-pre.5" |
1323 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1324 | checksum = "77d315d6f2e33f294412faa47f41b56bdb3fce72c999d384b5e78c8d21551b13" | 1324 | checksum = "32a5fc82ed0b7e7fba157331f0d8f64abd73bced6e7ac2a4dfa0c4cf0ab584e8" |
1325 | dependencies = [ | 1325 | dependencies = [ |
1326 | "countme", | 1326 | "countme", |
1327 | "hashbrown", | 1327 | "hashbrown", |
@@ -1411,9 +1411,9 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" | |||
1411 | 1411 | ||
1412 | [[package]] | 1412 | [[package]] |
1413 | name = "salsa" | 1413 | name = "salsa" |
1414 | version = "0.16.0" | 1414 | version = "0.16.1" |
1415 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1416 | checksum = "d8fadca2ab5de17acf66d744f4888049ca8f1bb9b8a1ab8afd9d032cc959c5dc" | 1416 | checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" |
1417 | dependencies = [ | 1417 | dependencies = [ |
1418 | "crossbeam-utils", | 1418 | "crossbeam-utils", |
1419 | "indexmap", | 1419 | "indexmap", |
diff --git a/Cargo.toml b/Cargo.toml index 46c64d35c..d34251fc0 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -27,3 +27,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. | |||
27 | # chalk-recursive = { path = "../chalk/chalk-recursive" } | 27 | # chalk-recursive = { path = "../chalk/chalk-recursive" } |
28 | 28 | ||
29 | # ungrammar = { path = "../ungrammar" } | 29 | # ungrammar = { path = "../ungrammar" } |
30 | |||
31 | # salsa = { path = "../salsa" } | ||
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 4a11622fc..e8fa3c56e 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -112,7 +112,7 @@ fn resolve_doc_path( | |||
112 | AttrDefId::MacroDefId(_) => return None, | 112 | AttrDefId::MacroDefId(_) => return None, |
113 | }; | 113 | }; |
114 | let path = ast::Path::parse(link).ok()?; | 114 | let path = ast::Path::parse(link).ok()?; |
115 | let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); | 115 | let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic()).unwrap(); |
116 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); | 116 | let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); |
117 | if resolved == PerNs::none() { | 117 | if resolved == PerNs::none() { |
118 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { | 118 | if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d8ccfde0c..f876339de 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1666,7 +1666,7 @@ impl Impl { | |||
1666 | .value | 1666 | .value |
1667 | .attrs() | 1667 | .attrs() |
1668 | .filter_map(|it| { | 1668 | .filter_map(|it| { |
1669 | let path = ModPath::from_src(it.path()?, &hygenic)?; | 1669 | let path = ModPath::from_src(db.upcast(), it.path()?, &hygenic)?; |
1670 | if path.as_ident()?.to_string() == "derive" { | 1670 | if path.as_ident()?.to_string() == "derive" { |
1671 | Some(it) | 1671 | Some(it) |
1672 | } else { | 1672 | } else { |
@@ -1744,6 +1744,10 @@ impl Type { | |||
1744 | } | 1744 | } |
1745 | } | 1745 | } |
1746 | 1746 | ||
1747 | pub fn strip_references(&self) -> Type { | ||
1748 | self.derived(self.ty.strip_references().clone()) | ||
1749 | } | ||
1750 | |||
1747 | pub fn is_unknown(&self) -> bool { | 1751 | pub fn is_unknown(&self) -> bool { |
1748 | self.ty.is_unknown() | 1752 | self.ty.is_unknown() |
1749 | } | 1753 | } |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 0895bd6f1..b5c65808e 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -283,7 +283,7 @@ impl SourceAnalyzer { | |||
283 | 283 | ||
284 | // This must be a normal source file rather than macro file. | 284 | // This must be a normal source file rather than macro file. |
285 | let hygiene = Hygiene::new(db.upcast(), self.file_id); | 285 | let hygiene = Hygiene::new(db.upcast(), self.file_id); |
286 | let ctx = body::LowerCtx::with_hygiene(&hygiene); | 286 | let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); |
287 | let hir_path = Path::from_src(path.clone(), &ctx)?; | 287 | let hir_path = Path::from_src(path.clone(), &ctx)?; |
288 | 288 | ||
289 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we | 289 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 0171d8a92..a2479016e 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -95,13 +95,17 @@ impl ops::Deref for AttrsWithOwner { | |||
95 | impl RawAttrs { | 95 | impl RawAttrs { |
96 | pub(crate) const EMPTY: Self = Self { entries: None }; | 96 | pub(crate) const EMPTY: Self = Self { entries: None }; |
97 | 97 | ||
98 | pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { | 98 | pub(crate) fn new( |
99 | db: &dyn DefDatabase, | ||
100 | owner: &dyn ast::AttrsOwner, | ||
101 | hygiene: &Hygiene, | ||
102 | ) -> Self { | ||
99 | let entries = collect_attrs(owner) | 103 | let entries = collect_attrs(owner) |
100 | .enumerate() | 104 | .enumerate() |
101 | .flat_map(|(i, attr)| { | 105 | .flat_map(|(i, attr)| { |
102 | let index = AttrId(i as u32); | 106 | let index = AttrId(i as u32); |
103 | match attr { | 107 | match attr { |
104 | Either::Left(attr) => Attr::from_src(attr, hygiene, index), | 108 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, index), |
105 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 109 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
106 | id: index, | 110 | id: index, |
107 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | 111 | input: Some(AttrInput::Literal(SmolStr::new(doc))), |
@@ -116,7 +120,7 @@ impl RawAttrs { | |||
116 | 120 | ||
117 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { | 121 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { |
118 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | 122 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); |
119 | Self::new(owner.value, &hygiene) | 123 | Self::new(db, owner.value, &hygiene) |
120 | } | 124 | } |
121 | 125 | ||
122 | pub(crate) fn merge(&self, other: Self) -> Self { | 126 | pub(crate) fn merge(&self, other: Self) -> Self { |
@@ -170,7 +174,7 @@ impl RawAttrs { | |||
170 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | 174 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; |
171 | // FIXME hygiene | 175 | // FIXME hygiene |
172 | let hygiene = Hygiene::new_unhygienic(); | 176 | let hygiene = Hygiene::new_unhygienic(); |
173 | Attr::from_src(attr, &hygiene, index) | 177 | Attr::from_src(db, attr, &hygiene, index) |
174 | }); | 178 | }); |
175 | 179 | ||
176 | let cfg_options = &crate_graph[krate].cfg_options; | 180 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -627,8 +631,13 @@ pub enum AttrInput { | |||
627 | } | 631 | } |
628 | 632 | ||
629 | impl Attr { | 633 | impl Attr { |
630 | fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> { | 634 | fn from_src( |
631 | let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); | 635 | db: &dyn DefDatabase, |
636 | ast: ast::Attr, | ||
637 | hygiene: &Hygiene, | ||
638 | id: AttrId, | ||
639 | ) -> Option<Attr> { | ||
640 | let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?); | ||
632 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { | 641 | let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { |
633 | let value = match lit.kind() { | 642 | let value = match lit.kind() { |
634 | ast::LiteralKind::String(string) => string.value()?.into(), | 643 | ast::LiteralKind::String(string) => string.value()?.into(), |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 131f424cc..8360426f1 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -72,7 +72,7 @@ impl CfgExpander { | |||
72 | } | 72 | } |
73 | 73 | ||
74 | pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { | 74 | pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { |
75 | RawAttrs::new(owner, &self.hygiene).filter(db, self.krate) | 75 | RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate) |
76 | } | 76 | } |
77 | 77 | ||
78 | pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { | 78 | pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { |
@@ -192,8 +192,8 @@ impl Expander { | |||
192 | self.current_file_id | 192 | self.current_file_id |
193 | } | 193 | } |
194 | 194 | ||
195 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 195 | fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> { |
196 | let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); | 196 | let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); |
197 | Path::from_src(path, &ctx) | 197 | Path::from_src(path, &ctx) |
198 | } | 198 | } |
199 | 199 | ||
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index c11da30d2..75dc19c11 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -40,23 +40,25 @@ use crate::{ | |||
40 | 40 | ||
41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
42 | 42 | ||
43 | pub struct LowerCtx { | 43 | pub struct LowerCtx<'a> { |
44 | pub db: &'a dyn DefDatabase, | ||
44 | hygiene: Hygiene, | 45 | hygiene: Hygiene, |
45 | file_id: Option<HirFileId>, | 46 | file_id: Option<HirFileId>, |
46 | source_ast_id_map: Option<Arc<AstIdMap>>, | 47 | source_ast_id_map: Option<Arc<AstIdMap>>, |
47 | } | 48 | } |
48 | 49 | ||
49 | impl LowerCtx { | 50 | impl<'a> LowerCtx<'a> { |
50 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | 51 | pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { |
51 | LowerCtx { | 52 | LowerCtx { |
53 | db, | ||
52 | hygiene: Hygiene::new(db.upcast(), file_id), | 54 | hygiene: Hygiene::new(db.upcast(), file_id), |
53 | file_id: Some(file_id), | 55 | file_id: Some(file_id), |
54 | source_ast_id_map: Some(db.ast_id_map(file_id)), | 56 | source_ast_id_map: Some(db.ast_id_map(file_id)), |
55 | } | 57 | } |
56 | } | 58 | } |
57 | 59 | ||
58 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | 60 | pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self { |
59 | LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } | 61 | LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } |
60 | } | 62 | } |
61 | 63 | ||
62 | pub(crate) fn hygiene(&self) -> &Hygiene { | 64 | pub(crate) fn hygiene(&self) -> &Hygiene { |
@@ -145,7 +147,7 @@ impl ExprCollector<'_> { | |||
145 | (self.body, self.source_map) | 147 | (self.body, self.source_map) |
146 | } | 148 | } |
147 | 149 | ||
148 | fn ctx(&self) -> LowerCtx { | 150 | fn ctx(&self) -> LowerCtx<'_> { |
149 | LowerCtx::new(self.db, self.expander.current_file_id) | 151 | LowerCtx::new(self.db, self.expander.current_file_id) |
150 | } | 152 | } |
151 | 153 | ||
@@ -376,7 +378,7 @@ impl ExprCollector<'_> { | |||
376 | ast::Expr::PathExpr(e) => { | 378 | ast::Expr::PathExpr(e) => { |
377 | let path = e | 379 | let path = e |
378 | .path() | 380 | .path() |
379 | .and_then(|path| self.expander.parse_path(path)) | 381 | .and_then(|path| self.expander.parse_path(self.db, path)) |
380 | .map(Expr::Path) | 382 | .map(Expr::Path) |
381 | .unwrap_or(Expr::Missing); | 383 | .unwrap_or(Expr::Missing); |
382 | self.alloc_expr(path, syntax_ptr) | 384 | self.alloc_expr(path, syntax_ptr) |
@@ -408,7 +410,8 @@ impl ExprCollector<'_> { | |||
408 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) | 410 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) |
409 | } | 411 | } |
410 | ast::Expr::RecordExpr(e) => { | 412 | ast::Expr::RecordExpr(e) => { |
411 | let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 413 | let path = |
414 | e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
412 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | 415 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { |
413 | let fields = nfl | 416 | let fields = nfl |
414 | .fields() | 417 | .fields() |
@@ -791,7 +794,8 @@ impl ExprCollector<'_> { | |||
791 | } | 794 | } |
792 | } | 795 | } |
793 | ast::Pat::TupleStructPat(p) => { | 796 | ast::Pat::TupleStructPat(p) => { |
794 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 797 | let path = |
798 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
795 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); | 799 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); |
796 | Pat::TupleStruct { path, args, ellipsis } | 800 | Pat::TupleStruct { path, args, ellipsis } |
797 | } | 801 | } |
@@ -801,7 +805,8 @@ impl ExprCollector<'_> { | |||
801 | Pat::Ref { pat, mutability } | 805 | Pat::Ref { pat, mutability } |
802 | } | 806 | } |
803 | ast::Pat::PathPat(p) => { | 807 | ast::Pat::PathPat(p) => { |
804 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 808 | let path = |
809 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
805 | path.map(Pat::Path).unwrap_or(Pat::Missing) | 810 | path.map(Pat::Path).unwrap_or(Pat::Missing) |
806 | } | 811 | } |
807 | ast::Pat::OrPat(p) => { | 812 | ast::Pat::OrPat(p) => { |
@@ -815,7 +820,8 @@ impl ExprCollector<'_> { | |||
815 | } | 820 | } |
816 | ast::Pat::WildcardPat(_) => Pat::Wild, | 821 | ast::Pat::WildcardPat(_) => Pat::Wild, |
817 | ast::Pat::RecordPat(p) => { | 822 | ast::Pat::RecordPat(p) => { |
818 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); | 823 | let path = |
824 | p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); | ||
819 | let args: Vec<_> = p | 825 | let args: Vec<_> = p |
820 | .record_pat_field_list() | 826 | .record_pat_field_list() |
821 | .expect("every struct should have a field list") | 827 | .expect("every struct should have a field list") |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index c06a37294..858e88038 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -386,7 +386,7 @@ mod tests { | |||
386 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); | 386 | let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); |
387 | let ast_path = | 387 | let ast_path = |
388 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); | 388 | parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); |
389 | let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); | 389 | let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap(); |
390 | 390 | ||
391 | let def_map = module.def_map(&db); | 391 | let def_map = module.def_map(&db); |
392 | let resolved = def_map | 392 | let resolved = def_map |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index eaeca01bd..8d13c7e04 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -88,7 +88,7 @@ impl ItemTree { | |||
88 | let mut item_tree = match_ast! { | 88 | let mut item_tree = match_ast! { |
89 | match syntax { | 89 | match syntax { |
90 | ast::SourceFile(file) => { | 90 | ast::SourceFile(file) => { |
91 | top_attrs = Some(RawAttrs::new(&file, &hygiene)); | 91 | top_attrs = Some(RawAttrs::new(db, &file, &hygiene)); |
92 | ctx.lower_module_items(&file) | 92 | ctx.lower_module_items(&file) |
93 | }, | 93 | }, |
94 | ast::MacroItems(items) => { | 94 | ast::MacroItems(items) => { |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 45b099cf3..5743b3386 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -31,18 +31,20 @@ where | |||
31 | } | 31 | } |
32 | } | 32 | } |
33 | 33 | ||
34 | pub(super) struct Ctx { | 34 | pub(super) struct Ctx<'a> { |
35 | db: &'a dyn DefDatabase, | ||
35 | tree: ItemTree, | 36 | tree: ItemTree, |
36 | hygiene: Hygiene, | 37 | hygiene: Hygiene, |
37 | file: HirFileId, | 38 | file: HirFileId, |
38 | source_ast_id_map: Arc<AstIdMap>, | 39 | source_ast_id_map: Arc<AstIdMap>, |
39 | body_ctx: crate::body::LowerCtx, | 40 | body_ctx: crate::body::LowerCtx<'a>, |
40 | forced_visibility: Option<RawVisibilityId>, | 41 | forced_visibility: Option<RawVisibilityId>, |
41 | } | 42 | } |
42 | 43 | ||
43 | impl Ctx { | 44 | impl<'a> Ctx<'a> { |
44 | pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { | 45 | pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { |
45 | Self { | 46 | Self { |
47 | db, | ||
46 | tree: ItemTree::default(), | 48 | tree: ItemTree::default(), |
47 | hygiene, | 49 | hygiene, |
48 | file, | 50 | file, |
@@ -126,7 +128,7 @@ impl Ctx { | |||
126 | | ast::Item::MacroDef(_) => {} | 128 | | ast::Item::MacroDef(_) => {} |
127 | }; | 129 | }; |
128 | 130 | ||
129 | let attrs = RawAttrs::new(item, &self.hygiene); | 131 | let attrs = RawAttrs::new(self.db, item, &self.hygiene); |
130 | let items = match item { | 132 | let items = match item { |
131 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), | 133 | ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), |
132 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), | 134 | ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), |
@@ -256,7 +258,7 @@ impl Ctx { | |||
256 | for field in fields.fields() { | 258 | for field in fields.fields() { |
257 | if let Some(data) = self.lower_record_field(&field) { | 259 | if let Some(data) = self.lower_record_field(&field) { |
258 | let idx = self.data().fields.alloc(data); | 260 | let idx = self.data().fields.alloc(data); |
259 | self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); | 261 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); |
260 | } | 262 | } |
261 | } | 263 | } |
262 | let end = self.next_field_idx(); | 264 | let end = self.next_field_idx(); |
@@ -276,7 +278,7 @@ impl Ctx { | |||
276 | for (i, field) in fields.fields().enumerate() { | 278 | for (i, field) in fields.fields().enumerate() { |
277 | let data = self.lower_tuple_field(i, &field); | 279 | let data = self.lower_tuple_field(i, &field); |
278 | let idx = self.data().fields.alloc(data); | 280 | let idx = self.data().fields.alloc(data); |
279 | self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); | 281 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); |
280 | } | 282 | } |
281 | let end = self.next_field_idx(); | 283 | let end = self.next_field_idx(); |
282 | IdRange::new(start..end) | 284 | IdRange::new(start..end) |
@@ -321,7 +323,7 @@ impl Ctx { | |||
321 | for variant in variants.variants() { | 323 | for variant in variants.variants() { |
322 | if let Some(data) = self.lower_variant(&variant) { | 324 | if let Some(data) = self.lower_variant(&variant) { |
323 | let idx = self.data().variants.alloc(data); | 325 | let idx = self.data().variants.alloc(data); |
324 | self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene)); | 326 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, &self.hygiene)); |
325 | } | 327 | } |
326 | } | 328 | } |
327 | let end = self.next_variant_idx(); | 329 | let end = self.next_variant_idx(); |
@@ -364,7 +366,7 @@ impl Ctx { | |||
364 | }; | 366 | }; |
365 | let ty = Interned::new(self_type); | 367 | let ty = Interned::new(self_type); |
366 | let idx = self.data().params.alloc(Param::Normal(ty)); | 368 | let idx = self.data().params.alloc(Param::Normal(ty)); |
367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); | 369 | self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, &self.hygiene)); |
368 | has_self_param = true; | 370 | has_self_param = true; |
369 | } | 371 | } |
370 | for param in param_list.params() { | 372 | for param in param_list.params() { |
@@ -376,7 +378,7 @@ impl Ctx { | |||
376 | self.data().params.alloc(Param::Normal(ty)) | 378 | self.data().params.alloc(Param::Normal(ty)) |
377 | } | 379 | } |
378 | }; | 380 | }; |
379 | self.add_attrs(idx.into(), RawAttrs::new(¶m, &self.hygiene)); | 381 | self.add_attrs(idx.into(), RawAttrs::new(self.db, ¶m, &self.hygiene)); |
380 | } | 382 | } |
381 | } | 383 | } |
382 | let end_param = self.next_param_idx(); | 384 | let end_param = self.next_param_idx(); |
@@ -522,10 +524,11 @@ impl Ctx { | |||
522 | let is_unsafe = trait_def.unsafe_token().is_some(); | 524 | let is_unsafe = trait_def.unsafe_token().is_some(); |
523 | let bounds = self.lower_type_bounds(trait_def); | 525 | let bounds = self.lower_type_bounds(trait_def); |
524 | let items = trait_def.assoc_item_list().map(|list| { | 526 | let items = trait_def.assoc_item_list().map(|list| { |
527 | let db = self.db; | ||
525 | self.with_inherited_visibility(visibility, |this| { | 528 | self.with_inherited_visibility(visibility, |this| { |
526 | list.assoc_items() | 529 | list.assoc_items() |
527 | .filter_map(|item| { | 530 | .filter_map(|item| { |
528 | let attrs = RawAttrs::new(&item, &this.hygiene); | 531 | let attrs = RawAttrs::new(db, &item, &this.hygiene); |
529 | this.collect_inner_items(item.syntax()); | 532 | this.collect_inner_items(item.syntax()); |
530 | this.lower_assoc_item(&item).map(|item| { | 533 | this.lower_assoc_item(&item).map(|item| { |
531 | this.add_attrs(ModItem::from(item).into(), attrs); | 534 | this.add_attrs(ModItem::from(item).into(), attrs); |
@@ -567,7 +570,7 @@ impl Ctx { | |||
567 | .filter_map(|item| { | 570 | .filter_map(|item| { |
568 | self.collect_inner_items(item.syntax()); | 571 | self.collect_inner_items(item.syntax()); |
569 | let assoc = self.lower_assoc_item(&item)?; | 572 | let assoc = self.lower_assoc_item(&item)?; |
570 | let attrs = RawAttrs::new(&item, &self.hygiene); | 573 | let attrs = RawAttrs::new(self.db, &item, &self.hygiene); |
571 | self.add_attrs(ModItem::from(assoc).into(), attrs); | 574 | self.add_attrs(ModItem::from(assoc).into(), attrs); |
572 | Some(assoc) | 575 | Some(assoc) |
573 | }) | 576 | }) |
@@ -585,6 +588,7 @@ impl Ctx { | |||
585 | let mut imports = Vec::new(); | 588 | let mut imports = Vec::new(); |
586 | let tree = self.tree.data_mut(); | 589 | let tree = self.tree.data_mut(); |
587 | ModPath::expand_use_item( | 590 | ModPath::expand_use_item( |
591 | self.db, | ||
588 | InFile::new(self.file, use_item.clone()), | 592 | InFile::new(self.file, use_item.clone()), |
589 | &self.hygiene, | 593 | &self.hygiene, |
590 | |path, _use_tree, is_glob, alias| { | 594 | |path, _use_tree, is_glob, alias| { |
@@ -618,7 +622,7 @@ impl Ctx { | |||
618 | } | 622 | } |
619 | 623 | ||
620 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { | 624 | fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { |
621 | let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); | 625 | let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?); |
622 | let ast_id = self.source_ast_id_map.ast_id(m); | 626 | let ast_id = self.source_ast_id_map.ast_id(m); |
623 | let res = MacroCall { path, ast_id }; | 627 | let res = MacroCall { path, ast_id }; |
624 | Some(id(self.data().macro_calls.alloc(res))) | 628 | Some(id(self.data().macro_calls.alloc(res))) |
@@ -647,7 +651,7 @@ impl Ctx { | |||
647 | list.extern_items() | 651 | list.extern_items() |
648 | .filter_map(|item| { | 652 | .filter_map(|item| { |
649 | self.collect_inner_items(item.syntax()); | 653 | self.collect_inner_items(item.syntax()); |
650 | let attrs = RawAttrs::new(&item, &self.hygiene); | 654 | let attrs = RawAttrs::new(self.db, &item, &self.hygiene); |
651 | let id: ModItem = match item { | 655 | let id: ModItem = match item { |
652 | ast::ExternItem::Fn(ast) => { | 656 | ast::ExternItem::Fn(ast) => { |
653 | let func_id = self.lower_function(&ast)?; | 657 | let func_id = self.lower_function(&ast)?; |
@@ -755,7 +759,7 @@ impl Ctx { | |||
755 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { | 759 | fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { |
756 | let vis = match self.forced_visibility { | 760 | let vis = match self.forced_visibility { |
757 | Some(vis) => return vis, | 761 | Some(vis) => return vis, |
758 | None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), | 762 | None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene), |
759 | }; | 763 | }; |
760 | 764 | ||
761 | self.data().vis.alloc(vis) | 765 | self.data().vis.alloc(vis) |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 25694f037..da46f16f7 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
654 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { | 654 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { |
655 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 655 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
656 | let h = Hygiene::new(db.upcast(), self.file_id); | 656 | let h = Hygiene::new(db.upcast(), self.file_id); |
657 | let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h)); | 657 | let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); |
658 | 658 | ||
659 | let path = match error_sink | 659 | let path = match error_sink |
660 | .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) | 660 | .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) |
@@ -712,7 +712,7 @@ fn macro_call_as_call_id( | |||
712 | krate, | 712 | krate, |
713 | macro_call, | 713 | macro_call, |
714 | def, | 714 | def, |
715 | &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), | 715 | &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?), |
716 | error_sink, | 716 | error_sink, |
717 | ) | 717 | ) |
718 | .map(MacroCallId::from) | 718 | .map(MacroCallId::from) |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ba027c44a..1bc72ec1f 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -599,6 +599,7 @@ mod diagnostics { | |||
599 | let mut cur = 0; | 599 | let mut cur = 0; |
600 | let mut tree = None; | 600 | let mut tree = None; |
601 | ModPath::expand_use_item( | 601 | ModPath::expand_use_item( |
602 | db, | ||
602 | InFile::new(ast.file_id, use_item), | 603 | InFile::new(ast.file_id, use_item), |
603 | &hygiene, | 604 | &hygiene, |
604 | |_mod_path, use_tree, _is_glob, _alias| { | 605 | |_mod_path, use_tree, _is_glob, _alias| { |
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 509e1bbbc..227ecd162 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -105,3 +105,55 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { | |||
105 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) | 105 | assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) |
106 | } | 106 | } |
107 | } | 107 | } |
108 | |||
109 | #[test] | ||
110 | fn typing_inside_a_function_should_not_invalidate_expansions() { | ||
111 | let (mut db, pos) = TestDB::with_position( | ||
112 | r#" | ||
113 | //- /lib.rs | ||
114 | macro_rules! m { | ||
115 | ($ident:ident) => { | ||
116 | fn $ident() { }; | ||
117 | } | ||
118 | } | ||
119 | mod foo; | ||
120 | |||
121 | //- /foo/mod.rs | ||
122 | pub mod bar; | ||
123 | |||
124 | //- /foo/bar.rs | ||
125 | m!(X); | ||
126 | fn quux() { 1$0 } | ||
127 | m!(Y); | ||
128 | m!(Z); | ||
129 | "#, | ||
130 | ); | ||
131 | let krate = db.test_crate(); | ||
132 | { | ||
133 | let events = db.log_executed(|| { | ||
134 | let crate_def_map = db.crate_def_map(krate); | ||
135 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
136 | assert_eq!(module_data.scope.resolutions().count(), 4); | ||
137 | }); | ||
138 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | ||
139 | assert_eq!(n_recalculated_item_trees, 6); | ||
140 | } | ||
141 | |||
142 | let new_text = r#" | ||
143 | m!(X); | ||
144 | fn quux() { 92 } | ||
145 | m!(Y); | ||
146 | m!(Z); | ||
147 | "#; | ||
148 | db.set_file_text(pos.file_id, Arc::new(new_text.to_string())); | ||
149 | |||
150 | { | ||
151 | let events = db.log_executed(|| { | ||
152 | let crate_def_map = db.crate_def_map(krate); | ||
153 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
154 | assert_eq!(module_data.scope.resolutions().count(), 4); | ||
155 | }); | ||
156 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | ||
157 | assert_eq!(n_recalculated_item_trees, 1); | ||
158 | } | ||
159 | } | ||
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 509f77850..a43441b1c 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -7,7 +7,7 @@ use std::{ | |||
7 | sync::Arc, | 7 | sync::Arc, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{ | 12 | use hir_expand::{ |
13 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
@@ -47,8 +47,8 @@ pub enum ImportAlias { | |||
47 | } | 47 | } |
48 | 48 | ||
49 | impl ModPath { | 49 | impl ModPath { |
50 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 50 | pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
51 | let ctx = LowerCtx::with_hygiene(hygiene); | 51 | let ctx = LowerCtx::with_hygiene(db, hygiene); |
52 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) | 52 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) |
53 | } | 53 | } |
54 | 54 | ||
@@ -64,12 +64,13 @@ impl ModPath { | |||
64 | 64 | ||
65 | /// Calls `cb` with all paths, represented by this use item. | 65 | /// Calls `cb` with all paths, represented by this use item. |
66 | pub(crate) fn expand_use_item( | 66 | pub(crate) fn expand_use_item( |
67 | db: &dyn DefDatabase, | ||
67 | item_src: InFile<ast::Use>, | 68 | item_src: InFile<ast::Use>, |
68 | hygiene: &Hygiene, | 69 | hygiene: &Hygiene, |
69 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), | 70 | mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), |
70 | ) { | 71 | ) { |
71 | if let Some(tree) = item_src.value.use_tree() { | 72 | if let Some(tree) = item_src.value.use_tree() { |
72 | lower::lower_use_tree(None, tree, hygiene, &mut cb); | 73 | lower::lower_use_tree(db, None, tree, hygiene, &mut cb); |
73 | } | 74 | } |
74 | } | 75 | } |
75 | 76 | ||
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 1df6db525..a873325b2 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -36,7 +36,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
36 | match segment.kind()? { | 36 | match segment.kind()? { |
37 | ast::PathSegmentKind::Name(name_ref) => { | 37 | ast::PathSegmentKind::Name(name_ref) => { |
38 | // FIXME: this should just return name | 38 | // FIXME: this should just return name |
39 | match hygiene.name_ref_to_name(name_ref) { | 39 | match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) { |
40 | Either::Left(name) => { | 40 | Either::Left(name) => { |
41 | let args = segment | 41 | let args = segment |
42 | .generic_arg_list() | 42 | .generic_arg_list() |
@@ -133,7 +133,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
133 | // We follow what it did anyway :) | 133 | // We follow what it did anyway :) |
134 | if segments.len() == 1 && kind == PathKind::Plain { | 134 | if segments.len() == 1 && kind == PathKind::Plain { |
135 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | 135 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
136 | if let Some(crate_id) = hygiene.local_inner_macros(path) { | 136 | if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) { |
137 | kind = PathKind::DollarCrate(crate_id); | 137 | kind = PathKind::DollarCrate(crate_id); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index e2965b033..ee80e3df3 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs | |||
@@ -7,9 +7,13 @@ use either::Either; | |||
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::{hygiene::Hygiene, name::AsName}; |
8 | use syntax::ast::{self, NameOwner}; | 8 | use syntax::ast::{self, NameOwner}; |
9 | 9 | ||
10 | use crate::path::{ImportAlias, ModPath, PathKind}; | 10 | use crate::{ |
11 | db::DefDatabase, | ||
12 | path::{ImportAlias, ModPath, PathKind}, | ||
13 | }; | ||
11 | 14 | ||
12 | pub(crate) fn lower_use_tree( | 15 | pub(crate) fn lower_use_tree( |
16 | db: &dyn DefDatabase, | ||
13 | prefix: Option<ModPath>, | 17 | prefix: Option<ModPath>, |
14 | tree: ast::UseTree, | 18 | tree: ast::UseTree, |
15 | hygiene: &Hygiene, | 19 | hygiene: &Hygiene, |
@@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree( | |||
21 | None => prefix, | 25 | None => prefix, |
22 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 26 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) |
23 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | 27 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) |
24 | Some(path) => match convert_path(prefix, path, hygiene) { | 28 | Some(path) => match convert_path(db, prefix, path, hygiene) { |
25 | Some(it) => Some(it), | 29 | Some(it) => Some(it), |
26 | None => return, // FIXME: report errors somewhere | 30 | None => return, // FIXME: report errors somewhere |
27 | }, | 31 | }, |
28 | }; | 32 | }; |
29 | for child_tree in use_tree_list.use_trees() { | 33 | for child_tree in use_tree_list.use_trees() { |
30 | lower_use_tree(prefix.clone(), child_tree, hygiene, cb); | 34 | lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb); |
31 | } | 35 | } |
32 | } else { | 36 | } else { |
33 | let alias = tree.rename().map(|a| { | 37 | let alias = tree.rename().map(|a| { |
@@ -47,7 +51,7 @@ pub(crate) fn lower_use_tree( | |||
47 | } | 51 | } |
48 | } | 52 | } |
49 | } | 53 | } |
50 | if let Some(path) = convert_path(prefix, ast_path, hygiene) { | 54 | if let Some(path) = convert_path(db, prefix, ast_path, hygiene) { |
51 | cb(path, &tree, is_glob, alias) | 55 | cb(path, &tree, is_glob, alias) |
52 | } | 56 | } |
53 | // FIXME: report errors somewhere | 57 | // FIXME: report errors somewhere |
@@ -61,9 +65,14 @@ pub(crate) fn lower_use_tree( | |||
61 | } | 65 | } |
62 | } | 66 | } |
63 | 67 | ||
64 | fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { | 68 | fn convert_path( |
69 | db: &dyn DefDatabase, | ||
70 | prefix: Option<ModPath>, | ||
71 | path: ast::Path, | ||
72 | hygiene: &Hygiene, | ||
73 | ) -> Option<ModPath> { | ||
65 | let prefix = if let Some(qual) = path.qualifier() { | 74 | let prefix = if let Some(qual) = path.qualifier() { |
66 | Some(convert_path(prefix, qual, hygiene)?) | 75 | Some(convert_path(db, prefix, qual, hygiene)?) |
67 | } else { | 76 | } else { |
68 | prefix | 77 | prefix |
69 | }; | 78 | }; |
@@ -71,7 +80,7 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> | |||
71 | let segment = path.segment()?; | 80 | let segment = path.segment()?; |
72 | let res = match segment.kind()? { | 81 | let res = match segment.kind()? { |
73 | ast::PathSegmentKind::Name(name_ref) => { | 82 | ast::PathSegmentKind::Name(name_ref) => { |
74 | match hygiene.name_ref_to_name(name_ref) { | 83 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { |
75 | Either::Left(name) => { | 84 | Either::Left(name) => { |
76 | // no type args in use | 85 | // no type args in use |
77 | let mut res = prefix.unwrap_or_else(|| { | 86 | let mut res = prefix.unwrap_or_else(|| { |
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index d4b7c9970..83500f54e 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -33,17 +33,19 @@ impl RawVisibility { | |||
33 | db: &dyn DefDatabase, | 33 | db: &dyn DefDatabase, |
34 | node: InFile<Option<ast::Visibility>>, | 34 | node: InFile<Option<ast::Visibility>>, |
35 | ) -> RawVisibility { | 35 | ) -> RawVisibility { |
36 | Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id)) | 36 | Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id)) |
37 | } | 37 | } |
38 | 38 | ||
39 | pub(crate) fn from_ast_with_hygiene( | 39 | pub(crate) fn from_ast_with_hygiene( |
40 | db: &dyn DefDatabase, | ||
40 | node: Option<ast::Visibility>, | 41 | node: Option<ast::Visibility>, |
41 | hygiene: &Hygiene, | 42 | hygiene: &Hygiene, |
42 | ) -> RawVisibility { | 43 | ) -> RawVisibility { |
43 | Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) | 44 | Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene) |
44 | } | 45 | } |
45 | 46 | ||
46 | pub(crate) fn from_ast_with_hygiene_and_default( | 47 | pub(crate) fn from_ast_with_hygiene_and_default( |
48 | db: &dyn DefDatabase, | ||
47 | node: Option<ast::Visibility>, | 49 | node: Option<ast::Visibility>, |
48 | default: RawVisibility, | 50 | default: RawVisibility, |
49 | hygiene: &Hygiene, | 51 | hygiene: &Hygiene, |
@@ -54,7 +56,7 @@ impl RawVisibility { | |||
54 | }; | 56 | }; |
55 | match node.kind() { | 57 | match node.kind() { |
56 | ast::VisibilityKind::In(path) => { | 58 | ast::VisibilityKind::In(path) => { |
57 | let path = ModPath::from_src(path, hygiene); | 59 | let path = ModPath::from_src(db, path, hygiene); |
58 | let path = match path { | 60 | let path = match path { |
59 | None => return RawVisibility::private(), | 61 | None => return RawVisibility::private(), |
60 | Some(path) => path, | 62 | Some(path) => path, |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 3e9abd8a1..d61f4b31a 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -283,7 +283,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | |||
283 | }; | 283 | }; |
284 | let loc = db.lookup_intern_macro(id); | 284 | let loc = db.lookup_intern_macro(id); |
285 | let arg = loc.kind.arg(db)?; | 285 | let arg = loc.kind.arg(db)?; |
286 | Some(arg.green()) | 286 | Some(arg.green().into()) |
287 | } | 287 | } |
288 | 288 | ||
289 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<TokenExpander>> { | 289 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<TokenExpander>> { |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index ed61ebca3..aca69e35a 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -32,10 +32,14 @@ impl Hygiene { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | // FIXME: this should just return name | 34 | // FIXME: this should just return name |
35 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | 35 | pub fn name_ref_to_name( |
36 | &self, | ||
37 | db: &dyn AstDatabase, | ||
38 | name_ref: ast::NameRef, | ||
39 | ) -> Either<Name, CrateId> { | ||
36 | if let Some(frames) = &self.frames { | 40 | if let Some(frames) = &self.frames { |
37 | if name_ref.text() == "$crate" { | 41 | if name_ref.text() == "$crate" { |
38 | if let Some(krate) = frames.root_crate(name_ref.syntax()) { | 42 | if let Some(krate) = frames.root_crate(db, name_ref.syntax()) { |
39 | return Either::Right(krate); | 43 | return Either::Right(krate); |
40 | } | 44 | } |
41 | } | 45 | } |
@@ -44,15 +48,19 @@ impl Hygiene { | |||
44 | Either::Left(name_ref.as_name()) | 48 | Either::Left(name_ref.as_name()) |
45 | } | 49 | } |
46 | 50 | ||
47 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { | 51 | pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> { |
48 | let mut token = path.syntax().first_token()?.text_range(); | 52 | let mut token = path.syntax().first_token()?.text_range(); |
49 | let frames = self.frames.as_ref()?; | 53 | let frames = self.frames.as_ref()?; |
50 | let mut current = frames.0.clone(); | 54 | let mut current = frames.0.clone(); |
51 | 55 | ||
52 | loop { | 56 | loop { |
53 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; | 57 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?; |
54 | if origin == Origin::Def { | 58 | if origin == Origin::Def { |
55 | return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; | 59 | return if current.local_inner { |
60 | frames.root_crate(db, path.syntax()) | ||
61 | } else { | ||
62 | None | ||
63 | }; | ||
56 | } | 64 | } |
57 | current = current.call_site.as_ref()?.clone(); | 65 | current = current.call_site.as_ref()?.clone(); |
58 | token = mapped.value; | 66 | token = mapped.value; |
@@ -82,13 +90,13 @@ impl HygieneFrames { | |||
82 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) | 90 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) |
83 | } | 91 | } |
84 | 92 | ||
85 | fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> { | 93 | fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> { |
86 | let mut token = node.first_token()?.text_range(); | 94 | let mut token = node.first_token()?.text_range(); |
87 | let mut result = self.0.krate; | 95 | let mut result = self.0.krate; |
88 | let mut current = self.0.clone(); | 96 | let mut current = self.0.clone(); |
89 | 97 | ||
90 | while let Some((mapped, origin)) = | 98 | while let Some((mapped, origin)) = |
91 | current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) | 99 | current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token)) |
92 | { | 100 | { |
93 | result = current.krate; | 101 | result = current.krate; |
94 | 102 | ||
@@ -112,7 +120,7 @@ impl HygieneFrames { | |||
112 | 120 | ||
113 | #[derive(Debug, Clone, PartialEq, Eq)] | 121 | #[derive(Debug, Clone, PartialEq, Eq)] |
114 | struct HygieneInfo { | 122 | struct HygieneInfo { |
115 | arg_start: InFile<TextSize>, | 123 | file: MacroFile, |
116 | /// The `macro_rules!` arguments. | 124 | /// The `macro_rules!` arguments. |
117 | def_start: Option<InFile<TextSize>>, | 125 | def_start: Option<InFile<TextSize>>, |
118 | 126 | ||
@@ -122,12 +130,24 @@ struct HygieneInfo { | |||
122 | } | 130 | } |
123 | 131 | ||
124 | impl HygieneInfo { | 132 | impl HygieneInfo { |
125 | fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { | 133 | fn map_ident_up( |
134 | &self, | ||
135 | db: &dyn AstDatabase, | ||
136 | token: TextRange, | ||
137 | ) -> Option<(InFile<TextRange>, Origin)> { | ||
126 | let token_id = self.exp_map.token_by_range(token)?; | 138 | let token_id = self.exp_map.token_by_range(token)?; |
127 | 139 | ||
128 | let (token_id, origin) = self.macro_def.map_id_up(token_id); | 140 | let (token_id, origin) = self.macro_def.map_id_up(token_id); |
129 | let (token_map, tt) = match origin { | 141 | let (token_map, tt) = match origin { |
130 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), | 142 | mbe::Origin::Call => { |
143 | let call_id = match self.file.macro_call_id { | ||
144 | MacroCallId::LazyMacro(lazy) => lazy, | ||
145 | MacroCallId::EagerMacro(_) => unreachable!(), | ||
146 | }; | ||
147 | let loc: MacroCallLoc = db.lookup_intern_macro(call_id); | ||
148 | let arg_start = loc.kind.arg(db)?.text_range().start(); | ||
149 | (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) | ||
150 | } | ||
131 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { | 151 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { |
132 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) | 152 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) |
133 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { | 153 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { |
@@ -147,8 +167,6 @@ fn make_hygiene_info( | |||
147 | macro_file: MacroFile, | 167 | macro_file: MacroFile, |
148 | loc: &MacroCallLoc, | 168 | loc: &MacroCallLoc, |
149 | ) -> Option<HygieneInfo> { | 169 | ) -> Option<HygieneInfo> { |
150 | let arg_tt = loc.kind.arg(db)?; | ||
151 | |||
152 | let def_offset = loc.def.ast_id().left().and_then(|id| { | 170 | let def_offset = loc.def.ast_id().left().and_then(|id| { |
153 | let def_tt = match id.to_node(db) { | 171 | let def_tt = match id.to_node(db) { |
154 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | 172 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), |
@@ -161,13 +179,7 @@ fn make_hygiene_info( | |||
161 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; | 179 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; |
162 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 180 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
163 | 181 | ||
164 | Some(HygieneInfo { | 182 | Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map }) |
165 | arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()), | ||
166 | def_start: def_offset, | ||
167 | macro_arg, | ||
168 | macro_def, | ||
169 | exp_map, | ||
170 | }) | ||
171 | } | 183 | } |
172 | 184 | ||
173 | impl HygieneFrame { | 185 | impl HygieneFrame { |
@@ -178,7 +190,8 @@ impl HygieneFrame { | |||
178 | MacroCallId::EagerMacro(_id) => (None, None, false), | 190 | MacroCallId::EagerMacro(_id) => (None, None, false), |
179 | MacroCallId::LazyMacro(id) => { | 191 | MacroCallId::LazyMacro(id) => { |
180 | let loc = db.lookup_intern_macro(id); | 192 | let loc = db.lookup_intern_macro(id); |
181 | let info = make_hygiene_info(db, macro_file, &loc); | 193 | let info = make_hygiene_info(db, macro_file, &loc) |
194 | .map(|info| (loc.kind.file_id(), info)); | ||
182 | match loc.def.kind { | 195 | match loc.def.kind { |
183 | MacroDefKind::Declarative(_) => { | 196 | MacroDefKind::Declarative(_) => { |
184 | (info, Some(loc.def.krate), loc.def.local_inner) | 197 | (info, Some(loc.def.krate), loc.def.local_inner) |
@@ -192,7 +205,7 @@ impl HygieneFrame { | |||
192 | }, | 205 | }, |
193 | }; | 206 | }; |
194 | 207 | ||
195 | let info = match info { | 208 | let (calling_file, info) = match info { |
196 | None => { | 209 | None => { |
197 | return HygieneFrame { | 210 | return HygieneFrame { |
198 | expansion: None, | 211 | expansion: None, |
@@ -206,7 +219,7 @@ impl HygieneFrame { | |||
206 | }; | 219 | }; |
207 | 220 | ||
208 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); | 221 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); |
209 | let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); | 222 | let call_site = Some(db.hygiene_frame(calling_file)); |
210 | 223 | ||
211 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } | 224 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } |
212 | } | 225 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 4fb7d9cf2..1f6edf7a2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -1000,7 +1000,7 @@ impl HirDisplay for TypeRef { | |||
1000 | } | 1000 | } |
1001 | TypeRef::Macro(macro_call) => { | 1001 | TypeRef::Macro(macro_call) => { |
1002 | let macro_call = macro_call.to_node(f.db.upcast()); | 1002 | let macro_call = macro_call.to_node(f.db.upcast()); |
1003 | let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); | 1003 | let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); |
1004 | match macro_call.path() { | 1004 | match macro_call.path() { |
1005 | Some(path) => match Path::from_src(path, &ctx) { | 1005 | Some(path) => match Path::from_src(path, &ctx) { |
1006 | Some(path) => path.hir_fmt(f)?, | 1006 | Some(path) => path.hir_fmt(f)?, |
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs index 2b9ed123c..a03988778 100644..100755 --- a/crates/ide/src/folding_ranges.rs +++ b/crates/ide/src/folding_ranges.rs | |||
@@ -20,6 +20,7 @@ pub enum FoldKind { | |||
20 | Consts, | 20 | Consts, |
21 | Statics, | 21 | Statics, |
22 | Array, | 22 | Array, |
23 | WhereClause, | ||
23 | } | 24 | } |
24 | 25 | ||
25 | #[derive(Debug)] | 26 | #[derive(Debug)] |
@@ -109,6 +110,13 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
109 | res.push(Fold { range, kind: FoldKind::Statics }) | 110 | res.push(Fold { range, kind: FoldKind::Statics }) |
110 | } | 111 | } |
111 | } | 112 | } |
113 | |||
114 | // Fold where clause | ||
115 | if node.kind() == WHERE_CLAUSE { | ||
116 | if let Some(range) = fold_range_for_where_clause(&node) { | ||
117 | res.push(Fold { range, kind: FoldKind::WhereClause }) | ||
118 | } | ||
119 | } | ||
112 | } | 120 | } |
113 | } | 121 | } |
114 | } | 122 | } |
@@ -241,6 +249,23 @@ fn contiguous_range_for_comment( | |||
241 | } | 249 | } |
242 | } | 250 | } |
243 | 251 | ||
252 | fn fold_range_for_where_clause(node: &SyntaxNode) -> Option<TextRange> { | ||
253 | let first_where_pred = node.first_child(); | ||
254 | let last_where_pred = node.last_child(); | ||
255 | |||
256 | if first_where_pred != last_where_pred { | ||
257 | let mut it = node.descendants_with_tokens(); | ||
258 | if let (Some(_where_clause), Some(where_kw), Some(last_comma)) = | ||
259 | (it.next(), it.next(), it.last()) | ||
260 | { | ||
261 | let start = where_kw.text_range().end(); | ||
262 | let end = last_comma.text_range().end(); | ||
263 | return Some(TextRange::new(start, end)); | ||
264 | } | ||
265 | } | ||
266 | None | ||
267 | } | ||
268 | |||
244 | #[cfg(test)] | 269 | #[cfg(test)] |
245 | mod tests { | 270 | mod tests { |
246 | use test_utils::extract_tags; | 271 | use test_utils::extract_tags; |
@@ -272,6 +297,7 @@ mod tests { | |||
272 | FoldKind::Consts => "consts", | 297 | FoldKind::Consts => "consts", |
273 | FoldKind::Statics => "statics", | 298 | FoldKind::Statics => "statics", |
274 | FoldKind::Array => "array", | 299 | FoldKind::Array => "array", |
300 | FoldKind::WhereClause => "whereclause", | ||
275 | }; | 301 | }; |
276 | assert_eq!(kind, &attr.unwrap()); | 302 | assert_eq!(kind, &attr.unwrap()); |
277 | } | 303 | } |
@@ -513,4 +539,23 @@ static SECOND_STATIC: &str = "second";</fold> | |||
513 | "#, | 539 | "#, |
514 | ) | 540 | ) |
515 | } | 541 | } |
542 | |||
543 | #[test] | ||
544 | fn fold_where_clause() { | ||
545 | // fold multi-line and don't fold single line. | ||
546 | check( | ||
547 | r#" | ||
548 | fn foo() | ||
549 | where<fold whereclause> | ||
550 | A: Foo, | ||
551 | B: Foo, | ||
552 | C: Foo, | ||
553 | D: Foo,</fold> {} | ||
554 | |||
555 | fn bar() | ||
556 | where | ||
557 | A: Bar, {} | ||
558 | "#, | ||
559 | ) | ||
560 | } | ||
516 | } | 561 | } |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index d5ef054d8..e0bf660c4 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -218,9 +218,7 @@ fn hint_iterator( | |||
218 | ty: &hir::Type, | 218 | ty: &hir::Type, |
219 | ) -> Option<SmolStr> { | 219 | ) -> Option<SmolStr> { |
220 | let db = sema.db; | 220 | let db = sema.db; |
221 | let strukt = std::iter::successors(Some(ty.clone()), |ty| ty.remove_ref()) | 221 | let strukt = ty.strip_references().as_adt()?; |
222 | .last() | ||
223 | .and_then(|strukt| strukt.as_adt())?; | ||
224 | let krate = strukt.krate(db); | 222 | let krate = strukt.krate(db); |
225 | if krate != famous_defs.core()? { | 223 | if krate != famous_defs.core()? { |
226 | return None; | 224 | return None; |
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index e2994eed4..78154bf3e 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -203,41 +203,37 @@ impl Completions { | |||
203 | fn complete_enum_variants( | 203 | fn complete_enum_variants( |
204 | acc: &mut Completions, | 204 | acc: &mut Completions, |
205 | ctx: &CompletionContext, | 205 | ctx: &CompletionContext, |
206 | ty: &hir::Type, | 206 | enum_data: hir::Enum, |
207 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), | 207 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), |
208 | ) { | 208 | ) { |
209 | if let Some(hir::Adt::Enum(enum_data)) = | 209 | let variants = enum_data.variants(ctx.db); |
210 | iter::successors(Some(ty.clone()), |ty| ty.remove_ref()).last().and_then(|ty| ty.as_adt()) | 210 | |
211 | { | 211 | let module = if let Some(module) = ctx.scope.module() { |
212 | let variants = enum_data.variants(ctx.db); | 212 | // Compute path from the completion site if available. |
213 | 213 | module | |
214 | let module = if let Some(module) = ctx.scope.module() { | 214 | } else { |
215 | // Compute path from the completion site if available. | 215 | // Otherwise fall back to the enum's definition site. |
216 | module | 216 | enum_data.module(ctx.db) |
217 | } else { | 217 | }; |
218 | // Otherwise fall back to the enum's definition site. | 218 | |
219 | enum_data.module(ctx.db) | 219 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
220 | }; | 220 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_data)) { |
221 | 221 | for &variant in &variants { | |
222 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 222 | let self_path = hir::ModPath::from_segments( |
223 | if impl_.self_ty(ctx.db) == *ty { | 223 | hir::PathKind::Plain, |
224 | for &variant in &variants { | 224 | iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), |
225 | let self_path = hir::ModPath::from_segments( | 225 | ); |
226 | hir::PathKind::Plain, | 226 | cb(acc, ctx, variant, self_path); |
227 | iter::once(known::SELF_TYPE).chain(iter::once(variant.name(ctx.db))), | ||
228 | ); | ||
229 | cb(acc, ctx, variant, self_path); | ||
230 | } | ||
231 | } | 227 | } |
232 | } | 228 | } |
229 | } | ||
233 | 230 | ||
234 | for variant in variants { | 231 | for variant in variants { |
235 | if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) { | 232 | if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) { |
236 | // Variants with trivial paths are already added by the existing completion logic, | 233 | // Variants with trivial paths are already added by the existing completion logic, |
237 | // so we should avoid adding these twice | 234 | // so we should avoid adding these twice |
238 | if path.segments().len() > 1 { | 235 | if path.segments().len() > 1 { |
239 | cb(acc, ctx, variant, path); | 236 | cb(acc, ctx, variant, path); |
240 | } | ||
241 | } | 237 | } |
242 | } | 238 | } |
243 | } | 239 | } |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index 808d7ff7e..8dc9ab73c 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -12,8 +12,10 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
12 | } | 12 | } |
13 | 13 | ||
14 | if !ctx.is_irrefutable_pat_binding { | 14 | if !ctx.is_irrefutable_pat_binding { |
15 | if let Some(ty) = ctx.expected_type.as_ref() { | 15 | if let Some(hir::Adt::Enum(e)) = |
16 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | 16 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
17 | { | ||
18 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | ||
17 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); | 19 | acc.add_qualified_variant_pat(ctx, variant, path.clone()); |
18 | acc.add_qualified_enum_variant(ctx, variant, path); | 20 | acc.add_qualified_enum_variant(ctx, variant, path); |
19 | }); | 21 | }); |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index ac69b720a..962aaf0df 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -35,14 +35,11 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
35 | None => return, | 35 | None => return, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | let ref_removed_ty = | ||
39 | std::iter::successors(Some(receiver_ty.clone()), |ty| ty.remove_ref()).last().unwrap(); | ||
40 | |||
41 | let cap = match ctx.config.snippet_cap { | 38 | let cap = match ctx.config.snippet_cap { |
42 | Some(it) => it, | 39 | Some(it) => it, |
43 | None => return, | 40 | None => return, |
44 | }; | 41 | }; |
45 | let try_enum = TryEnum::from_ty(&ctx.sema, &ref_removed_ty); | 42 | let try_enum = TryEnum::from_ty(&ctx.sema, &receiver_ty.strip_references()); |
46 | if let Some(try_enum) = &try_enum { | 43 | if let Some(try_enum) = &try_enum { |
47 | match try_enum { | 44 | match try_enum { |
48 | TryEnum::Result => { | 45 | TryEnum::Result => { |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index d2ebba65f..eedb44873 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -59,6 +59,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
59 | hir::ModuleDef::TypeAlias(a) => { | 59 | hir::ModuleDef::TypeAlias(a) => { |
60 | let ty = a.ty(ctx.db); | 60 | let ty = a.ty(ctx.db); |
61 | if let Some(Adt::Enum(e)) = ty.as_adt() { | 61 | if let Some(Adt::Enum(e)) = ty.as_adt() { |
62 | cov_mark::hit!(completes_variant_through_alias); | ||
62 | add_enum_variants(ctx, acc, e); | 63 | add_enum_variants(ctx, acc, e); |
63 | } | 64 | } |
64 | ty | 65 | ty |
@@ -68,6 +69,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
68 | Some(it) => it, | 69 | Some(it) => it, |
69 | None => return, | 70 | None => return, |
70 | }; | 71 | }; |
72 | cov_mark::hit!(completes_primitive_assoc_const); | ||
71 | builtin.ty(ctx.db, module) | 73 | builtin.ty(ctx.db, module) |
72 | } | 74 | } |
73 | _ => unreachable!(), | 75 | _ => unreachable!(), |
@@ -96,9 +98,8 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
96 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 98 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
97 | return None; | 99 | return None; |
98 | } | 100 | } |
99 | match item { | 101 | if let hir::AssocItem::TypeAlias(ty) = item { |
100 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} | 102 | acc.add_type_alias(ctx, ty) |
101 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
102 | } | 103 | } |
103 | None::<()> | 104 | None::<()> |
104 | }); | 105 | }); |
@@ -745,7 +746,7 @@ fn f() {} | |||
745 | } | 746 | } |
746 | 747 | ||
747 | #[test] | 748 | #[test] |
748 | fn completes_self_enum() { | 749 | fn completes_variant_through_self() { |
749 | check( | 750 | check( |
750 | r#" | 751 | r#" |
751 | enum Foo { | 752 | enum Foo { |
@@ -769,6 +770,7 @@ impl Foo { | |||
769 | 770 | ||
770 | #[test] | 771 | #[test] |
771 | fn completes_primitive_assoc_const() { | 772 | fn completes_primitive_assoc_const() { |
773 | cov_mark::check!(completes_primitive_assoc_const); | ||
772 | check( | 774 | check( |
773 | r#" | 775 | r#" |
774 | //- /lib.rs crate:lib deps:core | 776 | //- /lib.rs crate:lib deps:core |
@@ -792,7 +794,8 @@ impl u8 { | |||
792 | } | 794 | } |
793 | 795 | ||
794 | #[test] | 796 | #[test] |
795 | fn completes_through_alias() { | 797 | fn completes_variant_through_alias() { |
798 | cov_mark::check!(completes_variant_through_alias); | ||
796 | check( | 799 | check( |
797 | r#" | 800 | r#" |
798 | enum Foo { | 801 | enum Foo { |
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs index a26fe7c6c..968c0254d 100644 --- a/crates/ide_completion/src/completions/trait_impl.rs +++ b/crates/ide_completion/src/completions/trait_impl.rs | |||
@@ -36,7 +36,7 @@ use ide_db::{traits::get_missing_assoc_items, SymbolKind}; | |||
36 | use syntax::{ | 36 | use syntax::{ |
37 | ast::{self, edit, Impl}, | 37 | ast::{self, edit, Impl}, |
38 | display::function_declaration, | 38 | display::function_declaration, |
39 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, | 39 | AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, |
40 | }; | 40 | }; |
41 | use text_edit::TextEdit; | 41 | use text_edit::TextEdit; |
42 | 42 | ||
@@ -154,8 +154,7 @@ fn add_function_impl( | |||
154 | } else { | 154 | } else { |
155 | CompletionItemKind::SymbolKind(SymbolKind::Function) | 155 | CompletionItemKind::SymbolKind(SymbolKind::Function) |
156 | }; | 156 | }; |
157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 157 | let range = replacement_range(ctx, fn_def_node); |
158 | |||
159 | if let Some(src) = func.source(ctx.db) { | 158 | if let Some(src) = func.source(ctx.db) { |
160 | let function_decl = function_declaration(&src.value); | 159 | let function_decl = function_declaration(&src.value); |
161 | match ctx.config.snippet_cap { | 160 | match ctx.config.snippet_cap { |
@@ -183,8 +182,7 @@ fn add_type_alias_impl( | |||
183 | 182 | ||
184 | let snippet = format!("type {} = ", alias_name); | 183 | let snippet = format!("type {} = ", alias_name); |
185 | 184 | ||
186 | let range = TextRange::new(type_def_node.text_range().start(), ctx.source_range().end()); | 185 | let range = replacement_range(ctx, type_def_node); |
187 | |||
188 | let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 186 | let mut item = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); |
189 | item.text_edit(TextEdit::replace(range, snippet)) | 187 | item.text_edit(TextEdit::replace(range, snippet)) |
190 | .lookup_by(alias_name) | 188 | .lookup_by(alias_name) |
@@ -205,9 +203,7 @@ fn add_const_impl( | |||
205 | if let Some(source) = const_.source(ctx.db) { | 203 | if let Some(source) = const_.source(ctx.db) { |
206 | let snippet = make_const_compl_syntax(&source.value); | 204 | let snippet = make_const_compl_syntax(&source.value); |
207 | 205 | ||
208 | let range = | 206 | let range = replacement_range(ctx, const_def_node); |
209 | TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | ||
210 | |||
211 | let mut item = | 207 | let mut item = |
212 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); | 208 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()); |
213 | item.text_edit(TextEdit::replace(range, snippet)) | 209 | item.text_edit(TextEdit::replace(range, snippet)) |
@@ -242,6 +238,17 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String { | |||
242 | format!("{} = ", syntax.trim_end()) | 238 | format!("{} = ", syntax.trim_end()) |
243 | } | 239 | } |
244 | 240 | ||
241 | fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange { | ||
242 | let first_child = item | ||
243 | .children_with_tokens() | ||
244 | .find(|child| { | ||
245 | !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR) | ||
246 | }) | ||
247 | .unwrap_or_else(|| SyntaxElement::Node(item.clone())); | ||
248 | |||
249 | TextRange::new(first_child.text_range().start(), ctx.source_range().end()) | ||
250 | } | ||
251 | |||
245 | #[cfg(test)] | 252 | #[cfg(test)] |
246 | mod tests { | 253 | mod tests { |
247 | use expect_test::{expect, Expect}; | 254 | use expect_test::{expect, Expect}; |
@@ -734,4 +741,50 @@ impl Test for T {{ | |||
734 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); | 741 | test("CONST", "const $0", "const CONST: u16 = ", next_sibling); |
735 | } | 742 | } |
736 | } | 743 | } |
744 | |||
745 | #[test] | ||
746 | fn snippet_does_not_overwrite_comment_or_attr() { | ||
747 | let test = |completion: &str, hint: &str, completed: &str| { | ||
748 | check_edit( | ||
749 | completion, | ||
750 | &format!( | ||
751 | r#" | ||
752 | trait Foo {{ | ||
753 | type Type; | ||
754 | fn function(); | ||
755 | const CONST: i32 = 0; | ||
756 | }} | ||
757 | struct T; | ||
758 | |||
759 | impl Foo for T {{ | ||
760 | // Comment | ||
761 | #[bar] | ||
762 | {} | ||
763 | }} | ||
764 | "#, | ||
765 | hint | ||
766 | ), | ||
767 | &format!( | ||
768 | r#" | ||
769 | trait Foo {{ | ||
770 | type Type; | ||
771 | fn function(); | ||
772 | const CONST: i32 = 0; | ||
773 | }} | ||
774 | struct T; | ||
775 | |||
776 | impl Foo for T {{ | ||
777 | // Comment | ||
778 | #[bar] | ||
779 | {} | ||
780 | }} | ||
781 | "#, | ||
782 | completed | ||
783 | ), | ||
784 | ) | ||
785 | }; | ||
786 | test("function", "fn f$0", "fn function() {\n $0\n}"); | ||
787 | test("Type", "type T$0", "type Type = "); | ||
788 | test("CONST", "const C$0", "const CONST: i32 = "); | ||
789 | } | ||
737 | } | 790 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index 1b8b063e7..7875500c1 100644 --- a/crates/ide_completion/src/completions/unqualified_path.rs +++ b/crates/ide_completion/src/completions/unqualified_path.rs | |||
@@ -17,8 +17,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
17 | return; | 17 | return; |
18 | } | 18 | } |
19 | 19 | ||
20 | if let Some(ty) = &ctx.expected_type { | 20 | if let Some(hir::Adt::Enum(e)) = |
21 | super::complete_enum_variants(acc, ctx, ty, |acc, ctx, variant, path| { | 21 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
22 | { | ||
23 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | ||
22 | acc.add_qualified_enum_variant(ctx, variant, path) | 24 | acc.add_qualified_enum_variant(ctx, variant, path) |
23 | }); | 25 | }); |
24 | } | 26 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index f3fcb712c..62ef40818 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -381,7 +381,7 @@ impl<'a> CompletionContext<'a> { | |||
381 | let def = self.sema.to_def(&it); | 381 | let def = self.sema.to_def(&it); |
382 | (def.map(|def| def.ret_type(self.db)), None) | 382 | (def.map(|def| def.ret_type(self.db)), None) |
383 | }, | 383 | }, |
384 | ast::Stmt(it) => (None, None), | 384 | ast::Stmt(_it) => (None, None), |
385 | _ => { | 385 | _ => { |
386 | match node.parent() { | 386 | match node.parent() { |
387 | Some(n) => { | 387 | Some(n) => { |
diff --git a/crates/ide_db/src/line_index.rs b/crates/ide_db/src/line_index.rs index 8e9d8cca2..816edfe6a 100644 --- a/crates/ide_db/src/line_index.rs +++ b/crates/ide_db/src/line_index.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
6 | use stdx::partition_point; | ||
7 | use syntax::{TextRange, TextSize}; | 6 | use syntax::{TextRange, TextSize}; |
8 | 7 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 8 | #[derive(Clone, Debug, PartialEq, Eq)] |
@@ -97,7 +96,7 @@ impl LineIndex { | |||
97 | } | 96 | } |
98 | 97 | ||
99 | pub fn line_col(&self, offset: TextSize) -> LineCol { | 98 | pub fn line_col(&self, offset: TextSize) -> LineCol { |
100 | let line = partition_point(&self.newlines, |&it| it <= offset) - 1; | 99 | let line = self.newlines.partition_point(|&it| it <= offset) - 1; |
101 | let line_start_offset = self.newlines[line]; | 100 | let line_start_offset = self.newlines[line]; |
102 | let col = offset - line_start_offset; | 101 | let col = offset - line_start_offset; |
103 | LineCol { line: line as u32, col: col.into() } | 102 | LineCol { line: line as u32, col: col.into() } |
@@ -118,8 +117,8 @@ impl LineIndex { | |||
118 | } | 117 | } |
119 | 118 | ||
120 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | 119 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { |
121 | let lo = partition_point(&self.newlines, |&it| it < range.start()); | 120 | let lo = self.newlines.partition_point(|&it| it < range.start()); |
122 | let hi = partition_point(&self.newlines, |&it| it <= range.end()); | 121 | let hi = self.newlines.partition_point(|&it| it <= range.end()); |
123 | let all = iter::once(range.start()) | 122 | let all = iter::once(range.start()) |
124 | .chain(self.newlines[lo..hi].iter().copied()) | 123 | .chain(self.newlines[lo..hi].iter().copied()) |
125 | .chain(iter::once(range.end())); | 124 | .chain(iter::once(range.end())); |
diff --git a/crates/project_model/src/cfg_flag.rs b/crates/project_model/src/cfg_flag.rs index e92962cf6..bfdfd458f 100644 --- a/crates/project_model/src/cfg_flag.rs +++ b/crates/project_model/src/cfg_flag.rs | |||
@@ -4,7 +4,6 @@ | |||
4 | use std::str::FromStr; | 4 | use std::str::FromStr; |
5 | 5 | ||
6 | use cfg::CfgOptions; | 6 | use cfg::CfgOptions; |
7 | use stdx::split_once; | ||
8 | 7 | ||
9 | #[derive(Clone, Eq, PartialEq, Debug)] | 8 | #[derive(Clone, Eq, PartialEq, Debug)] |
10 | pub enum CfgFlag { | 9 | pub enum CfgFlag { |
@@ -15,7 +14,7 @@ pub enum CfgFlag { | |||
15 | impl FromStr for CfgFlag { | 14 | impl FromStr for CfgFlag { |
16 | type Err = String; | 15 | type Err = String; |
17 | fn from_str(s: &str) -> Result<Self, Self::Err> { | 16 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
18 | let res = match split_once(s, '=') { | 17 | let res = match s.split_once('=') { |
19 | Some((key, value)) => { | 18 | Some((key, value)) => { |
20 | if !(value.starts_with('"') && value.ends_with('"')) { | 19 | if !(value.starts_with('"') && value.ends_with('"')) { |
21 | return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); | 20 | return Err(format!("Invalid cfg ({:?}), value should be in quotes", s)); |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1d27aa7b3..ecf6fd12f 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -524,6 +524,7 @@ pub(crate) fn folding_range( | |||
524 | | FoldKind::ArgList | 524 | | FoldKind::ArgList |
525 | | FoldKind::Consts | 525 | | FoldKind::Consts |
526 | | FoldKind::Statics | 526 | | FoldKind::Statics |
527 | | FoldKind::WhereClause | ||
527 | | FoldKind::Array => None, | 528 | | FoldKind::Array => None, |
528 | }; | 529 | }; |
529 | 530 | ||
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 1b6211044..340fcacfa 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -65,20 +65,6 @@ pub fn replace(buf: &mut String, from: char, to: &str) { | |||
65 | *buf = buf.replace(from, to) | 65 | *buf = buf.replace(from, to) |
66 | } | 66 | } |
67 | 67 | ||
68 | // https://github.com/rust-lang/rust/issues/74773 | ||
69 | pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
70 | let mut split = haystack.splitn(2, delim); | ||
71 | let prefix = split.next()?; | ||
72 | let suffix = split.next()?; | ||
73 | Some((prefix, suffix)) | ||
74 | } | ||
75 | pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
76 | let mut split = haystack.rsplitn(2, delim); | ||
77 | let suffix = split.next()?; | ||
78 | let prefix = split.next()?; | ||
79 | Some((prefix, suffix)) | ||
80 | } | ||
81 | |||
82 | pub fn trim_indent(mut text: &str) -> String { | 68 | pub fn trim_indent(mut text: &str) -> String { |
83 | if text.starts_with('\n') { | 69 | if text.starts_with('\n') { |
84 | text = &text[1..]; | 70 | text = &text[1..]; |
@@ -89,7 +75,7 @@ pub fn trim_indent(mut text: &str) -> String { | |||
89 | .map(|it| it.len() - it.trim_start().len()) | 75 | .map(|it| it.len() - it.trim_start().len()) |
90 | .min() | 76 | .min() |
91 | .unwrap_or(0); | 77 | .unwrap_or(0); |
92 | lines_with_ends(text) | 78 | text.split_inclusive('\n') |
93 | .map( | 79 | .map( |
94 | |line| { | 80 | |line| { |
95 | if line.len() <= indent { | 81 | if line.len() <= indent { |
@@ -102,70 +88,12 @@ pub fn trim_indent(mut text: &str) -> String { | |||
102 | .collect() | 88 | .collect() |
103 | } | 89 | } |
104 | 90 | ||
105 | pub fn lines_with_ends(text: &str) -> LinesWithEnds { | ||
106 | LinesWithEnds { text } | ||
107 | } | ||
108 | |||
109 | pub struct LinesWithEnds<'a> { | ||
110 | text: &'a str, | ||
111 | } | ||
112 | |||
113 | impl<'a> Iterator for LinesWithEnds<'a> { | ||
114 | type Item = &'a str; | ||
115 | fn next(&mut self) -> Option<&'a str> { | ||
116 | if self.text.is_empty() { | ||
117 | return None; | ||
118 | } | ||
119 | let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1); | ||
120 | let (res, next) = self.text.split_at(idx); | ||
121 | self.text = next; | ||
122 | Some(res) | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /// Returns `idx` such that: | ||
127 | /// | ||
128 | /// ```text | ||
129 | /// ∀ x in slice[..idx]: pred(x) | ||
130 | /// && ∀ x in slice[idx..]: !pred(x) | ||
131 | /// ``` | ||
132 | /// | ||
133 | /// https://github.com/rust-lang/rust/issues/73831 | ||
134 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize | ||
135 | where | ||
136 | P: FnMut(&T) -> bool, | ||
137 | { | ||
138 | let mut left = 0; | ||
139 | let mut right = slice.len(); | ||
140 | |||
141 | while left != right { | ||
142 | let mid = left + (right - left) / 2; | ||
143 | // SAFETY: | ||
144 | // When left < right, left <= mid < right. | ||
145 | // Therefore left always increases and right always decreases, | ||
146 | // and either of them is selected. | ||
147 | // In both cases left <= right is satisfied. | ||
148 | // Therefore if left < right in a step, | ||
149 | // left <= right is satisfied in the next step. | ||
150 | // Therefore as long as left != right, 0 <= left < right <= len is satisfied | ||
151 | // and if this case 0 <= mid < len is satisfied too. | ||
152 | let value = unsafe { slice.get_unchecked(mid) }; | ||
153 | if pred(value) { | ||
154 | left = mid + 1; | ||
155 | } else { | ||
156 | right = mid; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | left | ||
161 | } | ||
162 | |||
163 | pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> | 91 | pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> |
164 | where | 92 | where |
165 | F: FnMut(&T) -> Ordering, | 93 | F: FnMut(&T) -> Ordering, |
166 | { | 94 | { |
167 | let start = partition_point(slice, |it| key(it) == Ordering::Less); | 95 | let start = slice.partition_point(|it| key(it) == Ordering::Less); |
168 | let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal); | 96 | let len = slice[start..].partition_point(|it| key(it) == Ordering::Equal); |
169 | start..start + len | 97 | start..start + len |
170 | } | 98 | } |
171 | 99 | ||
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 556f80882..c0bc59918 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = { version = "1.1", features = ["thread-local"] } |
15 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
16 | rowan = "=0.13.0-pre.3" | 16 | rowan = "=0.13.0-pre.5" |
17 | rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" } | 17 | rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" } |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | arrayvec = "0.7" | 19 | arrayvec = "0.7" |
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs index c9229c4e0..ba263be0d 100644 --- a/crates/syntax/src/algo.rs +++ b/crates/syntax/src/algo.rs | |||
@@ -555,7 +555,7 @@ impl SyntaxRewriter<'_> { | |||
555 | 555 | ||
556 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 556 | fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
557 | match element { | 557 | match element { |
558 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green()), | 558 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().into_owned()), |
559 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), | 559 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), |
560 | } | 560 | } |
561 | } | 561 | } |
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 42da09606..4bcea28cc 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs | |||
@@ -572,7 +572,7 @@ fn ast_from_text<N: AstNode>(text: &str) -> N { | |||
572 | } | 572 | } |
573 | 573 | ||
574 | fn unroot(n: SyntaxNode) -> SyntaxNode { | 574 | fn unroot(n: SyntaxNode) -> SyntaxNode { |
575 | SyntaxNode::new_root(n.green()) | 575 | SyntaxNode::new_root(n.green().into()) |
576 | } | 576 | } |
577 | 577 | ||
578 | pub mod tokens { | 578 | pub mod tokens { |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 492fbc4a0..bef49238f 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -1,30 +1,31 @@ | |||
1 | //! Various extension methods to ast Nodes, which are hard to code-generate. | 1 | //! Various extension methods to ast Nodes, which are hard to code-generate. |
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use std::{fmt, iter::successors}; | 4 | use std::{borrow::Cow, fmt, iter::successors}; |
5 | 5 | ||
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use parser::SyntaxKind; | 7 | use parser::SyntaxKind; |
8 | use rowan::{GreenNodeData, GreenTokenData}; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, | 11 | ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, |
11 | SmolStr, SyntaxElement, SyntaxToken, TokenText, T, | 12 | NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, |
12 | }; | 13 | }; |
13 | 14 | ||
14 | impl ast::Lifetime { | 15 | impl ast::Lifetime { |
15 | pub fn text(&self) -> TokenText { | 16 | pub fn text(&self) -> TokenText<'_> { |
16 | text_of_first_token(self.syntax()) | 17 | text_of_first_token(self.syntax()) |
17 | } | 18 | } |
18 | } | 19 | } |
19 | 20 | ||
20 | impl ast::Name { | 21 | impl ast::Name { |
21 | pub fn text(&self) -> TokenText { | 22 | pub fn text(&self) -> TokenText<'_> { |
22 | text_of_first_token(self.syntax()) | 23 | text_of_first_token(self.syntax()) |
23 | } | 24 | } |
24 | } | 25 | } |
25 | 26 | ||
26 | impl ast::NameRef { | 27 | impl ast::NameRef { |
27 | pub fn text(&self) -> TokenText { | 28 | pub fn text(&self) -> TokenText<'_> { |
28 | text_of_first_token(self.syntax()) | 29 | text_of_first_token(self.syntax()) |
29 | } | 30 | } |
30 | 31 | ||
@@ -33,11 +34,15 @@ impl ast::NameRef { | |||
33 | } | 34 | } |
34 | } | 35 | } |
35 | 36 | ||
36 | fn text_of_first_token(node: &SyntaxNode) -> TokenText { | 37 | fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> { |
37 | let first_token = | 38 | fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData { |
38 | node.green().children().next().and_then(|it| it.into_token()).unwrap().to_owned(); | 39 | green_ref.children().next().and_then(NodeOrToken::into_token).unwrap() |
40 | } | ||
39 | 41 | ||
40 | TokenText(first_token) | 42 | match node.green() { |
43 | Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()), | ||
44 | Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()), | ||
45 | } | ||
41 | } | 46 | } |
42 | 47 | ||
43 | #[derive(Debug, PartialEq, Eq, Clone)] | 48 | #[derive(Debug, PartialEq, Eq, Clone)] |
@@ -412,7 +417,7 @@ impl fmt::Display for NameOrNameRef { | |||
412 | } | 417 | } |
413 | 418 | ||
414 | impl NameOrNameRef { | 419 | impl NameOrNameRef { |
415 | pub fn text(&self) -> TokenText { | 420 | pub fn text(&self) -> TokenText<'_> { |
416 | match self { | 421 | match self { |
417 | NameOrNameRef::Name(name) => name.text(), | 422 | NameOrNameRef::Name(name) => name.text(), |
418 | NameOrNameRef::NameRef(name_ref) => name_ref.text(), | 423 | NameOrNameRef::NameRef(name_ref) => name_ref.text(), |
diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs index d2ed0a12a..f3e8b321a 100644 --- a/crates/syntax/src/token_text.rs +++ b/crates/syntax/src/token_text.rs | |||
@@ -2,75 +2,93 @@ | |||
2 | 2 | ||
3 | use std::{cmp::Ordering, fmt, ops}; | 3 | use std::{cmp::Ordering, fmt, ops}; |
4 | 4 | ||
5 | pub struct TokenText(pub(crate) rowan::GreenToken); | 5 | use rowan::GreenToken; |
6 | |||
7 | pub struct TokenText<'a>(pub(crate) Repr<'a>); | ||
8 | |||
9 | pub(crate) enum Repr<'a> { | ||
10 | Borrowed(&'a str), | ||
11 | Owned(GreenToken), | ||
12 | } | ||
13 | |||
14 | impl<'a> TokenText<'a> { | ||
15 | pub(crate) fn borrowed(text: &'a str) -> Self { | ||
16 | TokenText(Repr::Borrowed(text)) | ||
17 | } | ||
18 | |||
19 | pub(crate) fn owned(green: GreenToken) -> Self { | ||
20 | TokenText(Repr::Owned(green)) | ||
21 | } | ||
6 | 22 | ||
7 | impl TokenText { | ||
8 | pub fn as_str(&self) -> &str { | 23 | pub fn as_str(&self) -> &str { |
9 | self.0.text() | 24 | match self.0 { |
25 | Repr::Borrowed(it) => it, | ||
26 | Repr::Owned(ref green) => green.text(), | ||
27 | } | ||
10 | } | 28 | } |
11 | } | 29 | } |
12 | 30 | ||
13 | impl ops::Deref for TokenText { | 31 | impl ops::Deref for TokenText<'_> { |
14 | type Target = str; | 32 | type Target = str; |
15 | 33 | ||
16 | fn deref(&self) -> &str { | 34 | fn deref(&self) -> &str { |
17 | self.as_str() | 35 | self.as_str() |
18 | } | 36 | } |
19 | } | 37 | } |
20 | impl AsRef<str> for TokenText { | 38 | impl AsRef<str> for TokenText<'_> { |
21 | fn as_ref(&self) -> &str { | 39 | fn as_ref(&self) -> &str { |
22 | self.as_str() | 40 | self.as_str() |
23 | } | 41 | } |
24 | } | 42 | } |
25 | 43 | ||
26 | impl From<TokenText> for String { | 44 | impl From<TokenText<'_>> for String { |
27 | fn from(token_text: TokenText) -> Self { | 45 | fn from(token_text: TokenText) -> Self { |
28 | token_text.as_str().into() | 46 | token_text.as_str().into() |
29 | } | 47 | } |
30 | } | 48 | } |
31 | 49 | ||
32 | impl PartialEq<&'_ str> for TokenText { | 50 | impl PartialEq<&'_ str> for TokenText<'_> { |
33 | fn eq(&self, other: &&str) -> bool { | 51 | fn eq(&self, other: &&str) -> bool { |
34 | self.as_str() == *other | 52 | self.as_str() == *other |
35 | } | 53 | } |
36 | } | 54 | } |
37 | impl PartialEq<TokenText> for &'_ str { | 55 | impl PartialEq<TokenText<'_>> for &'_ str { |
38 | fn eq(&self, other: &TokenText) -> bool { | 56 | fn eq(&self, other: &TokenText) -> bool { |
39 | other == self | 57 | other == self |
40 | } | 58 | } |
41 | } | 59 | } |
42 | impl PartialEq<String> for TokenText { | 60 | impl PartialEq<String> for TokenText<'_> { |
43 | fn eq(&self, other: &String) -> bool { | 61 | fn eq(&self, other: &String) -> bool { |
44 | self.as_str() == other.as_str() | 62 | self.as_str() == other.as_str() |
45 | } | 63 | } |
46 | } | 64 | } |
47 | impl PartialEq<TokenText> for String { | 65 | impl PartialEq<TokenText<'_>> for String { |
48 | fn eq(&self, other: &TokenText) -> bool { | 66 | fn eq(&self, other: &TokenText) -> bool { |
49 | other == self | 67 | other == self |
50 | } | 68 | } |
51 | } | 69 | } |
52 | impl PartialEq for TokenText { | 70 | impl PartialEq for TokenText<'_> { |
53 | fn eq(&self, other: &TokenText) -> bool { | 71 | fn eq(&self, other: &TokenText) -> bool { |
54 | self.as_str() == other.as_str() | 72 | self.as_str() == other.as_str() |
55 | } | 73 | } |
56 | } | 74 | } |
57 | impl Eq for TokenText {} | 75 | impl Eq for TokenText<'_> {} |
58 | impl Ord for TokenText { | 76 | impl Ord for TokenText<'_> { |
59 | fn cmp(&self, other: &Self) -> Ordering { | 77 | fn cmp(&self, other: &Self) -> Ordering { |
60 | self.as_str().cmp(other.as_str()) | 78 | self.as_str().cmp(other.as_str()) |
61 | } | 79 | } |
62 | } | 80 | } |
63 | impl PartialOrd for TokenText { | 81 | impl PartialOrd for TokenText<'_> { |
64 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | 82 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
65 | Some(self.cmp(other)) | 83 | Some(self.cmp(other)) |
66 | } | 84 | } |
67 | } | 85 | } |
68 | impl fmt::Display for TokenText { | 86 | impl fmt::Display for TokenText<'_> { |
69 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 87 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
70 | fmt::Display::fmt(self.as_str(), f) | 88 | fmt::Display::fmt(self.as_str(), f) |
71 | } | 89 | } |
72 | } | 90 | } |
73 | impl fmt::Debug for TokenText { | 91 | impl fmt::Debug for TokenText<'_> { |
74 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 92 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
75 | fmt::Debug::fmt(self.as_str(), f) | 93 | fmt::Debug::fmt(self.as_str(), f) |
76 | } | 94 | } |
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs index 099baeca2..d0bddf7d8 100644 --- a/crates/test_utils/src/fixture.rs +++ b/crates/test_utils/src/fixture.rs | |||
@@ -62,7 +62,7 @@ | |||
62 | //! ``` | 62 | //! ``` |
63 | 63 | ||
64 | use rustc_hash::FxHashMap; | 64 | use rustc_hash::FxHashMap; |
65 | use stdx::{lines_with_ends, split_once, trim_indent}; | 65 | use stdx::trim_indent; |
66 | 66 | ||
67 | #[derive(Debug, Eq, PartialEq)] | 67 | #[derive(Debug, Eq, PartialEq)] |
68 | pub struct Fixture { | 68 | pub struct Fixture { |
@@ -93,7 +93,7 @@ impl Fixture { | |||
93 | 93 | ||
94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; | 94 | let default = if ra_fixture.contains("//-") { None } else { Some("//- /main.rs") }; |
95 | 95 | ||
96 | for (ix, line) in default.into_iter().chain(lines_with_ends(&fixture)).enumerate() { | 96 | for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() { |
97 | if line.contains("//-") { | 97 | if line.contains("//-") { |
98 | assert!( | 98 | assert!( |
99 | line.starts_with("//-"), | 99 | line.starts_with("//-"), |
@@ -133,14 +133,14 @@ impl Fixture { | |||
133 | let mut env = FxHashMap::default(); | 133 | let mut env = FxHashMap::default(); |
134 | let mut introduce_new_source_root = false; | 134 | let mut introduce_new_source_root = false; |
135 | for component in components[1..].iter() { | 135 | for component in components[1..].iter() { |
136 | let (key, value) = split_once(component, ':').unwrap(); | 136 | let (key, value) = component.split_once(':').unwrap(); |
137 | match key { | 137 | match key { |
138 | "crate" => krate = Some(value.to_string()), | 138 | "crate" => krate = Some(value.to_string()), |
139 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | 139 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), |
140 | "edition" => edition = Some(value.to_string()), | 140 | "edition" => edition = Some(value.to_string()), |
141 | "cfg" => { | 141 | "cfg" => { |
142 | for entry in value.split(',') { | 142 | for entry in value.split(',') { |
143 | match split_once(entry, '=') { | 143 | match entry.split_once('=') { |
144 | Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())), | 144 | Some((k, v)) => cfg_key_values.push((k.to_string(), v.to_string())), |
145 | None => cfg_atoms.push(entry.to_string()), | 145 | None => cfg_atoms.push(entry.to_string()), |
146 | } | 146 | } |
@@ -148,7 +148,7 @@ impl Fixture { | |||
148 | } | 148 | } |
149 | "env" => { | 149 | "env" => { |
150 | for key in value.split(',') { | 150 | for key in value.split(',') { |
151 | if let Some((k, v)) = split_once(key, '=') { | 151 | if let Some((k, v)) = key.split_once('=') { |
152 | env.insert(k.into(), v.into()); | 152 | env.insert(k.into(), v.into()); |
153 | } | 153 | } |
154 | } | 154 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 72466c957..fce4fd6bf 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -17,7 +17,7 @@ use std::{ | |||
17 | }; | 17 | }; |
18 | 18 | ||
19 | use profile::StopWatch; | 19 | use profile::StopWatch; |
20 | use stdx::{is_ci, lines_with_ends}; | 20 | use stdx::is_ci; |
21 | use text_size::{TextRange, TextSize}; | 21 | use text_size::{TextRange, TextSize}; |
22 | 22 | ||
23 | pub use dissimilar::diff as __diff; | 23 | pub use dissimilar::diff as __diff; |
@@ -181,7 +181,7 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | |||
181 | let mut prev_line_start: Option<TextSize> = None; | 181 | let mut prev_line_start: Option<TextSize> = None; |
182 | let mut line_start: TextSize = 0.into(); | 182 | let mut line_start: TextSize = 0.into(); |
183 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); | 183 | let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); |
184 | for line in lines_with_ends(text) { | 184 | for line in text.split_inclusive('\n') { |
185 | let mut this_line_annotations = Vec::new(); | 185 | let mut this_line_annotations = Vec::new(); |
186 | if let Some(idx) = line.find("//") { | 186 | if let Some(idx) = line.find("//") { |
187 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); | 187 | let annotation_offset = TextSize::of(&line[..idx + "//".len()]); |
diff --git a/docs/dev/style.md b/docs/dev/style.md index 00de7a711..d24a5952e 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -947,4 +947,4 @@ match p.current() { | |||
947 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. | 947 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. |
948 | If the line is too long, you want to split the sentence in two :-) | 948 | If the line is too long, you want to split the sentence in two :-) |
949 | 949 | ||
950 | **Rationale:** much easier to edit the text and read the diff. | 950 | **Rationale:** much easier to edit the text and read the diff, see [this link](https://asciidoctor.org/docs/asciidoc-recommended-practices/#one-sentence-per-line). |
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index 91d6a2853..7e2dccdfe 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
@@ -8,7 +8,7 @@ use xshell::{cmd, pushd}; | |||
8 | use crate::flags; | 8 | use crate::flags; |
9 | 9 | ||
10 | // Latest stable, feel free to send a PR if this lags behind. | 10 | // Latest stable, feel free to send a PR if this lags behind. |
11 | const REQUIRED_RUST_VERSION: u32 = 51; | 11 | const REQUIRED_RUST_VERSION: u32 = 52; |
12 | 12 | ||
13 | impl flags::Install { | 13 | impl flags::Install { |
14 | pub(crate) fn run(self) -> Result<()> { | 14 | pub(crate) fn run(self) -> Result<()> { |