diff options
Diffstat (limited to 'crates/hir_def/src/path')
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 44 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower/lower_use.rs | 78 |
2 files changed, 43 insertions, 79 deletions
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index a873325b2..f6220aa92 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | mod lower_use; | 3 | mod lower_use; |
4 | 4 | ||
5 | use crate::intern::Interned; | 5 | use crate::intern::Interned; |
6 | use std::sync::Arc; | ||
7 | 6 | ||
8 | use either::Either; | 7 | use either::Either; |
9 | use hir_expand::name::{name, AsName}; | 8 | use hir_expand::name::{name, AsName}; |
@@ -16,7 +15,7 @@ use crate::{ | |||
16 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 15 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
17 | }; | 16 | }; |
18 | 17 | ||
19 | pub(super) use lower_use::lower_use_tree; | 18 | pub(super) use lower_use::convert_path; |
20 | 19 | ||
21 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 20 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
22 | /// It correctly handles `$crate` based path from macro call. | 21 | /// It correctly handles `$crate` based path from macro call. |
@@ -48,7 +47,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
48 | segment.ret_type(), | 47 | segment.ret_type(), |
49 | ) | 48 | ) |
50 | }) | 49 | }) |
51 | .map(Arc::new); | 50 | .map(Interned::new); |
52 | segments.push(name); | 51 | segments.push(name); |
53 | generic_args.push(args) | 52 | generic_args.push(args) |
54 | } | 53 | } |
@@ -87,13 +86,13 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { | |||
87 | // Insert the type reference (T in the above example) as Self parameter for the trait | 86 | // Insert the type reference (T in the above example) as Self parameter for the trait |
88 | let last_segment = | 87 | let last_segment = |
89 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; | 88 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; |
90 | if last_segment.is_none() { | 89 | let mut args_inner = match last_segment { |
91 | *last_segment = Some(Arc::new(GenericArgs::empty())); | 90 | Some(it) => it.as_ref().clone(), |
91 | None => GenericArgs::empty(), | ||
92 | }; | 92 | }; |
93 | let args = last_segment.as_mut().unwrap(); | ||
94 | let mut args_inner = Arc::make_mut(args); | ||
95 | args_inner.has_self_type = true; | 93 | args_inner.has_self_type = true; |
96 | args_inner.args.insert(0, GenericArg::Type(self_type)); | 94 | args_inner.args.insert(0, GenericArg::Type(self_type)); |
95 | *last_segment = Some(Interned::new(args_inner)); | ||
97 | } | 96 | } |
98 | } | 97 | } |
99 | } | 98 | } |
@@ -171,7 +170,9 @@ pub(super) fn lower_generic_args( | |||
171 | let name = name_ref.as_name(); | 170 | let name = name_ref.as_name(); |
172 | let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); | 171 | let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); |
173 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { | 172 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { |
174 | l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() | 173 | l.bounds() |
174 | .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))) | ||
175 | .collect() | ||
175 | } else { | 176 | } else { |
176 | Vec::new() | 177 | Vec::new() |
177 | }; | 178 | }; |
@@ -204,15 +205,14 @@ fn lower_generic_args_from_fn_path( | |||
204 | ) -> Option<GenericArgs> { | 205 | ) -> Option<GenericArgs> { |
205 | let mut args = Vec::new(); | 206 | let mut args = Vec::new(); |
206 | let mut bindings = Vec::new(); | 207 | let mut bindings = Vec::new(); |
207 | if let Some(params) = params { | 208 | let params = params?; |
208 | let mut param_types = Vec::new(); | 209 | let mut param_types = Vec::new(); |
209 | for param in params.params() { | 210 | for param in params.params() { |
210 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); | 211 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); |
211 | param_types.push(type_ref); | 212 | param_types.push(type_ref); |
212 | } | ||
213 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | ||
214 | args.push(arg); | ||
215 | } | 213 | } |
214 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | ||
215 | args.push(arg); | ||
216 | if let Some(ret_type) = ret_type { | 216 | if let Some(ret_type) = ret_type { |
217 | let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); | 217 | let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); |
218 | bindings.push(AssociatedTypeBinding { | 218 | bindings.push(AssociatedTypeBinding { |
@@ -220,10 +220,14 @@ fn lower_generic_args_from_fn_path( | |||
220 | type_ref: Some(type_ref), | 220 | type_ref: Some(type_ref), |
221 | bounds: Vec::new(), | 221 | bounds: Vec::new(), |
222 | }); | 222 | }); |
223 | } | ||
224 | if args.is_empty() && bindings.is_empty() { | ||
225 | None | ||
226 | } else { | 223 | } else { |
227 | Some(GenericArgs { args, has_self_type: false, bindings }) | 224 | // -> () |
225 | let type_ref = TypeRef::Tuple(Vec::new()); | ||
226 | bindings.push(AssociatedTypeBinding { | ||
227 | name: name![Output], | ||
228 | type_ref: Some(type_ref), | ||
229 | bounds: Vec::new(), | ||
230 | }); | ||
228 | } | 231 | } |
232 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
229 | } | 233 | } |
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index ee80e3df3..0ee406f63 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs | |||
@@ -4,68 +4,15 @@ | |||
4 | use std::iter; | 4 | use std::iter; |
5 | 5 | ||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{hygiene::Hygiene, name::AsName}; | 7 | use hir_expand::hygiene::Hygiene; |
8 | use syntax::ast::{self, NameOwner}; | 8 | use syntax::{ast, AstNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | path::{ImportAlias, ModPath, PathKind}, | 12 | path::{ModPath, PathKind}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(crate) fn lower_use_tree( | 15 | pub(crate) fn convert_path( |
16 | db: &dyn DefDatabase, | ||
17 | prefix: Option<ModPath>, | ||
18 | tree: ast::UseTree, | ||
19 | hygiene: &Hygiene, | ||
20 | cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<ImportAlias>), | ||
21 | ) { | ||
22 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
23 | let prefix = match tree.path() { | ||
24 | // E.g. use something::{{{inner}}}; | ||
25 | None => prefix, | ||
26 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
27 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
28 | Some(path) => match convert_path(db, prefix, path, hygiene) { | ||
29 | Some(it) => Some(it), | ||
30 | None => return, // FIXME: report errors somewhere | ||
31 | }, | ||
32 | }; | ||
33 | for child_tree in use_tree_list.use_trees() { | ||
34 | lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb); | ||
35 | } | ||
36 | } else { | ||
37 | let alias = tree.rename().map(|a| { | ||
38 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | ||
39 | }); | ||
40 | let is_glob = tree.star_token().is_some(); | ||
41 | if let Some(ast_path) = tree.path() { | ||
42 | // Handle self in a path. | ||
43 | // E.g. `use something::{self, <...>}` | ||
44 | if ast_path.qualifier().is_none() { | ||
45 | if let Some(segment) = ast_path.segment() { | ||
46 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
47 | if let Some(prefix) = prefix { | ||
48 | cb(prefix, &tree, false, alias); | ||
49 | return; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | if let Some(path) = convert_path(db, prefix, ast_path, hygiene) { | ||
55 | cb(path, &tree, is_glob, alias) | ||
56 | } | ||
57 | // FIXME: report errors somewhere | ||
58 | // We get here if we do | ||
59 | } else if is_glob { | ||
60 | cov_mark::hit!(glob_enum_group); | ||
61 | if let Some(prefix) = prefix { | ||
62 | cb(prefix, &tree, is_glob, None) | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | |||
68 | fn convert_path( | ||
69 | db: &dyn DefDatabase, | 16 | db: &dyn DefDatabase, |
70 | prefix: Option<ModPath>, | 17 | prefix: Option<ModPath>, |
71 | path: ast::Path, | 18 | path: ast::Path, |
@@ -78,7 +25,7 @@ fn convert_path( | |||
78 | }; | 25 | }; |
79 | 26 | ||
80 | let segment = path.segment()?; | 27 | let segment = path.segment()?; |
81 | let res = match segment.kind()? { | 28 | let mut mod_path = match segment.kind()? { |
82 | ast::PathSegmentKind::Name(name_ref) => { | 29 | ast::PathSegmentKind::Name(name_ref) => { |
83 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { | 30 | match hygiene.name_ref_to_name(db.upcast(), name_ref) { |
84 | Either::Left(name) => { | 31 | Either::Left(name) => { |
@@ -125,5 +72,18 @@ fn convert_path( | |||
125 | return None; | 72 | return None; |
126 | } | 73 | } |
127 | }; | 74 | }; |
128 | Some(res) | 75 | |
76 | // handle local_inner_macros : | ||
77 | // Basically, even in rustc it is quite hacky: | ||
78 | // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 | ||
79 | // We follow what it did anyway :) | ||
80 | if mod_path.segments.len() == 1 && mod_path.kind == PathKind::Plain { | ||
81 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | ||
82 | if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) { | ||
83 | mod_path.kind = PathKind::DollarCrate(crate_id); | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
88 | Some(mod_path) | ||
129 | } | 89 | } |