Implement support for type aliases

This commit is contained in:
Florian Diebold 2019-02-24 17:25:41 +01:00
parent 5a684099e9
commit 5d72b96988
8 changed files with 102 additions and 11 deletions

View File

@ -626,6 +626,23 @@ impl Type {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
pub fn type_ref(self, db: &impl PersistentHirDatabase) -> Arc<TypeRef> {
db.type_alias_ref(self)
}
/// Builds a resolver for the type references in this type alias.
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
// take the outer scope...
let r = self
.impl_block(db)
.map(|ib| ib.resolver(db))
.unwrap_or_else(|| self.module(db).resolver(db));
// ...and add generic params, if present
let p = self.generic_params(db);
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
r
}
}
impl Docs for Type {

View File

@ -15,7 +15,7 @@ use crate::{
adt::{StructData, EnumData},
impl_block::{ModuleImplBlocks, ImplSourceMap},
generics::{GenericParams, GenericDef},
ids::SourceFileItemId, nameres::Namespace
ids::SourceFileItemId, nameres::Namespace, type_ref::TypeRef, code_model_api::Type
};
#[salsa::query_group(PersistentHirDatabaseStorage)]
@ -77,6 +77,9 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
#[salsa::invoke(crate::FnSignature::fn_signature_query)]
fn fn_signature(&self, func: Function) -> Arc<FnSignature>;
#[salsa::invoke(crate::type_alias::type_alias_ref_query)]
fn type_alias_ref(&self, typ: Type) -> Arc<TypeRef>;
}
#[salsa::query_group(HirDatabaseStorage)]

View File

@ -29,6 +29,7 @@ mod name;
mod module_tree;
mod nameres;
mod adt;
mod type_alias;
mod type_ref;
mod ty;
mod impl_block;

View File

@ -477,7 +477,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = self.insert_type_vars(ty.apply_substs(substs));
(ty, Some(var.into()))
}
TypableDef::Function(_) | TypableDef::Enum(_) => (Ty::Unknown, None),
TypableDef::Type(_) | TypableDef::Function(_) | TypableDef::Enum(_) => {
(Ty::Unknown, None)
}
}
}

View File

@ -10,7 +10,7 @@ use std::sync::Arc;
use crate::{
Function, Struct, StructField, Enum, EnumVariant, Path, Name,
ModuleDef,
ModuleDef, Type,
HirDatabase,
type_ref::TypeRef,
name::KnownName,
@ -109,7 +109,7 @@ impl Ty {
};
let ty = db.type_for_def(typable, Namespace::Types);
let substs = Ty::substs_from_path(db, resolver, path, typable);
ty.apply_substs(substs)
ty.subst(&substs)
}
pub(super) fn substs_from_path_segment(
@ -124,6 +124,7 @@ impl Ty {
TypableDef::Struct(s) => s.generic_params(db),
TypableDef::Enum(e) => e.generic_params(db),
TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db),
TypableDef::Type(t) => t.generic_params(db),
};
let parent_param_count = def_generics.count_parent_params();
substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
@ -159,9 +160,10 @@ impl Ty {
) -> Substs {
let last = path.segments.last().expect("path should have at least one segment");
let segment = match resolved {
TypableDef::Function(_) => last,
TypableDef::Struct(_) => last,
TypableDef::Enum(_) => last,
TypableDef::Function(_)
| TypableDef::Struct(_)
| TypableDef::Enum(_)
| TypableDef::Type(_) => last,
TypableDef::EnumVariant(_) => {
// the generic args for an enum variant may be either specified
// on the segment referring to the enum, or on the segment
@ -194,11 +196,13 @@ pub(crate) fn type_for_def(db: &impl HirDatabase, def: TypableDef, ns: Namespace
(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),
(TypableDef::Type(t), Namespace::Types) => type_for_type_alias(db, t),
// 'error' cases:
(TypableDef::Function(_), Namespace::Types) => Ty::Unknown,
(TypableDef::Enum(_), Namespace::Values) => Ty::Unknown,
(TypableDef::EnumVariant(_), Namespace::Types) => Ty::Unknown,
(TypableDef::Type(_), Namespace::Values) => Ty::Unknown,
}
}
@ -264,7 +268,7 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) ->
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
.collect::<Vec<_>>();
let substs = make_substs(&generics);
let output = type_for_enum(db, def.parent_enum(db)).apply_substs(substs.clone());
let output = type_for_enum(db, def.parent_enum(db)).subst(&substs);
let sig = Arc::new(FnSig { input, output });
Ty::FnDef { def: def.into(), sig, name, substs }
}
@ -298,14 +302,24 @@ fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty {
}
}
fn type_for_type_alias(db: &impl HirDatabase, t: Type) -> Ty {
let generics = t.generic_params(db);
let resolver = t.resolver(db);
let type_ref = t.type_ref(db);
let substs = make_substs(&generics);
let inner = Ty::from_hir(db, &resolver, &type_ref);
inner.subst(&substs)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TypableDef {
Function(Function),
Struct(Struct),
Enum(Enum),
EnumVariant(EnumVariant),
Type(Type),
}
impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant);
impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant, Type);
impl From<ModuleDef> for Option<TypableDef> {
fn from(def: ModuleDef) -> Option<TypableDef> {
@ -314,11 +328,11 @@ impl From<ModuleDef> for Option<TypableDef> {
ModuleDef::Struct(s) => s.into(),
ModuleDef::Enum(e) => e.into(),
ModuleDef::EnumVariant(v) => v.into(),
ModuleDef::Type(t) => t.into(),
ModuleDef::Const(_)
| ModuleDef::Static(_)
| ModuleDef::Module(_)
| ModuleDef::Trait(_)
| ModuleDef::Type(_) => return None,
| ModuleDef::Trait(_) => return None,
};
Some(res)
}

View File

@ -0,0 +1,23 @@
---
created: "2019-02-24T16:13:47.561870283Z"
creator: insta@0.6.3
source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
---
[117; 118) 'x': A<u32, i128>
[125; 126) 'y': A<&str, u128>
[139; 140) 'z': A<u8, i8>
[155; 212) '{ ...z.y; }': ()
[161; 162) 'x': A<u32, i128>
[161; 164) 'x.x': u32
[170; 171) 'x': A<u32, i128>
[170; 173) 'x.y': i128
[179; 180) 'y': A<&str, u128>
[179; 182) 'y.x': &str
[188; 189) 'y': A<&str, u128>
[188; 191) 'y.y': u128
[197; 198) 'z': A<u8, i8>
[197; 200) 'z.x': u8
[206; 207) 'z': A<u8, i8>
[206; 209) 'z.y': i8

View File

@ -740,6 +740,27 @@ fn test() {
);
}
#[test]
fn infer_type_alias() {
check_inference(
"infer_type_alias",
r#"
struct A<X, Y> { x: X, y: Y };
type Foo = A<u32, i128>;
type Bar<T> = A<T, u128>;
type Baz<U, V> = A<V, U>;
fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
x.x;
x.y;
y.x;
y.y;
z.x;
z.y;
}
"#,
)
}
#[test]
fn no_panic_on_field_of_enum() {
check_inference(

View File

@ -0,0 +1,10 @@
//! HIR for type aliases (i.e. the `type` keyword).
use std::sync::Arc;
use crate::{code_model_api::Type, db::PersistentHirDatabase, type_ref::TypeRef};
pub(crate) fn type_alias_ref_query(db: &impl PersistentHirDatabase, typ: Type) -> Arc<TypeRef> {
let (_, node) = typ.source(db);
Arc::new(TypeRef::from_ast_opt(node.type_ref()))
}