diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 119 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/db.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/coerce.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/simple.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/display.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 80 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
18 files changed, 317 insertions, 121 deletions
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index d9ce6bcff..445d215b7 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -24,7 +24,7 @@ use crate::{ | |||
24 | DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, | 24 | DefWithBodyId, HasModule, Lookup, ModuleDefId, ModuleId, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | struct Expander { | 27 | pub(crate) struct Expander { |
28 | crate_def_map: Arc<CrateDefMap>, | 28 | crate_def_map: Arc<CrateDefMap>, |
29 | current_file_id: HirFileId, | 29 | current_file_id: HirFileId, |
30 | hygiene: Hygiene, | 30 | hygiene: Hygiene, |
@@ -33,18 +33,22 @@ struct Expander { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | impl Expander { | 35 | impl Expander { |
36 | fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { | 36 | pub(crate) fn new( |
37 | db: &impl DefDatabase, | ||
38 | current_file_id: HirFileId, | ||
39 | module: ModuleId, | ||
40 | ) -> Expander { | ||
37 | let crate_def_map = db.crate_def_map(module.krate); | 41 | let crate_def_map = db.crate_def_map(module.krate); |
38 | let hygiene = Hygiene::new(db, current_file_id); | 42 | let hygiene = Hygiene::new(db, current_file_id); |
39 | let ast_id_map = db.ast_id_map(current_file_id); | 43 | let ast_id_map = db.ast_id_map(current_file_id); |
40 | Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module } | 44 | Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module } |
41 | } | 45 | } |
42 | 46 | ||
43 | fn enter_expand( | 47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
44 | &mut self, | 48 | &mut self, |
45 | db: &impl DefDatabase, | 49 | db: &DB, |
46 | macro_call: ast::MacroCall, | 50 | macro_call: ast::MacroCall, |
47 | ) -> Option<(Mark, ast::Expr)> { | 51 | ) -> Option<(Mark, T)> { |
48 | let ast_id = AstId::new( | 52 | let ast_id = AstId::new( |
49 | self.current_file_id, | 53 | self.current_file_id, |
50 | db.ast_id_map(self.current_file_id).ast_id(¯o_call), | 54 | db.ast_id_map(self.current_file_id).ast_id(¯o_call), |
@@ -55,7 +59,7 @@ impl Expander { | |||
55 | let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); | 59 | let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id)); |
56 | let file_id = call_id.as_file(); | 60 | let file_id = call_id.as_file(); |
57 | if let Some(node) = db.parse_or_expand(file_id) { | 61 | if let Some(node) = db.parse_or_expand(file_id) { |
58 | if let Some(expr) = ast::Expr::cast(node) { | 62 | if let Some(expr) = T::cast(node) { |
59 | log::debug!("macro expansion {:#?}", expr.syntax()); | 63 | log::debug!("macro expansion {:#?}", expr.syntax()); |
60 | 64 | ||
61 | let mark = Mark { | 65 | let mark = Mark { |
@@ -78,14 +82,14 @@ impl Expander { | |||
78 | None | 82 | None |
79 | } | 83 | } |
80 | 84 | ||
81 | fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) { | 85 | pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) { |
82 | self.hygiene = Hygiene::new(db, mark.file_id); | 86 | self.hygiene = Hygiene::new(db, mark.file_id); |
83 | self.current_file_id = mark.file_id; | 87 | self.current_file_id = mark.file_id; |
84 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 88 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
85 | mark.bomb.defuse(); | 89 | mark.bomb.defuse(); |
86 | } | 90 | } |
87 | 91 | ||
88 | fn to_source<T>(&self, value: T) -> InFile<T> { | 92 | pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> { |
89 | InFile { file_id: self.current_file_id, value } | 93 | InFile { file_id: self.current_file_id, value } |
90 | } | 94 | } |
91 | 95 | ||
@@ -110,7 +114,7 @@ impl Expander { | |||
110 | } | 114 | } |
111 | } | 115 | } |
112 | 116 | ||
113 | struct Mark { | 117 | pub(crate) struct Mark { |
114 | file_id: HirFileId, | 118 | file_id: HirFileId, |
115 | ast_id_map: Arc<AstIdMap>, | 119 | ast_id_map: Arc<AstIdMap>, |
116 | bomb: DropBomb, | 120 | bomb: DropBomb, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 853e17bae..be5d17d85 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -372,8 +372,9 @@ where | |||
372 | arg_types.push(type_ref); | 372 | arg_types.push(type_ref); |
373 | } | 373 | } |
374 | } | 374 | } |
375 | let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast); | ||
375 | let body = self.collect_expr_opt(e.body()); | 376 | let body = self.collect_expr_opt(e.body()); |
376 | self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr) | 377 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) |
377 | } | 378 | } |
378 | ast::Expr::BinExpr(e) => { | 379 | ast::Expr::BinExpr(e) => { |
379 | let lhs = self.collect_expr_opt(e.lhs()); | 380 | let lhs = self.collect_expr_opt(e.lhs()); |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 14e86936b..b0a3f1784 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -4,16 +4,16 @@ use std::sync::Arc; | |||
4 | 4 | ||
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | name::{name, AsName, Name}, | 6 | name::{name, AsName, Name}, |
7 | AstId, | 7 | AstId, InFile, |
8 | }; | 8 | }; |
9 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 9 | use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner}; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | db::DefDatabase, | 12 | db::DefDatabase, |
13 | src::HasSource, | 13 | src::HasSource, |
14 | type_ref::{Mutability, TypeRef}, | 14 | type_ref::{Mutability, TypeRef}, |
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, ImplId, Intern, | 15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, |
16 | Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 16 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | #[derive(Debug, Clone, PartialEq, Eq)] | 19 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -167,46 +167,24 @@ pub struct ImplData { | |||
167 | 167 | ||
168 | impl ImplData { | 168 | impl ImplData { |
169 | pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { | 169 | pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { |
170 | let src = id.lookup(db).source(db); | 170 | let impl_loc = id.lookup(db); |
171 | let items = db.ast_id_map(src.file_id); | 171 | let src = impl_loc.source(db); |
172 | 172 | ||
173 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); | 173 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); |
174 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); | 174 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); |
175 | let is_negative = src.value.is_negative(); | 175 | let is_negative = src.value.is_negative(); |
176 | let module_id = impl_loc.container.module(db); | ||
176 | 177 | ||
177 | let items = if let Some(item_list) = src.value.item_list() { | 178 | let mut items = Vec::new(); |
178 | item_list | 179 | if let Some(item_list) = src.value.item_list() { |
179 | .impl_items() | 180 | items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id)); |
180 | .map(|item_node| match item_node { | 181 | items.extend(collect_impl_items_in_macros( |
181 | ast::ImplItem::FnDef(it) => { | 182 | db, |
182 | let def = FunctionLoc { | 183 | module_id, |
183 | container: AssocContainerId::ImplId(id), | 184 | &src.with_value(item_list), |
184 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | 185 | id, |
185 | } | 186 | )); |
186 | .intern(db); | 187 | } |
187 | def.into() | ||
188 | } | ||
189 | ast::ImplItem::ConstDef(it) => { | ||
190 | let def = ConstLoc { | ||
191 | container: AssocContainerId::ImplId(id), | ||
192 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | ||
193 | } | ||
194 | .intern(db); | ||
195 | def.into() | ||
196 | } | ||
197 | ast::ImplItem::TypeAliasDef(it) => { | ||
198 | let def = TypeAliasLoc { | ||
199 | container: AssocContainerId::ImplId(id), | ||
200 | ast_id: AstId::new(src.file_id, items.ast_id(&it)), | ||
201 | } | ||
202 | .intern(db); | ||
203 | def.into() | ||
204 | } | ||
205 | }) | ||
206 | .collect() | ||
207 | } else { | ||
208 | Vec::new() | ||
209 | }; | ||
210 | 188 | ||
211 | let res = ImplData { target_trait, target_type, items, is_negative }; | 189 | let res = ImplData { target_trait, target_type, items, is_negative }; |
212 | Arc::new(res) | 190 | Arc::new(res) |
@@ -237,3 +215,66 @@ impl ConstData { | |||
237 | ConstData { name, type_ref } | 215 | ConstData { name, type_ref } |
238 | } | 216 | } |
239 | } | 217 | } |
218 | |||
219 | fn collect_impl_items_in_macros( | ||
220 | db: &impl DefDatabase, | ||
221 | module_id: ModuleId, | ||
222 | impl_block: &InFile<ast::ItemList>, | ||
223 | id: ImplId, | ||
224 | ) -> Vec<AssocItemId> { | ||
225 | let mut expander = Expander::new(db, impl_block.file_id, module_id); | ||
226 | let mut res = Vec::new(); | ||
227 | |||
228 | for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) { | ||
229 | if let Some((mark, items)) = expander.enter_expand(db, m) { | ||
230 | let items: InFile<ast::MacroItems> = expander.to_source(items); | ||
231 | expander.exit(db, mark); | ||
232 | res.extend(collect_impl_items( | ||
233 | db, | ||
234 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), | ||
235 | items.file_id, | ||
236 | id, | ||
237 | )); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | res | ||
242 | } | ||
243 | |||
244 | fn collect_impl_items( | ||
245 | db: &impl DefDatabase, | ||
246 | impl_items: impl Iterator<Item = ImplItem>, | ||
247 | file_id: crate::HirFileId, | ||
248 | id: ImplId, | ||
249 | ) -> Vec<AssocItemId> { | ||
250 | let items = db.ast_id_map(file_id); | ||
251 | |||
252 | impl_items | ||
253 | .map(|item_node| match item_node { | ||
254 | ast::ImplItem::FnDef(it) => { | ||
255 | let def = FunctionLoc { | ||
256 | container: AssocContainerId::ImplId(id), | ||
257 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
258 | } | ||
259 | .intern(db); | ||
260 | def.into() | ||
261 | } | ||
262 | ast::ImplItem::ConstDef(it) => { | ||
263 | let def = ConstLoc { | ||
264 | container: AssocContainerId::ImplId(id), | ||
265 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
266 | } | ||
267 | .intern(db); | ||
268 | def.into() | ||
269 | } | ||
270 | ast::ImplItem::TypeAliasDef(it) => { | ||
271 | let def = TypeAliasLoc { | ||
272 | container: AssocContainerId::ImplId(id), | ||
273 | ast_id: AstId::new(file_id, items.ast_id(&it)), | ||
274 | } | ||
275 | .intern(db); | ||
276 | def.into() | ||
277 | } | ||
278 | }) | ||
279 | .collect() | ||
280 | } | ||
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 6fad80a8d..a75ef9970 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -143,6 +143,7 @@ pub enum Expr { | |||
143 | Lambda { | 143 | Lambda { |
144 | args: Vec<PatId>, | 144 | args: Vec<PatId>, |
145 | arg_types: Vec<Option<TypeRef>>, | 145 | arg_types: Vec<Option<TypeRef>>, |
146 | ret_type: Option<TypeRef>, | ||
146 | body: ExprId, | 147 | body: ExprId, |
147 | }, | 148 | }, |
148 | Tuple { | 149 | Tuple { |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index bf8d6d1d4..acd4f4af1 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -48,6 +48,7 @@ use ra_arena::{impl_arena_id, RawId}; | |||
48 | use ra_db::{impl_intern_key, salsa, CrateId}; | 48 | use ra_db::{impl_intern_key, salsa, CrateId}; |
49 | use ra_syntax::{ast, AstNode}; | 49 | use ra_syntax::{ast, AstNode}; |
50 | 50 | ||
51 | use crate::body::Expander; | ||
51 | use crate::builtin_type::BuiltinType; | 52 | use crate::builtin_type::BuiltinType; |
52 | 53 | ||
53 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 54 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 00325cd99..8e1294201 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -135,7 +135,7 @@ impl Path { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | pub fn type_anchor(&self) -> Option<&TypeRef> { | 137 | pub fn type_anchor(&self) -> Option<&TypeRef> { |
138 | self.type_anchor.as_ref().map(|it| &**it) | 138 | self.type_anchor.as_deref() |
139 | } | 139 | } |
140 | 140 | ||
141 | pub fn segments(&self) -> PathSegments<'_> { | 141 | pub fn segments(&self) -> PathSegments<'_> { |
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index f68aca789..d86445abf 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -188,6 +188,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, macro_call_id: MacroCallId) -> Fragmen | |||
188 | ARG_LIST => FragmentKind::Expr, | 188 | ARG_LIST => FragmentKind::Expr, |
189 | TRY_EXPR => FragmentKind::Expr, | 189 | TRY_EXPR => FragmentKind::Expr, |
190 | TUPLE_EXPR => FragmentKind::Expr, | 190 | TUPLE_EXPR => FragmentKind::Expr, |
191 | ITEM_LIST => FragmentKind::Items, | ||
191 | _ => { | 192 | _ => { |
192 | // Unknown , Just guess it is `Items` | 193 | // Unknown , Just guess it is `Items` |
193 | FragmentKind::Items | 194 | FragmentKind::Items |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index bbbc391c4..e97b81473 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -196,7 +196,12 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
196 | trait_env: Arc<TraitEnvironment>, | 196 | trait_env: Arc<TraitEnvironment>, |
197 | obligations: Vec<Obligation>, | 197 | obligations: Vec<Obligation>, |
198 | result: InferenceResult, | 198 | result: InferenceResult, |
199 | /// The return type of the function being inferred. | 199 | /// The return type of the function being inferred, or the closure if we're |
200 | /// currently within one. | ||
201 | /// | ||
202 | /// We might consider using a nested inference context for checking | ||
203 | /// closures, but currently this is the only field that will change there, | ||
204 | /// so it doesn't make sense. | ||
200 | return_ty: Ty, | 205 | return_ty: Ty, |
201 | 206 | ||
202 | /// Impls of `CoerceUnsized` used in coercion. | 207 | /// Impls of `CoerceUnsized` used in coercion. |
@@ -455,7 +460,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
455 | } | 460 | } |
456 | 461 | ||
457 | fn infer_body(&mut self) { | 462 | fn infer_body(&mut self) { |
458 | self.infer_expr(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); | 463 | self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); |
459 | } | 464 | } |
460 | 465 | ||
461 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { | 466 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 0f4dac45e..83c0c2c3f 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -134,6 +134,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
134 | } | 134 | } |
135 | } | 135 | } |
136 | 136 | ||
137 | (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => { | ||
138 | from_ty = params[0].clone(); | ||
139 | } | ||
140 | |||
137 | _ => {} | 141 | _ => {} |
138 | } | 142 | } |
139 | 143 | ||
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 8be567917..3af05394c 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -41,7 +41,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
41 | 41 | ||
42 | /// Infer type of expression with possibly implicit coerce to the expected type. | 42 | /// Infer type of expression with possibly implicit coerce to the expected type. |
43 | /// Return the type after possible coercion. | 43 | /// Return the type after possible coercion. |
44 | fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { | 44 | pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { |
45 | let ty = self.infer_expr_inner(expr, &expected); | 45 | let ty = self.infer_expr_inner(expr, &expected); |
46 | let ty = if !self.coerce(&ty, &expected.ty) { | 46 | let ty = if !self.coerce(&ty, &expected.ty) { |
47 | self.result | 47 | self.result |
@@ -102,7 +102,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
102 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 102 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
103 | Ty::unit() | 103 | Ty::unit() |
104 | } | 104 | } |
105 | Expr::Lambda { body, args, arg_types } => { | 105 | Expr::Lambda { body, args, ret_type, arg_types } => { |
106 | assert_eq!(args.len(), arg_types.len()); | 106 | assert_eq!(args.len(), arg_types.len()); |
107 | 107 | ||
108 | let mut sig_tys = Vec::new(); | 108 | let mut sig_tys = Vec::new(); |
@@ -118,7 +118,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
118 | } | 118 | } |
119 | 119 | ||
120 | // add return type | 120 | // add return type |
121 | let ret_ty = self.table.new_type_var(); | 121 | let ret_ty = match ret_type { |
122 | Some(type_ref) => self.make_ty(type_ref), | ||
123 | None => self.table.new_type_var(), | ||
124 | }; | ||
122 | sig_tys.push(ret_ty.clone()); | 125 | sig_tys.push(ret_ty.clone()); |
123 | let sig_ty = Ty::apply( | 126 | let sig_ty = Ty::apply( |
124 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 127 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, |
@@ -134,7 +137,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
134 | // infer the body. | 137 | // infer the body. |
135 | self.coerce(&closure_ty, &expected.ty); | 138 | self.coerce(&closure_ty, &expected.ty); |
136 | 139 | ||
137 | self.infer_expr(*body, &Expectation::has_type(ret_ty)); | 140 | let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone()); |
141 | |||
142 | self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); | ||
143 | |||
144 | self.return_ty = prev_ret_ty; | ||
145 | |||
138 | closure_ty | 146 | closure_ty |
139 | } | 147 | } |
140 | Expr::Call { callee, args } => { | 148 | Expr::Call { callee, args } => { |
@@ -192,6 +200,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
192 | Expr::Return { expr } => { | 200 | Expr::Return { expr } => { |
193 | if let Some(expr) = expr { | 201 | if let Some(expr) = expr { |
194 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); | 202 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); |
203 | } else { | ||
204 | let unit = Ty::unit(); | ||
205 | self.coerce(&unit, &self.return_ty.clone()); | ||
195 | } | 206 | } |
196 | Ty::simple(TypeCtor::Never) | 207 | Ty::simple(TypeCtor::Never) |
197 | } | 208 | } |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index ac9e3872a..7e99a42ed 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -370,6 +370,22 @@ fn test() { | |||
370 | } | 370 | } |
371 | 371 | ||
372 | #[test] | 372 | #[test] |
373 | fn return_coerce_unknown() { | ||
374 | assert_snapshot!( | ||
375 | infer_with_mismatches(r#" | ||
376 | fn foo() -> u32 { | ||
377 | return unknown; | ||
378 | } | ||
379 | "#, true), | ||
380 | @r###" | ||
381 | [17; 40) '{ ...own; }': ! | ||
382 | [23; 37) 'return unknown': ! | ||
383 | [30; 37) 'unknown': u32 | ||
384 | "### | ||
385 | ); | ||
386 | } | ||
387 | |||
388 | #[test] | ||
373 | fn coerce_autoderef() { | 389 | fn coerce_autoderef() { |
374 | assert_snapshot!( | 390 | assert_snapshot!( |
375 | infer_with_mismatches(r#" | 391 | infer_with_mismatches(r#" |
@@ -440,3 +456,73 @@ fn test() { | |||
440 | "### | 456 | "### |
441 | ); | 457 | ); |
442 | } | 458 | } |
459 | |||
460 | #[test] | ||
461 | fn closure_return_coerce() { | ||
462 | assert_snapshot!( | ||
463 | infer_with_mismatches(r#" | ||
464 | fn foo() { | ||
465 | let x = || { | ||
466 | if true { | ||
467 | return &1u32; | ||
468 | } | ||
469 | &&1u32 | ||
470 | }; | ||
471 | } | ||
472 | "#, true), | ||
473 | @r###" | ||
474 | [10; 106) '{ ... }; }': () | ||
475 | [20; 21) 'x': || -> &u32 | ||
476 | [24; 103) '|| { ... }': || -> &u32 | ||
477 | [27; 103) '{ ... }': &u32 | ||
478 | [37; 82) 'if tru... }': () | ||
479 | [40; 44) 'true': bool | ||
480 | [45; 82) '{ ... }': ! | ||
481 | [59; 71) 'return &1u32': ! | ||
482 | [66; 71) '&1u32': &u32 | ||
483 | [67; 71) '1u32': u32 | ||
484 | [91; 97) '&&1u32': &&u32 | ||
485 | [92; 97) '&1u32': &u32 | ||
486 | [93; 97) '1u32': u32 | ||
487 | "### | ||
488 | ); | ||
489 | } | ||
490 | |||
491 | #[test] | ||
492 | fn coerce_fn_item_to_fn_ptr() { | ||
493 | assert_snapshot!( | ||
494 | infer_with_mismatches(r#" | ||
495 | fn foo(x: u32) -> isize { 1 } | ||
496 | fn test() { | ||
497 | let f: fn(u32) -> isize = foo; | ||
498 | } | ||
499 | "#, true), | ||
500 | @r###" | ||
501 | [8; 9) 'x': u32 | ||
502 | [25; 30) '{ 1 }': isize | ||
503 | [27; 28) '1': isize | ||
504 | [41; 79) '{ ...foo; }': () | ||
505 | [51; 52) 'f': fn(u32) -> isize | ||
506 | [73; 76) 'foo': fn foo(u32) -> isize | ||
507 | "### | ||
508 | ); | ||
509 | } | ||
510 | |||
511 | #[test] | ||
512 | fn coerce_closure_to_fn_ptr() { | ||
513 | assert_snapshot!( | ||
514 | infer_with_mismatches(r#" | ||
515 | fn test() { | ||
516 | let f: fn(u32) -> isize = |x| { 1 }; | ||
517 | } | ||
518 | "#, true), | ||
519 | @r###" | ||
520 | [11; 55) '{ ...1 }; }': () | ||
521 | [21; 22) 'f': fn(u32) -> isize | ||
522 | [43; 52) '|x| { 1 }': |u32| -> isize | ||
523 | [44; 45) 'x': u32 | ||
524 | [47; 52) '{ 1 }': isize | ||
525 | [49; 50) '1': isize | ||
526 | "### | ||
527 | ); | ||
528 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 812f171db..7fdbf996f 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -183,6 +183,25 @@ fn test() { S.foo()<|>; } | |||
183 | } | 183 | } |
184 | 184 | ||
185 | #[test] | 185 | #[test] |
186 | fn infer_impl_items_generated_by_macros() { | ||
187 | let t = type_at( | ||
188 | r#" | ||
189 | //- /main.rs | ||
190 | macro_rules! m { | ||
191 | () => (fn foo(&self) -> u128 {0}) | ||
192 | } | ||
193 | struct S; | ||
194 | impl S { | ||
195 | m!(); | ||
196 | } | ||
197 | |||
198 | fn test() { S.foo()<|>; } | ||
199 | "#, | ||
200 | ); | ||
201 | assert_eq!(t, "u128"); | ||
202 | } | ||
203 | |||
204 | #[test] | ||
186 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | 205 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { |
187 | let (db, pos) = TestDB::with_position( | 206 | let (db, pos) = TestDB::with_position( |
188 | r#" | 207 | r#" |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 18976c9ae..6fe647a5e 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -1606,3 +1606,58 @@ fn main() { | |||
1606 | ); | 1606 | ); |
1607 | assert_eq!(t, "u32"); | 1607 | assert_eq!(t, "u32"); |
1608 | } | 1608 | } |
1609 | |||
1610 | #[test] | ||
1611 | fn closure_return() { | ||
1612 | assert_snapshot!( | ||
1613 | infer(r#" | ||
1614 | fn foo() -> u32 { | ||
1615 | let x = || -> usize { return 1; }; | ||
1616 | } | ||
1617 | "#), | ||
1618 | @r###" | ||
1619 | [17; 59) '{ ...; }; }': () | ||
1620 | [27; 28) 'x': || -> usize | ||
1621 | [31; 56) '|| -> ...n 1; }': || -> usize | ||
1622 | [43; 56) '{ return 1; }': ! | ||
1623 | [45; 53) 'return 1': ! | ||
1624 | [52; 53) '1': usize | ||
1625 | "### | ||
1626 | ); | ||
1627 | } | ||
1628 | |||
1629 | #[test] | ||
1630 | fn closure_return_unit() { | ||
1631 | assert_snapshot!( | ||
1632 | infer(r#" | ||
1633 | fn foo() -> u32 { | ||
1634 | let x = || { return; }; | ||
1635 | } | ||
1636 | "#), | ||
1637 | @r###" | ||
1638 | [17; 48) '{ ...; }; }': () | ||
1639 | [27; 28) 'x': || -> () | ||
1640 | [31; 45) '|| { return; }': || -> () | ||
1641 | [34; 45) '{ return; }': ! | ||
1642 | [36; 42) 'return': ! | ||
1643 | "### | ||
1644 | ); | ||
1645 | } | ||
1646 | |||
1647 | #[test] | ||
1648 | fn closure_return_inferred() { | ||
1649 | assert_snapshot!( | ||
1650 | infer(r#" | ||
1651 | fn foo() -> u32 { | ||
1652 | let x = || { "test" }; | ||
1653 | } | ||
1654 | "#), | ||
1655 | @r###" | ||
1656 | [17; 47) '{ ..." }; }': () | ||
1657 | [27; 28) 'x': || -> &str | ||
1658 | [31; 44) '|| { "test" }': || -> &str | ||
1659 | [34; 44) '{ "test" }': &str | ||
1660 | [36; 42) '"test"': &str | ||
1661 | "### | ||
1662 | ); | ||
1663 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 2d92a5eec..76e2198b6 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -393,11 +393,11 @@ fn test() -> u64 { | |||
393 | [54; 55) 'a': S | 393 | [54; 55) 'a': S |
394 | [58; 59) 'S': S(fn(u32) -> u64) -> S | 394 | [58; 59) 'S': S(fn(u32) -> u64) -> S |
395 | [58; 68) 'S(|i| 2*i)': S | 395 | [58; 68) 'S(|i| 2*i)': S |
396 | [60; 67) '|i| 2*i': |i32| -> i32 | 396 | [60; 67) '|i| 2*i': |u32| -> u64 |
397 | [61; 62) 'i': i32 | 397 | [61; 62) 'i': u32 |
398 | [64; 65) '2': i32 | 398 | [64; 65) '2': u32 |
399 | [64; 67) '2*i': i32 | 399 | [64; 67) '2*i': u32 |
400 | [66; 67) 'i': i32 | 400 | [66; 67) 'i': u32 |
401 | [78; 79) 'b': u64 | 401 | [78; 79) 'b': u64 |
402 | [82; 83) 'a': S | 402 | [82; 83) 'a': S |
403 | [82; 85) 'a.0': fn(u32) -> u64 | 403 | [82; 85) 'a.0': fn(u32) -> u64 |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 30617412a..fbe89841b 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature; | |||
15 | pub use navigation_target::NavigationTarget; | 15 | pub use navigation_target::NavigationTarget; |
16 | pub use structure::{file_structure, StructureNode}; | 16 | pub use structure::{file_structure, StructureNode}; |
17 | 17 | ||
18 | pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; | 18 | pub(crate) use navigation_target::ToNav; |
19 | pub(crate) use short_label::ShortLabel; | 19 | pub(crate) use short_label::ShortLabel; |
20 | 20 | ||
21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index a227bf546..35e39f965 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -12,10 +12,7 @@ use ra_syntax::{ | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | db::RootDatabase, | 14 | db::RootDatabase, |
15 | display::{ | 15 | display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel}, |
16 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, | ||
17 | rust_code_markup_with_doc, ShortLabel, | ||
18 | }, | ||
19 | expand::descend_into_macros, | 16 | expand::descend_into_macros, |
20 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, | 17 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, |
21 | FilePosition, FileRange, RangeInfo, | 18 | FilePosition, FileRange, RangeInfo, |
@@ -95,11 +92,7 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { | |||
95 | } | 92 | } |
96 | } | 93 | } |
97 | 94 | ||
98 | fn hover_text_from_name_kind( | 95 | fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<String> { |
99 | db: &RootDatabase, | ||
100 | name_kind: NameKind, | ||
101 | no_fallback: &mut bool, | ||
102 | ) -> Option<String> { | ||
103 | return match name_kind { | 96 | return match name_kind { |
104 | Macro(it) => { | 97 | Macro(it) => { |
105 | let src = it.source(db); | 98 | let src = it.source(db); |
@@ -135,11 +128,7 @@ fn hover_text_from_name_kind( | |||
135 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), | 128 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), |
136 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), | 129 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), |
137 | }, | 130 | }, |
138 | Local(_) => { | 131 | Local(_) => None, |
139 | // Hover for these shows type names | ||
140 | *no_fallback = true; | ||
141 | None | ||
142 | } | ||
143 | TypeParam(_) | SelfType(_) => { | 132 | TypeParam(_) | SelfType(_) => { |
144 | // FIXME: Hover for generic param | 133 | // FIXME: Hover for generic param |
145 | None | 134 | None |
@@ -163,60 +152,35 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
163 | 152 | ||
164 | let mut res = HoverResult::new(); | 153 | let mut res = HoverResult::new(); |
165 | 154 | ||
166 | let mut range = match_ast! { | 155 | if let Some((range, name_kind)) = match_ast! { |
167 | match (token.value.parent()) { | 156 | match (token.value.parent()) { |
168 | ast::NameRef(name_ref) => { | 157 | ast::NameRef(name_ref) => { |
169 | let mut no_fallback = false; | 158 | classify_name_ref(db, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind)) |
170 | if let Some(name_kind) = | ||
171 | classify_name_ref(db, token.with_value(&name_ref)).map(|d| d.kind) | ||
172 | { | ||
173 | res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback)) | ||
174 | } | ||
175 | |||
176 | if res.is_empty() && !no_fallback { | ||
177 | // Fallback index based approach: | ||
178 | let symbols = crate::symbol_index::index_resolve(db, &name_ref); | ||
179 | for sym in symbols { | ||
180 | let docs = docs_from_symbol(db, &sym); | ||
181 | let desc = description_from_symbol(db, &sym); | ||
182 | res.extend(hover_text(docs, desc)); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | if !res.is_empty() { | ||
187 | Some(name_ref.syntax().text_range()) | ||
188 | } else { | ||
189 | None | ||
190 | } | ||
191 | }, | 159 | }, |
192 | ast::Name(name) => { | 160 | ast::Name(name) => { |
193 | if let Some(name_kind) = classify_name(db, token.with_value(&name)).map(|d| d.kind) { | 161 | classify_name(db, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind)) |
194 | res.extend(hover_text_from_name_kind(db, name_kind, &mut true)); | ||
195 | } | ||
196 | |||
197 | if !res.is_empty() { | ||
198 | Some(name.syntax().text_range()) | ||
199 | } else { | ||
200 | None | ||
201 | } | ||
202 | }, | 162 | }, |
203 | _ => None, | 163 | _ => None, |
204 | } | 164 | } |
205 | }; | 165 | } { |
166 | res.extend(hover_text_from_name_kind(db, name_kind)); | ||
206 | 167 | ||
207 | if range.is_none() { | 168 | if !res.is_empty() { |
208 | let node = token.value.ancestors().find(|n| { | 169 | return Some(RangeInfo::new(range, res)); |
209 | ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() | 170 | } |
210 | })?; | 171 | } |
211 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | ||
212 | res.extend(type_of(db, frange).map(rust_code_markup)); | ||
213 | range = Some(node.text_range()); | ||
214 | }; | ||
215 | 172 | ||
216 | let range = range?; | 173 | let node = token |
174 | .value | ||
175 | .ancestors() | ||
176 | .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?; | ||
177 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | ||
178 | res.extend(type_of(db, frange).map(rust_code_markup)); | ||
217 | if res.is_empty() { | 179 | if res.is_empty() { |
218 | return None; | 180 | return None; |
219 | } | 181 | } |
182 | let range = node.text_range(); | ||
183 | |||
220 | Some(RangeInfo::new(range, res)) | 184 | Some(RangeInfo::new(range, res)) |
221 | } | 185 | } |
222 | 186 | ||
@@ -314,7 +278,7 @@ mod tests { | |||
314 | &["pub fn foo() -> u32"], | 278 | &["pub fn foo() -> u32"], |
315 | ); | 279 | ); |
316 | 280 | ||
317 | // Multiple results | 281 | // Multiple candidates but results are ambiguous. |
318 | check_hover_result( | 282 | check_hover_result( |
319 | r#" | 283 | r#" |
320 | //- /a.rs | 284 | //- /a.rs |
@@ -335,7 +299,7 @@ mod tests { | |||
335 | let foo_test = fo<|>o(); | 299 | let foo_test = fo<|>o(); |
336 | } | 300 | } |
337 | "#, | 301 | "#, |
338 | &["pub fn foo() -> &str", "pub fn foo() -> u32", "pub fn foo(a: u32, b: u32)"], | 302 | &["{unknown}"], |
339 | ); | 303 | ); |
340 | } | 304 | } |
341 | 305 | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 9dd6bd3ea..8d65e2e08 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1426,6 +1426,9 @@ impl LambdaExpr { | |||
1426 | pub fn param_list(&self) -> Option<ParamList> { | 1426 | pub fn param_list(&self) -> Option<ParamList> { |
1427 | AstChildren::new(&self.syntax).next() | 1427 | AstChildren::new(&self.syntax).next() |
1428 | } | 1428 | } |
1429 | pub fn ret_type(&self) -> Option<RetType> { | ||
1430 | AstChildren::new(&self.syntax).next() | ||
1431 | } | ||
1429 | pub fn body(&self) -> Option<Expr> { | 1432 | pub fn body(&self) -> Option<Expr> { |
1430 | AstChildren::new(&self.syntax).next() | 1433 | AstChildren::new(&self.syntax).next() |
1431 | } | 1434 | } |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 9ffa9095b..a228fa9d6 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -426,7 +426,7 @@ Grammar( | |||
426 | "PathExpr": (options: ["Path"]), | 426 | "PathExpr": (options: ["Path"]), |
427 | "LambdaExpr": ( | 427 | "LambdaExpr": ( |
428 | options: [ | 428 | options: [ |
429 | "ParamList", | 429 | "ParamList", "RetType", |
430 | ["body", "Expr"], | 430 | ["body", "Expr"], |
431 | ] | 431 | ] |
432 | ), | 432 | ), |