aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/body.rs22
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/data.rs119
-rw-r--r--crates/ra_hir_def/src/expr.rs1
-rw-r--r--crates/ra_hir_def/src/lib.rs1
-rw-r--r--crates/ra_hir_def/src/path.rs2
-rw-r--r--crates/ra_hir_expand/src/db.rs1
-rw-r--r--crates/ra_hir_ty/src/infer.rs9
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs19
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs86
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs19
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs55
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs10
-rw-r--r--crates/ra_ide/src/display.rs2
-rw-r--r--crates/ra_ide/src/hover.rs80
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron2
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
27struct Expander { 27pub(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
35impl Expander { 35impl 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(&macro_call), 54 db.ast_id_map(self.current_file_id).ast_id(&macro_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
113struct Mark { 117pub(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
5use hir_expand::{ 5use hir_expand::{
6 name::{name, AsName, Name}, 6 name::{name, AsName, Name},
7 AstId, 7 AstId, InFile,
8}; 8};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner};
10 10
11use crate::{ 11use 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
168impl ImplData { 168impl 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
219fn 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
244fn 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};
48use ra_db::{impl_intern_key, salsa, CrateId}; 48use ra_db::{impl_intern_key, salsa, CrateId};
49use ra_syntax::{ast, AstNode}; 49use ra_syntax::{ast, AstNode};
50 50
51use crate::body::Expander;
51use crate::builtin_type::BuiltinType; 52use 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]
373fn return_coerce_unknown() {
374 assert_snapshot!(
375 infer_with_mismatches(r#"
376fn 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]
373fn coerce_autoderef() { 389fn 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]
461fn closure_return_coerce() {
462 assert_snapshot!(
463 infer_with_mismatches(r#"
464fn 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]
492fn coerce_fn_item_to_fn_ptr() {
493 assert_snapshot!(
494 infer_with_mismatches(r#"
495fn foo(x: u32) -> isize { 1 }
496fn 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]
512fn coerce_closure_to_fn_ptr() {
513 assert_snapshot!(
514 infer_with_mismatches(r#"
515fn 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]
186fn infer_impl_items_generated_by_macros() {
187 let t = type_at(
188 r#"
189//- /main.rs
190macro_rules! m {
191 () => (fn foo(&self) -> u128 {0})
192}
193struct S;
194impl S {
195 m!();
196}
197
198fn test() { S.foo()<|>; }
199"#,
200 );
201 assert_eq!(t, "u128");
202}
203
204#[test]
186fn infer_macro_with_dollar_crate_is_correct_in_expr() { 205fn 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]
1611fn closure_return() {
1612 assert_snapshot!(
1613 infer(r#"
1614fn 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]
1630fn closure_return_unit() {
1631 assert_snapshot!(
1632 infer(r#"
1633fn 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]
1648fn closure_return_inferred() {
1649 assert_snapshot!(
1650 infer(r#"
1651fn 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;
15pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode}; 16pub use structure::{file_structure, StructureNode};
17 17
18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; 18pub(crate) use navigation_target::ToNav;
19pub(crate) use short_label::ShortLabel; 19pub(crate) use short_label::ShortLabel;
20 20
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 21pub(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
13use crate::{ 13use 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
98fn hover_text_from_name_kind( 95fn 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 ),