Handle tuple structs / enum variants properly in type inference

This commit is contained in:
Florian Diebold 2019-02-17 17:29:51 +01:00
parent a725dd4f7a
commit b82db68400
5 changed files with 95 additions and 37 deletions

View File

@ -290,7 +290,11 @@ pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericPara
}
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
db.type_for_def((*self).into())
db.type_for_def((*self).into(), Namespace::Types)
}
pub fn constructor_ty(&self, db: &impl HirDatabase) -> Ty {
db.type_for_def((*self).into(), Namespace::Values)
}
// TODO move to a more general type
@ -350,7 +354,7 @@ pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericPara
}
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
db.type_for_def((*self).into())
db.type_for_def((*self).into(), Namespace::Types)
}
// TODO: move to a more general type
@ -425,7 +429,7 @@ pub struct Function {
pub(crate) id: FunctionId,
}
pub use crate::expr::ScopeEntryWithSyntax;
pub use crate::{ nameres::Namespace, expr::ScopeEntryWithSyntax};
/// The declared signature of a function.
#[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -15,7 +15,7 @@
adt::{StructData, EnumData},
impl_block::{ModuleImplBlocks, ImplSourceMap},
generics::{GenericParams, GenericDef},
ids::SourceFileItemId,
ids::SourceFileItemId, nameres::Namespace
};
#[salsa::query_group(PersistentHirDatabaseStorage)]
@ -88,7 +88,7 @@ pub trait HirDatabase: PersistentHirDatabase {
fn infer(&self, func: Function) -> Arc<InferenceResult>;
#[salsa::invoke(crate::ty::type_for_def)]
fn type_for_def(&self, def: TypableDef) -> Ty;
fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
#[salsa::invoke(crate::ty::type_for_field)]
fn type_for_field(&self, field: StructField) -> Ty;

View File

@ -348,7 +348,7 @@ fn resolve_import(
.into_iter()
.filter_map(|variant| {
let res = Resolution {
def: PerNs::both(variant.into(), e.into()),
def: PerNs::both(variant.into(), variant.into()),
import: Some(import_id),
};
let name = variant.name(self.db)?;
@ -628,7 +628,7 @@ fn resolve_path_fp(
// enum variant
tested_by!(item_map_enum_importing);
match e.variant(db, &segment.name) {
Some(variant) => PerNs::both(variant.into(), (*e).into()),
Some(variant) => PerNs::both(variant.into(), variant.into()),
None => PerNs::none(),
}
}

View File

@ -42,7 +42,7 @@
generics::GenericParams,
path::GenericArg,
adt::VariantDef,
resolve::{Resolver, Resolution},
resolve::{Resolver, Resolution}, nameres::Namespace
};
/// The ID of a type variable.
@ -226,6 +226,8 @@ pub enum Ty {
/// function has a unique type, which is output (for a function
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
///
/// This includes tuple struct / enum variant constructors as well.
///
/// For example the type of `bar` here:
///
/// ```rust
@ -233,8 +235,8 @@ pub enum Ty {
/// let bar = foo; // bar: fn() -> i32 {foo}
/// ```
FnDef {
// Function definition
def: Function,
/// The definition of the function / constructor.
def: CallableDef,
/// For display
name: Name,
/// Parameters and return type
@ -396,7 +398,7 @@ pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &P
None => return Ty::Unknown,
Some(it) => it,
};
let ty = db.type_for_def(typable);
let ty = db.type_for_def(typable, Namespace::Types);
let substs = Ty::substs_from_path(db, resolver, path, typable);
ty.apply_substs(substs)
}
@ -673,7 +675,47 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
let output = Ty::from_hir(db, &resolver, signature.ret_type());
let sig = Arc::new(FnSig { input, output });
let substs = make_substs(&generics);
Ty::FnDef { def, sig, name, substs }
Ty::FnDef { def: def.into(), sig, name, substs }
}
/// Compute the type of a tuple struct constructor.
fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
let var_data = def.variant_data(db);
let fields = match var_data.fields() {
Some(fields) => fields,
None => return type_for_struct(db, def), // Unit struct
};
let resolver = def.resolver(db);
let generics = def.generic_params(db);
let name = def.name(db).unwrap_or_else(Name::missing);
let input = fields
.iter()
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
.collect::<Vec<_>>();
let output = type_for_struct(db, def);
let sig = Arc::new(FnSig { input, output });
let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), sig, name, substs }
}
/// Compute the type of a tuple enum variant constructor.
fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
let var_data = def.variant_data(db);
let fields = match var_data.fields() {
Some(fields) => fields,
None => return type_for_enum(db, def.parent_enum(db)), // Unit variant
};
let resolver = def.parent_enum(db).resolver(db);
let generics = def.parent_enum(db).generic_params(db);
let name = def.name(db).unwrap_or_else(Name::missing);
let input = fields
.iter()
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
.collect::<Vec<_>>();
let output = type_for_enum(db, def.parent_enum(db));
let sig = Arc::new(FnSig { input, output });
let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), sig, name, substs }
}
fn make_substs(generics: &GenericParams) -> Substs {
@ -703,12 +745,6 @@ pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
}
}
pub(crate) fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> Ty {
let enum_parent = ev.parent_enum(db);
type_for_enum(db, enum_parent)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TypableDef {
Function(Function),
@ -735,12 +771,26 @@ fn from(def: ModuleDef) -> Option<TypableDef> {
}
}
pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
match def {
TypableDef::Function(f) => type_for_fn(db, f),
TypableDef::Struct(s) => type_for_struct(db, s),
TypableDef::Enum(e) => type_for_enum(db, e),
TypableDef::EnumVariant(v) => type_for_enum_variant(db, v),
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CallableDef {
Function(Function),
Struct(Struct),
EnumVariant(EnumVariant),
}
impl_froms!(CallableDef: Function, Struct, EnumVariant);
pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace) -> Ty {
match (def, ns) {
(TypableDef::Function(f), Namespace::Values) => type_for_fn(db, f),
(TypableDef::Struct(s), Namespace::Types) => type_for_struct(db, s),
(TypableDef::Struct(s), Namespace::Values) => type_for_struct_constructor(db, s),
(TypableDef::Enum(e), Namespace::Types) => type_for_enum(db, e),
(TypableDef::EnumVariant(v), Namespace::Values) => type_for_enum_variant_constructor(db, v),
// 'error' cases:
(TypableDef::Function(_), Namespace::Types) => Ty::Unknown,
(TypableDef::Enum(_), Namespace::Values) => Ty::Unknown,
(TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown,
}
}
@ -1127,7 +1177,7 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> {
let typable: Option<TypableDef> = def.into();
let typable = typable?;
let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
let ty = self.db.type_for_def(typable).apply_substs(substs);
let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
let ty = self.insert_type_vars(ty);
Some(ty)
}
@ -1178,12 +1228,12 @@ fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) {
let substs = Ty::substs_from_path(self.db, resolver, path, def);
match def {
TypableDef::Struct(s) => {
let ty = type_for_struct(self.db, s);
let ty = s.ty(self.db);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(s.into()))
}
TypableDef::EnumVariant(var) => {
let ty = type_for_enum_variant(self.db, var);
let ty = var.parent_enum(self.db).ty(self.db);
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(var.into()))
}
@ -1384,7 +1434,11 @@ fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
Some((ty, func)) => {
self.write_method_resolution(tgt_expr, func);
(ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
(
ty,
self.db.type_for_def(func.into(), Namespace::Values),
Some(func.generic_params(self.db)),
)
}
None => (Ty::Unknown, receiver_ty, None),
};

View File

@ -1,21 +1,21 @@
---
created: "2019-01-24T14:51:32.808861856+00:00"
creator: insta@0.5.2
expression: "&result"
created: "2019-02-17T16:16:58.863630956Z"
creator: insta@0.6.2
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[72; 154) '{ ...a.c; }': ()
[82; 83) 'c': [unknown]
[86; 87) 'C': C
[86; 90) 'C(1)': [unknown]
[88; 89) '1': i32
[82; 83) 'c': C
[86; 87) 'C': fn C(usize) -> C
[86; 90) 'C(1)': C
[88; 89) '1': usize
[96; 97) 'B': B
[107; 108) 'a': A
[114; 133) 'A { b:...C(1) }': A
[121; 122) 'B': B
[127; 128) 'C': C
[127; 128) 'C': fn C(usize) -> C
[127; 131) 'C(1)': C
[129; 130) '1': i32
[129; 130) '1': usize
[139; 140) 'a': A
[139; 142) 'a.b': B
[148; 149) 'a': A