mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #7627
7627: infer: update resolver when descending into block r=jonas-schievink a=jonas-schievink Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
commit
7ec03439a8
5 changed files with 139 additions and 32 deletions
|
@ -1495,6 +1495,20 @@ fn main(f: Foo) {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn internal_or() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
fn main() {
|
||||
enum Either { A(bool), B }
|
||||
match Either::B {
|
||||
//^^^^^^^^^ Missing match arm
|
||||
Either::A(true | false) => (),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
mod false_negatives {
|
||||
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
||||
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
||||
|
@ -1518,21 +1532,6 @@ fn main() {
|
|||
11..20 => (),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn internal_or() {
|
||||
// We do not currently handle patterns with internal `or`s.
|
||||
check_diagnostics(
|
||||
r#"
|
||||
fn main() {
|
||||
enum Either { A(bool), B }
|
||||
match Either::B {
|
||||
Either::A(true | false) => (),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -137,24 +137,33 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
self.coerce_merge_branch(&then_ty, &else_ty)
|
||||
}
|
||||
Expr::Block { statements, tail, label, id: _ } => match label {
|
||||
Some(_) => {
|
||||
let break_ty = self.table.new_type_var();
|
||||
self.breakables.push(BreakableContext {
|
||||
may_break: false,
|
||||
break_ty: break_ty.clone(),
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
let ty = self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
|
||||
let ctxt = self.breakables.pop().expect("breakable stack broken");
|
||||
if ctxt.may_break {
|
||||
ctxt.break_ty
|
||||
} else {
|
||||
ty
|
||||
Expr::Block { statements, tail, label, id: _ } => {
|
||||
let old_resolver = mem::replace(
|
||||
&mut self.resolver,
|
||||
resolver_for_expr(self.db.upcast(), self.owner, tgt_expr),
|
||||
);
|
||||
let ty = match label {
|
||||
Some(_) => {
|
||||
let break_ty = self.table.new_type_var();
|
||||
self.breakables.push(BreakableContext {
|
||||
may_break: false,
|
||||
break_ty: break_ty.clone(),
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
let ty =
|
||||
self.infer_block(statements, *tail, &Expectation::has_type(break_ty));
|
||||
let ctxt = self.breakables.pop().expect("breakable stack broken");
|
||||
if ctxt.may_break {
|
||||
ctxt.break_ty
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self.infer_block(statements, *tail, expected),
|
||||
},
|
||||
None => self.infer_block(statements, *tail, expected),
|
||||
};
|
||||
self.resolver = old_resolver;
|
||||
ty
|
||||
}
|
||||
Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
|
||||
Expr::TryBlock { body } => {
|
||||
let _inner = self.infer_expr(*body, expected);
|
||||
|
|
|
@ -2415,3 +2415,50 @@ fn infer_const_params() {
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_inner_type() {
|
||||
check_infer(
|
||||
r#"
|
||||
fn foo() {
|
||||
struct S { field: u32 }
|
||||
let s = S { field: 0 };
|
||||
let f = s.field;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
9..89 '{ ...eld; }': ()
|
||||
47..48 's': S
|
||||
51..65 'S { field: 0 }': S
|
||||
62..63 '0': u32
|
||||
75..76 'f': u32
|
||||
79..80 's': S
|
||||
79..86 's.field': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_nested_inner_type() {
|
||||
check_infer(
|
||||
r#"
|
||||
fn foo() {
|
||||
{
|
||||
let s = S { field: 0 };
|
||||
let f = s.field;
|
||||
}
|
||||
struct S { field: u32 }
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
9..109 '{ ...32 } }': ()
|
||||
15..79 '{ ... }': ()
|
||||
29..30 's': S
|
||||
33..47 'S { field: 0 }': S
|
||||
44..45 '0': u32
|
||||
61..62 'f': u32
|
||||
65..66 's': S
|
||||
65..72 's.field': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3151,3 +3151,54 @@ fn test() {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_use() {
|
||||
check_types(
|
||||
r#"
|
||||
mod m {
|
||||
pub trait Tr {
|
||||
fn method(&self) -> u8 { 0 }
|
||||
}
|
||||
|
||||
impl Tr for () {}
|
||||
}
|
||||
|
||||
fn f() {
|
||||
use m::Tr;
|
||||
|
||||
().method();
|
||||
//^^^^^^^^^^^ u8
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_use_in_block() {
|
||||
check_types(
|
||||
r#"
|
||||
mod m {
|
||||
pub trait Tr {
|
||||
fn method(&self) -> u8 { 0 }
|
||||
}
|
||||
|
||||
impl Tr for () {}
|
||||
}
|
||||
|
||||
fn f() {
|
||||
{
|
||||
use m::Tr;
|
||||
|
||||
().method();
|
||||
//^^^^^^^^^^^ u8
|
||||
}
|
||||
|
||||
{
|
||||
().method();
|
||||
//^^^^^^^^^^^ {unknown}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -654,6 +654,7 @@ fn main() {
|
|||
let test = "test";
|
||||
//^^^^ &str
|
||||
let test = InnerStruct {};
|
||||
//^^^^ InnerStruct
|
||||
|
||||
let test = unresolved();
|
||||
|
||||
|
|
Loading…
Reference in a new issue