diff options
Diffstat (limited to 'crates/ra_hir/src')
25 files changed, 1108 insertions, 590 deletions
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 7c9454c0b..b9ffb0c7a 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs | |||
@@ -1,11 +1,15 @@ | |||
1 | use ra_syntax::ast::{self, AstNode}; | 1 | use ra_syntax::{ |
2 | ast::{self, AstNode}, | ||
3 | SyntaxNode, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{ | 6 | use crate::{ |
4 | ids::AstItemDef, AstDatabase, Const, DefDatabase, Enum, EnumVariant, FieldSource, Function, | 7 | ids::AstItemDef, AstDatabase, Const, DefDatabase, Either, Enum, EnumVariant, FieldSource, |
5 | HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct, StructField, | 8 | Function, HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct, |
6 | Trait, TypeAlias, Union, | 9 | StructField, Trait, TypeAlias, Union, |
7 | }; | 10 | }; |
8 | 11 | ||
12 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
9 | pub struct Source<T> { | 13 | pub struct Source<T> { |
10 | pub file_id: HirFileId, | 14 | pub file_id: HirFileId, |
11 | pub ast: T, | 15 | pub ast: T, |
@@ -16,6 +20,15 @@ pub trait HasSource { | |||
16 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; | 20 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; |
17 | } | 21 | } |
18 | 22 | ||
23 | impl<T> Source<T> { | ||
24 | pub(crate) fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { | ||
25 | Source { file_id: self.file_id, ast: f(self.ast) } | ||
26 | } | ||
27 | pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
28 | db.parse_or_expand(self.file_id).expect("source created from invalid file") | ||
29 | } | ||
30 | } | ||
31 | |||
19 | /// NB: Module is !HasSource, because it has two source nodes at the same time: | 32 | /// NB: Module is !HasSource, because it has two source nodes at the same time: |
20 | /// definition and declaration. | 33 | /// definition and declaration. |
21 | impl Module { | 34 | impl Module { |
@@ -117,12 +130,12 @@ where | |||
117 | self, | 130 | self, |
118 | db: &impl HirDatabase, | 131 | db: &impl HirDatabase, |
119 | expr_id: crate::expr::ExprId, | 132 | expr_id: crate::expr::ExprId, |
120 | ) -> Option<Source<ast::Expr>> { | 133 | ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> { |
121 | let source_map = self.body_source_map(db); | 134 | let source_map = self.body_source_map(db); |
122 | let expr_syntax = source_map.expr_syntax(expr_id)?.a()?; | 135 | let source_ptr = source_map.expr_syntax(expr_id)?; |
123 | let source = self.source(db); | 136 | let root = source_ptr.file_syntax(db); |
124 | let ast = expr_syntax.to_node(&source.ast.syntax()); | 137 | let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root))); |
125 | Some(Source { file_id: source.file_id, ast }) | 138 | Some(source) |
126 | } | 139 | } |
127 | } | 140 | } |
128 | 141 | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index f669ab969..7b7974f5b 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -169,13 +169,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
169 | #[salsa::invoke(crate::ty::generic_defaults_query)] | 169 | #[salsa::invoke(crate::ty::generic_defaults_query)] |
170 | fn generic_defaults(&self, def: GenericDef) -> Substs; | 170 | fn generic_defaults(&self, def: GenericDef) -> Substs; |
171 | 171 | ||
172 | #[salsa::invoke(crate::expr::lower::body_with_source_map_query)] | 172 | #[salsa::invoke(crate::expr::body_with_source_map_query)] |
173 | fn body_with_source_map( | 173 | fn body_with_source_map( |
174 | &self, | 174 | &self, |
175 | def: DefWithBody, | 175 | def: DefWithBody, |
176 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); | 176 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); |
177 | 177 | ||
178 | #[salsa::invoke(crate::expr::lower::body_hir_query)] | 178 | #[salsa::invoke(crate::expr::body_hir_query)] |
179 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; | 179 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; |
180 | 180 | ||
181 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 181 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index bfd250f38..fc21e269f 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | path::GenericArgs, | 12 | path::GenericArgs, |
13 | ty::primitive::{UncertainFloatTy, UncertainIntTy}, | 13 | ty::primitive::{UncertainFloatTy, UncertainIntTy}, |
14 | type_ref::{Mutability, TypeRef}, | 14 | type_ref::{Mutability, TypeRef}, |
15 | DefWithBody, Either, HirDatabase, Name, Path, Resolver, | 15 | DefWithBody, Either, HasSource, HirDatabase, Name, Path, Resolver, Source, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub use self::scope::ExprScopes; | 18 | pub use self::scope::ExprScopes; |
@@ -43,23 +43,32 @@ pub struct Body { | |||
43 | body_expr: ExprId, | 43 | body_expr: ExprId, |
44 | } | 44 | } |
45 | 45 | ||
46 | type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
47 | type ExprSource = Source<ExprPtr>; | ||
48 | |||
49 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
50 | type PatSource = Source<PatPtr>; | ||
51 | |||
46 | /// An item body together with the mapping from syntax nodes to HIR expression | 52 | /// An item body together with the mapping from syntax nodes to HIR expression |
47 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | 53 | /// IDs. This is needed to go from e.g. a position in a file to the HIR |
48 | /// expression containing it; but for type inference etc., we want to operate on | 54 | /// expression containing it; but for type inference etc., we want to operate on |
49 | /// a structure that is agnostic to the actual positions of expressions in the | 55 | /// a structure that is agnostic to the actual positions of expressions in the |
50 | /// file, so that we don't recompute types whenever some whitespace is typed. | 56 | /// file, so that we don't recompute types whenever some whitespace is typed. |
57 | /// | ||
58 | /// One complication here is that, due to macro expansion, a single `Body` might | ||
59 | /// be spread across several files. So, for each ExprId and PatId, we record | ||
60 | /// both the HirFileId and the position inside the file. However, we only store | ||
61 | /// AST -> ExprId mapping for non-macro files, as it is not clear how to handle | ||
62 | /// this properly for macros. | ||
51 | #[derive(Default, Debug, Eq, PartialEq)] | 63 | #[derive(Default, Debug, Eq, PartialEq)] |
52 | pub struct BodySourceMap { | 64 | pub struct BodySourceMap { |
53 | expr_map: FxHashMap<ExprPtr, ExprId>, | 65 | expr_map: FxHashMap<ExprPtr, ExprId>, |
54 | expr_map_back: ArenaMap<ExprId, ExprPtr>, | 66 | expr_map_back: ArenaMap<ExprId, ExprSource>, |
55 | pat_map: FxHashMap<PatPtr, PatId>, | 67 | pat_map: FxHashMap<PatPtr, PatId>, |
56 | pat_map_back: ArenaMap<PatId, PatPtr>, | 68 | pat_map_back: ArenaMap<PatId, PatSource>, |
57 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | 69 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, |
58 | } | 70 | } |
59 | 71 | ||
60 | type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | ||
61 | type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
62 | |||
63 | impl Body { | 72 | impl Body { |
64 | pub fn params(&self) -> &[PatId] { | 73 | pub fn params(&self) -> &[PatId] { |
65 | &self.params | 74 | &self.params |
@@ -123,16 +132,16 @@ impl Index<PatId> for Body { | |||
123 | } | 132 | } |
124 | 133 | ||
125 | impl BodySourceMap { | 134 | impl BodySourceMap { |
126 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprPtr> { | 135 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> { |
127 | self.expr_map_back.get(expr).cloned() | 136 | self.expr_map_back.get(expr).copied() |
128 | } | 137 | } |
129 | 138 | ||
130 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | 139 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { |
131 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() | 140 | self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() |
132 | } | 141 | } |
133 | 142 | ||
134 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { | 143 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { |
135 | self.pat_map_back.get(pat).cloned() | 144 | self.pat_map_back.get(pat).copied() |
136 | } | 145 | } |
137 | 146 | ||
138 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | 147 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { |
@@ -524,3 +533,34 @@ impl Pat { | |||
524 | } | 533 | } |
525 | } | 534 | } |
526 | } | 535 | } |
536 | |||
537 | // Queries | ||
538 | pub(crate) fn body_with_source_map_query( | ||
539 | db: &impl HirDatabase, | ||
540 | def: DefWithBody, | ||
541 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
542 | let mut params = None; | ||
543 | |||
544 | let (file_id, body) = match def { | ||
545 | DefWithBody::Function(f) => { | ||
546 | let src = f.source(db); | ||
547 | params = src.ast.param_list(); | ||
548 | (src.file_id, src.ast.body().map(ast::Expr::from)) | ||
549 | } | ||
550 | DefWithBody::Const(c) => { | ||
551 | let src = c.source(db); | ||
552 | (src.file_id, src.ast.body()) | ||
553 | } | ||
554 | DefWithBody::Static(s) => { | ||
555 | let src = s.source(db); | ||
556 | (src.file_id, src.ast.body()) | ||
557 | } | ||
558 | }; | ||
559 | |||
560 | let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body); | ||
561 | (Arc::new(body), Arc::new(source_map)) | ||
562 | } | ||
563 | |||
564 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | ||
565 | db.body_with_source_map(def).0 | ||
566 | } | ||
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index f6a75a379..6afd80989 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_arena::Arena; | 1 | use ra_arena::Arena; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{ | 3 | ast::{ |
@@ -15,8 +13,8 @@ use crate::{ | |||
15 | path::GenericArgs, | 13 | path::GenericArgs, |
16 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | 14 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, |
17 | type_ref::TypeRef, | 15 | type_ref::TypeRef, |
18 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, | 16 | DefWithBody, Either, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, |
19 | Mutability, Path, Resolver, | 17 | Resolver, Source, |
20 | }; | 18 | }; |
21 | 19 | ||
22 | use super::{ | 20 | use super::{ |
@@ -24,14 +22,33 @@ use super::{ | |||
24 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, | 22 | LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, |
25 | }; | 23 | }; |
26 | 24 | ||
27 | pub(crate) struct ExprCollector<DB> { | 25 | pub(super) fn lower( |
28 | db: DB, | 26 | db: &impl HirDatabase, |
27 | resolver: Resolver, | ||
28 | file_id: HirFileId, | ||
29 | owner: DefWithBody, | 29 | owner: DefWithBody, |
30 | exprs: Arena<ExprId, Expr>, | 30 | params: Option<ast::ParamList>, |
31 | pats: Arena<PatId, Pat>, | 31 | body: Option<ast::Expr>, |
32 | source_map: BodySourceMap, | 32 | ) -> (Body, BodySourceMap) { |
33 | params: Vec<PatId>, | 33 | ExprCollector { |
34 | body_expr: Option<ExprId>, | 34 | resolver, |
35 | db, | ||
36 | original_file_id: file_id, | ||
37 | current_file_id: file_id, | ||
38 | source_map: BodySourceMap::default(), | ||
39 | body: Body { | ||
40 | owner, | ||
41 | exprs: Arena::default(), | ||
42 | pats: Arena::default(), | ||
43 | params: Vec::new(), | ||
44 | body_expr: ExprId((!0).into()), | ||
45 | }, | ||
46 | } | ||
47 | .collect(params, body) | ||
48 | } | ||
49 | |||
50 | struct ExprCollector<DB> { | ||
51 | db: DB, | ||
35 | resolver: Resolver, | 52 | resolver: Resolver, |
36 | // Expr collector expands macros along the way. original points to the file | 53 | // Expr collector expands macros along the way. original points to the file |
37 | // we started with, current points to the current macro expansion. source | 54 | // we started with, current points to the current macro expansion. source |
@@ -39,50 +56,95 @@ pub(crate) struct ExprCollector<DB> { | |||
39 | // current == original (see #1196) | 56 | // current == original (see #1196) |
40 | original_file_id: HirFileId, | 57 | original_file_id: HirFileId, |
41 | current_file_id: HirFileId, | 58 | current_file_id: HirFileId, |
59 | |||
60 | body: Body, | ||
61 | source_map: BodySourceMap, | ||
42 | } | 62 | } |
43 | 63 | ||
44 | impl<'a, DB> ExprCollector<&'a DB> | 64 | impl<'a, DB> ExprCollector<&'a DB> |
45 | where | 65 | where |
46 | DB: HirDatabase, | 66 | DB: HirDatabase, |
47 | { | 67 | { |
48 | fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self { | 68 | fn collect( |
49 | ExprCollector { | 69 | mut self, |
50 | owner, | 70 | param_list: Option<ast::ParamList>, |
51 | resolver, | 71 | body: Option<ast::Expr>, |
52 | db, | 72 | ) -> (Body, BodySourceMap) { |
53 | exprs: Arena::default(), | 73 | if let Some(param_list) = param_list { |
54 | pats: Arena::default(), | 74 | if let Some(self_param) = param_list.self_param() { |
55 | source_map: BodySourceMap::default(), | 75 | let ptr = AstPtr::new(&self_param); |
56 | params: Vec::new(), | 76 | let param_pat = self.alloc_pat( |
57 | body_expr: None, | 77 | Pat::Bind { |
58 | original_file_id: file_id, | 78 | name: SELF_PARAM, |
59 | current_file_id: file_id, | 79 | mode: BindingAnnotation::Unannotated, |
60 | } | 80 | subpat: None, |
81 | }, | ||
82 | Either::B(ptr), | ||
83 | ); | ||
84 | self.body.params.push(param_pat); | ||
85 | } | ||
86 | |||
87 | for param in param_list.params() { | ||
88 | let pat = match param.pat() { | ||
89 | None => continue, | ||
90 | Some(pat) => pat, | ||
91 | }; | ||
92 | let param_pat = self.collect_pat(pat); | ||
93 | self.body.params.push(param_pat); | ||
94 | } | ||
95 | }; | ||
96 | |||
97 | self.body.body_expr = self.collect_expr_opt(body); | ||
98 | (self.body, self.source_map) | ||
61 | } | 99 | } |
100 | |||
62 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 101 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
63 | let ptr = Either::A(ptr); | 102 | let ptr = Either::A(ptr); |
64 | let id = self.exprs.alloc(expr); | 103 | let id = self.body.exprs.alloc(expr); |
65 | if self.current_file_id == self.original_file_id { | 104 | if self.current_file_id == self.original_file_id { |
66 | self.source_map.expr_map.insert(ptr, id); | 105 | self.source_map.expr_map.insert(ptr, id); |
67 | self.source_map.expr_map_back.insert(id, ptr); | ||
68 | } | 106 | } |
107 | self.source_map | ||
108 | .expr_map_back | ||
109 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
110 | id | ||
111 | } | ||
112 | // desugared exprs don't have ptr, that's wrong and should be fixed | ||
113 | // somehow. | ||
114 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | ||
115 | self.body.exprs.alloc(expr) | ||
116 | } | ||
117 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | ||
118 | let ptr = Either::B(ptr); | ||
119 | let id = self.body.exprs.alloc(expr); | ||
120 | if self.current_file_id == self.original_file_id { | ||
121 | self.source_map.expr_map.insert(ptr, id); | ||
122 | } | ||
123 | self.source_map | ||
124 | .expr_map_back | ||
125 | .insert(id, Source { file_id: self.current_file_id, ast: ptr }); | ||
69 | id | 126 | id |
70 | } | 127 | } |
71 | |||
72 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | 128 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |
73 | let id = self.pats.alloc(pat); | 129 | let id = self.body.pats.alloc(pat); |
74 | |||
75 | if self.current_file_id == self.original_file_id { | 130 | if self.current_file_id == self.original_file_id { |
76 | self.source_map.pat_map.insert(ptr, id); | 131 | self.source_map.pat_map.insert(ptr, id); |
77 | self.source_map.pat_map_back.insert(id, ptr); | ||
78 | } | 132 | } |
79 | 133 | self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr }); | |
80 | id | 134 | id |
81 | } | 135 | } |
82 | 136 | ||
83 | fn empty_block(&mut self) -> ExprId { | 137 | fn empty_block(&mut self) -> ExprId { |
84 | let block = Expr::Block { statements: Vec::new(), tail: None }; | 138 | let block = Expr::Block { statements: Vec::new(), tail: None }; |
85 | self.exprs.alloc(block) | 139 | self.body.exprs.alloc(block) |
140 | } | ||
141 | |||
142 | fn missing_expr(&mut self) -> ExprId { | ||
143 | self.body.exprs.alloc(Expr::Missing) | ||
144 | } | ||
145 | |||
146 | fn missing_pat(&mut self) -> PatId { | ||
147 | self.body.pats.alloc(Pat::Missing) | ||
86 | } | 148 | } |
87 | 149 | ||
88 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | 150 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { |
@@ -100,14 +162,14 @@ where | |||
100 | }); | 162 | }); |
101 | 163 | ||
102 | let condition = match e.condition() { | 164 | let condition = match e.condition() { |
103 | None => self.exprs.alloc(Expr::Missing), | 165 | None => self.missing_expr(), |
104 | Some(condition) => match condition.pat() { | 166 | Some(condition) => match condition.pat() { |
105 | None => self.collect_expr_opt(condition.expr()), | 167 | None => self.collect_expr_opt(condition.expr()), |
106 | // if let -- desugar to match | 168 | // if let -- desugar to match |
107 | Some(pat) => { | 169 | Some(pat) => { |
108 | let pat = self.collect_pat(pat); | 170 | let pat = self.collect_pat(pat); |
109 | let match_expr = self.collect_expr_opt(condition.expr()); | 171 | let match_expr = self.collect_expr_opt(condition.expr()); |
110 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 172 | let placeholder_pat = self.missing_pat(); |
111 | let arms = vec![ | 173 | let arms = vec![ |
112 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, | 174 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, |
113 | MatchArm { | 175 | MatchArm { |
@@ -137,7 +199,7 @@ where | |||
137 | let body = self.collect_block_opt(e.loop_body()); | 199 | let body = self.collect_block_opt(e.loop_body()); |
138 | 200 | ||
139 | let condition = match e.condition() { | 201 | let condition = match e.condition() { |
140 | None => self.exprs.alloc(Expr::Missing), | 202 | None => self.missing_expr(), |
141 | Some(condition) => match condition.pat() { | 203 | Some(condition) => match condition.pat() { |
142 | None => self.collect_expr_opt(condition.expr()), | 204 | None => self.collect_expr_opt(condition.expr()), |
143 | // if let -- desugar to match | 205 | // if let -- desugar to match |
@@ -145,14 +207,14 @@ where | |||
145 | tested_by!(infer_while_let); | 207 | tested_by!(infer_while_let); |
146 | let pat = self.collect_pat(pat); | 208 | let pat = self.collect_pat(pat); |
147 | let match_expr = self.collect_expr_opt(condition.expr()); | 209 | let match_expr = self.collect_expr_opt(condition.expr()); |
148 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 210 | let placeholder_pat = self.missing_pat(); |
149 | let break_ = self.exprs.alloc(Expr::Break { expr: None }); | 211 | let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); |
150 | let arms = vec![ | 212 | let arms = vec![ |
151 | MatchArm { pats: vec![pat], expr: body, guard: None }, | 213 | MatchArm { pats: vec![pat], expr: body, guard: None }, |
152 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, | 214 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, |
153 | ]; | 215 | ]; |
154 | let match_expr = | 216 | let match_expr = |
155 | self.exprs.alloc(Expr::Match { expr: match_expr, arms }); | 217 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); |
156 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | 218 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); |
157 | } | 219 | } |
158 | }, | 220 | }, |
@@ -247,13 +309,12 @@ where | |||
247 | self.collect_expr(e) | 309 | self.collect_expr(e) |
248 | } else if let Some(nr) = field.name_ref() { | 310 | } else if let Some(nr) = field.name_ref() { |
249 | // field shorthand | 311 | // field shorthand |
250 | let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr))); | 312 | self.alloc_expr_field_shorthand( |
251 | let ptr = Either::B(AstPtr::new(&field)); | 313 | Expr::Path(Path::from_name_ref(&nr)), |
252 | self.source_map.expr_map.insert(ptr, id); | 314 | AstPtr::new(&field), |
253 | self.source_map.expr_map_back.insert(id, ptr); | 315 | ) |
254 | id | ||
255 | } else { | 316 | } else { |
256 | self.exprs.alloc(Expr::Missing) | 317 | self.missing_expr() |
257 | }, | 318 | }, |
258 | }) | 319 | }) |
259 | .collect(); | 320 | .collect(); |
@@ -420,7 +481,7 @@ where | |||
420 | if let Some(expr) = expr { | 481 | if let Some(expr) = expr { |
421 | self.collect_expr(expr) | 482 | self.collect_expr(expr) |
422 | } else { | 483 | } else { |
423 | self.exprs.alloc(Expr::Missing) | 484 | self.missing_expr() |
424 | } | 485 | } |
425 | } | 486 | } |
426 | 487 | ||
@@ -450,7 +511,7 @@ where | |||
450 | if let Some(block) = expr { | 511 | if let Some(block) = expr { |
451 | self.collect_block(block) | 512 | self.collect_block(block) |
452 | } else { | 513 | } else { |
453 | self.exprs.alloc(Expr::Missing) | 514 | self.missing_expr() |
454 | } | 515 | } |
455 | } | 516 | } |
456 | 517 | ||
@@ -519,60 +580,9 @@ where | |||
519 | if let Some(pat) = pat { | 580 | if let Some(pat) = pat { |
520 | self.collect_pat(pat) | 581 | self.collect_pat(pat) |
521 | } else { | 582 | } else { |
522 | self.pats.alloc(Pat::Missing) | 583 | self.missing_pat() |
523 | } | 584 | } |
524 | } | 585 | } |
525 | |||
526 | fn collect_const_body(&mut self, node: ast::ConstDef) { | ||
527 | let body = self.collect_expr_opt(node.body()); | ||
528 | self.body_expr = Some(body); | ||
529 | } | ||
530 | |||
531 | fn collect_static_body(&mut self, node: ast::StaticDef) { | ||
532 | let body = self.collect_expr_opt(node.body()); | ||
533 | self.body_expr = Some(body); | ||
534 | } | ||
535 | |||
536 | fn collect_fn_body(&mut self, node: ast::FnDef) { | ||
537 | if let Some(param_list) = node.param_list() { | ||
538 | if let Some(self_param) = param_list.self_param() { | ||
539 | let ptr = AstPtr::new(&self_param); | ||
540 | let param_pat = self.alloc_pat( | ||
541 | Pat::Bind { | ||
542 | name: SELF_PARAM, | ||
543 | mode: BindingAnnotation::Unannotated, | ||
544 | subpat: None, | ||
545 | }, | ||
546 | Either::B(ptr), | ||
547 | ); | ||
548 | self.params.push(param_pat); | ||
549 | } | ||
550 | |||
551 | for param in param_list.params() { | ||
552 | let pat = if let Some(pat) = param.pat() { | ||
553 | pat | ||
554 | } else { | ||
555 | continue; | ||
556 | }; | ||
557 | let param_pat = self.collect_pat(pat); | ||
558 | self.params.push(param_pat); | ||
559 | } | ||
560 | }; | ||
561 | |||
562 | let body = self.collect_block_opt(node.body()); | ||
563 | self.body_expr = Some(body); | ||
564 | } | ||
565 | |||
566 | fn finish(self) -> (Body, BodySourceMap) { | ||
567 | let body = Body { | ||
568 | owner: self.owner, | ||
569 | exprs: self.exprs, | ||
570 | pats: self.pats, | ||
571 | params: self.params, | ||
572 | body_expr: self.body_expr.expect("A body should have been collected"), | ||
573 | }; | ||
574 | (body, self.source_map) | ||
575 | } | ||
576 | } | 586 | } |
577 | 587 | ||
578 | impl From<ast::BinOp> for BinaryOp { | 588 | impl From<ast::BinOp> for BinaryOp { |
@@ -618,35 +628,3 @@ impl From<ast::BinOp> for BinaryOp { | |||
618 | } | 628 | } |
619 | } | 629 | } |
620 | } | 630 | } |
621 | |||
622 | pub(crate) fn body_with_source_map_query( | ||
623 | db: &impl HirDatabase, | ||
624 | def: DefWithBody, | ||
625 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | ||
626 | let mut collector; | ||
627 | |||
628 | match def { | ||
629 | DefWithBody::Const(ref c) => { | ||
630 | let src = c.source(db); | ||
631 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
632 | collector.collect_const_body(src.ast) | ||
633 | } | ||
634 | DefWithBody::Function(ref f) => { | ||
635 | let src = f.source(db); | ||
636 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
637 | collector.collect_fn_body(src.ast) | ||
638 | } | ||
639 | DefWithBody::Static(ref s) => { | ||
640 | let src = s.source(db); | ||
641 | collector = ExprCollector::new(def, src.file_id, def.resolver(db), db); | ||
642 | collector.collect_static_body(src.ast) | ||
643 | } | ||
644 | } | ||
645 | |||
646 | let (body, source_map) = collector.finish(); | ||
647 | (Arc::new(body), Arc::new(source_map)) | ||
648 | } | ||
649 | |||
650 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { | ||
651 | db.body_with_source_map(def).0 | ||
652 | } | ||
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 6fdaf1fce..1202913e2 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -1,9 +1,8 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::ast::{self, AstNode}; | 3 | use ra_syntax::ast; |
4 | use rustc_hash::FxHashSet; | 4 | use rustc_hash::FxHashSet; |
5 | 5 | ||
6 | use super::{Expr, ExprId, RecordLitField}; | ||
7 | use crate::{ | 6 | use crate::{ |
8 | adt::AdtDef, | 7 | adt::AdtDef, |
9 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, | 8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, |
@@ -11,9 +10,11 @@ use crate::{ | |||
11 | name, | 10 | name, |
12 | path::{PathKind, PathSegment}, | 11 | path::{PathKind, PathSegment}, |
13 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | 12 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, |
14 | Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, | 13 | Function, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, |
15 | }; | 14 | }; |
16 | 15 | ||
16 | use super::{Expr, ExprId, RecordLitField}; | ||
17 | |||
17 | pub(crate) struct ExprValidator<'a, 'b: 'a> { | 18 | pub(crate) struct ExprValidator<'a, 'b: 'a> { |
18 | func: Function, | 19 | func: Function, |
19 | infer: Arc<InferenceResult>, | 20 | infer: Arc<InferenceResult>, |
@@ -78,25 +79,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
78 | return; | 79 | return; |
79 | } | 80 | } |
80 | let source_map = self.func.body_source_map(db); | 81 | let source_map = self.func.body_source_map(db); |
81 | let file_id = self.func.source(db).file_id; | 82 | |
82 | let parse = db.parse(file_id.original_file(db)); | 83 | if let Some(source_ptr) = source_map.expr_syntax(id) { |
83 | let source_file = parse.tree(); | 84 | if let Some(expr) = source_ptr.ast.a() { |
84 | if let Some(field_list_node) = source_map | 85 | let root = source_ptr.file_syntax(db); |
85 | .expr_syntax(id) | 86 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { |
86 | .and_then(|ptr| ptr.a()) | 87 | if let Some(field_list) = record_lit.record_field_list() { |
87 | .map(|ptr| ptr.to_node(source_file.syntax())) | 88 | self.sink.push(MissingFields { |
88 | .and_then(|expr| match expr { | 89 | file: source_ptr.file_id, |
89 | ast::Expr::RecordLit(it) => Some(it), | 90 | field_list: AstPtr::new(&field_list), |
90 | _ => None, | 91 | missed_fields, |
91 | }) | 92 | }) |
92 | .and_then(|lit| lit.record_field_list()) | 93 | } |
93 | { | 94 | } |
94 | let field_list_ptr = AstPtr::new(&field_list_node); | 95 | } |
95 | self.sink.push(MissingFields { | ||
96 | file: file_id, | ||
97 | field_list: field_list_ptr, | ||
98 | missed_fields, | ||
99 | }) | ||
100 | } | 96 | } |
101 | } | 97 | } |
102 | 98 | ||
@@ -136,10 +132,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
136 | 132 | ||
137 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { | 133 | if params.len() == 2 && ¶ms[0] == &mismatch.actual { |
138 | let source_map = self.func.body_source_map(db); | 134 | let source_map = self.func.body_source_map(db); |
139 | let file_id = self.func.source(db).file_id; | ||
140 | 135 | ||
141 | if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.a()) { | 136 | if let Some(source_ptr) = source_map.expr_syntax(id) { |
142 | self.sink.push(MissingOkInTailExpr { file: file_id, expr }); | 137 | if let Some(expr) = source_ptr.ast.a() { |
138 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); | ||
139 | } | ||
143 | } | 140 | } |
144 | } | 141 | } |
145 | } | 142 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 752653ad7..c3e589921 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -69,7 +69,9 @@ pub use self::{ | |||
69 | resolve::Resolution, | 69 | resolve::Resolution, |
70 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 70 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
71 | source_id::{AstIdMap, ErasedFileAstId}, | 71 | source_id::{AstIdMap, ErasedFileAstId}, |
72 | ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, | 72 | ty::{ |
73 | display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | ||
74 | }, | ||
73 | type_ref::Mutability, | 75 | type_ref::Mutability, |
74 | }; | 76 | }; |
75 | 77 | ||
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 5b15eee90..fe119b97c 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -11,4 +11,6 @@ test_utils::marks!( | |||
11 | match_ergonomics_ref | 11 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | 12 | trait_resolution_on_fn_type |
13 | infer_while_let | 13 | infer_while_let |
14 | macro_rules_from_other_crates_are_visible_with_macro_use | ||
15 | prelude_is_macro_use | ||
14 | ); | 16 | ); |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 77a44a275..972f0ece5 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -157,7 +157,7 @@ impl MockDatabase { | |||
157 | self.set_file_text(file_id, text); | 157 | self.set_file_text(file_id, text); |
158 | self.set_file_relative_path(file_id, rel_path.clone()); | 158 | self.set_file_relative_path(file_id, rel_path.clone()); |
159 | self.set_file_source_root(file_id, source_root_id); | 159 | self.set_file_source_root(file_id, source_root_id); |
160 | source_root.files.insert(rel_path, file_id); | 160 | source_root.insert_file(rel_path, file_id); |
161 | 161 | ||
162 | if is_crate_root { | 162 | if is_crate_root { |
163 | let mut crate_graph = CrateGraph::default(); | 163 | let mut crate_graph = CrateGraph::default(); |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index bbdc606cd..fe90879b6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -1,55 +1,56 @@ | |||
1 | /// This module implements import-resolution/macro expansion algorithm. | 1 | //! This module implements import-resolution/macro expansion algorithm. |
2 | /// | 2 | //! |
3 | /// The result of this module is `CrateDefMap`: a data structure which contains: | 3 | //! The result of this module is `CrateDefMap`: a data structure which contains: |
4 | /// | 4 | //! |
5 | /// * a tree of modules for the crate | 5 | //! * a tree of modules for the crate |
6 | /// * for each module, a set of items visible in the module (directly declared | 6 | //! * for each module, a set of items visible in the module (directly declared |
7 | /// or imported) | 7 | //! or imported) |
8 | /// | 8 | //! |
9 | /// Note that `CrateDefMap` contains fully macro expanded code. | 9 | //! Note that `CrateDefMap` contains fully macro expanded code. |
10 | /// | 10 | //! |
11 | /// Computing `CrateDefMap` can be partitioned into several logically | 11 | //! Computing `CrateDefMap` can be partitioned into several logically |
12 | /// independent "phases". The phases are mutually recursive though, there's no | 12 | //! independent "phases". The phases are mutually recursive though, there's no |
13 | /// strict ordering. | 13 | //! strict ordering. |
14 | /// | 14 | //! |
15 | /// ## Collecting RawItems | 15 | //! ## Collecting RawItems |
16 | /// | 16 | //! |
17 | /// This happens in the `raw` module, which parses a single source file into a | 17 | //! This happens in the `raw` module, which parses a single source file into a |
18 | /// set of top-level items. Nested imports are desugared to flat imports in | 18 | //! set of top-level items. Nested imports are desugared to flat imports in |
19 | /// this phase. Macro calls are represented as a triple of (Path, Option<Name>, | 19 | //! this phase. Macro calls are represented as a triple of (Path, Option<Name>, |
20 | /// TokenTree). | 20 | //! TokenTree). |
21 | /// | 21 | //! |
22 | /// ## Collecting Modules | 22 | //! ## Collecting Modules |
23 | /// | 23 | //! |
24 | /// This happens in the `collector` module. In this phase, we recursively walk | 24 | //! This happens in the `collector` module. In this phase, we recursively walk |
25 | /// tree of modules, collect raw items from submodules, populate module scopes | 25 | //! tree of modules, collect raw items from submodules, populate module scopes |
26 | /// with defined items (so, we assign item ids in this phase) and record the set | 26 | //! with defined items (so, we assign item ids in this phase) and record the set |
27 | /// of unresolved imports and macros. | 27 | //! of unresolved imports and macros. |
28 | /// | 28 | //! |
29 | /// While we walk tree of modules, we also record macro_rules definitions and | 29 | //! While we walk tree of modules, we also record macro_rules definitions and |
30 | /// expand calls to macro_rules defined macros. | 30 | //! expand calls to macro_rules defined macros. |
31 | /// | 31 | //! |
32 | /// ## Resolving Imports | 32 | //! ## Resolving Imports |
33 | /// | 33 | //! |
34 | /// We maintain a list of currently unresolved imports. On every iteration, we | 34 | //! We maintain a list of currently unresolved imports. On every iteration, we |
35 | /// try to resolve some imports from this list. If the import is resolved, we | 35 | //! try to resolve some imports from this list. If the import is resolved, we |
36 | /// record it, by adding an item to current module scope and, if necessary, by | 36 | //! record it, by adding an item to current module scope and, if necessary, by |
37 | /// recursively populating glob imports. | 37 | //! recursively populating glob imports. |
38 | /// | 38 | //! |
39 | /// ## Resolving Macros | 39 | //! ## Resolving Macros |
40 | /// | 40 | //! |
41 | /// macro_rules from the same crate use a global mutable namespace. We expand | 41 | //! macro_rules from the same crate use a global mutable namespace. We expand |
42 | /// them immediately, when we collect modules. | 42 | //! them immediately, when we collect modules. |
43 | /// | 43 | //! |
44 | /// Macros from other crates (including proc-macros) can be used with | 44 | //! Macros from other crates (including proc-macros) can be used with |
45 | /// `foo::bar!` syntax. We handle them similarly to imports. There's a list of | 45 | //! `foo::bar!` syntax. We handle them similarly to imports. There's a list of |
46 | /// unexpanded macros. On every iteration, we try to resolve each macro call | 46 | //! unexpanded macros. On every iteration, we try to resolve each macro call |
47 | /// path and, upon success, we run macro expansion and "collect module" phase | 47 | //! path and, upon success, we run macro expansion and "collect module" phase |
48 | /// on the result | 48 | //! on the result |
49 | 49 | ||
50 | mod per_ns; | 50 | mod per_ns; |
51 | mod raw; | 51 | mod raw; |
52 | mod collector; | 52 | mod collector; |
53 | mod mod_resolution; | ||
53 | #[cfg(test)] | 54 | #[cfg(test)] |
54 | mod tests; | 55 | mod tests; |
55 | 56 | ||
@@ -101,6 +102,8 @@ pub struct CrateDefMap { | |||
101 | /// However, do we want to put it as a global variable? | 102 | /// However, do we want to put it as a global variable? |
102 | poison_macros: FxHashSet<MacroDefId>, | 103 | poison_macros: FxHashSet<MacroDefId>, |
103 | 104 | ||
105 | exported_macros: FxHashMap<Name, MacroDefId>, | ||
106 | |||
104 | diagnostics: Vec<DefDiagnostic>, | 107 | diagnostics: Vec<DefDiagnostic>, |
105 | } | 108 | } |
106 | 109 | ||
@@ -245,6 +248,7 @@ impl CrateDefMap { | |||
245 | root, | 248 | root, |
246 | modules, | 249 | modules, |
247 | poison_macros: FxHashSet::default(), | 250 | poison_macros: FxHashSet::default(), |
251 | exported_macros: FxHashMap::default(), | ||
248 | diagnostics: Vec::new(), | 252 | diagnostics: Vec::new(), |
249 | } | 253 | } |
250 | }; | 254 | }; |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7da2dcdff..5af26f953 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,9 +1,5 @@ | |||
1 | use std::borrow::Cow; | 1 | use ra_db::FileId; |
2 | use std::sync::Arc; | 2 | use ra_syntax::ast; |
3 | |||
4 | use ra_db::{FileId, SourceRoot}; | ||
5 | use ra_syntax::{ast, SmolStr}; | ||
6 | use relative_path::RelativePathBuf; | ||
7 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
8 | use test_utils::tested_by; | 4 | use test_utils::tested_by; |
9 | 5 | ||
@@ -12,8 +8,10 @@ use crate::{ | |||
12 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 8 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
13 | name::MACRO_RULES, | 9 | name::MACRO_RULES, |
14 | nameres::{ | 10 | nameres::{ |
15 | diagnostics::DefDiagnostic, raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, | 11 | diagnostics::DefDiagnostic, |
16 | ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, | 12 | mod_resolution::{resolve_submodule, ParentModule}, |
13 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | ||
14 | ReachedFixedPoint, Resolution, ResolveMode, | ||
17 | }, | 15 | }, |
18 | AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, | 16 | AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, |
19 | Struct, Trait, TypeAlias, Union, | 17 | Struct, Trait, TypeAlias, Union, |
@@ -157,11 +155,45 @@ where | |||
157 | // crate root, even if the parent modules is **not** visible. | 155 | // crate root, even if the parent modules is **not** visible. |
158 | if export { | 156 | if export { |
159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 157 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); |
158 | |||
159 | // Exported macros are collected in crate level ready for | ||
160 | // glob import with `#[macro_use]`. | ||
161 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
160 | } | 162 | } |
161 | self.update(module_id, None, &[(name.clone(), def)]); | 163 | self.update(module_id, None, &[(name.clone(), def)]); |
162 | self.global_macro_scope.insert(name, macro_id); | 164 | self.global_macro_scope.insert(name, macro_id); |
163 | } | 165 | } |
164 | 166 | ||
167 | /// Import macros from `#[macro_use] extern crate`. | ||
168 | /// | ||
169 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
170 | fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { | ||
171 | log::debug!( | ||
172 | "importing macros from extern crate: {:?} ({:?})", | ||
173 | import, | ||
174 | self.def_map.edition, | ||
175 | ); | ||
176 | |||
177 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
178 | &import | ||
179 | .path | ||
180 | .as_ident() | ||
181 | .expect("extern crate should have been desugared to one-element path"), | ||
182 | ); | ||
183 | |||
184 | if let Some(ModuleDef::Module(m)) = res.take_types() { | ||
185 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
186 | self.import_all_macros_exported(m); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | fn import_all_macros_exported(&mut self, module: Module) { | ||
191 | let item_map = self.db.crate_def_map(module.krate); | ||
192 | for (name, ¯o_id) in &item_map.exported_macros { | ||
193 | self.global_macro_scope.insert(name.clone(), macro_id); | ||
194 | } | ||
195 | } | ||
196 | |||
165 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 197 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
166 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 198 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
167 | let mut resolved = Vec::new(); | 199 | let mut resolved = Vec::new(); |
@@ -491,13 +523,31 @@ where | |||
491 | DB: DefDatabase, | 523 | DB: DefDatabase, |
492 | { | 524 | { |
493 | fn collect(&mut self, items: &[raw::RawItem]) { | 525 | fn collect(&mut self, items: &[raw::RawItem]) { |
526 | // Prelude module is always considered to be `#[macro_use]`. | ||
527 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | ||
528 | tested_by!(prelude_is_macro_use); | ||
529 | self.def_collector.import_all_macros_exported(prelude_module); | ||
530 | } | ||
531 | |||
532 | // This should be processed eagerly instead of deferred to resolving. | ||
533 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | ||
534 | // any other items. | ||
535 | for item in items { | ||
536 | if let raw::RawItem::Import(import_id) = *item { | ||
537 | let import = self.raw_items[import_id].clone(); | ||
538 | if import.is_extern_crate && import.is_macro_use { | ||
539 | self.def_collector.import_macros_from_extern_crate(&import); | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | |||
494 | for item in items { | 544 | for item in items { |
495 | match *item { | 545 | match *item { |
496 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 546 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), |
497 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( | 547 | raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( |
498 | self.module_id, | 548 | self.module_id, |
499 | import, | 549 | import_id, |
500 | self.raw_items[import].clone(), | 550 | self.raw_items[import_id].clone(), |
501 | )), | 551 | )), |
502 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 552 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), |
503 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 553 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
@@ -531,7 +581,7 @@ where | |||
531 | name, | 581 | name, |
532 | is_root, | 582 | is_root, |
533 | attr_path.as_ref(), | 583 | attr_path.as_ref(), |
534 | self.parent_module.as_ref(), | 584 | self.parent_module, |
535 | ) { | 585 | ) { |
536 | Ok(file_id) => { | 586 | Ok(file_id) => { |
537 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 587 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -642,180 +692,6 @@ fn is_macro_rules(path: &Path) -> bool { | |||
642 | path.as_ident() == Some(&MACRO_RULES) | 692 | path.as_ident() == Some(&MACRO_RULES) |
643 | } | 693 | } |
644 | 694 | ||
645 | fn resolve_submodule( | ||
646 | db: &impl DefDatabase, | ||
647 | file_id: HirFileId, | ||
648 | name: &Name, | ||
649 | is_root: bool, | ||
650 | attr_path: Option<&SmolStr>, | ||
651 | parent_module: Option<&ParentModule>, | ||
652 | ) -> Result<FileId, RelativePathBuf> { | ||
653 | let file_id = file_id.original_file(db); | ||
654 | let source_root_id = db.file_source_root(file_id); | ||
655 | let path = db.file_relative_path(file_id); | ||
656 | let root = RelativePathBuf::default(); | ||
657 | let dir_path = path.parent().unwrap_or(&root); | ||
658 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
659 | |||
660 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | ||
661 | (Some(file_path), Some(parent_module)) => { | ||
662 | let file_path = normalize_attribute_path(file_path); | ||
663 | match parent_module.attribute_path() { | ||
664 | Some(parent_module_attr_path) => { | ||
665 | let path = dir_path | ||
666 | .join(format!( | ||
667 | "{}/{}", | ||
668 | normalize_attribute_path(parent_module_attr_path), | ||
669 | file_path | ||
670 | )) | ||
671 | .normalize(); | ||
672 | ResolutionMode::InlineModuleWithAttributePath( | ||
673 | InsideInlineModuleMode::WithAttributePath(path), | ||
674 | ) | ||
675 | } | ||
676 | None => { | ||
677 | let path = | ||
678 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
679 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
680 | path, | ||
681 | )) | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
686 | Some(parent_module_attr_path) => { | ||
687 | let path = dir_path.join(format!( | ||
688 | "{}/{}.rs", | ||
689 | normalize_attribute_path(parent_module_attr_path), | ||
690 | name | ||
691 | )); | ||
692 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
693 | } | ||
694 | None => { | ||
695 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
696 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
697 | } | ||
698 | }, | ||
699 | (Some(file_path), None) => { | ||
700 | let file_path = normalize_attribute_path(file_path); | ||
701 | let path = dir_path.join(file_path.as_ref()).normalize(); | ||
702 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | ||
703 | } | ||
704 | _ => { | ||
705 | let is_dir_owner = is_root || mod_name == "mod"; | ||
706 | if is_dir_owner { | ||
707 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
708 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
709 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { | ||
710 | file: file_mod, | ||
711 | directory: dir_mod, | ||
712 | }) | ||
713 | } else { | ||
714 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
715 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
716 | } | ||
717 | } | ||
718 | }; | ||
719 | |||
720 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
721 | } | ||
722 | |||
723 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | ||
724 | let current_dir = "./"; | ||
725 | let windows_path_separator = r#"\"#; | ||
726 | let current_dir_normalize = if file_path.starts_with(current_dir) { | ||
727 | &file_path[current_dir.len()..] | ||
728 | } else { | ||
729 | file_path.as_str() | ||
730 | }; | ||
731 | if current_dir_normalize.contains(windows_path_separator) { | ||
732 | Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) | ||
733 | } else { | ||
734 | Cow::Borrowed(current_dir_normalize) | ||
735 | } | ||
736 | } | ||
737 | |||
738 | enum OutOfLineMode { | ||
739 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
740 | FileInDirectory(RelativePathBuf), | ||
741 | WithAttributePath(RelativePathBuf), | ||
742 | } | ||
743 | |||
744 | impl OutOfLineMode { | ||
745 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
746 | match self { | ||
747 | OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) { | ||
748 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
749 | file_id => resolve_find_result(file_id, file), | ||
750 | }, | ||
751 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
752 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | |||
757 | enum InsideInlineModuleMode { | ||
758 | File(RelativePathBuf), | ||
759 | WithAttributePath(RelativePathBuf), | ||
760 | } | ||
761 | |||
762 | impl InsideInlineModuleMode { | ||
763 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
764 | match self { | ||
765 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
766 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
767 | resolve_simple_path(source_root, path) | ||
768 | } | ||
769 | } | ||
770 | } | ||
771 | } | ||
772 | |||
773 | enum ResolutionMode { | ||
774 | OutOfLine(OutOfLineMode), | ||
775 | InsideInlineModule(InsideInlineModuleMode), | ||
776 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
777 | } | ||
778 | |||
779 | impl ResolutionMode { | ||
780 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
781 | use self::ResolutionMode::*; | ||
782 | |||
783 | match self { | ||
784 | OutOfLine(mode) => mode.resolve(source_root), | ||
785 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
786 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | |||
791 | fn resolve_simple_path( | ||
792 | source_root: Arc<SourceRoot>, | ||
793 | path: &RelativePathBuf, | ||
794 | ) -> Result<FileId, RelativePathBuf> { | ||
795 | resolve_find_result(source_root.files.get(path), path) | ||
796 | } | ||
797 | |||
798 | fn resolve_find_result( | ||
799 | file_id: Option<&FileId>, | ||
800 | path: &RelativePathBuf, | ||
801 | ) -> Result<FileId, RelativePathBuf> { | ||
802 | match file_id { | ||
803 | Some(file_id) => Ok(file_id.clone()), | ||
804 | None => Err(path.clone()), | ||
805 | } | ||
806 | } | ||
807 | |||
808 | struct ParentModule<'a> { | ||
809 | name: &'a Name, | ||
810 | attr_path: Option<&'a SmolStr>, | ||
811 | } | ||
812 | |||
813 | impl<'a> ParentModule<'a> { | ||
814 | pub fn attribute_path(&self) -> Option<&SmolStr> { | ||
815 | self.attr_path.filter(|p| !p.is_empty()) | ||
816 | } | ||
817 | } | ||
818 | |||
819 | #[cfg(test)] | 695 | #[cfg(test)] |
820 | mod tests { | 696 | mod tests { |
821 | use ra_db::SourceDatabase; | 697 | use ra_db::SourceDatabase; |
@@ -860,6 +736,7 @@ mod tests { | |||
860 | root, | 736 | root, |
861 | modules, | 737 | modules, |
862 | poison_macros: FxHashSet::default(), | 738 | poison_macros: FxHashSet::default(), |
739 | exported_macros: FxHashMap::default(), | ||
863 | diagnostics: Vec::new(), | 740 | diagnostics: Vec::new(), |
864 | } | 741 | } |
865 | }; | 742 | }; |
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs new file mode 100644 index 000000000..918c9591f --- /dev/null +++ b/crates/ra_hir/src/nameres/mod_resolution.rs | |||
@@ -0,0 +1,186 @@ | |||
1 | //! This module resolves `mod foo;` declaration to file. | ||
2 | |||
3 | use std::{borrow::Cow, sync::Arc}; | ||
4 | |||
5 | use ra_db::{FileId, SourceRoot}; | ||
6 | use ra_syntax::SmolStr; | ||
7 | use relative_path::RelativePathBuf; | ||
8 | |||
9 | use crate::{DefDatabase, HirFileId, Name}; | ||
10 | |||
11 | #[derive(Clone, Copy)] | ||
12 | pub(super) struct ParentModule<'a> { | ||
13 | pub(super) name: &'a Name, | ||
14 | pub(super) attr_path: Option<&'a SmolStr>, | ||
15 | } | ||
16 | |||
17 | impl<'a> ParentModule<'a> { | ||
18 | fn attribute_path(&self) -> Option<&SmolStr> { | ||
19 | self.attr_path.filter(|p| !p.is_empty()) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | pub(super) fn resolve_submodule( | ||
24 | db: &impl DefDatabase, | ||
25 | file_id: HirFileId, | ||
26 | name: &Name, | ||
27 | is_root: bool, | ||
28 | attr_path: Option<&SmolStr>, | ||
29 | parent_module: Option<ParentModule<'_>>, | ||
30 | ) -> Result<FileId, RelativePathBuf> { | ||
31 | let file_id = file_id.original_file(db); | ||
32 | let source_root_id = db.file_source_root(file_id); | ||
33 | let path = db.file_relative_path(file_id); | ||
34 | let root = RelativePathBuf::default(); | ||
35 | let dir_path = path.parent().unwrap_or(&root); | ||
36 | let mod_name = path.file_stem().unwrap_or("unknown"); | ||
37 | |||
38 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | ||
39 | (Some(file_path), Some(parent_module)) => { | ||
40 | let file_path = normalize_attribute_path(file_path); | ||
41 | match parent_module.attribute_path() { | ||
42 | Some(parent_module_attr_path) => { | ||
43 | let path = dir_path | ||
44 | .join(format!( | ||
45 | "{}/{}", | ||
46 | normalize_attribute_path(parent_module_attr_path), | ||
47 | file_path | ||
48 | )) | ||
49 | .normalize(); | ||
50 | ResolutionMode::InlineModuleWithAttributePath( | ||
51 | InsideInlineModuleMode::WithAttributePath(path), | ||
52 | ) | ||
53 | } | ||
54 | None => { | ||
55 | let path = | ||
56 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
57 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
58 | path, | ||
59 | )) | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
64 | Some(parent_module_attr_path) => { | ||
65 | let path = dir_path.join(format!( | ||
66 | "{}/{}.rs", | ||
67 | normalize_attribute_path(parent_module_attr_path), | ||
68 | name | ||
69 | )); | ||
70 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
71 | } | ||
72 | None => { | ||
73 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
74 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
75 | } | ||
76 | }, | ||
77 | (Some(file_path), None) => { | ||
78 | let file_path = normalize_attribute_path(file_path); | ||
79 | let path = dir_path.join(file_path.as_ref()).normalize(); | ||
80 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | ||
81 | } | ||
82 | (None, None) => { | ||
83 | let is_dir_owner = is_root || mod_name == "mod"; | ||
84 | if is_dir_owner { | ||
85 | let file_mod = dir_path.join(format!("{}.rs", name)); | ||
86 | let dir_mod = dir_path.join(format!("{}/mod.rs", name)); | ||
87 | ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs { | ||
88 | file: file_mod, | ||
89 | directory: dir_mod, | ||
90 | }) | ||
91 | } else { | ||
92 | let path = dir_path.join(format!("{}/{}.rs", mod_name, name)); | ||
93 | ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path)) | ||
94 | } | ||
95 | } | ||
96 | }; | ||
97 | |||
98 | resolve_mode.resolve(db.source_root(source_root_id)) | ||
99 | } | ||
100 | |||
101 | fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { | ||
102 | let current_dir = "./"; | ||
103 | let windows_path_separator = r#"\"#; | ||
104 | let current_dir_normalize = if file_path.starts_with(current_dir) { | ||
105 | &file_path[current_dir.len()..] | ||
106 | } else { | ||
107 | file_path.as_str() | ||
108 | }; | ||
109 | if current_dir_normalize.contains(windows_path_separator) { | ||
110 | Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/")) | ||
111 | } else { | ||
112 | Cow::Borrowed(current_dir_normalize) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | enum OutOfLineMode { | ||
117 | RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf }, | ||
118 | FileInDirectory(RelativePathBuf), | ||
119 | WithAttributePath(RelativePathBuf), | ||
120 | } | ||
121 | |||
122 | impl OutOfLineMode { | ||
123 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
124 | match self { | ||
125 | OutOfLineMode::RootOrModRs { file, directory } => { | ||
126 | match source_root.file_by_relative_path(file) { | ||
127 | None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()), | ||
128 | file_id => resolve_find_result(file_id, file), | ||
129 | } | ||
130 | } | ||
131 | OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path), | ||
132 | OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path), | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | enum InsideInlineModuleMode { | ||
138 | File(RelativePathBuf), | ||
139 | WithAttributePath(RelativePathBuf), | ||
140 | } | ||
141 | |||
142 | impl InsideInlineModuleMode { | ||
143 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
144 | match self { | ||
145 | InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path), | ||
146 | InsideInlineModuleMode::WithAttributePath(path) => { | ||
147 | resolve_simple_path(source_root, path) | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | enum ResolutionMode { | ||
154 | OutOfLine(OutOfLineMode), | ||
155 | InsideInlineModule(InsideInlineModuleMode), | ||
156 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
157 | } | ||
158 | |||
159 | impl ResolutionMode { | ||
160 | pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> { | ||
161 | use self::ResolutionMode::*; | ||
162 | |||
163 | match self { | ||
164 | OutOfLine(mode) => mode.resolve(source_root), | ||
165 | InsideInlineModule(mode) => mode.resolve(source_root), | ||
166 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | fn resolve_simple_path( | ||
172 | source_root: Arc<SourceRoot>, | ||
173 | path: &RelativePathBuf, | ||
174 | ) -> Result<FileId, RelativePathBuf> { | ||
175 | resolve_find_result(source_root.file_by_relative_path(path), path) | ||
176 | } | ||
177 | |||
178 | fn resolve_find_result( | ||
179 | file_id: Option<FileId>, | ||
180 | path: &RelativePathBuf, | ||
181 | ) -> Result<FileId, RelativePathBuf> { | ||
182 | match file_id { | ||
183 | Some(file_id) => Ok(file_id.clone()), | ||
184 | None => Err(path.clone()), | ||
185 | } | ||
186 | } | ||
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 2f973359f..129b047eb 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -154,6 +154,7 @@ pub struct ImportData { | |||
154 | pub(super) is_glob: bool, | 154 | pub(super) is_glob: bool, |
155 | pub(super) is_prelude: bool, | 155 | pub(super) is_prelude: bool, |
156 | pub(super) is_extern_crate: bool, | 156 | pub(super) is_extern_crate: bool, |
157 | pub(super) is_macro_use: bool, | ||
157 | } | 158 | } |
158 | 159 | ||
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 160 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -293,8 +294,14 @@ impl RawItemsCollector { | |||
293 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 294 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
294 | 295 | ||
295 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 296 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { |
296 | let import_data = | 297 | let import_data = ImportData { |
297 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; | 298 | path, |
299 | alias, | ||
300 | is_glob, | ||
301 | is_prelude, | ||
302 | is_extern_crate: false, | ||
303 | is_macro_use: false, | ||
304 | }; | ||
298 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 305 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); |
299 | }) | 306 | }) |
300 | } | 307 | } |
@@ -307,12 +314,14 @@ impl RawItemsCollector { | |||
307 | if let Some(name_ref) = extern_crate.name_ref() { | 314 | if let Some(name_ref) = extern_crate.name_ref() { |
308 | let path = Path::from_name_ref(&name_ref); | 315 | let path = Path::from_name_ref(&name_ref); |
309 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 316 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
317 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
310 | let import_data = ImportData { | 318 | let import_data = ImportData { |
311 | path, | 319 | path, |
312 | alias, | 320 | alias, |
313 | is_glob: false, | 321 | is_glob: false, |
314 | is_prelude: false, | 322 | is_prelude: false, |
315 | is_extern_crate: true, | 323 | is_extern_crate: true, |
324 | is_macro_use, | ||
316 | }; | 325 | }; |
317 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 326 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); |
318 | } | 327 | } |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index c1dbad283..4ff897ca5 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -2,7 +2,7 @@ mod macros; | |||
2 | mod globs; | 2 | mod globs; |
3 | mod incremental; | 3 | mod incremental; |
4 | mod primitives; | 4 | mod primitives; |
5 | mod mods; | 5 | mod mod_resolution; |
6 | 6 | ||
7 | use std::sync::Arc; | 7 | use std::sync::Arc; |
8 | 8 | ||
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 631df2cef..aece1515b 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -99,14 +99,14 @@ fn macro_rules_from_other_crates_are_visible() { | |||
99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | 99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
100 | let map = def_map_with_crate_graph( | 100 | let map = def_map_with_crate_graph( |
101 | " | 101 | " |
102 | //- /main.rs | 102 | //- /main.rs |
103 | macro_rules! baz { | 103 | macro_rules! baz { |
104 | () => { | 104 | () => { |
105 | use foo::bar; | 105 | use foo::bar; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | foo!(); | 109 | foo!(); |
110 | bar!(); | 110 | bar!(); |
111 | baz!(); | 111 | baz!(); |
112 | 112 | ||
@@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
114 | #[macro_export] | 114 | #[macro_export] |
115 | macro_rules! foo { | 115 | macro_rules! foo { |
116 | () => { | 116 | () => { |
117 | struct Foo { field: u32 } | 117 | struct Foo { field: u32 } |
118 | } | 118 | } |
119 | } | 119 | } |
120 | #[macro_export] | 120 | #[macro_export] |
@@ -137,3 +137,114 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
137 | â‹®foo: m | 137 | â‹®foo: m |
138 | "###); | 138 | "###); |
139 | } | 139 | } |
140 | |||
141 | #[test] | ||
142 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | ||
143 | covers!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
144 | let map = def_map_with_crate_graph( | ||
145 | " | ||
146 | //- /main.rs | ||
147 | structs!(Foo); | ||
148 | structs_priv!(Bar); | ||
149 | structs_not_exported!(MacroNotResolved1); | ||
150 | crate::structs!(MacroNotResolved2); | ||
151 | |||
152 | mod bar; | ||
153 | |||
154 | #[macro_use] | ||
155 | extern crate foo; | ||
156 | |||
157 | //- /bar.rs | ||
158 | structs!(Baz); | ||
159 | crate::structs!(MacroNotResolved3); | ||
160 | |||
161 | //- /lib.rs | ||
162 | #[macro_export] | ||
163 | macro_rules! structs { | ||
164 | ($i:ident) => { struct $i; } | ||
165 | } | ||
166 | |||
167 | macro_rules! structs_not_exported { | ||
168 | ($i:ident) => { struct $i; } | ||
169 | } | ||
170 | |||
171 | mod priv_mod { | ||
172 | #[macro_export] | ||
173 | macro_rules! structs_priv { | ||
174 | ($i:ident) => { struct $i; } | ||
175 | } | ||
176 | } | ||
177 | ", | ||
178 | crate_graph! { | ||
179 | "main": ("/main.rs", ["foo"]), | ||
180 | "foo": ("/lib.rs", []), | ||
181 | }, | ||
182 | ); | ||
183 | assert_snapshot!(map, @r###" | ||
184 | â‹®crate | ||
185 | â‹®Bar: t v | ||
186 | â‹®Foo: t v | ||
187 | â‹®bar: t | ||
188 | â‹®foo: t | ||
189 | â‹® | ||
190 | â‹®crate::bar | ||
191 | â‹®Baz: t v | ||
192 | "###); | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn prelude_is_macro_use() { | ||
197 | covers!(prelude_is_macro_use); | ||
198 | let map = def_map_with_crate_graph( | ||
199 | " | ||
200 | //- /main.rs | ||
201 | structs!(Foo); | ||
202 | structs_priv!(Bar); | ||
203 | structs_outside!(Out); | ||
204 | crate::structs!(MacroNotResolved2); | ||
205 | |||
206 | mod bar; | ||
207 | |||
208 | //- /bar.rs | ||
209 | structs!(Baz); | ||
210 | crate::structs!(MacroNotResolved3); | ||
211 | |||
212 | //- /lib.rs | ||
213 | #[prelude_import] | ||
214 | use self::prelude::*; | ||
215 | |||
216 | mod prelude { | ||
217 | #[macro_export] | ||
218 | macro_rules! structs { | ||
219 | ($i:ident) => { struct $i; } | ||
220 | } | ||
221 | |||
222 | mod priv_mod { | ||
223 | #[macro_export] | ||
224 | macro_rules! structs_priv { | ||
225 | ($i:ident) => { struct $i; } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | #[macro_export] | ||
231 | macro_rules! structs_outside { | ||
232 | ($i:ident) => { struct $i; } | ||
233 | } | ||
234 | ", | ||
235 | crate_graph! { | ||
236 | "main": ("/main.rs", ["foo"]), | ||
237 | "foo": ("/lib.rs", []), | ||
238 | }, | ||
239 | ); | ||
240 | assert_snapshot!(map, @r###" | ||
241 | â‹®crate | ||
242 | â‹®Bar: t v | ||
243 | â‹®Foo: t v | ||
244 | â‹®Out: t v | ||
245 | â‹®bar: t | ||
246 | â‹® | ||
247 | â‹®crate::bar | ||
248 | â‹®Baz: t v | ||
249 | "###); | ||
250 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs index 4f8398460..4f8398460 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs | |||
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 5ee71e421..24316fc91 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -31,7 +31,8 @@ pub struct GenericArgs { | |||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | 31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type |
32 | /// is left out. | 32 | /// is left out. |
33 | pub has_self_type: bool, | 33 | pub has_self_type: bool, |
34 | // someday also bindings | 34 | /// Associated type bindings like in `Iterator<Item = T>`. |
35 | pub bindings: Vec<(Name, TypeRef)>, | ||
35 | } | 36 | } |
36 | 37 | ||
37 | /// A single generic argument. | 38 | /// A single generic argument. |
@@ -170,16 +171,24 @@ impl GenericArgs { | |||
170 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | 171 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); |
171 | args.push(GenericArg::Type(type_ref)); | 172 | args.push(GenericArg::Type(type_ref)); |
172 | } | 173 | } |
173 | // lifetimes and assoc type args ignored for now | 174 | // lifetimes ignored for now |
174 | if !args.is_empty() { | 175 | let mut bindings = Vec::new(); |
175 | Some(GenericArgs { args, has_self_type: false }) | 176 | for assoc_type_arg in node.assoc_type_args() { |
176 | } else { | 177 | if let Some(name_ref) = assoc_type_arg.name_ref() { |
178 | let name = name_ref.as_name(); | ||
179 | let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); | ||
180 | bindings.push((name, type_ref)); | ||
181 | } | ||
182 | } | ||
183 | if args.is_empty() && bindings.is_empty() { | ||
177 | None | 184 | None |
185 | } else { | ||
186 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
178 | } | 187 | } |
179 | } | 188 | } |
180 | 189 | ||
181 | pub(crate) fn empty() -> GenericArgs { | 190 | pub(crate) fn empty() -> GenericArgs { |
182 | GenericArgs { args: Vec::new(), has_self_type: false } | 191 | GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } |
183 | } | 192 | } |
184 | } | 193 | } |
185 | 194 | ||
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index e5f4d11a6..fdbe5e8b0 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -228,7 +228,7 @@ impl SourceAnalyzer { | |||
228 | let scopes = db.expr_scopes(def); | 228 | let scopes = db.expr_scopes(def); |
229 | let scope = match offset { | 229 | let scope = match offset { |
230 | None => scope_for(&scopes, &source_map, &node), | 230 | None => scope_for(&scopes, &source_map, &node), |
231 | Some(offset) => scope_for_offset(&scopes, &source_map, offset), | 231 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), |
232 | }; | 232 | }; |
233 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | 233 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); |
234 | SourceAnalyzer { | 234 | SourceAnalyzer { |
@@ -330,6 +330,7 @@ impl SourceAnalyzer { | |||
330 | .body_source_map | 330 | .body_source_map |
331 | .as_ref()? | 331 | .as_ref()? |
332 | .pat_syntax(it)? | 332 | .pat_syntax(it)? |
333 | .ast // FIXME: ignoring file_id here is definitelly wrong | ||
333 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); | 334 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); |
334 | PathResolution::LocalBinding(pat_ptr) | 335 | PathResolution::LocalBinding(pat_ptr) |
335 | } | 336 | } |
@@ -354,7 +355,7 @@ impl SourceAnalyzer { | |||
354 | ret.and_then(|entry| { | 355 | ret.and_then(|entry| { |
355 | Some(ScopeEntryWithSyntax { | 356 | Some(ScopeEntryWithSyntax { |
356 | name: entry.name().clone(), | 357 | name: entry.name().clone(), |
357 | ptr: source_map.pat_syntax(entry.pat())?, | 358 | ptr: source_map.pat_syntax(entry.pat())?.ast, |
358 | }) | 359 | }) |
359 | }) | 360 | }) |
360 | } | 361 | } |
@@ -470,20 +471,27 @@ fn scope_for( | |||
470 | fn scope_for_offset( | 471 | fn scope_for_offset( |
471 | scopes: &ExprScopes, | 472 | scopes: &ExprScopes, |
472 | source_map: &BodySourceMap, | 473 | source_map: &BodySourceMap, |
474 | file_id: HirFileId, | ||
473 | offset: TextUnit, | 475 | offset: TextUnit, |
474 | ) -> Option<ScopeId> { | 476 | ) -> Option<ScopeId> { |
475 | scopes | 477 | scopes |
476 | .scope_by_expr() | 478 | .scope_by_expr() |
477 | .iter() | 479 | .iter() |
478 | .filter_map(|(id, scope)| { | 480 | .filter_map(|(id, scope)| { |
479 | let ast_ptr = source_map.expr_syntax(*id)?.a()?; | 481 | let source = source_map.expr_syntax(*id)?; |
480 | Some((ast_ptr.syntax_node_ptr(), scope)) | 482 | // FIXME: correctly handle macro expansion |
483 | if source.file_id != file_id { | ||
484 | return None; | ||
485 | } | ||
486 | let syntax_node_ptr = | ||
487 | source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
488 | Some((syntax_node_ptr, scope)) | ||
481 | }) | 489 | }) |
482 | // find containing scope | 490 | // find containing scope |
483 | .min_by_key(|(ptr, _scope)| { | 491 | .min_by_key(|(ptr, _scope)| { |
484 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | 492 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) |
485 | }) | 493 | }) |
486 | .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) | 494 | .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope)) |
487 | } | 495 | } |
488 | 496 | ||
489 | // XXX: during completion, cursor might be outside of any particular | 497 | // XXX: during completion, cursor might be outside of any particular |
@@ -492,6 +500,7 @@ fn adjust( | |||
492 | scopes: &ExprScopes, | 500 | scopes: &ExprScopes, |
493 | source_map: &BodySourceMap, | 501 | source_map: &BodySourceMap, |
494 | ptr: SyntaxNodePtr, | 502 | ptr: SyntaxNodePtr, |
503 | file_id: HirFileId, | ||
495 | offset: TextUnit, | 504 | offset: TextUnit, |
496 | ) -> Option<ScopeId> { | 505 | ) -> Option<ScopeId> { |
497 | let r = ptr.range(); | 506 | let r = ptr.range(); |
@@ -499,8 +508,14 @@ fn adjust( | |||
499 | .scope_by_expr() | 508 | .scope_by_expr() |
500 | .iter() | 509 | .iter() |
501 | .filter_map(|(id, scope)| { | 510 | .filter_map(|(id, scope)| { |
502 | let ast_ptr = source_map.expr_syntax(*id)?.a()?; | 511 | let source = source_map.expr_syntax(*id)?; |
503 | Some((ast_ptr.syntax_node_ptr(), scope)) | 512 | // FIXME: correctly handle macro expansion |
513 | if source.file_id != file_id { | ||
514 | return None; | ||
515 | } | ||
516 | let syntax_node_ptr = | ||
517 | source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
518 | Some((syntax_node_ptr, scope)) | ||
504 | }) | 519 | }) |
505 | .map(|(ptr, scope)| (ptr.range(), scope)) | 520 | .map(|(ptr, scope)| (ptr.range(), scope)) |
506 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | 521 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index b54c80318..a3df08827 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -120,12 +120,44 @@ pub struct ProjectionTy { | |||
120 | pub parameters: Substs, | 120 | pub parameters: Substs, |
121 | } | 121 | } |
122 | 122 | ||
123 | impl ProjectionTy { | ||
124 | pub fn trait_ref(&self, db: &impl HirDatabase) -> TraitRef { | ||
125 | TraitRef { | ||
126 | trait_: self | ||
127 | .associated_ty | ||
128 | .parent_trait(db) | ||
129 | .expect("projection ty without parent trait"), | ||
130 | substs: self.parameters.clone(), | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | impl TypeWalk for ProjectionTy { | ||
136 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
137 | self.parameters.walk(f); | ||
138 | } | ||
139 | |||
140 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
141 | self.parameters.walk_mut(f); | ||
142 | } | ||
143 | } | ||
144 | |||
123 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 145 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
124 | pub struct UnselectedProjectionTy { | 146 | pub struct UnselectedProjectionTy { |
125 | pub type_name: Name, | 147 | pub type_name: Name, |
126 | pub parameters: Substs, | 148 | pub parameters: Substs, |
127 | } | 149 | } |
128 | 150 | ||
151 | impl TypeWalk for UnselectedProjectionTy { | ||
152 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
153 | self.parameters.walk(f); | ||
154 | } | ||
155 | |||
156 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
157 | self.parameters.walk_mut(f); | ||
158 | } | ||
159 | } | ||
160 | |||
129 | /// A type. | 161 | /// A type. |
130 | /// | 162 | /// |
131 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 163 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -282,20 +314,14 @@ impl TraitRef { | |||
282 | pub fn self_ty(&self) -> &Ty { | 314 | pub fn self_ty(&self) -> &Ty { |
283 | &self.substs[0] | 315 | &self.substs[0] |
284 | } | 316 | } |
317 | } | ||
285 | 318 | ||
286 | pub fn subst(mut self, substs: &Substs) -> TraitRef { | 319 | impl TypeWalk for TraitRef { |
287 | self.substs.walk_mut(&mut |ty_mut| { | 320 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
288 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
289 | *ty_mut = ty.subst(substs); | ||
290 | }); | ||
291 | self | ||
292 | } | ||
293 | |||
294 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
295 | self.substs.walk(f); | 321 | self.substs.walk(f); |
296 | } | 322 | } |
297 | 323 | ||
298 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 324 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
299 | self.substs.walk_mut(f); | 325 | self.substs.walk_mut(f); |
300 | } | 326 | } |
301 | } | 327 | } |
@@ -306,6 +332,8 @@ impl TraitRef { | |||
306 | pub enum GenericPredicate { | 332 | pub enum GenericPredicate { |
307 | /// The given trait needs to be implemented for its type parameters. | 333 | /// The given trait needs to be implemented for its type parameters. |
308 | Implemented(TraitRef), | 334 | Implemented(TraitRef), |
335 | /// An associated type bindings like in `Iterator<Item = T>`. | ||
336 | Projection(ProjectionPredicate), | ||
309 | /// We couldn't resolve the trait reference. (If some type parameters can't | 337 | /// We couldn't resolve the trait reference. (If some type parameters can't |
310 | /// be resolved, they will just be Unknown). | 338 | /// be resolved, they will just be Unknown). |
311 | Error, | 339 | Error, |
@@ -319,25 +347,35 @@ impl GenericPredicate { | |||
319 | } | 347 | } |
320 | } | 348 | } |
321 | 349 | ||
322 | pub fn subst(self, substs: &Substs) -> GenericPredicate { | 350 | pub fn is_implemented(&self) -> bool { |
323 | match self { | 351 | match self { |
324 | GenericPredicate::Implemented(trait_ref) => { | 352 | GenericPredicate::Implemented(_) => true, |
325 | GenericPredicate::Implemented(trait_ref.subst(substs)) | 353 | _ => false, |
326 | } | ||
327 | GenericPredicate::Error => self, | ||
328 | } | 354 | } |
329 | } | 355 | } |
330 | 356 | ||
331 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | 357 | pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> { |
358 | match self { | ||
359 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
360 | GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), | ||
361 | GenericPredicate::Error => None, | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | |||
366 | impl TypeWalk for GenericPredicate { | ||
367 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
332 | match self { | 368 | match self { |
333 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), | 369 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), |
370 | GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), | ||
334 | GenericPredicate::Error => {} | 371 | GenericPredicate::Error => {} |
335 | } | 372 | } |
336 | } | 373 | } |
337 | 374 | ||
338 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 375 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
339 | match self { | 376 | match self { |
340 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), | 377 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), |
378 | GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), | ||
341 | GenericPredicate::Error => {} | 379 | GenericPredicate::Error => {} |
342 | } | 380 | } |
343 | } | 381 | } |
@@ -378,16 +416,16 @@ impl FnSig { | |||
378 | pub fn ret(&self) -> &Ty { | 416 | pub fn ret(&self) -> &Ty { |
379 | &self.params_and_return[self.params_and_return.len() - 1] | 417 | &self.params_and_return[self.params_and_return.len() - 1] |
380 | } | 418 | } |
419 | } | ||
381 | 420 | ||
382 | /// Applies the given substitutions to all types in this signature and | 421 | impl TypeWalk for FnSig { |
383 | /// returns the result. | 422 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
384 | pub fn subst(&self, substs: &Substs) -> FnSig { | 423 | for t in self.params_and_return.iter() { |
385 | let result: Vec<_> = | 424 | t.walk(f); |
386 | self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); | 425 | } |
387 | FnSig { params_and_return: result.into() } | ||
388 | } | 426 | } |
389 | 427 | ||
390 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 428 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
391 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | 429 | // Without an Arc::make_mut_slice, we can't avoid the clone here: |
392 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); | 430 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); |
393 | for t in &mut v { | 431 | for t in &mut v { |
@@ -411,64 +449,6 @@ impl Ty { | |||
411 | Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) | 449 | Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) |
412 | } | 450 | } |
413 | 451 | ||
414 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
415 | match self { | ||
416 | Ty::Apply(a_ty) => { | ||
417 | for t in a_ty.parameters.iter() { | ||
418 | t.walk(f); | ||
419 | } | ||
420 | } | ||
421 | Ty::Projection(p_ty) => { | ||
422 | for t in p_ty.parameters.iter() { | ||
423 | t.walk(f); | ||
424 | } | ||
425 | } | ||
426 | Ty::UnselectedProjection(p_ty) => { | ||
427 | for t in p_ty.parameters.iter() { | ||
428 | t.walk(f); | ||
429 | } | ||
430 | } | ||
431 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
432 | for p in predicates.iter() { | ||
433 | p.walk(f); | ||
434 | } | ||
435 | } | ||
436 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
437 | } | ||
438 | f(self); | ||
439 | } | ||
440 | |||
441 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
442 | match self { | ||
443 | Ty::Apply(a_ty) => { | ||
444 | a_ty.parameters.walk_mut(f); | ||
445 | } | ||
446 | Ty::Projection(p_ty) => { | ||
447 | p_ty.parameters.walk_mut(f); | ||
448 | } | ||
449 | Ty::UnselectedProjection(p_ty) => { | ||
450 | p_ty.parameters.walk_mut(f); | ||
451 | } | ||
452 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
453 | let mut v: Vec<_> = predicates.iter().cloned().collect(); | ||
454 | for p in &mut v { | ||
455 | p.walk_mut(f); | ||
456 | } | ||
457 | *predicates = v.into(); | ||
458 | } | ||
459 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
460 | } | ||
461 | f(self); | ||
462 | } | ||
463 | |||
464 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty { | ||
465 | self.walk_mut(&mut |ty_mut| { | ||
466 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
467 | *ty_mut = f(ty); | ||
468 | }); | ||
469 | self | ||
470 | } | ||
471 | |||
472 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | 452 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { |
473 | match self { | 453 | match self { |
474 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | 454 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { |
@@ -544,10 +524,53 @@ impl Ty { | |||
544 | } | 524 | } |
545 | } | 525 | } |
546 | 526 | ||
527 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
528 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
529 | pub fn substs(&self) -> Option<Substs> { | ||
530 | match self { | ||
531 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
532 | _ => None, | ||
533 | } | ||
534 | } | ||
535 | |||
536 | /// If this is an `impl Trait` or `dyn Trait`, returns that trait. | ||
537 | pub fn inherent_trait(&self) -> Option<Trait> { | ||
538 | match self { | ||
539 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
540 | predicates.iter().find_map(|pred| match pred { | ||
541 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | ||
542 | _ => None, | ||
543 | }) | ||
544 | } | ||
545 | _ => None, | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /// This allows walking structures that contain types to do something with those | ||
551 | /// types, similar to Chalk's `Fold` trait. | ||
552 | pub trait TypeWalk { | ||
553 | fn walk(&self, f: &mut impl FnMut(&Ty)); | ||
554 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); | ||
555 | |||
556 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self | ||
557 | where | ||
558 | Self: Sized, | ||
559 | { | ||
560 | self.walk_mut(&mut |ty_mut| { | ||
561 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
562 | *ty_mut = f(ty); | ||
563 | }); | ||
564 | self | ||
565 | } | ||
566 | |||
547 | /// Replaces type parameters in this type using the given `Substs`. (So e.g. | 567 | /// Replaces type parameters in this type using the given `Substs`. (So e.g. |
548 | /// if `self` is `&[T]`, where type parameter T has index 0, and the | 568 | /// if `self` is `&[T]`, where type parameter T has index 0, and the |
549 | /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) | 569 | /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) |
550 | pub fn subst(self, substs: &Substs) -> Ty { | 570 | fn subst(self, substs: &Substs) -> Self |
571 | where | ||
572 | Self: Sized, | ||
573 | { | ||
551 | self.fold(&mut |ty| match ty { | 574 | self.fold(&mut |ty| match ty { |
552 | Ty::Param { idx, name } => { | 575 | Ty::Param { idx, name } => { |
553 | substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) | 576 | substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) |
@@ -557,24 +580,21 @@ impl Ty { | |||
557 | } | 580 | } |
558 | 581 | ||
559 | /// Substitutes `Ty::Bound` vars (as opposed to type parameters). | 582 | /// Substitutes `Ty::Bound` vars (as opposed to type parameters). |
560 | pub fn subst_bound_vars(self, substs: &Substs) -> Ty { | 583 | fn subst_bound_vars(self, substs: &Substs) -> Self |
584 | where | ||
585 | Self: Sized, | ||
586 | { | ||
561 | self.fold(&mut |ty| match ty { | 587 | self.fold(&mut |ty| match ty { |
562 | Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), | 588 | Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), |
563 | ty => ty, | 589 | ty => ty, |
564 | }) | 590 | }) |
565 | } | 591 | } |
566 | 592 | ||
567 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
568 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
569 | pub fn substs(&self) -> Option<Substs> { | ||
570 | match self { | ||
571 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
572 | _ => None, | ||
573 | } | ||
574 | } | ||
575 | |||
576 | /// Shifts up `Ty::Bound` vars by `n`. | 593 | /// Shifts up `Ty::Bound` vars by `n`. |
577 | pub fn shift_bound_vars(self, n: i32) -> Ty { | 594 | fn shift_bound_vars(self, n: i32) -> Self |
595 | where | ||
596 | Self: Sized, | ||
597 | { | ||
578 | self.fold(&mut |ty| match ty { | 598 | self.fold(&mut |ty| match ty { |
579 | Ty::Bound(idx) => { | 599 | Ty::Bound(idx) => { |
580 | assert!(idx as i32 >= -n); | 600 | assert!(idx as i32 >= -n); |
@@ -583,18 +603,57 @@ impl Ty { | |||
583 | ty => ty, | 603 | ty => ty, |
584 | }) | 604 | }) |
585 | } | 605 | } |
606 | } | ||
586 | 607 | ||
587 | /// If this is an `impl Trait` or `dyn Trait`, returns that trait. | 608 | impl TypeWalk for Ty { |
588 | pub fn inherent_trait(&self) -> Option<Trait> { | 609 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
610 | match self { | ||
611 | Ty::Apply(a_ty) => { | ||
612 | for t in a_ty.parameters.iter() { | ||
613 | t.walk(f); | ||
614 | } | ||
615 | } | ||
616 | Ty::Projection(p_ty) => { | ||
617 | for t in p_ty.parameters.iter() { | ||
618 | t.walk(f); | ||
619 | } | ||
620 | } | ||
621 | Ty::UnselectedProjection(p_ty) => { | ||
622 | for t in p_ty.parameters.iter() { | ||
623 | t.walk(f); | ||
624 | } | ||
625 | } | ||
626 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
627 | for p in predicates.iter() { | ||
628 | p.walk(f); | ||
629 | } | ||
630 | } | ||
631 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
632 | } | ||
633 | f(self); | ||
634 | } | ||
635 | |||
636 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
589 | match self { | 637 | match self { |
638 | Ty::Apply(a_ty) => { | ||
639 | a_ty.parameters.walk_mut(f); | ||
640 | } | ||
641 | Ty::Projection(p_ty) => { | ||
642 | p_ty.parameters.walk_mut(f); | ||
643 | } | ||
644 | Ty::UnselectedProjection(p_ty) => { | ||
645 | p_ty.parameters.walk_mut(f); | ||
646 | } | ||
590 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | 647 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { |
591 | predicates.iter().find_map(|pred| match pred { | 648 | let mut v: Vec<_> = predicates.iter().cloned().collect(); |
592 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 649 | for p in &mut v { |
593 | _ => None, | 650 | p.walk_mut(f); |
594 | }) | 651 | } |
652 | *predicates = v.into(); | ||
595 | } | 653 | } |
596 | _ => None, | 654 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
597 | } | 655 | } |
656 | f(self); | ||
598 | } | 657 | } |
599 | } | 658 | } |
600 | 659 | ||
@@ -742,20 +801,66 @@ impl HirDisplay for Ty { | |||
742 | Ty::Opaque(_) => write!(f, "impl ")?, | 801 | Ty::Opaque(_) => write!(f, "impl ")?, |
743 | _ => unreachable!(), | 802 | _ => unreachable!(), |
744 | }; | 803 | }; |
745 | // looping by hand here just to format the bounds in a slightly nicer way | 804 | // Note: This code is written to produce nice results (i.e. |
805 | // corresponding to surface Rust) for types that can occur in | ||
806 | // actual Rust. It will have weird results if the predicates | ||
807 | // aren't as expected (i.e. self types = $0, projection | ||
808 | // predicates for a certain trait come after the Implemented | ||
809 | // predicate for that trait). | ||
746 | let mut first = true; | 810 | let mut first = true; |
811 | let mut angle_open = false; | ||
747 | for p in predicates.iter() { | 812 | for p in predicates.iter() { |
748 | if !first { | ||
749 | write!(f, " + ")?; | ||
750 | } | ||
751 | first = false; | ||
752 | match p { | 813 | match p { |
753 | // don't show the $0 self type | ||
754 | GenericPredicate::Implemented(trait_ref) => { | 814 | GenericPredicate::Implemented(trait_ref) => { |
755 | trait_ref.hir_fmt_ext(f, false)? | 815 | if angle_open { |
816 | write!(f, ">")?; | ||
817 | } | ||
818 | if !first { | ||
819 | write!(f, " + ")?; | ||
820 | } | ||
821 | // We assume that the self type is $0 (i.e. the | ||
822 | // existential) here, which is the only thing that's | ||
823 | // possible in actual Rust, and hence don't print it | ||
824 | write!( | ||
825 | f, | ||
826 | "{}", | ||
827 | trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing) | ||
828 | )?; | ||
829 | if trait_ref.substs.len() > 1 { | ||
830 | write!(f, "<")?; | ||
831 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
832 | // there might be assoc type bindings, so we leave the angle brackets open | ||
833 | angle_open = true; | ||
834 | } | ||
835 | } | ||
836 | GenericPredicate::Projection(projection_pred) => { | ||
837 | // in types in actual Rust, these will always come | ||
838 | // after the corresponding Implemented predicate | ||
839 | if angle_open { | ||
840 | write!(f, ", ")?; | ||
841 | } else { | ||
842 | write!(f, "<")?; | ||
843 | angle_open = true; | ||
844 | } | ||
845 | let name = projection_pred.projection_ty.associated_ty.name(f.db); | ||
846 | write!(f, "{} = ", name)?; | ||
847 | projection_pred.ty.hir_fmt(f)?; | ||
848 | } | ||
849 | GenericPredicate::Error => { | ||
850 | if angle_open { | ||
851 | // impl Trait<X, {error}> | ||
852 | write!(f, ", ")?; | ||
853 | } else if !first { | ||
854 | // impl Trait + {error} | ||
855 | write!(f, " + ")?; | ||
856 | } | ||
857 | p.hir_fmt(f)?; | ||
756 | } | 858 | } |
757 | GenericPredicate::Error => p.hir_fmt(f)?, | ||
758 | } | 859 | } |
860 | first = false; | ||
861 | } | ||
862 | if angle_open { | ||
863 | write!(f, ">")?; | ||
759 | } | 864 | } |
760 | } | 865 | } |
761 | Ty::Unknown => write!(f, "{{unknown}}")?, | 866 | Ty::Unknown => write!(f, "{{unknown}}")?, |
@@ -766,13 +871,12 @@ impl HirDisplay for Ty { | |||
766 | } | 871 | } |
767 | 872 | ||
768 | impl TraitRef { | 873 | impl TraitRef { |
769 | fn hir_fmt_ext( | 874 | fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { |
770 | &self, | 875 | self.substs[0].hir_fmt(f)?; |
771 | f: &mut HirFormatter<impl HirDatabase>, | 876 | if use_as { |
772 | with_self_ty: bool, | 877 | write!(f, " as ")?; |
773 | ) -> fmt::Result { | 878 | } else { |
774 | if with_self_ty { | 879 | write!(f, ": ")?; |
775 | write!(f, "{}: ", self.substs[0].display(f.db),)?; | ||
776 | } | 880 | } |
777 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; | 881 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; |
778 | if self.substs.len() > 1 { | 882 | if self.substs.len() > 1 { |
@@ -786,7 +890,7 @@ impl TraitRef { | |||
786 | 890 | ||
787 | impl HirDisplay for TraitRef { | 891 | impl HirDisplay for TraitRef { |
788 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 892 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
789 | self.hir_fmt_ext(f, true) | 893 | self.hir_fmt_ext(f, false) |
790 | } | 894 | } |
791 | } | 895 | } |
792 | 896 | ||
@@ -800,6 +904,16 @@ impl HirDisplay for GenericPredicate { | |||
800 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 904 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
801 | match self { | 905 | match self { |
802 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | 906 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, |
907 | GenericPredicate::Projection(projection_pred) => { | ||
908 | write!(f, "<")?; | ||
909 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
910 | write!( | ||
911 | f, | ||
912 | ">::{} = {}", | ||
913 | projection_pred.projection_ty.associated_ty.name(f.db), | ||
914 | projection_pred.ty.display(f.db) | ||
915 | )?; | ||
916 | } | ||
803 | GenericPredicate::Error => write!(f, "{{error}}")?, | 917 | GenericPredicate::Error => write!(f, "{{error}}")?, |
804 | } | 918 | } |
805 | Ok(()) | 919 | Ok(()) |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 2535d4ae7..08f52a53b 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -7,7 +7,7 @@ use std::iter::successors; | |||
7 | 7 | ||
8 | use log::{info, warn}; | 8 | use log::{info, warn}; |
9 | 9 | ||
10 | use super::{traits::Solution, Canonical, Ty}; | 10 | use super::{traits::Solution, Canonical, Ty, TypeWalk}; |
11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; | 11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; |
12 | 12 | ||
13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index b89a40b4b..ec3b7ffef 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -30,7 +30,7 @@ use super::{ | |||
30 | autoderef, lower, method_resolution, op, primitive, | 30 | autoderef, lower, method_resolution, op, primitive, |
31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
32 | ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, | 32 | ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, |
33 | Ty, TypableDef, TypeCtor, | 33 | Ty, TypableDef, TypeCtor, TypeWalk, |
34 | }; | 34 | }; |
35 | use crate::{ | 35 | use crate::{ |
36 | adt::VariantDef, | 36 | adt::VariantDef, |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index e7e8825d1..9a0d2d8f9 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use super::{InferenceContext, Obligation}; | 3 | use super::{InferenceContext, Obligation}; |
4 | use crate::db::HirDatabase; | 4 | use crate::db::HirDatabase; |
5 | use crate::ty::{ | 5 | use crate::ty::{ |
6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, | 6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 47d161277..f6f0137cf 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,10 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{ |
12 | FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
13 | TypeWalk, | ||
14 | }; | ||
12 | use crate::{ | 15 | use crate::{ |
13 | adt::VariantDef, | 16 | adt::VariantDef, |
14 | generics::HasGenericParams, | 17 | generics::HasGenericParams, |
@@ -62,7 +65,9 @@ impl Ty { | |||
62 | let self_ty = Ty::Bound(0); | 65 | let self_ty = Ty::Bound(0); |
63 | let predicates = bounds | 66 | let predicates = bounds |
64 | .iter() | 67 | .iter() |
65 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 68 | .flat_map(|b| { |
69 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
70 | }) | ||
66 | .collect::<Vec<_>>(); | 71 | .collect::<Vec<_>>(); |
67 | Ty::Dyn(predicates.into()) | 72 | Ty::Dyn(predicates.into()) |
68 | } | 73 | } |
@@ -70,7 +75,9 @@ impl Ty { | |||
70 | let self_ty = Ty::Bound(0); | 75 | let self_ty = Ty::Bound(0); |
71 | let predicates = bounds | 76 | let predicates = bounds |
72 | .iter() | 77 | .iter() |
73 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 78 | .flat_map(|b| { |
79 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
80 | }) | ||
74 | .collect::<Vec<_>>(); | 81 | .collect::<Vec<_>>(); |
75 | Ty::Opaque(predicates.into()) | 82 | Ty::Opaque(predicates.into()) |
76 | } | 83 | } |
@@ -326,15 +333,6 @@ impl TraitRef { | |||
326 | TraitRef { trait_, substs } | 333 | TraitRef { trait_, substs } |
327 | } | 334 | } |
328 | 335 | ||
329 | pub(crate) fn from_where_predicate( | ||
330 | db: &impl HirDatabase, | ||
331 | resolver: &Resolver, | ||
332 | pred: &WherePredicate, | ||
333 | ) -> Option<TraitRef> { | ||
334 | let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); | ||
335 | TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty) | ||
336 | } | ||
337 | |||
338 | pub(crate) fn from_type_bound( | 336 | pub(crate) fn from_type_bound( |
339 | db: &impl HirDatabase, | 337 | db: &impl HirDatabase, |
340 | resolver: &Resolver, | 338 | resolver: &Resolver, |
@@ -349,26 +347,58 @@ impl TraitRef { | |||
349 | } | 347 | } |
350 | 348 | ||
351 | impl GenericPredicate { | 349 | impl GenericPredicate { |
352 | pub(crate) fn from_where_predicate( | 350 | pub(crate) fn from_where_predicate<'a>( |
353 | db: &impl HirDatabase, | 351 | db: &'a impl HirDatabase, |
354 | resolver: &Resolver, | 352 | resolver: &'a Resolver, |
355 | where_predicate: &WherePredicate, | 353 | where_predicate: &'a WherePredicate, |
356 | ) -> GenericPredicate { | 354 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
357 | TraitRef::from_where_predicate(db, &resolver, where_predicate) | 355 | let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref); |
358 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 356 | GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty) |
359 | } | 357 | } |
360 | 358 | ||
361 | pub(crate) fn from_type_bound( | 359 | pub(crate) fn from_type_bound<'a>( |
362 | db: &impl HirDatabase, | 360 | db: &'a impl HirDatabase, |
363 | resolver: &Resolver, | 361 | resolver: &'a Resolver, |
364 | bound: &TypeBound, | 362 | bound: &'a TypeBound, |
365 | self_ty: Ty, | 363 | self_ty: Ty, |
366 | ) -> GenericPredicate { | 364 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
367 | TraitRef::from_type_bound(db, &resolver, bound, self_ty) | 365 | let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty); |
368 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 366 | iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented)) |
367 | .chain( | ||
368 | trait_ref.into_iter().flat_map(move |tr| { | ||
369 | assoc_type_bindings_from_type_bound(db, resolver, bound, tr) | ||
370 | }), | ||
371 | ) | ||
369 | } | 372 | } |
370 | } | 373 | } |
371 | 374 | ||
375 | fn assoc_type_bindings_from_type_bound<'a>( | ||
376 | db: &'a impl HirDatabase, | ||
377 | resolver: &'a Resolver, | ||
378 | bound: &'a TypeBound, | ||
379 | trait_ref: TraitRef, | ||
380 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
381 | let last_segment = match bound { | ||
382 | TypeBound::Path(path) => path.segments.last(), | ||
383 | TypeBound::Error => None, | ||
384 | }; | ||
385 | last_segment | ||
386 | .into_iter() | ||
387 | .flat_map(|segment| segment.args_and_bindings.iter()) | ||
388 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | ||
389 | .map(move |(name, type_ref)| { | ||
390 | let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) { | ||
391 | None => return GenericPredicate::Error, | ||
392 | Some(t) => t, | ||
393 | }; | ||
394 | let projection_ty = | ||
395 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | ||
396 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
397 | let projection_predicate = ProjectionPredicate { projection_ty, ty }; | ||
398 | GenericPredicate::Projection(projection_predicate) | ||
399 | }) | ||
400 | } | ||
401 | |||
372 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 402 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
373 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 403 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
374 | /// the constructor function `(usize) -> Foo` which lives in the values | 404 | /// the constructor function `(usize) -> Foo` which lives in the values |
@@ -425,7 +455,7 @@ pub(crate) fn trait_env( | |||
425 | ) -> Arc<super::TraitEnvironment> { | 455 | ) -> Arc<super::TraitEnvironment> { |
426 | let predicates = resolver | 456 | let predicates = resolver |
427 | .where_predicates_in_scope() | 457 | .where_predicates_in_scope() |
428 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 458 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
429 | .collect::<Vec<_>>(); | 459 | .collect::<Vec<_>>(); |
430 | 460 | ||
431 | Arc::new(super::TraitEnvironment { predicates }) | 461 | Arc::new(super::TraitEnvironment { predicates }) |
@@ -439,7 +469,7 @@ pub(crate) fn generic_predicates_query( | |||
439 | let resolver = def.resolver(db); | 469 | let resolver = def.resolver(db); |
440 | let predicates = resolver | 470 | let predicates = resolver |
441 | .where_predicates_in_scope() | 471 | .where_predicates_in_scope() |
442 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 472 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
443 | .collect::<Vec<_>>(); | 473 | .collect::<Vec<_>>(); |
444 | predicates.into() | 474 | predicates.into() |
445 | } | 475 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index d344ab12e..d92d4659b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2793,6 +2793,10 @@ fn main() { | |||
2793 | } | 2793 | } |
2794 | "#), | 2794 | "#), |
2795 | @r###" | 2795 | @r###" |
2796 | ![0; 17) '{Foo(v...,2,])}': Foo | ||
2797 | ![1; 4) 'Foo': Foo({unknown}) -> Foo | ||
2798 | ![1; 16) 'Foo(vec![1,2,])': Foo | ||
2799 | ![5; 15) 'vec![1,2,]': {unknown} | ||
2796 | [156; 182) '{ ...,2); }': () | 2800 | [156; 182) '{ ...,2); }': () |
2797 | [166; 167) 'x': Foo | 2801 | [166; 167) 'x': Foo |
2798 | "### | 2802 | "### |
@@ -3548,6 +3552,97 @@ fn test() { | |||
3548 | ); | 3552 | ); |
3549 | } | 3553 | } |
3550 | 3554 | ||
3555 | #[test] | ||
3556 | fn assoc_type_bindings() { | ||
3557 | assert_snapshot!( | ||
3558 | infer(r#" | ||
3559 | trait Trait { | ||
3560 | type Type; | ||
3561 | } | ||
3562 | |||
3563 | fn get<T: Trait>(t: T) -> <T as Trait>::Type {} | ||
3564 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
3565 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
3566 | |||
3567 | struct S<T>; | ||
3568 | impl<T> Trait for S<T> { type Type = T; } | ||
3569 | |||
3570 | fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | ||
3571 | get(x); | ||
3572 | get2(x); | ||
3573 | get(y); | ||
3574 | get2(y); | ||
3575 | get(set(S)); | ||
3576 | get2(set(S)); | ||
3577 | get2(S::<str>); | ||
3578 | } | ||
3579 | "#), | ||
3580 | @r###" | ||
3581 | [50; 51) 't': T | ||
3582 | [78; 80) '{}': () | ||
3583 | [112; 113) 't': T | ||
3584 | [123; 125) '{}': () | ||
3585 | [155; 156) 't': T | ||
3586 | [166; 169) '{t}': T | ||
3587 | [167; 168) 't': T | ||
3588 | [257; 258) 'x': T | ||
3589 | [263; 264) 'y': impl Trait<Type = i64> | ||
3590 | [290; 398) '{ ...r>); }': () | ||
3591 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | ||
3592 | [296; 302) 'get(x)': {unknown} | ||
3593 | [300; 301) 'x': T | ||
3594 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | ||
3595 | [308; 315) 'get2(x)': {unknown} | ||
3596 | [313; 314) 'x': T | ||
3597 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type | ||
3598 | [321; 327) 'get(y)': {unknown} | ||
3599 | [325; 326) 'y': impl Trait<Type = i64> | ||
3600 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | ||
3601 | [333; 340) 'get2(y)': {unknown} | ||
3602 | [338; 339) 'y': impl Trait<Type = i64> | ||
3603 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type | ||
3604 | [346; 357) 'get(set(S))': u64 | ||
3605 | [350; 353) 'set': fn set<S<u64>>(T) -> T | ||
3606 | [350; 356) 'set(S)': S<u64> | ||
3607 | [354; 355) 'S': S<u64> | ||
3608 | [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U | ||
3609 | [363; 375) 'get2(set(S))': u64 | ||
3610 | [368; 371) 'set': fn set<S<u64>>(T) -> T | ||
3611 | [368; 374) 'set(S)': S<u64> | ||
3612 | [372; 373) 'S': S<u64> | ||
3613 | [381; 385) 'get2': fn get2<str, S<str>>(T) -> U | ||
3614 | [381; 395) 'get2(S::<str>)': str | ||
3615 | [386; 394) 'S::<str>': S<str> | ||
3616 | "### | ||
3617 | ); | ||
3618 | } | ||
3619 | |||
3620 | #[test] | ||
3621 | fn projection_eq_within_chalk() { | ||
3622 | // std::env::set_var("CHALK_DEBUG", "1"); | ||
3623 | assert_snapshot!( | ||
3624 | infer(r#" | ||
3625 | trait Trait1 { | ||
3626 | type Type; | ||
3627 | } | ||
3628 | trait Trait2<T> { | ||
3629 | fn foo(self) -> T; | ||
3630 | } | ||
3631 | impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} | ||
3632 | |||
3633 | fn test<T: Trait1<Type = u32>>(x: T) { | ||
3634 | x.foo(); | ||
3635 | } | ||
3636 | "#), | ||
3637 | @r###" | ||
3638 | [62; 66) 'self': Self | ||
3639 | [164; 165) 'x': T | ||
3640 | [170; 186) '{ ...o(); }': () | ||
3641 | [176; 177) 'x': T | ||
3642 | [176; 183) 'x.foo()': {unknown} | ||
3643 | "### | ||
3644 | ); | ||
3645 | } | ||
3551 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3646 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3552 | let file = db.parse(pos.file_id).ok().unwrap(); | 3647 | let file = db.parse(pos.file_id).ok().unwrap(); |
3553 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3648 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
@@ -3566,7 +3661,6 @@ fn infer(content: &str) -> String { | |||
3566 | let source_file = db.parse(file_id).ok().unwrap(); | 3661 | let source_file = db.parse(file_id).ok().unwrap(); |
3567 | 3662 | ||
3568 | let mut acc = String::new(); | 3663 | let mut acc = String::new(); |
3569 | // acc.push_str("\n"); | ||
3570 | 3664 | ||
3571 | let mut infer_def = |inference_result: Arc<InferenceResult>, | 3665 | let mut infer_def = |inference_result: Arc<InferenceResult>, |
3572 | body_source_map: Arc<BodySourceMap>| { | 3666 | body_source_map: Arc<BodySourceMap>| { |
@@ -3574,7 +3668,9 @@ fn infer(content: &str) -> String { | |||
3574 | 3668 | ||
3575 | for (pat, ty) in inference_result.type_of_pat.iter() { | 3669 | for (pat, ty) in inference_result.type_of_pat.iter() { |
3576 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 3670 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
3577 | Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), | 3671 | Some(sp) => { |
3672 | sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) | ||
3673 | } | ||
3578 | None => continue, | 3674 | None => continue, |
3579 | }; | 3675 | }; |
3580 | types.push((syntax_ptr, ty)); | 3676 | types.push((syntax_ptr, ty)); |
@@ -3582,22 +3678,34 @@ fn infer(content: &str) -> String { | |||
3582 | 3678 | ||
3583 | for (expr, ty) in inference_result.type_of_expr.iter() { | 3679 | for (expr, ty) in inference_result.type_of_expr.iter() { |
3584 | let syntax_ptr = match body_source_map.expr_syntax(expr) { | 3680 | let syntax_ptr = match body_source_map.expr_syntax(expr) { |
3585 | Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), | 3681 | Some(sp) => { |
3682 | sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) | ||
3683 | } | ||
3586 | None => continue, | 3684 | None => continue, |
3587 | }; | 3685 | }; |
3588 | types.push((syntax_ptr, ty)); | 3686 | types.push((syntax_ptr, ty)); |
3589 | } | 3687 | } |
3590 | 3688 | ||
3591 | // sort ranges for consistency | 3689 | // sort ranges for consistency |
3592 | types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); | 3690 | types.sort_by_key(|(src_ptr, _)| (src_ptr.ast.range().start(), src_ptr.ast.range().end())); |
3593 | for (syntax_ptr, ty) in &types { | 3691 | for (src_ptr, ty) in &types { |
3594 | let node = syntax_ptr.to_node(source_file.syntax()); | 3692 | let node = src_ptr.ast.to_node(&src_ptr.file_syntax(&db)); |
3693 | |||
3595 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { | 3694 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { |
3596 | (self_param.self_kw_token().text_range(), "self".to_string()) | 3695 | (self_param.self_kw_token().text_range(), "self".to_string()) |
3597 | } else { | 3696 | } else { |
3598 | (syntax_ptr.range(), node.text().to_string().replace("\n", " ")) | 3697 | (src_ptr.ast.range(), node.text().to_string().replace("\n", " ")) |
3599 | }; | 3698 | }; |
3600 | write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); | 3699 | let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; |
3700 | write!( | ||
3701 | acc, | ||
3702 | "{}{} '{}': {}\n", | ||
3703 | macro_prefix, | ||
3704 | range, | ||
3705 | ellipsize(text, 15), | ||
3706 | ty.display(&db) | ||
3707 | ) | ||
3708 | .unwrap(); | ||
3601 | } | 3709 | } |
3602 | }; | 3710 | }; |
3603 | 3711 | ||
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index b634f0b79..6e0271a96 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -8,7 +8,7 @@ use ra_db::salsa; | |||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | 10 | ||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, ToChalk}; | 14 | use self::chalk::{from_chalk, ToChalk}; |
@@ -124,6 +124,9 @@ impl Obligation { | |||
124 | pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { | 124 | pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { |
125 | match predicate { | 125 | match predicate { |
126 | GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), | 126 | GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), |
127 | GenericPredicate::Projection(projection_pred) => { | ||
128 | Some(Obligation::Projection(projection_pred)) | ||
129 | } | ||
127 | GenericPredicate::Error => None, | 130 | GenericPredicate::Error => None, |
128 | } | 131 | } |
129 | } | 132 | } |
@@ -135,6 +138,18 @@ pub struct ProjectionPredicate { | |||
135 | pub ty: Ty, | 138 | pub ty: Ty, |
136 | } | 139 | } |
137 | 140 | ||
141 | impl TypeWalk for ProjectionPredicate { | ||
142 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
143 | self.projection_ty.walk(f); | ||
144 | self.ty.walk(f); | ||
145 | } | ||
146 | |||
147 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
148 | self.projection_ty.walk_mut(f); | ||
149 | self.ty.walk_mut(f); | ||
150 | } | ||
151 | } | ||
152 | |||
138 | /// Solve a trait goal using Chalk. | 153 | /// Solve a trait goal using Chalk. |
139 | pub(crate) fn trait_solve_query( | 154 | pub(crate) fn trait_solve_query( |
140 | db: &impl HirDatabase, | 155 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 2ebc06135..c201c5e50 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | ty::display::HirDisplay, | 19 | ty::display::HirDisplay, |
20 | ty::{ | 20 | ty::{ |
21 | ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 21 | ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
22 | TypeWalk, | ||
22 | }, | 23 | }, |
23 | Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, | 24 | Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, |
24 | }; | 25 | }; |
@@ -211,6 +212,13 @@ impl ToChalk for GenericPredicate { | |||
211 | GenericPredicate::Implemented(trait_ref) => { | 212 | GenericPredicate::Implemented(trait_ref) => { |
212 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | 213 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) |
213 | } | 214 | } |
215 | GenericPredicate::Projection(projection_pred) => make_binders( | ||
216 | chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq { | ||
217 | projection: projection_pred.projection_ty.to_chalk(db), | ||
218 | ty: projection_pred.ty.to_chalk(db), | ||
219 | }), | ||
220 | 0, | ||
221 | ), | ||
214 | GenericPredicate::Error => { | 222 | GenericPredicate::Error => { |
215 | let impossible_trait_ref = chalk_ir::TraitRef { | 223 | let impossible_trait_ref = chalk_ir::TraitRef { |
216 | trait_id: UNKNOWN_TRAIT, | 224 | trait_id: UNKNOWN_TRAIT, |