diff options
Diffstat (limited to 'crates')
31 files changed, 973 insertions, 318 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 7955bf0b5..62500602a 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -6,10 +6,11 @@ use std::{cell::RefCell, fmt, iter::successors}; | |||
6 | 6 | ||
7 | use base_db::{FileId, FileRange}; | 7 | use base_db::{FileId, FileRange}; |
8 | use hir_def::{ | 8 | use hir_def::{ |
9 | body, | ||
9 | resolver::{self, HasResolver, Resolver, TypeNs}, | 10 | resolver::{self, HasResolver, Resolver, TypeNs}, |
10 | AsMacroCall, FunctionId, TraitId, VariantId, | 11 | AsMacroCall, FunctionId, TraitId, VariantId, |
11 | }; | 12 | }; |
12 | use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; | 13 | use hir_expand::{name::AsName, ExpansionInfo}; |
13 | use hir_ty::associated_type_shorthand_candidates; | 14 | use hir_ty::associated_type_shorthand_candidates; |
14 | use itertools::Itertools; | 15 | use itertools::Itertools; |
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -853,8 +854,8 @@ impl<'a> SemanticsScope<'a> { | |||
853 | /// Resolve a path as-if it was written at the given scope. This is | 854 | /// Resolve a path as-if it was written at the given scope. This is |
854 | /// necessary a heuristic, as it doesn't take hygiene into account. | 855 | /// necessary a heuristic, as it doesn't take hygiene into account. |
855 | pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { | 856 | pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { |
856 | let hygiene = Hygiene::new(self.db.upcast(), self.file_id); | 857 | let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); |
857 | let path = Path::from_src(path.clone(), &hygiene)?; | 858 | let path = Path::from_src(path.clone(), &ctx)?; |
858 | resolve_hir_path(self.db, &self.resolver, &path) | 859 | resolve_hir_path(self.db, &self.resolver, &path) |
859 | } | 860 | } |
860 | } | 861 | } |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 847d2537d..0895bd6f1 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -9,6 +9,7 @@ use std::{iter::once, sync::Arc}; | |||
9 | 9 | ||
10 | use hir_def::{ | 10 | use hir_def::{ |
11 | body::{ | 11 | body::{ |
12 | self, | ||
12 | scope::{ExprScopes, ScopeId}, | 13 | scope::{ExprScopes, ScopeId}, |
13 | Body, BodySourceMap, | 14 | Body, BodySourceMap, |
14 | }, | 15 | }, |
@@ -202,8 +203,8 @@ impl SourceAnalyzer { | |||
202 | db: &dyn HirDatabase, | 203 | db: &dyn HirDatabase, |
203 | macro_call: InFile<&ast::MacroCall>, | 204 | macro_call: InFile<&ast::MacroCall>, |
204 | ) -> Option<MacroDef> { | 205 | ) -> Option<MacroDef> { |
205 | let hygiene = Hygiene::new(db.upcast(), macro_call.file_id); | 206 | let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); |
206 | let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; | 207 | let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; |
207 | self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) | 208 | self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) |
208 | } | 209 | } |
209 | 210 | ||
@@ -281,7 +282,9 @@ impl SourceAnalyzer { | |||
281 | } | 282 | } |
282 | 283 | ||
283 | // This must be a normal source file rather than macro file. | 284 | // This must be a normal source file rather than macro file. |
284 | let hir_path = Path::from_src(path.clone(), &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); | ||
287 | let hir_path = Path::from_src(path.clone(), &ctx)?; | ||
285 | 288 | ||
286 | // 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 |
287 | // trying to resolve foo::bar. | 290 | // trying to resolve foo::bar. |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 786fad6e1..d9294d93a 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -545,7 +545,7 @@ fn inner_attributes( | |||
545 | _ => return None, | 545 | _ => return None, |
546 | } | 546 | } |
547 | }; | 547 | }; |
548 | let attrs = attrs.filter(|attr| attr.excl_token().is_some()); | 548 | let attrs = attrs.filter(|attr| attr.kind().is_inner()); |
549 | let docs = docs.filter(|doc| doc.is_inner()); | 549 | let docs = docs.filter(|doc| doc.is_inner()); |
550 | Some((attrs, docs)) | 550 | Some((attrs, docs)) |
551 | } | 551 | } |
@@ -740,7 +740,7 @@ fn collect_attrs( | |||
740 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) | 740 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) |
741 | .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); | 741 | .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); |
742 | 742 | ||
743 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | 743 | let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer()); |
744 | let attrs = outer_attrs | 744 | let attrs = outer_attrs |
745 | .chain(inner_attrs.into_iter().flatten()) | 745 | .chain(inner_attrs.into_iter().flatten()) |
746 | .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); | 746 | .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 96b959967..131f424cc 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -21,7 +21,7 @@ use profile::Count; | |||
21 | use rustc_hash::FxHashMap; | 21 | use rustc_hash::FxHashMap; |
22 | use syntax::{ast, AstNode, AstPtr}; | 22 | use syntax::{ast, AstNode, AstPtr}; |
23 | 23 | ||
24 | pub(crate) use lower::LowerCtx; | 24 | pub use lower::LowerCtx; |
25 | 25 | ||
26 | use crate::{ | 26 | use crate::{ |
27 | attr::{Attrs, RawAttrs}, | 27 | attr::{Attrs, RawAttrs}, |
@@ -37,13 +37,15 @@ use crate::{ | |||
37 | 37 | ||
38 | /// A subset of Expander that only deals with cfg attributes. We only need it to | 38 | /// A subset of Expander that only deals with cfg attributes. We only need it to |
39 | /// avoid cyclic queries in crate def map during enum processing. | 39 | /// avoid cyclic queries in crate def map during enum processing. |
40 | #[derive(Debug)] | ||
40 | pub(crate) struct CfgExpander { | 41 | pub(crate) struct CfgExpander { |
41 | cfg_options: CfgOptions, | 42 | cfg_options: CfgOptions, |
42 | hygiene: Hygiene, | 43 | hygiene: Hygiene, |
43 | krate: CrateId, | 44 | krate: CrateId, |
44 | } | 45 | } |
45 | 46 | ||
46 | pub(crate) struct Expander { | 47 | #[derive(Debug)] |
48 | pub struct Expander { | ||
47 | cfg_expander: CfgExpander, | 49 | cfg_expander: CfgExpander, |
48 | def_map: Arc<DefMap>, | 50 | def_map: Arc<DefMap>, |
49 | current_file_id: HirFileId, | 51 | current_file_id: HirFileId, |
@@ -80,11 +82,7 @@ impl CfgExpander { | |||
80 | } | 82 | } |
81 | 83 | ||
82 | impl Expander { | 84 | impl Expander { |
83 | pub(crate) fn new( | 85 | pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { |
84 | db: &dyn DefDatabase, | ||
85 | current_file_id: HirFileId, | ||
86 | module: ModuleId, | ||
87 | ) -> Expander { | ||
88 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); | 86 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); |
89 | let def_map = module.def_map(db); | 87 | let def_map = module.def_map(db); |
90 | let ast_id_map = db.ast_id_map(current_file_id); | 88 | let ast_id_map = db.ast_id_map(current_file_id); |
@@ -98,7 +96,7 @@ impl Expander { | |||
98 | } | 96 | } |
99 | } | 97 | } |
100 | 98 | ||
101 | pub(crate) fn enter_expand<T: ast::AstNode>( | 99 | pub fn enter_expand<T: ast::AstNode>( |
102 | &mut self, | 100 | &mut self, |
103 | db: &dyn DefDatabase, | 101 | db: &dyn DefDatabase, |
104 | macro_call: ast::MacroCall, | 102 | macro_call: ast::MacroCall, |
@@ -170,7 +168,7 @@ impl Expander { | |||
170 | Ok(ExpandResult { value: Some((mark, node)), err }) | 168 | Ok(ExpandResult { value: Some((mark, node)), err }) |
171 | } | 169 | } |
172 | 170 | ||
173 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | 171 | pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { |
174 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); | 172 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); |
175 | self.current_file_id = mark.file_id; | 173 | self.current_file_id = mark.file_id; |
176 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 174 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
@@ -190,8 +188,13 @@ impl Expander { | |||
190 | &self.cfg_expander.cfg_options | 188 | &self.cfg_expander.cfg_options |
191 | } | 189 | } |
192 | 190 | ||
191 | pub fn current_file_id(&self) -> HirFileId { | ||
192 | self.current_file_id | ||
193 | } | ||
194 | |||
193 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 195 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { |
194 | Path::from_src(path, &self.cfg_expander.hygiene) | 196 | let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); |
197 | Path::from_src(path, &ctx) | ||
195 | } | 198 | } |
196 | 199 | ||
197 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { | 200 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { |
@@ -204,7 +207,8 @@ impl Expander { | |||
204 | } | 207 | } |
205 | } | 208 | } |
206 | 209 | ||
207 | pub(crate) struct Mark { | 210 | #[derive(Debug)] |
211 | pub struct Mark { | ||
208 | file_id: HirFileId, | 212 | file_id: HirFileId, |
209 | ast_id_map: Arc<AstIdMap>, | 213 | ast_id_map: Arc<AstIdMap>, |
210 | bomb: DropBomb, | 214 | bomb: DropBomb, |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index c0b0b7841..c11da30d2 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` | 1 | //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` |
2 | //! representation. | 2 | //! representation. |
3 | 3 | ||
4 | use std::mem; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{ | 7 | use hir_expand::{ |
8 | ast_id_map::{AstIdMap, FileAstId}, | ||
8 | hygiene::Hygiene, | 9 | hygiene::Hygiene, |
9 | name::{name, AsName, Name}, | 10 | name::{name, AsName, Name}, |
10 | ExpandError, HirFileId, | 11 | ExpandError, HirFileId, |
@@ -39,20 +40,39 @@ use crate::{ | |||
39 | 40 | ||
40 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
41 | 42 | ||
42 | pub(crate) struct LowerCtx { | 43 | pub struct LowerCtx { |
43 | hygiene: Hygiene, | 44 | hygiene: Hygiene, |
45 | file_id: Option<HirFileId>, | ||
46 | source_ast_id_map: Option<Arc<AstIdMap>>, | ||
44 | } | 47 | } |
45 | 48 | ||
46 | impl LowerCtx { | 49 | impl LowerCtx { |
47 | pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | 50 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { |
48 | LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } | 51 | LowerCtx { |
52 | hygiene: Hygiene::new(db.upcast(), file_id), | ||
53 | file_id: Some(file_id), | ||
54 | source_ast_id_map: Some(db.ast_id_map(file_id)), | ||
55 | } | ||
56 | } | ||
57 | |||
58 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | ||
59 | LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } | ||
60 | } | ||
61 | |||
62 | pub(crate) fn hygiene(&self) -> &Hygiene { | ||
63 | &self.hygiene | ||
49 | } | 64 | } |
50 | pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { | 65 | |
51 | LowerCtx { hygiene: hygiene.clone() } | 66 | pub(crate) fn file_id(&self) -> HirFileId { |
67 | self.file_id.unwrap() | ||
52 | } | 68 | } |
53 | 69 | ||
54 | pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { | 70 | pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { |
55 | Path::from_src(ast, &self.hygiene) | 71 | Path::from_src(ast, self) |
72 | } | ||
73 | |||
74 | pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> { | ||
75 | self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item)) | ||
56 | } | 76 | } |
57 | } | 77 | } |
58 | 78 | ||
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 94e08f835..16a94a058 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -104,6 +104,11 @@ impl ItemTree { | |||
104 | // items and expanded during block DefMap computation | 104 | // items and expanded during block DefMap computation |
105 | return Default::default(); | 105 | return Default::default(); |
106 | }, | 106 | }, |
107 | ast::Type(ty) => { | ||
108 | // Types can contain inner items. We return an empty item tree in this case, but | ||
109 | // still need to collect inner items. | ||
110 | ctx.lower_inner_items(ty.syntax()) | ||
111 | }, | ||
107 | ast::Expr(e) => { | 112 | ast::Expr(e) => { |
108 | // Macros can expand to expressions. We return an empty item tree in this case, but | 113 | // Macros can expand to expressions. We return an empty item tree in this case, but |
109 | // still need to collect inner items. | 114 | // still need to collect inner items. |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 5ac1670b5..25694f037 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -688,6 +688,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> { | |||
688 | } | 688 | } |
689 | } | 689 | } |
690 | 690 | ||
691 | #[derive(Debug)] | ||
691 | pub struct UnresolvedMacro { | 692 | pub struct UnresolvedMacro { |
692 | pub path: ModPath, | 693 | pub path: ModPath, |
693 | } | 694 | } |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index b528ff8ba..509f77850 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -48,7 +48,8 @@ pub enum ImportAlias { | |||
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(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { |
51 | lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone()) | 51 | let ctx = LowerCtx::with_hygiene(hygiene); |
52 | lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) | ||
52 | } | 53 | } |
53 | 54 | ||
54 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { | 55 | pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { |
@@ -167,8 +168,8 @@ pub enum GenericArg { | |||
167 | impl Path { | 168 | impl Path { |
168 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 169 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
169 | /// It correctly handles `$crate` based path from macro call. | 170 | /// It correctly handles `$crate` based path from macro call. |
170 | pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | 171 | pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> { |
171 | lower::lower_path(path, hygiene) | 172 | lower::lower_path(path, ctx) |
172 | } | 173 | } |
173 | 174 | ||
174 | /// Converts a known mod path to `Path`. | 175 | /// Converts a known mod path to `Path`. |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 7b29d9d4f..1df6db525 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -6,10 +6,7 @@ use crate::intern::Interned; | |||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use either::Either; | 8 | use either::Either; |
9 | use hir_expand::{ | 9 | use hir_expand::name::{name, AsName}; |
10 | hygiene::Hygiene, | ||
11 | name::{name, AsName}, | ||
12 | }; | ||
13 | use syntax::ast::{self, AstNode, TypeBoundsOwner}; | 10 | use syntax::ast::{self, AstNode, TypeBoundsOwner}; |
14 | 11 | ||
15 | use super::AssociatedTypeBinding; | 12 | use super::AssociatedTypeBinding; |
@@ -23,12 +20,12 @@ pub(super) use lower_use::lower_use_tree; | |||
23 | 20 | ||
24 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 21 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
25 | /// It correctly handles `$crate` based path from macro call. | 22 | /// It correctly handles `$crate` based path from macro call. |
26 | pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { | 23 | pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { |
27 | let mut kind = PathKind::Plain; | 24 | let mut kind = PathKind::Plain; |
28 | let mut type_anchor = None; | 25 | let mut type_anchor = None; |
29 | let mut segments = Vec::new(); | 26 | let mut segments = Vec::new(); |
30 | let mut generic_args = Vec::new(); | 27 | let mut generic_args = Vec::new(); |
31 | let ctx = LowerCtx::with_hygiene(hygiene); | 28 | let hygiene = ctx.hygiene(); |
32 | loop { | 29 | loop { |
33 | let segment = path.segment()?; | 30 | let segment = path.segment()?; |
34 | 31 | ||
@@ -43,10 +40,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
43 | Either::Left(name) => { | 40 | Either::Left(name) => { |
44 | let args = segment | 41 | let args = segment |
45 | .generic_arg_list() | 42 | .generic_arg_list() |
46 | .and_then(|it| lower_generic_args(&ctx, it)) | 43 | .and_then(|it| lower_generic_args(ctx, it)) |
47 | .or_else(|| { | 44 | .or_else(|| { |
48 | lower_generic_args_from_fn_path( | 45 | lower_generic_args_from_fn_path( |
49 | &ctx, | 46 | ctx, |
50 | segment.param_list(), | 47 | segment.param_list(), |
51 | segment.ret_type(), | 48 | segment.ret_type(), |
52 | ) | 49 | ) |
@@ -64,7 +61,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
64 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | 61 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { |
65 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | 62 | assert!(path.qualifier().is_none()); // this can only occur at the first segment |
66 | 63 | ||
67 | let self_type = TypeRef::from_ast(&ctx, type_ref?); | 64 | let self_type = TypeRef::from_ast(ctx, type_ref?); |
68 | 65 | ||
69 | match trait_ref { | 66 | match trait_ref { |
70 | // <T>::foo | 67 | // <T>::foo |
@@ -74,7 +71,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
74 | } | 71 | } |
75 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 72 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
76 | Some(trait_ref) => { | 73 | Some(trait_ref) => { |
77 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | 74 | let path = Path::from_src(trait_ref.path()?, ctx)?; |
78 | let mod_path = (*path.mod_path).clone(); | 75 | let mod_path = (*path.mod_path).clone(); |
79 | let num_segments = path.mod_path.segments.len(); | 76 | let num_segments = path.mod_path.segments.len(); |
80 | kind = mod_path.kind; | 77 | kind = mod_path.kind; |
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index 4c24aae94..ea29da5da 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! HIR for references to types. Paths in these are not yet resolved. They can | 1 | //! HIR for references to types. Paths in these are not yet resolved. They can |
2 | //! be directly created from an ast::TypeRef, without further queries. | 2 | //! be directly created from an ast::TypeRef, without further queries. |
3 | use hir_expand::name::Name; | 3 | |
4 | use hir_expand::{name::Name, AstId, InFile}; | ||
4 | use syntax::ast; | 5 | use syntax::ast; |
5 | 6 | ||
6 | use crate::{body::LowerCtx, path::Path}; | 7 | use crate::{body::LowerCtx, path::Path}; |
@@ -68,6 +69,7 @@ impl TraitRef { | |||
68 | } | 69 | } |
69 | } | 70 | } |
70 | } | 71 | } |
72 | |||
71 | /// Compare ty::Ty | 73 | /// Compare ty::Ty |
72 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 74 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
73 | pub enum TypeRef { | 75 | pub enum TypeRef { |
@@ -84,6 +86,7 @@ pub enum TypeRef { | |||
84 | // For | 86 | // For |
85 | ImplTrait(Vec<TypeBound>), | 87 | ImplTrait(Vec<TypeBound>), |
86 | DynTrait(Vec<TypeBound>), | 88 | DynTrait(Vec<TypeBound>), |
89 | Macro(AstId<ast::MacroCall>), | ||
87 | Error, | 90 | Error, |
88 | } | 91 | } |
89 | 92 | ||
@@ -116,7 +119,7 @@ pub enum TypeBound { | |||
116 | 119 | ||
117 | impl TypeRef { | 120 | impl TypeRef { |
118 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. | 121 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. |
119 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { | 122 | pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { |
120 | match node { | 123 | match node { |
121 | ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), | 124 | ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), |
122 | ast::Type::TupleType(inner) => { | 125 | ast::Type::TupleType(inner) => { |
@@ -176,8 +179,13 @@ impl TypeRef { | |||
176 | ast::Type::DynTraitType(inner) => { | 179 | ast::Type::DynTraitType(inner) => { |
177 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) | 180 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
178 | } | 181 | } |
179 | // FIXME: Macros in type position are not yet supported. | 182 | ast::Type::MacroType(mt) => match mt.macro_call() { |
180 | ast::Type::MacroType(_) => TypeRef::Error, | 183 | Some(mc) => ctx |
184 | .ast_id(&mc) | ||
185 | .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc))) | ||
186 | .unwrap_or(TypeRef::Error), | ||
187 | None => TypeRef::Error, | ||
188 | }, | ||
181 | } | 189 | } |
182 | } | 190 | } |
183 | 191 | ||
@@ -215,7 +223,7 @@ impl TypeRef { | |||
215 | } | 223 | } |
216 | } | 224 | } |
217 | TypeRef::Path(path) => go_path(path, f), | 225 | TypeRef::Path(path) => go_path(path, f), |
218 | TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} | 226 | TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {} |
219 | }; | 227 | }; |
220 | } | 228 | } |
221 | 229 | ||
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index ca705ee9d..1e4b0cc19 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -440,6 +440,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
440 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | 440 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, |
441 | MACRO_STMTS => FragmentKind::Statements, | 441 | MACRO_STMTS => FragmentKind::Statements, |
442 | MACRO_PAT => FragmentKind::Pattern, | 442 | MACRO_PAT => FragmentKind::Pattern, |
443 | MACRO_TYPE => FragmentKind::Type, | ||
443 | ITEM_LIST => FragmentKind::Items, | 444 | ITEM_LIST => FragmentKind::Items, |
444 | LET_STMT => { | 445 | LET_STMT => { |
445 | // FIXME: Handle LHS Pattern | 446 | // FIXME: Handle LHS Pattern |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index ef126e4ad..a5ac32d3c 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -31,6 +31,7 @@ use parser::FragmentKind; | |||
31 | use std::sync::Arc; | 31 | use std::sync::Arc; |
32 | use syntax::{algo::SyntaxRewriter, SyntaxNode}; | 32 | use syntax::{algo::SyntaxRewriter, SyntaxNode}; |
33 | 33 | ||
34 | #[derive(Debug)] | ||
34 | pub struct ErrorEmitted { | 35 | pub struct ErrorEmitted { |
35 | _private: (), | 36 | _private: (), |
36 | } | 37 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index e7c9dabc2..4fb7d9cf2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -9,6 +9,7 @@ use std::{ | |||
9 | 9 | ||
10 | use chalk_ir::BoundVar; | 10 | use chalk_ir::BoundVar; |
11 | use hir_def::{ | 11 | use hir_def::{ |
12 | body, | ||
12 | db::DefDatabase, | 13 | db::DefDatabase, |
13 | find_path, | 14 | find_path, |
14 | generics::TypeParamProvenance, | 15 | generics::TypeParamProvenance, |
@@ -18,7 +19,7 @@ use hir_def::{ | |||
18 | visibility::Visibility, | 19 | visibility::Visibility, |
19 | AssocContainerId, Lookup, ModuleId, TraitId, | 20 | AssocContainerId, Lookup, ModuleId, TraitId, |
20 | }; | 21 | }; |
21 | use hir_expand::name::Name; | 22 | use hir_expand::{hygiene::Hygiene, name::Name}; |
22 | 23 | ||
23 | use crate::{ | 24 | use crate::{ |
24 | const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, | 25 | const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, |
@@ -997,6 +998,18 @@ impl HirDisplay for TypeRef { | |||
997 | write!(f, "dyn ")?; | 998 | write!(f, "dyn ")?; |
998 | f.write_joined(bounds, " + ")?; | 999 | f.write_joined(bounds, " + ")?; |
999 | } | 1000 | } |
1001 | TypeRef::Macro(macro_call) => { | ||
1002 | let macro_call = macro_call.to_node(f.db.upcast()); | ||
1003 | let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); | ||
1004 | match macro_call.path() { | ||
1005 | Some(path) => match Path::from_src(path, &ctx) { | ||
1006 | Some(path) => path.hir_fmt(f)?, | ||
1007 | None => write!(f, "{{macro}}")?, | ||
1008 | }, | ||
1009 | None => write!(f, "{{macro}}")?, | ||
1010 | } | ||
1011 | write!(f, "!(..)")?; | ||
1012 | } | ||
1000 | TypeRef::Error => write!(f, "{{error}}")?, | 1013 | TypeRef::Error => write!(f, "{{error}}")?, |
1001 | } | 1014 | } |
1002 | Ok(()) | 1015 | Ok(()) |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index a035686bc..7fd46becd 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -5,12 +5,14 @@ | |||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | 5 | //! - Building the type for an item: This happens through the `type_for_def` query. |
6 | //! | 6 | //! |
7 | //! This usually involves resolving names, collecting generic arguments etc. | 7 | //! This usually involves resolving names, collecting generic arguments etc. |
8 | use std::cell::{Cell, RefCell}; | ||
8 | use std::{iter, sync::Arc}; | 9 | use std::{iter, sync::Arc}; |
9 | 10 | ||
10 | use base_db::CrateId; | 11 | use base_db::CrateId; |
11 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; | 12 | use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; |
12 | use hir_def::{ | 13 | use hir_def::{ |
13 | adt::StructKind, | 14 | adt::StructKind, |
15 | body::{Expander, LowerCtx}, | ||
14 | builtin_type::BuiltinType, | 16 | builtin_type::BuiltinType, |
15 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, | 17 | generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, |
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 18 | path::{GenericArg, Path, PathSegment, PathSegments}, |
@@ -20,10 +22,11 @@ use hir_def::{ | |||
20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, | 22 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | TypeAliasId, TypeParamId, UnionId, VariantId, | 23 | TypeAliasId, TypeParamId, UnionId, VariantId, |
22 | }; | 24 | }; |
23 | use hir_expand::name::Name; | 25 | use hir_expand::{name::Name, ExpandResult}; |
24 | use la_arena::ArenaMap; | 26 | use la_arena::ArenaMap; |
25 | use smallvec::SmallVec; | 27 | use smallvec::SmallVec; |
26 | use stdx::impl_from; | 28 | use stdx::impl_from; |
29 | use syntax::ast; | ||
27 | 30 | ||
28 | use crate::{ | 31 | use crate::{ |
29 | db::HirDatabase, | 32 | db::HirDatabase, |
@@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> { | |||
50 | /// possible currently, so this should be fine for now. | 53 | /// possible currently, so this should be fine for now. |
51 | pub type_param_mode: TypeParamLoweringMode, | 54 | pub type_param_mode: TypeParamLoweringMode, |
52 | pub impl_trait_mode: ImplTraitLoweringMode, | 55 | pub impl_trait_mode: ImplTraitLoweringMode, |
53 | impl_trait_counter: std::cell::Cell<u16>, | 56 | impl_trait_counter: Cell<u16>, |
54 | /// When turning `impl Trait` into opaque types, we have to collect the | 57 | /// When turning `impl Trait` into opaque types, we have to collect the |
55 | /// bounds at the same time to get the IDs correct (without becoming too | 58 | /// bounds at the same time to get the IDs correct (without becoming too |
56 | /// complicated). I don't like using interior mutability (as for the | 59 | /// complicated). I don't like using interior mutability (as for the |
@@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> { | |||
59 | /// we're grouping the mutable data (the counter and this field) together | 62 | /// we're grouping the mutable data (the counter and this field) together |
60 | /// with the immutable context (the references to the DB and resolver). | 63 | /// with the immutable context (the references to the DB and resolver). |
61 | /// Splitting this up would be a possible fix. | 64 | /// Splitting this up would be a possible fix. |
62 | opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, | 65 | opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>, |
66 | expander: RefCell<Option<Expander>>, | ||
63 | } | 67 | } |
64 | 68 | ||
65 | impl<'a> TyLoweringContext<'a> { | 69 | impl<'a> TyLoweringContext<'a> { |
66 | pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { | 70 | pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { |
67 | let impl_trait_counter = std::cell::Cell::new(0); | 71 | let impl_trait_counter = Cell::new(0); |
68 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; | 72 | let impl_trait_mode = ImplTraitLoweringMode::Disallowed; |
69 | let type_param_mode = TypeParamLoweringMode::Placeholder; | 73 | let type_param_mode = TypeParamLoweringMode::Placeholder; |
70 | let in_binders = DebruijnIndex::INNERMOST; | 74 | let in_binders = DebruijnIndex::INNERMOST; |
71 | let opaque_type_data = std::cell::RefCell::new(Vec::new()); | 75 | let opaque_type_data = RefCell::new(Vec::new()); |
72 | Self { | 76 | Self { |
73 | db, | 77 | db, |
74 | resolver, | 78 | resolver, |
@@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> { | |||
77 | impl_trait_counter, | 81 | impl_trait_counter, |
78 | type_param_mode, | 82 | type_param_mode, |
79 | opaque_type_data, | 83 | opaque_type_data, |
84 | expander: RefCell::new(None), | ||
80 | } | 85 | } |
81 | } | 86 | } |
82 | 87 | ||
@@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> { | |||
86 | f: impl FnOnce(&TyLoweringContext) -> T, | 91 | f: impl FnOnce(&TyLoweringContext) -> T, |
87 | ) -> T { | 92 | ) -> T { |
88 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); | 93 | let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); |
94 | let expander = self.expander.replace(None); | ||
89 | let new_ctx = Self { | 95 | let new_ctx = Self { |
90 | in_binders: debruijn, | 96 | in_binders: debruijn, |
91 | impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), | 97 | impl_trait_counter: Cell::new(self.impl_trait_counter.get()), |
92 | opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), | 98 | opaque_type_data: RefCell::new(opaque_ty_data_vec), |
99 | expander: RefCell::new(expander), | ||
93 | ..*self | 100 | ..*self |
94 | }; | 101 | }; |
95 | let result = f(&new_ctx); | 102 | let result = f(&new_ctx); |
96 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); | 103 | self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); |
97 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); | 104 | self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); |
105 | self.expander.replace(new_ctx.expander.into_inner()); | ||
98 | result | 106 | result |
99 | } | 107 | } |
100 | 108 | ||
@@ -287,6 +295,53 @@ impl<'a> TyLoweringContext<'a> { | |||
287 | } | 295 | } |
288 | } | 296 | } |
289 | } | 297 | } |
298 | TypeRef::Macro(macro_call) => { | ||
299 | let (expander, recursion_start) = { | ||
300 | let mut expander = self.expander.borrow_mut(); | ||
301 | if expander.is_some() { | ||
302 | (Some(expander), false) | ||
303 | } else { | ||
304 | if let Some(module_id) = self.resolver.module() { | ||
305 | *expander = Some(Expander::new( | ||
306 | self.db.upcast(), | ||
307 | macro_call.file_id, | ||
308 | module_id, | ||
309 | )); | ||
310 | (Some(expander), true) | ||
311 | } else { | ||
312 | (None, false) | ||
313 | } | ||
314 | } | ||
315 | }; | ||
316 | let ty = if let Some(mut expander) = expander { | ||
317 | let expander_mut = expander.as_mut().unwrap(); | ||
318 | let macro_call = macro_call.to_node(self.db.upcast()); | ||
319 | match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) { | ||
320 | Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { | ||
321 | let ctx = | ||
322 | LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); | ||
323 | let type_ref = TypeRef::from_ast(&ctx, expanded); | ||
324 | |||
325 | drop(expander); | ||
326 | let ty = self.lower_ty(&type_ref); | ||
327 | |||
328 | self.expander | ||
329 | .borrow_mut() | ||
330 | .as_mut() | ||
331 | .unwrap() | ||
332 | .exit(self.db.upcast(), mark); | ||
333 | Some(ty) | ||
334 | } | ||
335 | _ => None, | ||
336 | } | ||
337 | } else { | ||
338 | None | ||
339 | }; | ||
340 | if recursion_start { | ||
341 | *self.expander.borrow_mut() = None; | ||
342 | } | ||
343 | ty.unwrap_or_else(|| TyKind::Error.intern(&Interner)) | ||
344 | } | ||
290 | TypeRef::Error => TyKind::Error.intern(&Interner), | 345 | TypeRef::Error => TyKind::Error.intern(&Interner), |
291 | }; | 346 | }; |
292 | (ty, res) | 347 | (ty, res) |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index b8e373ed8..6588aa46c 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -1074,3 +1074,202 @@ fn macro_in_arm() { | |||
1074 | "#]], | 1074 | "#]], |
1075 | ); | 1075 | ); |
1076 | } | 1076 | } |
1077 | |||
1078 | #[test] | ||
1079 | fn macro_in_type_alias_position() { | ||
1080 | check_infer( | ||
1081 | r#" | ||
1082 | macro_rules! U32 { | ||
1083 | () => { u32 }; | ||
1084 | } | ||
1085 | |||
1086 | trait Foo { | ||
1087 | type Ty; | ||
1088 | } | ||
1089 | |||
1090 | impl<T> Foo for T { | ||
1091 | type Ty = U32!(); | ||
1092 | } | ||
1093 | |||
1094 | type TayTo = U32!(); | ||
1095 | |||
1096 | fn testy() { | ||
1097 | let a: <() as Foo>::Ty; | ||
1098 | let b: TayTo; | ||
1099 | } | ||
1100 | "#, | ||
1101 | expect![[r#" | ||
1102 | 147..196 '{ ...yTo; }': () | ||
1103 | 157..158 'a': u32 | ||
1104 | 185..186 'b': u32 | ||
1105 | "#]], | ||
1106 | ); | ||
1107 | } | ||
1108 | |||
1109 | #[test] | ||
1110 | fn nested_macro_in_type_alias_position() { | ||
1111 | check_infer( | ||
1112 | r#" | ||
1113 | macro_rules! U32Inner2 { | ||
1114 | () => { u32 }; | ||
1115 | } | ||
1116 | |||
1117 | macro_rules! U32Inner1 { | ||
1118 | () => { U32Inner2!() }; | ||
1119 | } | ||
1120 | |||
1121 | macro_rules! U32 { | ||
1122 | () => { U32Inner1!() }; | ||
1123 | } | ||
1124 | |||
1125 | trait Foo { | ||
1126 | type Ty; | ||
1127 | } | ||
1128 | |||
1129 | impl<T> Foo for T { | ||
1130 | type Ty = U32!(); | ||
1131 | } | ||
1132 | |||
1133 | type TayTo = U32!(); | ||
1134 | |||
1135 | fn testy() { | ||
1136 | let a: <() as Foo>::Ty; | ||
1137 | let b: TayTo; | ||
1138 | } | ||
1139 | "#, | ||
1140 | expect![[r#" | ||
1141 | 259..308 '{ ...yTo; }': () | ||
1142 | 269..270 'a': u32 | ||
1143 | 297..298 'b': u32 | ||
1144 | "#]], | ||
1145 | ); | ||
1146 | } | ||
1147 | |||
1148 | #[test] | ||
1149 | fn macros_in_type_alias_position_generics() { | ||
1150 | check_infer( | ||
1151 | r#" | ||
1152 | struct Foo<A, B>(A, B); | ||
1153 | |||
1154 | macro_rules! U32 { | ||
1155 | () => { u32 }; | ||
1156 | } | ||
1157 | |||
1158 | macro_rules! Bar { | ||
1159 | () => { Foo<U32!(), U32!()> }; | ||
1160 | } | ||
1161 | |||
1162 | trait Moo { | ||
1163 | type Ty; | ||
1164 | } | ||
1165 | |||
1166 | impl<T> Moo for T { | ||
1167 | type Ty = Bar!(); | ||
1168 | } | ||
1169 | |||
1170 | type TayTo = Bar!(); | ||
1171 | |||
1172 | fn main() { | ||
1173 | let a: <() as Moo>::Ty; | ||
1174 | let b: TayTo; | ||
1175 | } | ||
1176 | "#, | ||
1177 | expect![[r#" | ||
1178 | 228..277 '{ ...yTo; }': () | ||
1179 | 238..239 'a': Foo<u32, u32> | ||
1180 | 266..267 'b': Foo<u32, u32> | ||
1181 | "#]], | ||
1182 | ); | ||
1183 | } | ||
1184 | |||
1185 | #[test] | ||
1186 | fn macros_in_type_position() { | ||
1187 | check_infer( | ||
1188 | r#" | ||
1189 | struct Foo<A, B>(A, B); | ||
1190 | |||
1191 | macro_rules! U32 { | ||
1192 | () => { u32 }; | ||
1193 | } | ||
1194 | |||
1195 | macro_rules! Bar { | ||
1196 | () => { Foo<U32!(), U32!()> }; | ||
1197 | } | ||
1198 | |||
1199 | fn main() { | ||
1200 | let a: Bar!(); | ||
1201 | } | ||
1202 | "#, | ||
1203 | expect![[r#" | ||
1204 | 133..155 '{ ...!(); }': () | ||
1205 | 143..144 'a': Foo<u32, u32> | ||
1206 | "#]], | ||
1207 | ); | ||
1208 | } | ||
1209 | |||
1210 | #[test] | ||
1211 | fn macros_in_type_generics() { | ||
1212 | check_infer( | ||
1213 | r#" | ||
1214 | struct Foo<A, B>(A, B); | ||
1215 | |||
1216 | macro_rules! U32 { | ||
1217 | () => { u32 }; | ||
1218 | } | ||
1219 | |||
1220 | macro_rules! Bar { | ||
1221 | () => { Foo<U32!(), U32!()> }; | ||
1222 | } | ||
1223 | |||
1224 | trait Moo { | ||
1225 | type Ty; | ||
1226 | } | ||
1227 | |||
1228 | impl<T> Moo for T { | ||
1229 | type Ty = Foo<Bar!(), Bar!()>; | ||
1230 | } | ||
1231 | |||
1232 | type TayTo = Foo<Bar!(), U32!()>; | ||
1233 | |||
1234 | fn main() { | ||
1235 | let a: <() as Moo>::Ty; | ||
1236 | let b: TayTo; | ||
1237 | } | ||
1238 | "#, | ||
1239 | expect![[r#" | ||
1240 | 254..303 '{ ...yTo; }': () | ||
1241 | 264..265 'a': Foo<Foo<u32, u32>, Foo<u32, u32>> | ||
1242 | 292..293 'b': Foo<Foo<u32, u32>, u32> | ||
1243 | "#]], | ||
1244 | ); | ||
1245 | } | ||
1246 | |||
1247 | #[test] | ||
1248 | fn infinitely_recursive_macro_type() { | ||
1249 | check_infer( | ||
1250 | r#" | ||
1251 | struct Bar<T, X>(T, X); | ||
1252 | |||
1253 | macro_rules! Foo { | ||
1254 | () => { Foo!() } | ||
1255 | } | ||
1256 | |||
1257 | macro_rules! U32 { | ||
1258 | () => { u32 } | ||
1259 | } | ||
1260 | |||
1261 | type A = Foo!(); | ||
1262 | type B = Bar<Foo!(), U32!()>; | ||
1263 | |||
1264 | fn main() { | ||
1265 | let a: A; | ||
1266 | let b: B; | ||
1267 | } | ||
1268 | "#, | ||
1269 | expect![[r#" | ||
1270 | 166..197 '{ ...: B; }': () | ||
1271 | 176..177 'a': {unknown} | ||
1272 | 190..191 'b': Bar<{unknown}, u32> | ||
1273 | "#]], | ||
1274 | ); | ||
1275 | } | ||
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index c5dc14a23..cb5a8e19a 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -108,13 +108,13 @@ pub(crate) fn external_docs( | |||
108 | let node = token.parent()?; | 108 | let node = token.parent()?; |
109 | let definition = match_ast! { | 109 | let definition = match_ast! { |
110 | match node { | 110 | match node { |
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db))?, |
112 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), | 112 | ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db))?, |
113 | _ => None, | 113 | _ => return None, |
114 | } | 114 | } |
115 | }; | 115 | }; |
116 | 116 | ||
117 | get_doc_link(db, definition?) | 117 | get_doc_link(db, definition) |
118 | } | 118 | } |
119 | 119 | ||
120 | /// Extracts all links from a given markdown text. | 120 | /// Extracts all links from a given markdown text. |
@@ -214,20 +214,20 @@ fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, Cow | |||
214 | // This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented | 214 | // This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented |
215 | // https://github.com/rust-lang/rfcs/pull/2988 | 215 | // https://github.com/rust-lang/rfcs/pull/2988 |
216 | fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | 216 | fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { |
217 | // Get the outermost definition for the moduledef. This is used to resolve the public path to the type, | 217 | // Get the outermost definition for the module def. This is used to resolve the public path to the type, |
218 | // then we can join the method, field, etc onto it if required. | 218 | // then we can join the method, field, etc onto it if required. |
219 | let target_def: ModuleDef = match definition { | 219 | let target_def: ModuleDef = match definition { |
220 | Definition::ModuleDef(moddef) => match moddef { | 220 | Definition::ModuleDef(def) => match def { |
221 | ModuleDef::Function(f) => f | 221 | ModuleDef::Function(f) => f |
222 | .as_assoc_item(db) | 222 | .as_assoc_item(db) |
223 | .and_then(|assoc| match assoc.container(db) { | 223 | .and_then(|assoc| match assoc.container(db) { |
224 | AssocItemContainer::Trait(t) => Some(t.into()), | 224 | AssocItemContainer::Trait(t) => Some(t.into()), |
225 | AssocItemContainer::Impl(impld) => { | 225 | AssocItemContainer::Impl(impl_) => { |
226 | impld.self_ty(db).as_adt().map(|adt| adt.into()) | 226 | impl_.self_ty(db).as_adt().map(|adt| adt.into()) |
227 | } | 227 | } |
228 | }) | 228 | }) |
229 | .unwrap_or_else(|| f.clone().into()), | 229 | .unwrap_or_else(|| def), |
230 | moddef => moddef, | 230 | def => def, |
231 | }, | 231 | }, |
232 | Definition::Field(f) => f.parent_def(db).into(), | 232 | Definition::Field(f) => f.parent_def(db).into(), |
233 | // FIXME: Handle macros | 233 | // FIXME: Handle macros |
@@ -236,17 +236,28 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { | |||
236 | 236 | ||
237 | let ns = ItemInNs::from(target_def); | 237 | let ns = ItemInNs::from(target_def); |
238 | 238 | ||
239 | let module = definition.module(db)?; | 239 | let krate = match definition { |
240 | let krate = module.krate(); | 240 | // Definition::module gives back the parent module, we don't want that as it fails for root modules |
241 | Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(), | ||
242 | _ => definition.module(db)?.krate(), | ||
243 | }; | ||
241 | let import_map = db.import_map(krate.into()); | 244 | let import_map = db.import_map(krate.into()); |
242 | let base = once(krate.display_name(db)?.to_string()) | 245 | |
243 | .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string())) | 246 | let mut base = krate.display_name(db)?.to_string(); |
244 | .join("/") | 247 | let is_root_module = matches!( |
245 | + "/"; | 248 | definition, |
249 | Definition::ModuleDef(ModuleDef::Module(module)) if krate.root_module(db) == module | ||
250 | ); | ||
251 | if !is_root_module { | ||
252 | base = once(base) | ||
253 | .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string())) | ||
254 | .join("/"); | ||
255 | } | ||
256 | base += "/"; | ||
246 | 257 | ||
247 | let filename = get_symbol_filename(db, &target_def); | 258 | let filename = get_symbol_filename(db, &target_def); |
248 | let fragment = match definition { | 259 | let fragment = match definition { |
249 | Definition::ModuleDef(moddef) => match moddef { | 260 | Definition::ModuleDef(def) => match def { |
250 | ModuleDef::Function(f) => { | 261 | ModuleDef::Function(f) => { |
251 | get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f))) | 262 | get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f))) |
252 | } | 263 | } |
@@ -533,6 +544,19 @@ mod tests { | |||
533 | } | 544 | } |
534 | 545 | ||
535 | #[test] | 546 | #[test] |
547 | fn test_doc_url_crate() { | ||
548 | check( | ||
549 | r#" | ||
550 | //- /main.rs crate:main deps:test | ||
551 | use test$0::Foo; | ||
552 | //- /lib.rs crate:test | ||
553 | pub struct Foo; | ||
554 | "#, | ||
555 | expect![[r#"https://docs.rs/test/*/test/index.html"#]], | ||
556 | ); | ||
557 | } | ||
558 | |||
559 | #[test] | ||
536 | fn test_doc_url_struct() { | 560 | fn test_doc_url_struct() { |
537 | check( | 561 | check( |
538 | r#" | 562 | r#" |
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs index 8cc877c1c..18552459b 100644 --- a/crates/ide/src/syntax_highlighting/highlight.rs +++ b/crates/ide/src/syntax_highlighting/highlight.rs | |||
@@ -222,7 +222,7 @@ pub(super) fn element( | |||
222 | T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] | 222 | T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] |
223 | if element.parent().and_then(ast::BinExpr::cast).is_some() => | 223 | if element.parent().and_then(ast::BinExpr::cast).is_some() => |
224 | { | 224 | { |
225 | HlTag::Operator(HlOperator::Comparision).into() | 225 | HlTag::Operator(HlOperator::Comparison).into() |
226 | } | 226 | } |
227 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { | 227 | _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { |
228 | HlTag::Operator(HlOperator::Other).into() | 228 | HlTag::Operator(HlOperator::Other).into() |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 8128d231d..e58392d67 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -96,7 +96,7 @@ pub enum HlOperator { | |||
96 | /// &&, ||, ! | 96 | /// &&, ||, ! |
97 | Logical, | 97 | Logical, |
98 | /// >, <, ==, >=, <=, != | 98 | /// >, <, ==, >=, <=, != |
99 | Comparision, | 99 | Comparison, |
100 | /// | 100 | /// |
101 | Other, | 101 | Other, |
102 | } | 102 | } |
@@ -151,7 +151,7 @@ impl HlTag { | |||
151 | HlOperator::Bitwise => "bitwise", | 151 | HlOperator::Bitwise => "bitwise", |
152 | HlOperator::Arithmetic => "arithmetic", | 152 | HlOperator::Arithmetic => "arithmetic", |
153 | HlOperator::Logical => "logical", | 153 | HlOperator::Logical => "logical", |
154 | HlOperator::Comparision => "comparision", | 154 | HlOperator::Comparison => "comparison", |
155 | HlOperator::Other => "operator", | 155 | HlOperator::Other => "operator", |
156 | }, | 156 | }, |
157 | HlTag::StringLiteral => "string_literal", | 157 | HlTag::StringLiteral => "string_literal", |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index 059414274..78a57fbdc 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -599,7 +599,12 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu | |||
599 | // we have selected a few statements in a block | 599 | // we have selected a few statements in a block |
600 | // so covering_element returns the whole block | 600 | // so covering_element returns the whole block |
601 | if node.kind() == BLOCK_EXPR { | 601 | if node.kind() == BLOCK_EXPR { |
602 | let body = FunctionBody::from_range(node.clone(), selection_range); | 602 | // Extract the full statements. |
603 | let statements_range = node | ||
604 | .children() | ||
605 | .filter(|c| selection_range.intersect(c.text_range()).is_some()) | ||
606 | .fold(selection_range, |acc, c| acc.cover(c.text_range())); | ||
607 | let body = FunctionBody::from_range(node.clone(), statements_range); | ||
603 | if body.is_some() { | 608 | if body.is_some() { |
604 | return body; | 609 | return body; |
605 | } | 610 | } |
@@ -610,7 +615,8 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu | |||
610 | // so we try to expand covering_element to parent and repeat the previous | 615 | // so we try to expand covering_element to parent and repeat the previous |
611 | if let Some(parent) = node.parent() { | 616 | if let Some(parent) = node.parent() { |
612 | if parent.kind() == BLOCK_EXPR { | 617 | if parent.kind() == BLOCK_EXPR { |
613 | let body = FunctionBody::from_range(parent, selection_range); | 618 | // Extract the full statement. |
619 | let body = FunctionBody::from_range(parent, node.text_range()); | ||
614 | if body.is_some() { | 620 | if body.is_some() { |
615 | return body; | 621 | return body; |
616 | } | 622 | } |
@@ -1785,6 +1791,60 @@ fn $0fun_name() -> i32 { | |||
1785 | } | 1791 | } |
1786 | 1792 | ||
1787 | #[test] | 1793 | #[test] |
1794 | fn extract_partial_block_single_line() { | ||
1795 | check_assist( | ||
1796 | extract_function, | ||
1797 | r#" | ||
1798 | fn foo() { | ||
1799 | let n = 1; | ||
1800 | let mut v = $0n * n;$0 | ||
1801 | v += 1; | ||
1802 | }"#, | ||
1803 | r#" | ||
1804 | fn foo() { | ||
1805 | let n = 1; | ||
1806 | let mut v = fun_name(n); | ||
1807 | v += 1; | ||
1808 | } | ||
1809 | |||
1810 | fn $0fun_name(n: i32) -> i32 { | ||
1811 | let mut v = n * n; | ||
1812 | v | ||
1813 | }"#, | ||
1814 | ); | ||
1815 | } | ||
1816 | |||
1817 | #[test] | ||
1818 | fn extract_partial_block() { | ||
1819 | check_assist( | ||
1820 | extract_function, | ||
1821 | r#" | ||
1822 | fn foo() { | ||
1823 | let m = 2; | ||
1824 | let n = 1; | ||
1825 | let mut v = m $0* n; | ||
1826 | let mut w = 3;$0 | ||
1827 | v += 1; | ||
1828 | w += 1; | ||
1829 | }"#, | ||
1830 | r#" | ||
1831 | fn foo() { | ||
1832 | let m = 2; | ||
1833 | let n = 1; | ||
1834 | let (mut v, mut w) = fun_name(m, n); | ||
1835 | v += 1; | ||
1836 | w += 1; | ||
1837 | } | ||
1838 | |||
1839 | fn $0fun_name(m: i32, n: i32) -> (i32, i32) { | ||
1840 | let mut v = m * n; | ||
1841 | let mut w = 3; | ||
1842 | (v, w) | ||
1843 | }"#, | ||
1844 | ); | ||
1845 | } | ||
1846 | |||
1847 | #[test] | ||
1788 | fn argument_form_expr() { | 1848 | fn argument_form_expr() { |
1789 | check_assist( | 1849 | check_assist( |
1790 | extract_function, | 1850 | extract_function, |
diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs index 02782eb6d..9f4f71d6c 100644 --- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs +++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | use syntax::{ | 2 | use syntax::{ |
3 | ast::{self, GenericParamsOwner, NameOwner}, | 3 | ast::{self, edit_in_place::GenericParamsOwnerEdit, make, GenericParamsOwner}, |
4 | AstNode, TextRange, TextSize, | 4 | ted::{self, Position}, |
5 | AstNode, TextRange, | ||
5 | }; | 6 | }; |
6 | 7 | ||
7 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; | 8 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; |
@@ -37,10 +38,12 @@ static ASSIST_LABEL: &str = "Introduce named lifetime"; | |||
37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 38 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
38 | let lifetime = | 39 | let lifetime = |
39 | ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?; | 40 | ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?; |
41 | let lifetime_loc = lifetime.lifetime_ident_token()?.text_range(); | ||
42 | |||
40 | if let Some(fn_def) = lifetime.syntax().ancestors().find_map(ast::Fn::cast) { | 43 | if let Some(fn_def) = lifetime.syntax().ancestors().find_map(ast::Fn::cast) { |
41 | generate_fn_def_assist(acc, &fn_def, lifetime.lifetime_ident_token()?.text_range()) | 44 | generate_fn_def_assist(acc, fn_def, lifetime_loc, lifetime) |
42 | } else if let Some(impl_def) = lifetime.syntax().ancestors().find_map(ast::Impl::cast) { | 45 | } else if let Some(impl_def) = lifetime.syntax().ancestors().find_map(ast::Impl::cast) { |
43 | generate_impl_def_assist(acc, &impl_def, lifetime.lifetime_ident_token()?.text_range()) | 46 | generate_impl_def_assist(acc, impl_def, lifetime_loc, lifetime) |
44 | } else { | 47 | } else { |
45 | None | 48 | None |
46 | } | 49 | } |
@@ -49,26 +52,26 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) - | |||
49 | /// Generate the assist for the fn def case | 52 | /// Generate the assist for the fn def case |
50 | fn generate_fn_def_assist( | 53 | fn generate_fn_def_assist( |
51 | acc: &mut Assists, | 54 | acc: &mut Assists, |
52 | fn_def: &ast::Fn, | 55 | fn_def: ast::Fn, |
53 | lifetime_loc: TextRange, | 56 | lifetime_loc: TextRange, |
57 | lifetime: ast::Lifetime, | ||
54 | ) -> Option<()> { | 58 | ) -> Option<()> { |
55 | let param_list: ast::ParamList = fn_def.param_list()?; | 59 | let param_list: ast::ParamList = fn_def.param_list()?; |
56 | let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.generic_param_list())?; | 60 | let new_lifetime_param = generate_unique_lifetime_param_name(fn_def.generic_param_list())?; |
57 | let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end(); | ||
58 | let self_param = | 61 | let self_param = |
59 | // use the self if it's a reference and has no explicit lifetime | 62 | // use the self if it's a reference and has no explicit lifetime |
60 | param_list.self_param().filter(|p| p.lifetime().is_none() && p.amp_token().is_some()); | 63 | param_list.self_param().filter(|p| p.lifetime().is_none() && p.amp_token().is_some()); |
61 | // compute the location which implicitly has the same lifetime as the anonymous lifetime | 64 | // compute the location which implicitly has the same lifetime as the anonymous lifetime |
62 | let loc_needing_lifetime = if let Some(self_param) = self_param { | 65 | let loc_needing_lifetime = if let Some(self_param) = self_param { |
63 | // if we have a self reference, use that | 66 | // if we have a self reference, use that |
64 | Some(self_param.name()?.syntax().text_range().start()) | 67 | Some(NeedsLifetime::SelfParam(self_param)) |
65 | } else { | 68 | } else { |
66 | // otherwise, if there's a single reference parameter without a named liftime, use that | 69 | // otherwise, if there's a single reference parameter without a named liftime, use that |
67 | let fn_params_without_lifetime: Vec<_> = param_list | 70 | let fn_params_without_lifetime: Vec<_> = param_list |
68 | .params() | 71 | .params() |
69 | .filter_map(|param| match param.ty() { | 72 | .filter_map(|param| match param.ty() { |
70 | Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime().is_none() => { | 73 | Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime().is_none() => { |
71 | Some(ascribed_type.amp_token()?.text_range().end()) | 74 | Some(NeedsLifetime::RefType(ascribed_type)) |
72 | } | 75 | } |
73 | _ => None, | 76 | _ => None, |
74 | }) | 77 | }) |
@@ -81,30 +84,46 @@ fn generate_fn_def_assist( | |||
81 | } | 84 | } |
82 | }; | 85 | }; |
83 | acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { | 86 | acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { |
84 | add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); | 87 | let fn_def = builder.make_ast_mut(fn_def); |
85 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | 88 | let lifetime = builder.make_ast_mut(lifetime); |
86 | loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); | 89 | let loc_needing_lifetime = |
90 | loc_needing_lifetime.and_then(|it| it.make_mut(builder).to_position()); | ||
91 | |||
92 | add_lifetime_param(fn_def.get_or_create_generic_param_list(), new_lifetime_param); | ||
93 | ted::replace( | ||
94 | lifetime.syntax(), | ||
95 | make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(), | ||
96 | ); | ||
97 | loc_needing_lifetime.map(|position| { | ||
98 | ted::insert(position, make_ast_lifetime(new_lifetime_param).clone_for_update().syntax()) | ||
99 | }); | ||
87 | }) | 100 | }) |
88 | } | 101 | } |
89 | 102 | ||
90 | /// Generate the assist for the impl def case | 103 | /// Generate the assist for the impl def case |
91 | fn generate_impl_def_assist( | 104 | fn generate_impl_def_assist( |
92 | acc: &mut Assists, | 105 | acc: &mut Assists, |
93 | impl_def: &ast::Impl, | 106 | impl_def: ast::Impl, |
94 | lifetime_loc: TextRange, | 107 | lifetime_loc: TextRange, |
108 | lifetime: ast::Lifetime, | ||
95 | ) -> Option<()> { | 109 | ) -> Option<()> { |
96 | let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.generic_param_list())?; | 110 | let new_lifetime_param = generate_unique_lifetime_param_name(impl_def.generic_param_list())?; |
97 | let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); | ||
98 | acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { | 111 | acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { |
99 | add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); | 112 | let impl_def = builder.make_ast_mut(impl_def); |
100 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | 113 | let lifetime = builder.make_ast_mut(lifetime); |
114 | |||
115 | add_lifetime_param(impl_def.get_or_create_generic_param_list(), new_lifetime_param); | ||
116 | ted::replace( | ||
117 | lifetime.syntax(), | ||
118 | make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(), | ||
119 | ); | ||
101 | }) | 120 | }) |
102 | } | 121 | } |
103 | 122 | ||
104 | /// Given a type parameter list, generate a unique lifetime parameter name | 123 | /// Given a type parameter list, generate a unique lifetime parameter name |
105 | /// which is not in the list | 124 | /// which is not in the list |
106 | fn generate_unique_lifetime_param_name( | 125 | fn generate_unique_lifetime_param_name( |
107 | existing_type_param_list: &Option<ast::GenericParamList>, | 126 | existing_type_param_list: Option<ast::GenericParamList>, |
108 | ) -> Option<char> { | 127 | ) -> Option<char> { |
109 | match existing_type_param_list { | 128 | match existing_type_param_list { |
110 | Some(type_params) => { | 129 | Some(type_params) => { |
@@ -118,25 +137,37 @@ fn generate_unique_lifetime_param_name( | |||
118 | } | 137 | } |
119 | } | 138 | } |
120 | 139 | ||
121 | /// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise | 140 | fn add_lifetime_param(type_params: ast::GenericParamList, new_lifetime_param: char) { |
122 | /// add new type params brackets with the lifetime parameter at `new_type_params_loc`. | 141 | let generic_param = |
123 | fn add_lifetime_param<TypeParamsOwner: ast::GenericParamsOwner>( | 142 | make::generic_param(format!("'{}", new_lifetime_param), None).clone_for_update(); |
124 | type_params_owner: &TypeParamsOwner, | 143 | type_params.add_generic_param(generic_param); |
125 | builder: &mut AssistBuilder, | 144 | } |
126 | new_type_params_loc: TextSize, | 145 | |
127 | new_lifetime_param: char, | 146 | fn make_ast_lifetime(new_lifetime_param: char) -> ast::Lifetime { |
128 | ) { | 147 | make::generic_param(format!("'{}", new_lifetime_param), None) |
129 | match type_params_owner.generic_param_list() { | 148 | .syntax() |
130 | // add the new lifetime parameter to an existing type param list | 149 | .descendants() |
131 | Some(type_params) => { | 150 | .find_map(ast::Lifetime::cast) |
132 | builder.insert( | 151 | .unwrap() |
133 | (u32::from(type_params.syntax().text_range().end()) - 1).into(), | 152 | } |
134 | format!(", '{}", new_lifetime_param), | 153 | |
135 | ); | 154 | enum NeedsLifetime { |
155 | SelfParam(ast::SelfParam), | ||
156 | RefType(ast::RefType), | ||
157 | } | ||
158 | |||
159 | impl NeedsLifetime { | ||
160 | fn make_mut(self, builder: &mut AssistBuilder) -> Self { | ||
161 | match self { | ||
162 | Self::SelfParam(it) => Self::SelfParam(builder.make_ast_mut(it)), | ||
163 | Self::RefType(it) => Self::RefType(builder.make_ast_mut(it)), | ||
136 | } | 164 | } |
137 | // create a new type param list containing only the new lifetime parameter | 165 | } |
138 | None => { | 166 | |
139 | builder.insert(new_type_params_loc, format!("<'{}>", new_lifetime_param)); | 167 | fn to_position(self) -> Option<Position> { |
168 | match self { | ||
169 | Self::SelfParam(it) => Some(Position::after(it.amp_token()?)), | ||
170 | Self::RefType(it) => Some(Position::after(it.amp_token()?)), | ||
140 | } | 171 | } |
141 | } | 172 | } |
142 | } | 173 | } |
@@ -312,4 +343,13 @@ mod tests { | |||
312 | r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, | 343 | r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, |
313 | ); | 344 | ); |
314 | } | 345 | } |
346 | |||
347 | #[test] | ||
348 | fn test_function_add_lifetime_to_self_ref_mut() { | ||
349 | check_assist( | ||
350 | introduce_named_lifetime, | ||
351 | r#"fn foo(&mut self) -> &'_$0 ()"#, | ||
352 | r#"fn foo<'a>(&'a mut self) -> &'a ()"#, | ||
353 | ); | ||
354 | } | ||
315 | } | 355 | } |
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 94cbf7d85..6ae3e734f 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs | |||
@@ -283,17 +283,21 @@ pub(super) fn path_type(p: &mut Parser) { | |||
283 | // type B = crate::foo!(); | 283 | // type B = crate::foo!(); |
284 | fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { | 284 | fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { |
285 | assert!(paths::is_path_start(p)); | 285 | assert!(paths::is_path_start(p)); |
286 | let r = p.start(); | ||
286 | let m = p.start(); | 287 | let m = p.start(); |
288 | |||
287 | paths::type_path(p); | 289 | paths::type_path(p); |
288 | 290 | ||
289 | let kind = if p.at(T![!]) && !p.at(T![!=]) { | 291 | let kind = if p.at(T![!]) && !p.at(T![!=]) { |
290 | items::macro_call_after_excl(p); | 292 | items::macro_call_after_excl(p); |
291 | MACRO_CALL | 293 | m.complete(p, MACRO_CALL); |
294 | MACRO_TYPE | ||
292 | } else { | 295 | } else { |
296 | m.abandon(p); | ||
293 | PATH_TYPE | 297 | PATH_TYPE |
294 | }; | 298 | }; |
295 | 299 | ||
296 | let path = m.complete(p, kind); | 300 | let path = r.complete(p, kind); |
297 | 301 | ||
298 | if allow_bounds { | 302 | if allow_bounds { |
299 | opt_type_bounds_as_dyn_trait_type(p, path); | 303 | opt_type_bounds_as_dyn_trait_type(p, path); |
@@ -319,7 +323,7 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { | |||
319 | fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { | 323 | fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { |
320 | assert!(matches!( | 324 | assert!(matches!( |
321 | type_marker.kind(), | 325 | type_marker.kind(), |
322 | SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL | 326 | SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE |
323 | )); | 327 | )); |
324 | if !p.at(T![+]) { | 328 | if !p.at(T![+]) { |
325 | return; | 329 | return; |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index adc059817..ecab89b2a 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -49,7 +49,7 @@ define_semantic_token_types![ | |||
49 | (CHAR_LITERAL, "characterLiteral"), | 49 | (CHAR_LITERAL, "characterLiteral"), |
50 | (COLON, "colon"), | 50 | (COLON, "colon"), |
51 | (COMMA, "comma"), | 51 | (COMMA, "comma"), |
52 | (COMPARISION, "comparision"), | 52 | (COMPARISON, "comparison"), |
53 | (CONST_PARAMETER, "constParameter"), | 53 | (CONST_PARAMETER, "constParameter"), |
54 | (DOT, "dot"), | 54 | (DOT, "dot"), |
55 | (ESCAPE_SEQUENCE, "escapeSequence"), | 55 | (ESCAPE_SEQUENCE, "escapeSequence"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index fe4d0733d..c2361b32e 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -469,7 +469,7 @@ fn semantic_token_type_and_modifiers( | |||
469 | HlOperator::Bitwise => semantic_tokens::BITWISE, | 469 | HlOperator::Bitwise => semantic_tokens::BITWISE, |
470 | HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, | 470 | HlOperator::Arithmetic => semantic_tokens::ARITHMETIC, |
471 | HlOperator::Logical => semantic_tokens::LOGICAL, | 471 | HlOperator::Logical => semantic_tokens::LOGICAL, |
472 | HlOperator::Comparision => semantic_tokens::COMPARISION, | 472 | HlOperator::Comparison => semantic_tokens::COMPARISON, |
473 | HlOperator::Other => semantic_tokens::OPERATOR, | 473 | HlOperator::Other => semantic_tokens::OPERATOR, |
474 | }, | 474 | }, |
475 | HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, | 475 | HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 529bd0eb1..04f97f368 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -14,10 +14,29 @@ use crate::{ | |||
14 | use super::NameOwner; | 14 | use super::NameOwner; |
15 | 15 | ||
16 | pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit { | 16 | pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit { |
17 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList; | ||
17 | fn get_or_create_where_clause(&self) -> ast::WhereClause; | 18 | fn get_or_create_where_clause(&self) -> ast::WhereClause; |
18 | } | 19 | } |
19 | 20 | ||
20 | impl GenericParamsOwnerEdit for ast::Fn { | 21 | impl GenericParamsOwnerEdit for ast::Fn { |
22 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { | ||
23 | match self.generic_param_list() { | ||
24 | Some(it) => it, | ||
25 | None => { | ||
26 | let position = if let Some(name) = self.name() { | ||
27 | Position::after(name.syntax) | ||
28 | } else if let Some(fn_token) = self.fn_token() { | ||
29 | Position::after(fn_token) | ||
30 | } else if let Some(param_list) = self.param_list() { | ||
31 | Position::before(param_list.syntax) | ||
32 | } else { | ||
33 | Position::last_child_of(self.syntax()) | ||
34 | }; | ||
35 | create_generic_param_list(position) | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
21 | fn get_or_create_where_clause(&self) -> WhereClause { | 40 | fn get_or_create_where_clause(&self) -> WhereClause { |
22 | if self.where_clause().is_none() { | 41 | if self.where_clause().is_none() { |
23 | let position = if let Some(ty) = self.ret_type() { | 42 | let position = if let Some(ty) = self.ret_type() { |
@@ -34,6 +53,20 @@ impl GenericParamsOwnerEdit for ast::Fn { | |||
34 | } | 53 | } |
35 | 54 | ||
36 | impl GenericParamsOwnerEdit for ast::Impl { | 55 | impl GenericParamsOwnerEdit for ast::Impl { |
56 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { | ||
57 | match self.generic_param_list() { | ||
58 | Some(it) => it, | ||
59 | None => { | ||
60 | let position = if let Some(imp_token) = self.impl_token() { | ||
61 | Position::after(imp_token) | ||
62 | } else { | ||
63 | Position::last_child_of(self.syntax()) | ||
64 | }; | ||
65 | create_generic_param_list(position) | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
37 | fn get_or_create_where_clause(&self) -> WhereClause { | 70 | fn get_or_create_where_clause(&self) -> WhereClause { |
38 | if self.where_clause().is_none() { | 71 | if self.where_clause().is_none() { |
39 | let position = if let Some(items) = self.assoc_item_list() { | 72 | let position = if let Some(items) = self.assoc_item_list() { |
@@ -48,6 +81,22 @@ impl GenericParamsOwnerEdit for ast::Impl { | |||
48 | } | 81 | } |
49 | 82 | ||
50 | impl GenericParamsOwnerEdit for ast::Trait { | 83 | impl GenericParamsOwnerEdit for ast::Trait { |
84 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { | ||
85 | match self.generic_param_list() { | ||
86 | Some(it) => it, | ||
87 | None => { | ||
88 | let position = if let Some(name) = self.name() { | ||
89 | Position::after(name.syntax) | ||
90 | } else if let Some(trait_token) = self.trait_token() { | ||
91 | Position::after(trait_token) | ||
92 | } else { | ||
93 | Position::last_child_of(self.syntax()) | ||
94 | }; | ||
95 | create_generic_param_list(position) | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
51 | fn get_or_create_where_clause(&self) -> WhereClause { | 100 | fn get_or_create_where_clause(&self) -> WhereClause { |
52 | if self.where_clause().is_none() { | 101 | if self.where_clause().is_none() { |
53 | let position = if let Some(items) = self.assoc_item_list() { | 102 | let position = if let Some(items) = self.assoc_item_list() { |
@@ -62,6 +111,22 @@ impl GenericParamsOwnerEdit for ast::Trait { | |||
62 | } | 111 | } |
63 | 112 | ||
64 | impl GenericParamsOwnerEdit for ast::Struct { | 113 | impl GenericParamsOwnerEdit for ast::Struct { |
114 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { | ||
115 | match self.generic_param_list() { | ||
116 | Some(it) => it, | ||
117 | None => { | ||
118 | let position = if let Some(name) = self.name() { | ||
119 | Position::after(name.syntax) | ||
120 | } else if let Some(struct_token) = self.struct_token() { | ||
121 | Position::after(struct_token) | ||
122 | } else { | ||
123 | Position::last_child_of(self.syntax()) | ||
124 | }; | ||
125 | create_generic_param_list(position) | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
65 | fn get_or_create_where_clause(&self) -> WhereClause { | 130 | fn get_or_create_where_clause(&self) -> WhereClause { |
66 | if self.where_clause().is_none() { | 131 | if self.where_clause().is_none() { |
67 | let tfl = self.field_list().and_then(|fl| match fl { | 132 | let tfl = self.field_list().and_then(|fl| match fl { |
@@ -84,6 +149,22 @@ impl GenericParamsOwnerEdit for ast::Struct { | |||
84 | } | 149 | } |
85 | 150 | ||
86 | impl GenericParamsOwnerEdit for ast::Enum { | 151 | impl GenericParamsOwnerEdit for ast::Enum { |
152 | fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { | ||
153 | match self.generic_param_list() { | ||
154 | Some(it) => it, | ||
155 | None => { | ||
156 | let position = if let Some(name) = self.name() { | ||
157 | Position::after(name.syntax) | ||
158 | } else if let Some(enum_token) = self.enum_token() { | ||
159 | Position::after(enum_token) | ||
160 | } else { | ||
161 | Position::last_child_of(self.syntax()) | ||
162 | }; | ||
163 | create_generic_param_list(position) | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
87 | fn get_or_create_where_clause(&self) -> WhereClause { | 168 | fn get_or_create_where_clause(&self) -> WhereClause { |
88 | if self.where_clause().is_none() { | 169 | if self.where_clause().is_none() { |
89 | let position = if let Some(gpl) = self.generic_param_list() { | 170 | let position = if let Some(gpl) = self.generic_param_list() { |
@@ -104,6 +185,37 @@ fn create_where_clause(position: Position) { | |||
104 | ted::insert(position, where_clause.syntax()); | 185 | ted::insert(position, where_clause.syntax()); |
105 | } | 186 | } |
106 | 187 | ||
188 | fn create_generic_param_list(position: Position) -> ast::GenericParamList { | ||
189 | let gpl = make::generic_param_list(empty()).clone_for_update(); | ||
190 | ted::insert_raw(position, gpl.syntax()); | ||
191 | gpl | ||
192 | } | ||
193 | |||
194 | impl ast::GenericParamList { | ||
195 | pub fn add_generic_param(&self, generic_param: ast::GenericParam) { | ||
196 | match self.generic_params().last() { | ||
197 | Some(last_param) => { | ||
198 | let mut elems = Vec::new(); | ||
199 | if !last_param | ||
200 | .syntax() | ||
201 | .siblings_with_tokens(Direction::Next) | ||
202 | .any(|it| it.kind() == T![,]) | ||
203 | { | ||
204 | elems.push(make::token(T![,]).into()); | ||
205 | elems.push(make::tokens::single_space().into()); | ||
206 | }; | ||
207 | elems.push(generic_param.syntax().clone().into()); | ||
208 | let after_last_param = Position::after(last_param.syntax()); | ||
209 | ted::insert_all(after_last_param, elems); | ||
210 | } | ||
211 | None => { | ||
212 | let after_l_angle = Position::after(self.l_angle_token().unwrap()); | ||
213 | ted::insert(after_l_angle, generic_param.syntax()) | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
107 | impl ast::WhereClause { | 219 | impl ast::WhereClause { |
108 | pub fn add_predicate(&self, predicate: ast::WherePred) { | 220 | pub fn add_predicate(&self, predicate: ast::WherePred) { |
109 | if let Some(pred) = self.predicates().last() { | 221 | if let Some(pred) = self.predicates().last() { |
@@ -164,3 +276,44 @@ impl ast::Use { | |||
164 | ted::remove(self.syntax()) | 276 | ted::remove(self.syntax()) |
165 | } | 277 | } |
166 | } | 278 | } |
279 | |||
280 | #[cfg(test)] | ||
281 | mod tests { | ||
282 | use std::fmt; | ||
283 | |||
284 | use crate::SourceFile; | ||
285 | |||
286 | use super::*; | ||
287 | |||
288 | fn ast_mut_from_text<N: AstNode>(text: &str) -> N { | ||
289 | let parse = SourceFile::parse(text); | ||
290 | parse.tree().syntax().descendants().find_map(N::cast).unwrap().clone_for_update() | ||
291 | } | ||
292 | |||
293 | #[test] | ||
294 | fn test_create_generic_param_list() { | ||
295 | fn check_create_gpl<N: GenericParamsOwnerEdit + fmt::Display>(before: &str, after: &str) { | ||
296 | let gpl_owner = ast_mut_from_text::<N>(before); | ||
297 | gpl_owner.get_or_create_generic_param_list(); | ||
298 | assert_eq!(gpl_owner.to_string(), after); | ||
299 | } | ||
300 | |||
301 | check_create_gpl::<ast::Fn>("fn foo", "fn foo<>"); | ||
302 | check_create_gpl::<ast::Fn>("fn foo() {}", "fn foo<>() {}"); | ||
303 | |||
304 | check_create_gpl::<ast::Impl>("impl", "impl<>"); | ||
305 | check_create_gpl::<ast::Impl>("impl Struct {}", "impl<> Struct {}"); | ||
306 | check_create_gpl::<ast::Impl>("impl Trait for Struct {}", "impl<> Trait for Struct {}"); | ||
307 | |||
308 | check_create_gpl::<ast::Trait>("trait Trait<>", "trait Trait<>"); | ||
309 | check_create_gpl::<ast::Trait>("trait Trait<> {}", "trait Trait<> {}"); | ||
310 | |||
311 | check_create_gpl::<ast::Struct>("struct A", "struct A<>"); | ||
312 | check_create_gpl::<ast::Struct>("struct A;", "struct A<>;"); | ||
313 | check_create_gpl::<ast::Struct>("struct A();", "struct A<>();"); | ||
314 | check_create_gpl::<ast::Struct>("struct A {}", "struct A<> {}"); | ||
315 | |||
316 | check_create_gpl::<ast::Enum>("enum E", "enum E<>"); | ||
317 | check_create_gpl::<ast::Enum>("enum E {", "enum E<> {"); | ||
318 | } | ||
319 | } | ||
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index ae98dbd26..171099661 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -125,6 +125,18 @@ pub enum AttrKind { | |||
125 | Outer, | 125 | Outer, |
126 | } | 126 | } |
127 | 127 | ||
128 | impl AttrKind { | ||
129 | /// Returns `true` if the attr_kind is [`Inner`]. | ||
130 | pub fn is_inner(&self) -> bool { | ||
131 | matches!(self, Self::Inner) | ||
132 | } | ||
133 | |||
134 | /// Returns `true` if the attr_kind is [`Outer`]. | ||
135 | pub fn is_outer(&self) -> bool { | ||
136 | matches!(self, Self::Outer) | ||
137 | } | ||
138 | } | ||
139 | |||
128 | impl ast::Attr { | 140 | impl ast::Attr { |
129 | pub fn as_simple_atom(&self) -> Option<SmolStr> { | 141 | pub fn as_simple_atom(&self) -> Option<SmolStr> { |
130 | if self.eq_token().is_some() || self.token_tree().is_some() { | 142 | if self.eq_token().is_some() || self.token_tree().is_some() { |
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 177d4ff67..450f2e447 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs | |||
@@ -165,6 +165,13 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken | |||
165 | if right.kind() == T![;] || right.kind() == T![,] { | 165 | if right.kind() == T![;] || right.kind() == T![,] { |
166 | return None; | 166 | return None; |
167 | } | 167 | } |
168 | if left.kind() == T![<] || right.kind() == T![>] { | ||
169 | return None; | ||
170 | } | ||
171 | if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME { | ||
172 | return None; | ||
173 | } | ||
174 | |||
168 | if right.kind() == SyntaxKind::USE { | 175 | if right.kind() == SyntaxKind::USE { |
169 | let indent = IndentLevel::from_element(left); | 176 | let indent = IndentLevel::from_element(left); |
170 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); | 177 | return Some(make::tokens::whitespace(&format!("\n{}", indent))); |
diff --git a/crates/syntax/src/validation/block.rs b/crates/syntax/src/validation/block.rs index ad9901468..40170014f 100644 --- a/crates/syntax/src/validation/block.rs +++ b/crates/syntax/src/validation/block.rs | |||
@@ -13,7 +13,7 @@ pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<Syntax | |||
13 | _ => {} | 13 | _ => {} |
14 | } | 14 | } |
15 | } | 15 | } |
16 | errors.extend(block.attrs().map(|attr| { | 16 | errors.extend(block.attrs().filter(|attr| attr.kind().is_inner()).map(|attr| { |
17 | SyntaxError::new( | 17 | SyntaxError::new( |
18 | "A block in this position cannot accept inner attributes", | 18 | "A block in this position cannot accept inner attributes", |
19 | attr.syntax().text_range(), | 19 | attr.syntax().text_range(), |
diff --git a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast index 3016a6574..1ff3f7656 100644 --- a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast +++ b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast | |||
@@ -7,15 +7,16 @@ [email protected] | |||
7 | [email protected] " " | 7 | [email protected] " " |
8 | [email protected] "=" | 8 | [email protected] "=" |
9 | [email protected] " " | 9 | [email protected] " " |
10 | [email protected] | 10 | [email protected] |
11 | [email protected] | 11 | [email protected] |
12 | [email protected] | 12 | [email protected] |
13 | [email protected] | 13 | [email protected] |
14 | [email protected] "foo" | 14 | [email protected] |
15 | [email protected] "!" | 15 | [email protected] "foo" |
16 | [email protected] | 16 | [email protected] "!" |
17 | [email protected] "(" | 17 | [email protected] |
18 | [email protected] ")" | 18 | [email protected] "(" |
19 | [email protected] ")" | ||
19 | [email protected] ";" | 20 | [email protected] ";" |
20 | [email protected] "\n" | 21 | [email protected] "\n" |
21 | [email protected] | 22 | [email protected] |
@@ -26,19 +27,20 @@ [email protected] | |||
26 | [email protected] " " | 27 | [email protected] " " |
27 | [email protected] "=" | 28 | [email protected] "=" |
28 | [email protected] " " | 29 | [email protected] " " |
29 | [email protected] | 30 | [email protected] |
30 | [email protected] | 31 | [email protected] |
31 | [email protected] | 32 | [email protected] |
32 | [email protected] | 33 | [email protected] |
33 | [email protected] | 34 | [email protected] |
34 | [email protected] "crate" | 35 | [email protected] |
35 | [email protected] "::" | 36 | [email protected] "crate" |
36 | [email protected] | 37 | [email protected] "::" |
37 | [email protected] | 38 | [email protected] |
38 | [email protected] "foo" | 39 | [email protected] |
39 | [email protected] "!" | 40 | [email protected] "foo" |
40 | [email protected] | 41 | [email protected] "!" |
41 | [email protected] "(" | 42 | [email protected] |
42 | [email protected] ")" | 43 | [email protected] "(" |
44 | [email protected] ")" | ||
43 | [email protected] ";" | 45 | [email protected] ";" |
44 | [email protected] "\n" | 46 | [email protected] "\n" |
diff --git a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast new file mode 100644 index 000000000..50ab52d32 --- /dev/null +++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast | |||
@@ -0,0 +1,218 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "inner" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] "\n " | ||
14 | [email protected] | ||
15 | [email protected] "#" | ||
16 | [email protected] "!" | ||
17 | [email protected] "[" | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "doc" | ||
22 | [email protected] | ||
23 | [email protected] "(" | ||
24 | [email protected] "\"Inner attributes all ..." | ||
25 | [email protected] ")" | ||
26 | [email protected] "]" | ||
27 | [email protected] "\n " | ||
28 | [email protected] "//! As are ModuleDoc ..." | ||
29 | [email protected] "\n " | ||
30 | [email protected] | ||
31 | [email protected] | ||
32 | [email protected] "{" | ||
33 | [email protected] "\n " | ||
34 | [email protected] | ||
35 | [email protected] "#" | ||
36 | [email protected] "!" | ||
37 | [email protected] "[" | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "doc" | ||
42 | [email protected] | ||
43 | [email protected] "(" | ||
44 | [email protected] "\"Inner attributes are ..." | ||
45 | [email protected] ")" | ||
46 | [email protected] "]" | ||
47 | [email protected] "\n " | ||
48 | [email protected] | ||
49 | [email protected] "#" | ||
50 | [email protected] "!" | ||
51 | [email protected] "[" | ||
52 | [email protected] | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] "doc" | ||
56 | [email protected] | ||
57 | [email protected] "(" | ||
58 | [email protected] "\"Being validated is n ..." | ||
59 | [email protected] ")" | ||
60 | [email protected] "]" | ||
61 | [email protected] "\n " | ||
62 | [email protected] "//! As are ModuleDoc ..." | ||
63 | [email protected] "\n " | ||
64 | [email protected] "}" | ||
65 | [email protected] ";" | ||
66 | [email protected] "\n " | ||
67 | [email protected] | ||
68 | [email protected] "{" | ||
69 | [email protected] "\n " | ||
70 | [email protected] | ||
71 | [email protected] "#" | ||
72 | [email protected] "!" | ||
73 | [email protected] "[" | ||
74 | [email protected] | ||
75 | [email protected] | ||
76 | [email protected] | ||
77 | [email protected] "doc" | ||
78 | [email protected] | ||
79 | [email protected] "(" | ||
80 | [email protected] "\"Inner attributes are ..." | ||
81 | [email protected] ")" | ||
82 | [email protected] "]" | ||
83 | [email protected] "\n " | ||
84 | [email protected] "//! As are ModuleDoc ..." | ||
85 | [email protected] "\n " | ||
86 | [email protected] "}" | ||
87 | [email protected] "\n" | ||
88 | [email protected] "}" | ||
89 | [email protected] "\n\n" | ||
90 | [email protected] | ||
91 | [email protected] "fn" | ||
92 | [email protected] " " | ||
93 | [email protected] | ||
94 | [email protected] "outer" | ||
95 | [email protected] | ||
96 | [email protected] "(" | ||
97 | [email protected] ")" | ||
98 | [email protected] " " | ||
99 | [email protected] | ||
100 | [email protected] "{" | ||
101 | [email protected] "\n " | ||
102 | [email protected] | ||
103 | [email protected] "let" | ||
104 | [email protected] " " | ||
105 | [email protected] | ||
106 | [email protected] "_" | ||
107 | [email protected] " " | ||
108 | [email protected] "=" | ||
109 | [email protected] " " | ||
110 | [email protected] | ||
111 | [email protected] | ||
112 | [email protected] "#" | ||
113 | [email protected] "[" | ||
114 | [email protected] | ||
115 | [email protected] | ||
116 | [email protected] | ||
117 | [email protected] "doc" | ||
118 | [email protected] | ||
119 | [email protected] "(" | ||
120 | [email protected] "\"Outer attributes are ..." | ||
121 | [email protected] ")" | ||
122 | [email protected] "]" | ||
123 | [email protected] " " | ||
124 | [email protected] "{" | ||
125 | [email protected] "}" | ||
126 | [email protected] ";" | ||
127 | [email protected] "\n" | ||
128 | [email protected] "}" | ||
129 | [email protected] "\n\n" | ||
130 | [email protected] "// https://github.com ..." | ||
131 | [email protected] "\n" | ||
132 | [email protected] | ||
133 | [email protected] "impl" | ||
134 | [email protected] " " | ||
135 | [email protected] | ||
136 | [email protected] | ||
137 | [email protected] | ||
138 | [email protected] | ||
139 | [email protected] "Whatever" | ||
140 | [email protected] " " | ||
141 | [email protected] | ||
142 | [email protected] "{" | ||
143 | [email protected] "\n " | ||
144 | [email protected] | ||
145 | [email protected] "fn" | ||
146 | [email protected] " " | ||
147 | [email protected] | ||
148 | [email protected] "salsa_event" | ||
149 | [email protected] | ||
150 | [email protected] "(" | ||
151 | [email protected] | ||
152 | [email protected] "&" | ||
153 | [email protected] | ||
154 | [email protected] "self" | ||
155 | [email protected] "," | ||
156 | [email protected] " " | ||
157 | [email protected] | ||
158 | [email protected] | ||
159 | [email protected] | ||
160 | [email protected] "event_fn" | ||
161 | [email protected] ":" | ||
162 | [email protected] " " | ||
163 | [email protected] | ||
164 | [email protected] "impl" | ||
165 | [email protected] " " | ||
166 | [email protected] | ||
167 | [email protected] | ||
168 | [email protected] | ||
169 | [email protected] | ||
170 | [email protected] | ||
171 | [email protected] | ||
172 | [email protected] "Fn" | ||
173 | [email protected] | ||
174 | [email protected] "(" | ||
175 | [email protected] ")" | ||
176 | [email protected] " " | ||
177 | [email protected] | ||
178 | [email protected] "->" | ||
179 | [email protected] " " | ||
180 | [email protected] | ||
181 | [email protected] | ||
182 | [email protected] | ||
183 | [email protected] | ||
184 | [email protected] "Event" | ||
185 | [email protected] | ||
186 | [email protected] "<" | ||
187 | [email protected] | ||
188 | [email protected] | ||
189 | [email protected] | ||
190 | [email protected] | ||
191 | [email protected] | ||
192 | [email protected] "Self" | ||
193 | [email protected] ">" | ||
194 | [email protected] ")" | ||
195 | [email protected] " " | ||
196 | [email protected] | ||
197 | [email protected] "{" | ||
198 | [email protected] "\n " | ||
199 | [email protected] | ||
200 | [email protected] "#" | ||
201 | [email protected] "!" | ||
202 | [email protected] "[" | ||
203 | [email protected] | ||
204 | [email protected] | ||
205 | [email protected] | ||
206 | [email protected] "allow" | ||
207 | [email protected] | ||
208 | [email protected] "(" | ||
209 | [email protected] "unused_variables" | ||
210 | [email protected] ")" | ||
211 | [email protected] "]" | ||
212 | [email protected] " " | ||
213 | [email protected] "// this is `inner_at ..." | ||
214 | [email protected] "\n " | ||
215 | [email protected] "}" | ||
216 | [email protected] "\n" | ||
217 | [email protected] "}" | ||
218 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs index 88df8138e..ed4593759 100644 --- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs +++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | fn block() { | 1 | fn inner() { |
2 | #![doc("Inner attributes allowed here")] | 2 | #![doc("Inner attributes allowed here")] |
3 | //! As are ModuleDoc style comments | 3 | //! As are ModuleDoc style comments |
4 | { | 4 | { |
@@ -12,6 +12,10 @@ fn block() { | |||
12 | } | 12 | } |
13 | } | 13 | } |
14 | 14 | ||
15 | fn outer() { | ||
16 | let _ = #[doc("Outer attributes are always allowed")] {}; | ||
17 | } | ||
18 | |||
15 | // https://github.com/rust-analyzer/rust-analyzer/issues/689 | 19 | // https://github.com/rust-analyzer/rust-analyzer/issues/689 |
16 | impl Whatever { | 20 | impl Whatever { |
17 | fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) { | 21 | fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) { |
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast deleted file mode 100644 index 6afed5f05..000000000 --- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast +++ /dev/null | |||
@@ -1,178 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "block" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] "\n " | ||
14 | [email protected] | ||
15 | [email protected] "#" | ||
16 | [email protected] "!" | ||
17 | [email protected] "[" | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "doc" | ||
22 | [email protected] | ||
23 | [email protected] "(" | ||
24 | [email protected] "\"Inner attributes all ..." | ||
25 | [email protected] ")" | ||
26 | [email protected] "]" | ||
27 | [email protected] "\n " | ||
28 | [email protected] "//! As are ModuleDoc ..." | ||
29 | [email protected] "\n " | ||
30 | [email protected] | ||
31 | [email protected] | ||
32 | [email protected] "{" | ||
33 | [email protected] "\n " | ||
34 | [email protected] | ||
35 | [email protected] "#" | ||
36 | [email protected] "!" | ||
37 | [email protected] "[" | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "doc" | ||
42 | [email protected] | ||
43 | [email protected] "(" | ||
44 | [email protected] "\"Inner attributes are ..." | ||
45 | [email protected] ")" | ||
46 | [email protected] "]" | ||
47 | [email protected] "\n " | ||
48 | [email protected] | ||
49 | [email protected] "#" | ||
50 | [email protected] "!" | ||
51 | [email protected] "[" | ||
52 | [email protected] | ||
53 | [email protected] | ||
54 | [email protected] | ||
55 | [email protected] "doc" | ||
56 | [email protected] | ||
57 | [email protected] "(" | ||
58 | [email protected] "\"Being validated is n ..." | ||
59 | [email protected] ")" | ||
60 | [email protected] "]" | ||
61 | [email protected] "\n " | ||
62 | [email protected] "//! As are ModuleDoc ..." | ||
63 | [email protected] "\n " | ||
64 | [email protected] "}" | ||
65 | [email protected] ";" | ||
66 | [email protected] "\n " | ||
67 | [email protected] | ||
68 | [email protected] "{" | ||
69 | [email protected] "\n " | ||
70 | [email protected] | ||
71 | [email protected] "#" | ||
72 | [email protected] "!" | ||
73 | [email protected] "[" | ||
74 | [email protected] | ||
75 | [email protected] | ||
76 | [email protected] | ||
77 | [email protected] "doc" | ||
78 | [email protected] | ||
79 | [email protected] "(" | ||
80 | [email protected] "\"Inner attributes are ..." | ||
81 | [email protected] ")" | ||
82 | [email protected] "]" | ||
83 | [email protected] "\n " | ||
84 | [email protected] "//! As are ModuleDoc ..." | ||
85 | [email protected] "\n " | ||
86 | [email protected] "}" | ||
87 | [email protected] "\n" | ||
88 | [email protected] "}" | ||
89 | [email protected] "\n\n" | ||
90 | [email protected] "// https://github.com ..." | ||
91 | [email protected] "\n" | ||
92 | [email protected] | ||
93 | [email protected] "impl" | ||
94 | [email protected] " " | ||
95 | [email protected] | ||
96 | [email protected] | ||
97 | [email protected] | ||
98 | [email protected] | ||
99 | [email protected] "Whatever" | ||
100 | [email protected] " " | ||
101 | [email protected] | ||
102 | [email protected] "{" | ||
103 | [email protected] "\n " | ||
104 | [email protected] | ||
105 | [email protected] "fn" | ||
106 | [email protected] " " | ||
107 | [email protected] | ||
108 | [email protected] "salsa_event" | ||
109 | [email protected] | ||
110 | [email protected] "(" | ||
111 | [email protected] | ||
112 | [email protected] "&" | ||
113 | [email protected] | ||
114 | [email protected] "self" | ||
115 | [email protected] "," | ||
116 | [email protected] " " | ||
117 | [email protected] | ||
118 | [email protected] | ||
119 | [email protected] | ||
120 | [email protected] "event_fn" | ||
121 | [email protected] ":" | ||
122 | [email protected] " " | ||
123 | [email protected] | ||
124 | [email protected] "impl" | ||
125 | [email protected] " " | ||
126 | [email protected] | ||
127 | [email protected] | ||
128 | [email protected] | ||
129 | [email protected] | ||
130 | [email protected] | ||
131 | [email protected] | ||
132 | [email protected] "Fn" | ||
133 | [email protected] | ||
134 | [email protected] "(" | ||
135 | [email protected] ")" | ||
136 | [email protected] " " | ||
137 | [email protected] | ||
138 | [email protected] "->" | ||
139 | [email protected] " " | ||
140 | [email protected] | ||
141 | [email protected] | ||
142 | [email protected] | ||
143 | [email protected] | ||
144 | [email protected] "Event" | ||
145 | [email protected] | ||
146 | [email protected] "<" | ||
147 | [email protected] | ||
148 | [email protected] | ||
149 | [email protected] | ||
150 | [email protected] | ||
151 | [email protected] | ||
152 | [email protected] "Self" | ||
153 | [email protected] ">" | ||
154 | [email protected] ")" | ||
155 | [email protected] " " | ||
156 | [email protected] | ||
157 | [email protected] "{" | ||
158 | [email protected] "\n " | ||
159 | [email protected] | ||
160 | [email protected] "#" | ||
161 | [email protected] "!" | ||
162 | [email protected] "[" | ||
163 | [email protected] | ||
164 | [email protected] | ||
165 | [email protected] | ||
166 | [email protected] "allow" | ||
167 | [email protected] | ||
168 | [email protected] "(" | ||
169 | [email protected] "unused_variables" | ||
170 | [email protected] ")" | ||
171 | [email protected] "]" | ||
172 | [email protected] " " | ||
173 | [email protected] "// this is `inner_at ..." | ||
174 | [email protected] "\n " | ||
175 | [email protected] "}" | ||
176 | [email protected] "\n" | ||
177 | [email protected] "}" | ||
178 | [email protected] "\n" | ||