Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #13856 - WaffleLapkin:typeck_try{}, r=Veykril
fix: Type check unstable `try{}` blocks ![Peek 2022-12-29 01-40](https://user-images.githubusercontent.com/38225716/209875594-8bf9c9e2-9998-40b0-8820-28c7f2d9bae4.gif) Fixes https://github.com/rust-lang/rust-analyzer/issues/11843
bors 2022-12-31
parent 6892b16 · parent aaa682c · commit ea8897c
-rw-r--r--crates/hir-ty/src/infer.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs17
-rw-r--r--crates/hir-ty/src/tests/simple.rs28
-rw-r--r--crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs40
4 files changed, 46 insertions, 41 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 7cf4fb1050..18e45511a4 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -688,7 +688,7 @@ impl<'a> InferenceContext<'a> {
}
}
- /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
+ /// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty.kind(Interner) {
TyKind::Error => self.table.new_type_var(),
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index b1f4de8260..d4050f9af4 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -152,11 +152,20 @@ impl<'a> InferenceContext<'a> {
.1
}
Expr::TryBlock { body } => {
- self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
- let _inner = this.infer_expr(*body, expected);
+ // The type that is returned from the try block
+ let try_ty = self.table.new_type_var();
+ if let Some(ty) = expected.only_has_type(&mut self.table) {
+ self.unify(&try_ty, &ty);
+ }
+
+ // The ok-ish type that is expected from the last expression
+ let ok_ty = self.resolve_associated_type(try_ty.clone(), self.resolve_ops_try_ok());
+
+ self.with_breakable_ctx(BreakableKind::Block, ok_ty.clone(), None, |this| {
+ this.infer_expr(*body, &Expectation::has_type(ok_ty));
});
- // FIXME should be std::result::Result<{inner}, _>
- self.err_ty()
+
+ try_ty
}
Expr::Async { body } => {
let ret_ty = self.table.new_type_var();
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index d7431443b8..146145523b 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -2064,17 +2064,17 @@ fn fn_pointer_return() {
fn block_modifiers_smoke_test() {
check_infer(
r#"
-//- minicore: future
+//- minicore: future, try
async fn main() {
let x = unsafe { 92 };
let y = async { async { () }.await };
- let z = try { () };
+ let z: core::ops::ControlFlow<(), _> = try { () };
let w = const { 92 };
let t = 'a: { 92 };
}
"#,
expect![[r#"
- 16..162 '{ ...2 }; }': ()
+ 16..193 '{ ...2 }; }': ()
26..27 'x': i32
30..43 'unsafe { 92 }': i32
30..43 'unsafe { 92 }': i32
@@ -2086,17 +2086,17 @@ async fn main() {
65..77 'async { () }': impl Future<Output = ()>
65..83 'async ....await': ()
73..75 '()': ()
- 95..96 'z': {unknown}
- 99..109 'try { () }': ()
- 99..109 'try { () }': {unknown}
- 105..107 '()': ()
- 119..120 'w': i32
- 123..135 'const { 92 }': i32
- 123..135 'const { 92 }': i32
- 131..133 '92': i32
- 145..146 't': i32
- 149..159 ''a: { 92 }': i32
- 155..157 '92': i32
+ 95..96 'z': ControlFlow<(), ()>
+ 130..140 'try { () }': ()
+ 130..140 'try { () }': ControlFlow<(), ()>
+ 136..138 '()': ()
+ 150..151 'w': i32
+ 154..166 'const { 92 }': i32
+ 154..166 'const { 92 }': i32
+ 162..164 '92': i32
+ 176..177 't': i32
+ 180..190 ''a: { 92 }': i32
+ 186..188 '92': i32
"#]],
)
}
diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index 0c92e706b3..10e637979f 100644
--- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -38,12 +38,12 @@ fn foo() {
}
#[test]
- fn try_blocks_are_borders() {
+ fn async_blocks_are_borders() {
check_diagnostics(
r#"
fn foo() {
'a: loop {
- try {
+ async {
break;
//^^^^^ error: break outside of loop
break 'a;
@@ -60,12 +60,12 @@ fn foo() {
}
#[test]
- fn async_blocks_are_borders() {
+ fn closures_are_borders() {
check_diagnostics(
r#"
fn foo() {
'a: loop {
- try {
+ || {
break;
//^^^^^ error: break outside of loop
break 'a;
@@ -82,21 +82,17 @@ fn foo() {
}
#[test]
- fn closures_are_borders() {
+ fn blocks_pass_through() {
check_diagnostics(
r#"
fn foo() {
'a: loop {
- try {
- break;
- //^^^^^ error: break outside of loop
- break 'a;
- //^^^^^^^^ error: break outside of loop
- continue;
- //^^^^^^^^ error: continue outside of loop
- continue 'a;
- //^^^^^^^^^^^ error: continue outside of loop
- };
+ {
+ break;
+ break 'a;
+ continue;
+ continue 'a;
+ }
}
}
"#,
@@ -104,17 +100,17 @@ fn foo() {
}
#[test]
- fn blocks_pass_through() {
+ fn try_blocks_pass_through() {
check_diagnostics(
r#"
fn foo() {
'a: loop {
- {
- break;
- break 'a;
- continue;
- continue 'a;
- }
+ try {
+ break;
+ break 'a;
+ continue;
+ continue 'a;
+ };
}
}
"#,