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
This commit is contained in:
bors 2022-12-30 21:35:46 +00:00
commit ea8897c9be
4 changed files with 48 additions and 43 deletions

View File

@ -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 { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty.kind(Interner) { match ty.kind(Interner) {
TyKind::Error => self.table.new_type_var(), TyKind::Error => self.table.new_type_var(),

View File

@ -152,11 +152,20 @@ impl<'a> InferenceContext<'a> {
.1 .1
} }
Expr::TryBlock { body } => { Expr::TryBlock { body } => {
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { // The type that is returned from the try block
let _inner = this.infer_expr(*body, expected); 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 } => { Expr::Async { body } => {
let ret_ty = self.table.new_type_var(); let ret_ty = self.table.new_type_var();

View File

@ -2064,17 +2064,17 @@ fn fn_pointer_return() {
fn block_modifiers_smoke_test() { fn block_modifiers_smoke_test() {
check_infer( check_infer(
r#" r#"
//- minicore: future //- minicore: future, try
async fn main() { async fn main() {
let x = unsafe { 92 }; let x = unsafe { 92 };
let y = async { async { () }.await }; let y = async { async { () }.await };
let z = try { () }; let z: core::ops::ControlFlow<(), _> = try { () };
let w = const { 92 }; let w = const { 92 };
let t = 'a: { 92 }; let t = 'a: { 92 };
} }
"#, "#,
expect![[r#" expect![[r#"
16..162 '{ ...2 }; }': () 16..193 '{ ...2 }; }': ()
26..27 'x': i32 26..27 'x': i32
30..43 'unsafe { 92 }': i32 30..43 'unsafe { 92 }': 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..77 'async { () }': impl Future<Output = ()>
65..83 'async ....await': () 65..83 'async ....await': ()
73..75 '()': () 73..75 '()': ()
95..96 'z': {unknown} 95..96 'z': ControlFlow<(), ()>
99..109 'try { () }': () 130..140 'try { () }': ()
99..109 'try { () }': {unknown} 130..140 'try { () }': ControlFlow<(), ()>
105..107 '()': () 136..138 '()': ()
119..120 'w': i32 150..151 'w': i32
123..135 'const { 92 }': i32 154..166 'const { 92 }': i32
123..135 'const { 92 }': i32 154..166 'const { 92 }': i32
131..133 '92': i32 162..164 '92': i32
145..146 't': i32 176..177 't': i32
149..159 ''a: { 92 }': i32 180..190 ''a: { 92 }': i32
155..157 '92': i32 186..188 '92': i32
"#]], "#]],
) )
} }

View File

@ -37,35 +37,13 @@ fn foo() {
); );
} }
#[test]
fn try_blocks_are_borders() {
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
};
}
}
"#,
);
}
#[test] #[test]
fn async_blocks_are_borders() { fn async_blocks_are_borders() {
check_diagnostics( check_diagnostics(
r#" r#"
fn foo() { fn foo() {
'a: loop { 'a: loop {
try { async {
break; break;
//^^^^^ error: break outside of loop //^^^^^ error: break outside of loop
break 'a; break 'a;
@ -87,7 +65,7 @@ fn foo() {
r#" r#"
fn foo() { fn foo() {
'a: loop { 'a: loop {
try { || {
break; break;
//^^^^^ error: break outside of loop //^^^^^ error: break outside of loop
break 'a; break 'a;
@ -121,6 +99,24 @@ fn foo() {
); );
} }
#[test]
fn try_blocks_pass_through() {
check_diagnostics(
r#"
fn foo() {
'a: loop {
try {
break;
break 'a;
continue;
continue 'a;
};
}
}
"#,
);
}
#[test] #[test]
fn label_blocks() { fn label_blocks() {
check_diagnostics( check_diagnostics(