aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs29
-rw-r--r--crates/hir_ty/src/infer/expr.rs43
-rw-r--r--crates/hir_ty/src/tests/simple.rs47
-rw-r--r--crates/hir_ty/src/tests/traits.rs51
4 files changed, 138 insertions, 32 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index fbe760c39..1c1423fbf 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -1495,6 +1495,20 @@ fn main(f: Foo) {
1495 ); 1495 );
1496 } 1496 }
1497 1497
1498 #[test]
1499 fn internal_or() {
1500 check_diagnostics(
1501 r#"
1502fn main() {
1503 enum Either { A(bool), B }
1504 match Either::B {
1505 //^^^^^^^^^ Missing match arm
1506 Either::A(true | false) => (),
1507 }
1508}
1509"#,
1510 );
1511 }
1498 mod false_negatives { 1512 mod false_negatives {
1499 //! The implementation of match checking here is a work in progress. As we roll this out, we 1513 //! The implementation of match checking here is a work in progress. As we roll this out, we
1500 //! prefer false negatives to false positives (ideally there would be no false positives). This 1514 //! prefer false negatives to false positives (ideally there would be no false positives). This
@@ -1521,20 +1535,5 @@ fn main() {
1521"#, 1535"#,
1522 ); 1536 );
1523 } 1537 }
1524
1525 #[test]
1526 fn internal_or() {
1527 // We do not currently handle patterns with internal `or`s.
1528 check_diagnostics(
1529 r#"
1530fn main() {
1531 enum Either { A(bool), B }
1532 match Either::B {
1533 Either::A(true | false) => (),
1534 }
1535}
1536"#,
1537 );
1538 }
1539 } 1538 }
1540} 1539}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 12f1591c8..cb59a6937 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -137,24 +137,33 @@ impl<'a> InferenceContext<'a> {
137 137
138 self.coerce_merge_branch(&then_ty, &else_ty) 138 self.coerce_merge_branch(&then_ty, &else_ty)
139 } 139 }
140 Expr::Block { statements, tail, label, id: _ } => match label { 140 Expr::Block { statements, tail, label, id: _ } => {
141 Some(_) => { 141 let old_resolver = mem::replace(
142 let break_ty = self.table.new_type_var(); 142 &mut self.resolver,
143 self.breakables.push(BreakableContext { 143 resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
144 may_break: false, 144 );
145 break_ty: break_ty.clone(), 145 let ty = match label {
146 label: label.map(|label| self.body[label].name.clone()), 146 Some(_) => {
147 }); 147 let break_ty = self.table.new_type_var();
148 let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty)); 148 self.breakables.push(BreakableContext {
149 let ctxt = self.breakables.pop().expect("breakable stack broken"); 149 may_break: false,
150 if ctxt.may_break { 150 break_ty: break_ty.clone(),
151 ctxt.break_ty 151 label: label.map(|label| self.body[label].name.clone()),
152 } else { 152 });
153 ty 153 let ty =
154 self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
155 let ctxt = self.breakables.pop().expect("breakable stack broken");
156 if ctxt.may_break {
157 ctxt.break_ty
158 } else {
159 ty
160 }
154 } 161 }
155 } 162 None => self.infer_block(statements, *tail, expected),
156 None => self.infer_block(statements, *tail, expected), 163 };
157 }, 164 self.resolver = old_resolver;
165 ty
166 }
158 Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), 167 Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
159 Expr::TryBlock { body } => { 168 Expr::TryBlock { body } => {
160 let _inner = self.infer_expr(*body, expected); 169 let _inner = self.infer_expr(*body, expected);
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 16682f76f..20ceb7415 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2415,3 +2415,50 @@ fn infer_const_params() {
2415 "#]], 2415 "#]],
2416 ); 2416 );
2417} 2417}
2418
2419#[test]
2420fn infer_inner_type() {
2421 check_infer(
2422 r#"
2423 fn foo() {
2424 struct S { field: u32 }
2425 let s = S { field: 0 };
2426 let f = s.field;
2427 }
2428 "#,
2429 expect![[r#"
2430 9..89 '{ ...eld; }': ()
2431 47..48 's': S
2432 51..65 'S { field: 0 }': S
2433 62..63 '0': u32
2434 75..76 'f': u32
2435 79..80 's': S
2436 79..86 's.field': u32
2437 "#]],
2438 );
2439}
2440
2441#[test]
2442fn infer_nested_inner_type() {
2443 check_infer(
2444 r#"
2445 fn foo() {
2446 {
2447 let s = S { field: 0 };
2448 let f = s.field;
2449 }
2450 struct S { field: u32 }
2451 }
2452 "#,
2453 expect![[r#"
2454 9..109 '{ ...32 } }': ()
2455 15..79 '{ ... }': ()
2456 29..30 's': S
2457 33..47 'S { field: 0 }': S
2458 44..45 '0': u32
2459 61..62 'f': u32
2460 65..66 's': S
2461 65..72 's.field': u32
2462 "#]],
2463 );
2464}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index e5a3f95a6..e030f4a97 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3151,3 +3151,54 @@ fn test() {
3151 "#, 3151 "#,
3152 ); 3152 );
3153} 3153}
3154
3155#[test]
3156fn inner_use() {
3157 check_types(
3158 r#"
3159mod m {
3160 pub trait Tr {
3161 fn method(&self) -> u8 { 0 }
3162 }
3163
3164 impl Tr for () {}
3165}
3166
3167fn f() {
3168 use m::Tr;
3169
3170 ().method();
3171 //^^^^^^^^^^^ u8
3172}
3173 "#,
3174 );
3175}
3176
3177#[test]
3178fn inner_use_in_block() {
3179 check_types(
3180 r#"
3181mod m {
3182 pub trait Tr {
3183 fn method(&self) -> u8 { 0 }
3184 }
3185
3186 impl Tr for () {}
3187}
3188
3189fn f() {
3190 {
3191 use m::Tr;
3192
3193 ().method();
3194 //^^^^^^^^^^^ u8
3195 }
3196
3197 {
3198 ().method();
3199 //^^^^^^^^^^^ {unknown}
3200 }
3201}
3202 "#,
3203 );
3204}