diff options
author | Florian Diebold <[email protected]> | 2019-02-17 16:29:51 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-17 19:53:13 +0000 |
commit | b82db684003b817d47c1bc8c0d3c6afc88be2663 (patch) | |
tree | 7ec419545aee3e4f7297c6792eec1efebba4eb24 /crates/ra_hir | |
parent | a725dd4f7ac2b88541189f0f726ce86876c36add (diff) |
Handle tuple structs / enum variants properly in type inference
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 96 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap | 18 |
5 files changed, 95 insertions, 37 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 26ebc445b..9da8a482d 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -290,7 +290,11 @@ impl Struct { | |||
290 | } | 290 | } |
291 | 291 | ||
292 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 292 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
293 | db.type_for_def((*self).into()) | 293 | db.type_for_def((*self).into(), Namespace::Types) |
294 | } | ||
295 | |||
296 | pub fn constructor_ty(&self, db: &impl HirDatabase) -> Ty { | ||
297 | db.type_for_def((*self).into(), Namespace::Values) | ||
294 | } | 298 | } |
295 | 299 | ||
296 | // TODO move to a more general type | 300 | // TODO move to a more general type |
@@ -350,7 +354,7 @@ impl Enum { | |||
350 | } | 354 | } |
351 | 355 | ||
352 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 356 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
353 | db.type_for_def((*self).into()) | 357 | db.type_for_def((*self).into(), Namespace::Types) |
354 | } | 358 | } |
355 | 359 | ||
356 | // TODO: move to a more general type | 360 | // TODO: move to a more general type |
@@ -425,7 +429,7 @@ pub struct Function { | |||
425 | pub(crate) id: FunctionId, | 429 | pub(crate) id: FunctionId, |
426 | } | 430 | } |
427 | 431 | ||
428 | pub use crate::expr::ScopeEntryWithSyntax; | 432 | pub use crate::{ nameres::Namespace, expr::ScopeEntryWithSyntax}; |
429 | 433 | ||
430 | /// The declared signature of a function. | 434 | /// The declared signature of a function. |
431 | #[derive(Debug, Clone, PartialEq, Eq)] | 435 | #[derive(Debug, Clone, PartialEq, Eq)] |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 740a7be7a..fc0ee068c 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
17 | generics::{GenericParams, GenericDef}, | 17 | generics::{GenericParams, GenericDef}, |
18 | ids::SourceFileItemId, | 18 | ids::SourceFileItemId, nameres::Namespace |
19 | }; | 19 | }; |
20 | 20 | ||
21 | #[salsa::query_group(PersistentHirDatabaseStorage)] | 21 | #[salsa::query_group(PersistentHirDatabaseStorage)] |
@@ -88,7 +88,7 @@ pub trait HirDatabase: PersistentHirDatabase { | |||
88 | fn infer(&self, func: Function) -> Arc<InferenceResult>; | 88 | fn infer(&self, func: Function) -> Arc<InferenceResult>; |
89 | 89 | ||
90 | #[salsa::invoke(crate::ty::type_for_def)] | 90 | #[salsa::invoke(crate::ty::type_for_def)] |
91 | fn type_for_def(&self, def: TypableDef) -> Ty; | 91 | fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; |
92 | 92 | ||
93 | #[salsa::invoke(crate::ty::type_for_field)] | 93 | #[salsa::invoke(crate::ty::type_for_field)] |
94 | fn type_for_field(&self, field: StructField) -> Ty; | 94 | fn type_for_field(&self, field: StructField) -> Ty; |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index e35b4b129..bd920bfea 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -348,7 +348,7 @@ where | |||
348 | .into_iter() | 348 | .into_iter() |
349 | .filter_map(|variant| { | 349 | .filter_map(|variant| { |
350 | let res = Resolution { | 350 | let res = Resolution { |
351 | def: PerNs::both(variant.into(), e.into()), | 351 | def: PerNs::both(variant.into(), variant.into()), |
352 | import: Some(import_id), | 352 | import: Some(import_id), |
353 | }; | 353 | }; |
354 | let name = variant.name(self.db)?; | 354 | let name = variant.name(self.db)?; |
@@ -628,7 +628,7 @@ impl ItemMap { | |||
628 | // enum variant | 628 | // enum variant |
629 | tested_by!(item_map_enum_importing); | 629 | tested_by!(item_map_enum_importing); |
630 | match e.variant(db, &segment.name) { | 630 | match e.variant(db, &segment.name) { |
631 | Some(variant) => PerNs::both(variant.into(), (*e).into()), | 631 | Some(variant) => PerNs::both(variant.into(), variant.into()), |
632 | None => PerNs::none(), | 632 | None => PerNs::none(), |
633 | } | 633 | } |
634 | } | 634 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 562ad1f49..fb98ac907 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -42,7 +42,7 @@ use crate::{ | |||
42 | generics::GenericParams, | 42 | generics::GenericParams, |
43 | path::GenericArg, | 43 | path::GenericArg, |
44 | adt::VariantDef, | 44 | adt::VariantDef, |
45 | resolve::{Resolver, Resolution}, | 45 | resolve::{Resolver, Resolution}, nameres::Namespace |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /// The ID of a type variable. | 48 | /// The ID of a type variable. |
@@ -226,6 +226,8 @@ pub enum Ty { | |||
226 | /// function has a unique type, which is output (for a function | 226 | /// function has a unique type, which is output (for a function |
227 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. | 227 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. |
228 | /// | 228 | /// |
229 | /// This includes tuple struct / enum variant constructors as well. | ||
230 | /// | ||
229 | /// For example the type of `bar` here: | 231 | /// For example the type of `bar` here: |
230 | /// | 232 | /// |
231 | /// ```rust | 233 | /// ```rust |
@@ -233,8 +235,8 @@ pub enum Ty { | |||
233 | /// let bar = foo; // bar: fn() -> i32 {foo} | 235 | /// let bar = foo; // bar: fn() -> i32 {foo} |
234 | /// ``` | 236 | /// ``` |
235 | FnDef { | 237 | FnDef { |
236 | // Function definition | 238 | /// The definition of the function / constructor. |
237 | def: Function, | 239 | def: CallableDef, |
238 | /// For display | 240 | /// For display |
239 | name: Name, | 241 | name: Name, |
240 | /// Parameters and return type | 242 | /// Parameters and return type |
@@ -396,7 +398,7 @@ impl Ty { | |||
396 | None => return Ty::Unknown, | 398 | None => return Ty::Unknown, |
397 | Some(it) => it, | 399 | Some(it) => it, |
398 | }; | 400 | }; |
399 | let ty = db.type_for_def(typable); | 401 | let ty = db.type_for_def(typable, Namespace::Types); |
400 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 402 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
401 | ty.apply_substs(substs) | 403 | ty.apply_substs(substs) |
402 | } | 404 | } |
@@ -673,7 +675,47 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | |||
673 | let output = Ty::from_hir(db, &resolver, signature.ret_type()); | 675 | let output = Ty::from_hir(db, &resolver, signature.ret_type()); |
674 | let sig = Arc::new(FnSig { input, output }); | 676 | let sig = Arc::new(FnSig { input, output }); |
675 | let substs = make_substs(&generics); | 677 | let substs = make_substs(&generics); |
676 | Ty::FnDef { def, sig, name, substs } | 678 | Ty::FnDef { def: def.into(), sig, name, substs } |
679 | } | ||
680 | |||
681 | /// Compute the type of a tuple struct constructor. | ||
682 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { | ||
683 | let var_data = def.variant_data(db); | ||
684 | let fields = match var_data.fields() { | ||
685 | Some(fields) => fields, | ||
686 | None => return type_for_struct(db, def), // Unit struct | ||
687 | }; | ||
688 | let resolver = def.resolver(db); | ||
689 | let generics = def.generic_params(db); | ||
690 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
691 | let input = fields | ||
692 | .iter() | ||
693 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
694 | .collect::<Vec<_>>(); | ||
695 | let output = type_for_struct(db, def); | ||
696 | let sig = Arc::new(FnSig { input, output }); | ||
697 | let substs = make_substs(&generics); | ||
698 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
699 | } | ||
700 | |||
701 | /// Compute the type of a tuple enum variant constructor. | ||
702 | fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty { | ||
703 | let var_data = def.variant_data(db); | ||
704 | let fields = match var_data.fields() { | ||
705 | Some(fields) => fields, | ||
706 | None => return type_for_enum(db, def.parent_enum(db)), // Unit variant | ||
707 | }; | ||
708 | let resolver = def.parent_enum(db).resolver(db); | ||
709 | let generics = def.parent_enum(db).generic_params(db); | ||
710 | let name = def.name(db).unwrap_or_else(Name::missing); | ||
711 | let input = fields | ||
712 | .iter() | ||
713 | .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) | ||
714 | .collect::<Vec<_>>(); | ||
715 | let output = type_for_enum(db, def.parent_enum(db)); | ||
716 | let sig = Arc::new(FnSig { input, output }); | ||
717 | let substs = make_substs(&generics); | ||
718 | Ty::FnDef { def: def.into(), sig, name, substs } | ||
677 | } | 719 | } |
678 | 720 | ||
679 | fn make_substs(generics: &GenericParams) -> Substs { | 721 | fn make_substs(generics: &GenericParams) -> Substs { |
@@ -703,12 +745,6 @@ pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { | |||
703 | } | 745 | } |
704 | } | 746 | } |
705 | 747 | ||
706 | pub(crate) fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> Ty { | ||
707 | let enum_parent = ev.parent_enum(db); | ||
708 | |||
709 | type_for_enum(db, enum_parent) | ||
710 | } | ||
711 | |||
712 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 748 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
713 | pub enum TypableDef { | 749 | pub enum TypableDef { |
714 | Function(Function), | 750 | Function(Function), |
@@ -735,12 +771,26 @@ impl From<ModuleDef> for Option<TypableDef> { | |||
735 | } | 771 | } |
736 | } | 772 | } |
737 | 773 | ||
738 | pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty { | 774 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
739 | match def { | 775 | pub enum CallableDef { |
740 | TypableDef::Function(f) => type_for_fn(db, f), | 776 | Function(Function), |
741 | TypableDef::Struct(s) => type_for_struct(db, s), | 777 | Struct(Struct), |
742 | TypableDef::Enum(e) => type_for_enum(db, e), | 778 | EnumVariant(EnumVariant), |
743 | TypableDef::EnumVariant(v) => type_for_enum_variant(db, v), | 779 | } |
780 | impl_froms!(CallableDef: Function, Struct, EnumVariant); | ||
781 | |||
782 | pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace) -> Ty { | ||
783 | match (def, ns) { | ||
784 | (TypableDef::Function(f), Namespace::Values) => type_for_fn(db, f), | ||
785 | (TypableDef::Struct(s), Namespace::Types) => type_for_struct(db, s), | ||
786 | (TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s), | ||
787 | (TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e), | ||
788 | (TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v), | ||
789 | |||
790 | // 'error' cases: | ||
791 | (TypableDef::Function(_), Namespace::Types) => Ty::Unknown, | ||
792 | (TypableDef::Enum(_), Namespace::Values) => Ty::Unknown, | ||
793 | (TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown, | ||
744 | } | 794 | } |
745 | } | 795 | } |
746 | 796 | ||
@@ -1127,7 +1177,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1127 | let typable: Option<TypableDef> = def.into(); | 1177 | let typable: Option<TypableDef> = def.into(); |
1128 | let typable = typable?; | 1178 | let typable = typable?; |
1129 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 1179 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
1130 | let ty = self.db.type_for_def(typable).apply_substs(substs); | 1180 | let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); |
1131 | let ty = self.insert_type_vars(ty); | 1181 | let ty = self.insert_type_vars(ty); |
1132 | Some(ty) | 1182 | Some(ty) |
1133 | } | 1183 | } |
@@ -1178,12 +1228,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1178 | let substs = Ty::substs_from_path(self.db, resolver, path, def); | 1228 | let substs = Ty::substs_from_path(self.db, resolver, path, def); |
1179 | match def { | 1229 | match def { |
1180 | TypableDef::Struct(s) => { | 1230 | TypableDef::Struct(s) => { |
1181 | let ty = type_for_struct(self.db, s); | 1231 | let ty = s.ty(self.db); |
1182 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | 1232 | let ty = self.insert_type_vars(ty.apply_substs(substs)); |
1183 | (ty, Some(s.into())) | 1233 | (ty, Some(s.into())) |
1184 | } | 1234 | } |
1185 | TypableDef::EnumVariant(var) => { | 1235 | TypableDef::EnumVariant(var) => { |
1186 | let ty = type_for_enum_variant(self.db, var); | 1236 | let ty = var.parent_enum(self.db).ty(self.db); |
1187 | let ty = self.insert_type_vars(ty.apply_substs(substs)); | 1237 | let ty = self.insert_type_vars(ty.apply_substs(substs)); |
1188 | (ty, Some(var.into())) | 1238 | (ty, Some(var.into())) |
1189 | } | 1239 | } |
@@ -1384,7 +1434,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1384 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { | 1434 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { |
1385 | Some((ty, func)) => { | 1435 | Some((ty, func)) => { |
1386 | self.write_method_resolution(tgt_expr, func); | 1436 | self.write_method_resolution(tgt_expr, func); |
1387 | (ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db))) | 1437 | ( |
1438 | ty, | ||
1439 | self.db.type_for_def(func.into(), Namespace::Values), | ||
1440 | Some(func.generic_params(self.db)), | ||
1441 | ) | ||
1388 | } | 1442 | } |
1389 | None => (Ty::Unknown, receiver_ty, None), | 1443 | None => (Ty::Unknown, receiver_ty, None), |
1390 | }; | 1444 | }; |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap index 8747fae18..294186b06 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap | |||
@@ -1,21 +1,21 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-24T14:51:32.808861856+00:00" | 2 | created: "2019-02-17T16:16:58.863630956Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | 4 | source: crates/ra_hir/src/ty/tests.rs |
5 | expression: "&result" | ||
6 | --- | 6 | --- |
7 | [72; 154) '{ ...a.c; }': () | 7 | [72; 154) '{ ...a.c; }': () |
8 | [82; 83) 'c': [unknown] | 8 | [82; 83) 'c': C |
9 | [86; 87) 'C': C | 9 | [86; 87) 'C': fn C(usize) -> C |
10 | [86; 90) 'C(1)': [unknown] | 10 | [86; 90) 'C(1)': C |
11 | [88; 89) '1': i32 | 11 | [88; 89) '1': usize |
12 | [96; 97) 'B': B | 12 | [96; 97) 'B': B |
13 | [107; 108) 'a': A | 13 | [107; 108) 'a': A |
14 | [114; 133) 'A { b:...C(1) }': A | 14 | [114; 133) 'A { b:...C(1) }': A |
15 | [121; 122) 'B': B | 15 | [121; 122) 'B': B |
16 | [127; 128) 'C': C | 16 | [127; 128) 'C': fn C(usize) -> C |
17 | [127; 131) 'C(1)': C | 17 | [127; 131) 'C(1)': C |
18 | [129; 130) '1': i32 | 18 | [129; 130) '1': usize |
19 | [139; 140) 'a': A | 19 | [139; 140) 'a': A |
20 | [139; 142) 'a.b': B | 20 | [139; 142) 'a.b': B |
21 | [148; 149) 'a': A | 21 | [148; 149) 'a': A |