aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/expr.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/simple.rs55
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs10
-rw-r--r--crates/ra_ide/src/goto_definition.rs36
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt9
13 files changed, 220 insertions, 19 deletions
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/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_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/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/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index 9b5744789..79d332e8c 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -425,6 +425,42 @@ mod tests {
425 } 425 }
426 426
427 #[test] 427 #[test]
428 fn goto_definition_works_for_macro_inside_pattern() {
429 check_goto(
430 "
431 //- /lib.rs
432 macro_rules! foo {() => {0}}
433
434 fn bar() {
435 match (0,1) {
436 (<|>foo!(), _) => {}
437 }
438 }
439 ",
440 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
441 "macro_rules! foo {() => {0}}|foo",
442 );
443 }
444
445 #[test]
446 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
447 check_goto(
448 "
449 //- /lib.rs
450 macro_rules! foo {() => {0}}
451
452 fn bar() {
453 match 0 {
454 <|>foo!() => {}
455 }
456 }
457 ",
458 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
459 "macro_rules! foo {() => {0}}|foo",
460 );
461 }
462
463 #[test]
428 fn goto_def_for_methods() { 464 fn goto_def_for_methods() {
429 covers!(goto_def_for_methods); 465 covers!(goto_def_for_methods);
430 check_goto( 466 check_goto(
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index f5d12278c..422a4e3dc 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -50,7 +50,7 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
50 // let m!(x) = 0; 50 // let m!(x) = 0;
51 // } 51 // }
52 if lhs.kind() == PATH_PAT && p.at(T![!]) { 52 if lhs.kind() == PATH_PAT && p.at(T![!]) {
53 let m = lhs.precede(p); 53 let m = lhs.undo_completion(p);
54 items::macro_call_after_excl(p); 54 items::macro_call_after_excl(p);
55 m.complete(p, MACRO_CALL); 55 m.complete(p, MACRO_CALL);
56 } 56 }
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 ),
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
index 4a714ad6b..b05ccc0ed 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
@@ -16,11 +16,10 @@ SOURCE_FILE@[0; 33)
16 LET_KW@[16; 19) "let" 16 LET_KW@[16; 19) "let"
17 WHITESPACE@[19; 20) " " 17 WHITESPACE@[19; 20) " "
18 MACRO_CALL@[20; 25) 18 MACRO_CALL@[20; 25)
19 PATH_PAT@[20; 21) 19 PATH@[20; 21)
20 PATH@[20; 21) 20 PATH_SEGMENT@[20; 21)
21 PATH_SEGMENT@[20; 21) 21 NAME_REF@[20; 21)
22 NAME_REF@[20; 21) 22 IDENT@[20; 21) "m"
23 IDENT@[20; 21) "m"
24 EXCL@[21; 22) "!" 23 EXCL@[21; 22) "!"
25 TOKEN_TREE@[22; 25) 24 TOKEN_TREE@[22; 25)
26 L_PAREN@[22; 23) "(" 25 L_PAREN@[22; 23) "("