aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/path
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/path')
-rw-r--r--crates/hir_def/src/path/lower.rs44
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs78
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 @@
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned; 5use crate::intern::Interned;
6use std::sync::Arc;
7 6
8use either::Either; 7use either::Either;
9use hir_expand::name::{name, AsName}; 8use 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
19pub(super) use lower_use::lower_use_tree; 18pub(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 @@
4use std::iter; 4use std::iter;
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{hygiene::Hygiene, name::AsName}; 7use hir_expand::hygiene::Hygiene;
8use syntax::ast::{self, NameOwner}; 8use syntax::{ast, AstNode};
9 9
10use crate::{ 10use crate::{
11 db::DefDatabase, 11 db::DefDatabase,
12 path::{ImportAlias, ModPath, PathKind}, 12 path::{ModPath, PathKind},
13}; 13};
14 14
15pub(crate) fn lower_use_tree( 15pub(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
68fn 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}