mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Handle tuple structs / enum variants properly in type inference
This commit is contained in:
parent
a725dd4f7a
commit
b82db68400
5 changed files with 95 additions and 37 deletions
|
@ -290,7 +290,11 @@ impl Struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
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
|
// TODO move to a more general type
|
||||||
|
@ -350,7 +354,7 @@ impl Enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty(&self, db: &impl HirDatabase) -> Ty {
|
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
|
// TODO: move to a more general type
|
||||||
|
@ -425,7 +429,7 @@ pub struct Function {
|
||||||
pub(crate) id: FunctionId,
|
pub(crate) id: FunctionId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::expr::ScopeEntryWithSyntax;
|
pub use crate::{ nameres::Namespace, expr::ScopeEntryWithSyntax};
|
||||||
|
|
||||||
/// The declared signature of a function.
|
/// The declared signature of a function.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
adt::{StructData, EnumData},
|
adt::{StructData, EnumData},
|
||||||
impl_block::{ModuleImplBlocks, ImplSourceMap},
|
impl_block::{ModuleImplBlocks, ImplSourceMap},
|
||||||
generics::{GenericParams, GenericDef},
|
generics::{GenericParams, GenericDef},
|
||||||
ids::SourceFileItemId,
|
ids::SourceFileItemId, nameres::Namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
#[salsa::query_group(PersistentHirDatabaseStorage)]
|
#[salsa::query_group(PersistentHirDatabaseStorage)]
|
||||||
|
@ -88,7 +88,7 @@ pub trait HirDatabase: PersistentHirDatabase {
|
||||||
fn infer(&self, func: Function) -> Arc<InferenceResult>;
|
fn infer(&self, func: Function) -> Arc<InferenceResult>;
|
||||||
|
|
||||||
#[salsa::invoke(crate::ty::type_for_def)]
|
#[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)]
|
#[salsa::invoke(crate::ty::type_for_field)]
|
||||||
fn type_for_field(&self, field: StructField) -> Ty;
|
fn type_for_field(&self, field: StructField) -> Ty;
|
||||||
|
|
|
@ -348,7 +348,7 @@ where
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|variant| {
|
||||||
let res = Resolution {
|
let res = Resolution {
|
||||||
def: PerNs::both(variant.into(), e.into()),
|
def: PerNs::both(variant.into(), variant.into()),
|
||||||
import: Some(import_id),
|
import: Some(import_id),
|
||||||
};
|
};
|
||||||
let name = variant.name(self.db)?;
|
let name = variant.name(self.db)?;
|
||||||
|
@ -628,7 +628,7 @@ impl ItemMap {
|
||||||
// enum variant
|
// enum variant
|
||||||
tested_by!(item_map_enum_importing);
|
tested_by!(item_map_enum_importing);
|
||||||
match e.variant(db, &segment.name) {
|
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(),
|
None => PerNs::none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ use crate::{
|
||||||
generics::GenericParams,
|
generics::GenericParams,
|
||||||
path::GenericArg,
|
path::GenericArg,
|
||||||
adt::VariantDef,
|
adt::VariantDef,
|
||||||
resolve::{Resolver, Resolution},
|
resolve::{Resolver, Resolution}, nameres::Namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The ID of a type variable.
|
/// The ID of a type variable.
|
||||||
|
@ -226,6 +226,8 @@ pub enum Ty {
|
||||||
/// function has a unique type, which is output (for a function
|
/// function has a unique type, which is output (for a function
|
||||||
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
|
/// 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:
|
/// For example the type of `bar` here:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
@ -233,8 +235,8 @@ pub enum Ty {
|
||||||
/// let bar = foo; // bar: fn() -> i32 {foo}
|
/// let bar = foo; // bar: fn() -> i32 {foo}
|
||||||
/// ```
|
/// ```
|
||||||
FnDef {
|
FnDef {
|
||||||
// Function definition
|
/// The definition of the function / constructor.
|
||||||
def: Function,
|
def: CallableDef,
|
||||||
/// For display
|
/// For display
|
||||||
name: Name,
|
name: Name,
|
||||||
/// Parameters and return type
|
/// Parameters and return type
|
||||||
|
@ -396,7 +398,7 @@ impl Ty {
|
||||||
None => return Ty::Unknown,
|
None => return Ty::Unknown,
|
||||||
Some(it) => it,
|
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);
|
let substs = Ty::substs_from_path(db, resolver, path, typable);
|
||||||
ty.apply_substs(substs)
|
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 output = Ty::from_hir(db, &resolver, signature.ret_type());
|
||||||
let sig = Arc::new(FnSig { input, output });
|
let sig = Arc::new(FnSig { input, output });
|
||||||
let substs = make_substs(&generics);
|
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 {
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum TypableDef {
|
pub enum TypableDef {
|
||||||
Function(Function),
|
Function(Function),
|
||||||
|
@ -735,12 +771,26 @@ impl From<ModuleDef> for Option<TypableDef> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty {
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
match def {
|
pub enum CallableDef {
|
||||||
TypableDef::Function(f) => type_for_fn(db, f),
|
Function(Function),
|
||||||
TypableDef::Struct(s) => type_for_struct(db, s),
|
Struct(Struct),
|
||||||
TypableDef::Enum(e) => type_for_enum(db, e),
|
EnumVariant(EnumVariant),
|
||||||
TypableDef::EnumVariant(v) => type_for_enum_variant(db, v),
|
}
|
||||||
|
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 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let typable: Option<TypableDef> = def.into();
|
let typable: Option<TypableDef> = def.into();
|
||||||
let typable = typable?;
|
let typable = typable?;
|
||||||
let substs = Ty::substs_from_path(self.db, &self.resolver, path, 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);
|
let ty = self.insert_type_vars(ty);
|
||||||
Some(ty)
|
Some(ty)
|
||||||
}
|
}
|
||||||
|
@ -1178,12 +1228,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let substs = Ty::substs_from_path(self.db, resolver, path, def);
|
let substs = Ty::substs_from_path(self.db, resolver, path, def);
|
||||||
match def {
|
match def {
|
||||||
TypableDef::Struct(s) => {
|
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));
|
let ty = self.insert_type_vars(ty.apply_substs(substs));
|
||||||
(ty, Some(s.into()))
|
(ty, Some(s.into()))
|
||||||
}
|
}
|
||||||
TypableDef::EnumVariant(var) => {
|
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));
|
let ty = self.insert_type_vars(ty.apply_substs(substs));
|
||||||
(ty, Some(var.into()))
|
(ty, Some(var.into()))
|
||||||
}
|
}
|
||||||
|
@ -1384,7 +1434,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
|
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
|
||||||
Some((ty, func)) => {
|
Some((ty, func)) => {
|
||||||
self.write_method_resolution(tgt_expr, 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),
|
None => (Ty::Unknown, receiver_ty, None),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
---
|
---
|
||||||
created: "2019-01-24T14:51:32.808861856+00:00"
|
created: "2019-02-17T16:16:58.863630956Z"
|
||||||
creator: insta@0.5.2
|
creator: insta@0.6.2
|
||||||
expression: "&result"
|
|
||||||
source: crates/ra_hir/src/ty/tests.rs
|
source: crates/ra_hir/src/ty/tests.rs
|
||||||
|
expression: "&result"
|
||||||
---
|
---
|
||||||
[72; 154) '{ ...a.c; }': ()
|
[72; 154) '{ ...a.c; }': ()
|
||||||
[82; 83) 'c': [unknown]
|
[82; 83) 'c': C
|
||||||
[86; 87) 'C': C
|
[86; 87) 'C': fn C(usize) -> C
|
||||||
[86; 90) 'C(1)': [unknown]
|
[86; 90) 'C(1)': C
|
||||||
[88; 89) '1': i32
|
[88; 89) '1': usize
|
||||||
[96; 97) 'B': B
|
[96; 97) 'B': B
|
||||||
[107; 108) 'a': A
|
[107; 108) 'a': A
|
||||||
[114; 133) 'A { b:...C(1) }': A
|
[114; 133) 'A { b:...C(1) }': A
|
||||||
[121; 122) 'B': B
|
[121; 122) 'B': B
|
||||||
[127; 128) 'C': C
|
[127; 128) 'C': fn C(usize) -> C
|
||||||
[127; 131) 'C(1)': C
|
[127; 131) 'C(1)': C
|
||||||
[129; 130) '1': i32
|
[129; 130) '1': usize
|
||||||
[139; 140) 'a': A
|
[139; 140) 'a': A
|
||||||
[139; 142) 'a.b': B
|
[139; 142) 'a.b': B
|
||||||
[148; 149) 'a': A
|
[148; 149) 'a': A
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue