mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-25 13:24:22 +00:00
Implement support for type aliases
This commit is contained in:
parent
5a684099e9
commit
5d72b96988
@ -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 {
|
||||
|
@ -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)]
|
||||
|
@ -29,6 +29,7 @@ mod name;
|
||||
mod module_tree;
|
||||
mod nameres;
|
||||
mod adt;
|
||||
mod type_alias;
|
||||
mod type_ref;
|
||||
mod ty;
|
||||
mod impl_block;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
23
crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap
Normal file
23
crates/ra_hir/src/ty/snapshots/tests__infer_type_alias.snap
Normal 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
|
||||
|
@ -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(
|
||||
|
10
crates/ra_hir/src/type_alias.rs
Normal file
10
crates/ra_hir/src/type_alias.rs
Normal 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()))
|
||||
}
|
Loading…
Reference in New Issue
Block a user