mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 11:59:49 +00:00
Add crude implementation of tuplestruct pattern inference
This commit is contained in:
parent
3b0de53904
commit
9c2d83a4c8
3 changed files with 89 additions and 40 deletions
|
@ -877,7 +877,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty {
|
||||
let body = Arc::clone(&self.body); // avoid borrow checker problem
|
||||
|
||||
match (&body[pat], &expected.ty) {
|
||||
let ty = match (&body[pat], &expected.ty) {
|
||||
(Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args))
|
||||
if args.len() == tuple_args.len() =>
|
||||
{
|
||||
|
@ -885,42 +885,71 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
// FIXME: can we do w/o cloning?
|
||||
self.infer_pat(pat, &Expectation::has_type(ty.clone()));
|
||||
}
|
||||
expected.ty.clone()
|
||||
}
|
||||
(&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut))
|
||||
if mutability == ty_mut =>
|
||||
{
|
||||
self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone()));
|
||||
expected.ty.clone()
|
||||
}
|
||||
(pattern, &Ty::Adt { def_id, .. }) => {
|
||||
let adt_def = def_id.resolve(self.db);
|
||||
match (pattern, adt_def) {
|
||||
(&Pat::Struct, Def::Struct(s)) => {}
|
||||
(
|
||||
&Pat::TupleStruct {
|
||||
path: ref p,
|
||||
args: ref sub_pats,
|
||||
},
|
||||
Def::Enum(ref e),
|
||||
) => {
|
||||
// TODO: resolve enum
|
||||
(
|
||||
&Pat::TupleStruct {
|
||||
path: ref p,
|
||||
args: ref sub_pats,
|
||||
},
|
||||
_expected,
|
||||
) => {
|
||||
let def = p
|
||||
.as_ref()
|
||||
.and_then(|path| self.module.resolve_path(self.db, &path).take_types())
|
||||
.map(|def_id| def_id.resolve(self.db));
|
||||
|
||||
if let Some(def) = def {
|
||||
let (ty, fields) = match def {
|
||||
Def::Struct(s) => {
|
||||
let fields: Vec<_> = self
|
||||
.db
|
||||
.struct_data(s.def_id())
|
||||
.variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
(type_for_struct(self.db, s), fields)
|
||||
}
|
||||
Def::EnumVariant(ev) => {
|
||||
let fields: Vec<_> =
|
||||
ev.variant_data(self.db).fields().iter().cloned().collect();
|
||||
(type_for_enum_variant(self.db, ev), fields)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// walk subpats
|
||||
if fields.len() == sub_pats.len() {
|
||||
for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) {
|
||||
let sub_ty = Ty::from_hir(
|
||||
self.db,
|
||||
&self.module,
|
||||
self.impl_block.as_ref(),
|
||||
&field.type_ref,
|
||||
);
|
||||
|
||||
self.infer_pat(sub_pat, &Expectation::has_type(sub_ty));
|
||||
}
|
||||
|
||||
ty
|
||||
} else {
|
||||
expected.ty.clone()
|
||||
}
|
||||
(
|
||||
&Pat::TupleStruct {
|
||||
path: ref p,
|
||||
args: ref sub_pats,
|
||||
},
|
||||
Def::EnumVariant(ref e),
|
||||
) => {
|
||||
let variant_data = self.db.enum_variant_data(e.def_id);
|
||||
}
|
||||
_ => {}
|
||||
} else {
|
||||
expected.ty.clone()
|
||||
}
|
||||
}
|
||||
// TODO: implement more
|
||||
(_, ref _expected_ty) => {}
|
||||
(_, ref _expected_ty) => expected.ty.clone(),
|
||||
};
|
||||
// use a new type variable if we got Ty::Unknown here
|
||||
let ty = self.insert_type_vars_shallow(expected.ty.clone());
|
||||
let ty = self.insert_type_vars_shallow(ty);
|
||||
self.unify(&ty, &expected.ty);
|
||||
let ty = self.resolve_ty_as_possible(ty);
|
||||
self.write_pat_ty(pat, ty.clone());
|
||||
|
|
|
@ -359,7 +359,22 @@ fn test(x: &str, y: isize) {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn infer_pattern() {
|
||||
fn infer_simple_pattern() {
|
||||
check_inference(
|
||||
r#"
|
||||
fn test(x: &i32) {
|
||||
let y = x;
|
||||
let &z = x;
|
||||
let a = z;
|
||||
let (c, d) = (1, "hello");
|
||||
}
|
||||
"#,
|
||||
"pattern.txt",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_adt_pattern() {
|
||||
check_inference(
|
||||
r#"
|
||||
enum E {
|
||||
|
@ -367,23 +382,16 @@ enum E {
|
|||
B
|
||||
}
|
||||
|
||||
fn test(x: &i32) {
|
||||
let y = x;
|
||||
let &z = x;
|
||||
let a = z;
|
||||
let (c, d) = (1, "hello");
|
||||
struct S(u32, E);
|
||||
|
||||
fn test() {
|
||||
let e = E::A { x: 3 };
|
||||
if let E::A { x: x } = e {
|
||||
x
|
||||
};
|
||||
match e {
|
||||
E::A { x } => x,
|
||||
E::B => 1,
|
||||
};
|
||||
|
||||
let S(y, z) = foo;
|
||||
let E::A { x: new_var } = e;
|
||||
}
|
||||
"#,
|
||||
"pattern.txt",
|
||||
"adt_pattern.txt",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
12
crates/ra_hir/src/ty/tests/data/adt_pattern.txt
Normal file
12
crates/ra_hir/src/ty/tests/data/adt_pattern.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
[49; 192) '{ ... }; }': ()
|
||||
[59; 60) 'e': E
|
||||
[63; 76) 'E::A { x: 3 }': E
|
||||
[73; 74) '3': usize
|
||||
[82; 124) 'if let... }': [unknown]
|
||||
[105; 106) 'e': E
|
||||
[107; 124) '{ ... }': [unknown]
|
||||
[117; 118) 'x': [unknown]
|
||||
[130; 189) 'match ... }': [unknown]
|
||||
[136; 137) 'e': E
|
||||
[162; 163) 'x': [unknown]
|
||||
[181; 182) '1': i32
|
Loading…
Add table
Add a link
Reference in a new issue