Resolve the Self type

This commit is contained in:
Florian Diebold 2018-12-29 23:20:12 +01:00
parent d4db61b9a1
commit 538147bf94
3 changed files with 71 additions and 24 deletions

View file

@ -51,6 +51,7 @@ impl Name {
"u128" => KnownName::U128,
"f32" => KnownName::F32,
"f64" => KnownName::F64,
"Self" => KnownName::Self_,
_ => return None,
};
Some(name)
@ -84,7 +85,7 @@ impl AsName for ra_db::Dependency {
// const ISIZE: Name = Name::new("isize")
// ```
// but const-fn is not that powerful yet.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum KnownName {
Isize,
I8,
@ -102,4 +103,6 @@ pub(crate) enum KnownName {
F32,
F64,
Self_,
}

View file

@ -31,9 +31,10 @@ use ra_syntax::{
};
use crate::{
Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName,
Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
db::HirDatabase,
type_ref::{TypeRef, Mutability},
name::KnownName,
};
/// The ID of a type variable.
@ -235,6 +236,7 @@ impl Ty {
pub(crate) fn from_hir(
db: &impl HirDatabase,
module: &Module,
impl_block: Option<&ImplBlock>,
type_ref: &TypeRef,
) -> Cancelable<Self> {
Ok(match type_ref {
@ -242,29 +244,29 @@ impl Ty {
TypeRef::Tuple(inner) => {
let inner_tys = inner
.iter()
.map(|tr| Ty::from_hir(db, module, tr))
.map(|tr| Ty::from_hir(db, module, impl_block, tr))
.collect::<Cancelable<Vec<_>>>()?;
Ty::Tuple(inner_tys.into())
}
TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, path)?,
TypeRef::RawPtr(inner, mutability) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
Ty::RawPtr(Arc::new(inner_ty), *mutability)
}
TypeRef::Array(_inner) => Ty::Unknown, // TODO
TypeRef::Slice(inner) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
Ty::Slice(Arc::new(inner_ty))
}
TypeRef::Reference(inner, mutability) => {
let inner_ty = Ty::from_hir(db, module, inner)?;
let inner_ty = Ty::from_hir(db, module, impl_block, inner)?;
Ty::Ref(Arc::new(inner_ty), *mutability)
}
TypeRef::Placeholder => Ty::Unknown,
TypeRef::Fn(params) => {
let mut inner_tys = params
.iter()
.map(|tr| Ty::from_hir(db, module, tr))
.map(|tr| Ty::from_hir(db, module, impl_block, tr))
.collect::<Cancelable<Vec<_>>>()?;
let return_ty = inner_tys
.pop()
@ -279,9 +281,21 @@ impl Ty {
})
}
pub(crate) fn from_hir_opt(
db: &impl HirDatabase,
module: &Module,
impl_block: Option<&ImplBlock>,
type_ref: Option<&TypeRef>,
) -> Cancelable<Self> {
type_ref
.map(|t| Ty::from_hir(db, module, impl_block, t))
.unwrap_or(Ok(Ty::Unknown))
}
pub(crate) fn from_hir_path(
db: &impl HirDatabase,
module: &Module,
impl_block: Option<&ImplBlock>,
path: &Path,
) -> Cancelable<Self> {
if let Some(name) = path.as_ident() {
@ -291,6 +305,8 @@ impl Ty {
return Ok(Ty::Uint(uint_ty));
} else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
return Ok(Ty::Float(float_ty));
} else if name.as_known_name() == Some(KnownName::Self_) {
return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target()));
}
}
@ -308,18 +324,20 @@ impl Ty {
pub(crate) fn from_ast_opt(
db: &impl HirDatabase,
module: &Module,
impl_block: Option<&ImplBlock>,
node: Option<ast::TypeRef>,
) -> Cancelable<Self> {
node.map(|n| Ty::from_ast(db, module, n))
node.map(|n| Ty::from_ast(db, module, impl_block, n))
.unwrap_or(Ok(Ty::Unknown))
}
pub(crate) fn from_ast(
db: &impl HirDatabase,
module: &Module,
impl_block: Option<&ImplBlock>,
node: ast::TypeRef,
) -> Cancelable<Self> {
Ty::from_hir(db, module, &TypeRef::from_ast(node))
Ty::from_hir(db, module, impl_block, &TypeRef::from_ast(node))
}
pub fn unit() -> Self {
@ -402,18 +420,19 @@ impl fmt::Display for Ty {
fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
let syntax = f.syntax(db);
let module = f.module(db)?;
let impl_block = f.impl_block(db)?;
let node = syntax.borrowed();
// TODO we ignore type parameters for now
let input = node
.param_list()
.map(|pl| {
pl.params()
.map(|p| Ty::from_ast_opt(db, &module, p.type_ref()))
.map(|p| Ty::from_ast_opt(db, &module, impl_block.as_ref(), p.type_ref()))
.collect()
})
.unwrap_or_else(|| Ok(Vec::new()))?;
let output = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) {
Ty::from_ast(db, &module, type_ref)?
Ty::from_ast(db, &module, impl_block.as_ref(), type_ref)?
} else {
Ty::unit()
};
@ -467,12 +486,13 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name)
),
};
let module = def_id.module(db)?;
let impl_block = def_id.impl_block(db)?;
let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
tr
} else {
return Ok(Ty::Unknown);
};
Ty::from_hir(db, &module, &type_ref)
Ty::from_hir(db, &module, impl_block.as_ref(), &type_ref)
}
/// The result of type inference: A mapping from expressions and patterns to types.
@ -499,12 +519,18 @@ struct InferenceContext<'a, D: HirDatabase> {
/// The self param for the current method, if it exists.
self_param: Option<LocalSyntaxPtr>,
module: Module,
impl_block: Option<ImplBlock>,
var_unification_table: InPlaceUnificationTable<TypeVarId>,
type_of: FxHashMap<LocalSyntaxPtr, Ty>,
}
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self {
fn new(
db: &'a D,
scopes: Arc<FnScopes>,
module: Module,
impl_block: Option<ImplBlock>,
) -> Self {
InferenceContext {
type_of: FxHashMap::default(),
var_unification_table: InPlaceUnificationTable::new(),
@ -512,6 +538,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
db,
scopes,
module,
impl_block,
}
}
@ -835,7 +862,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
ast::Expr::CastExpr(e) => {
let _inner_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
let cast_ty = Ty::from_ast_opt(
self.db,
&self.module,
self.impl_block.as_ref(),
e.type_ref(),
)?;
let cast_ty = self.insert_type_vars(cast_ty);
// TODO do the coercion...
cast_ty
@ -889,7 +921,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
for stmt in node.statements() {
match stmt {
ast::Stmt::LetStmt(stmt) => {
let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
let decl_ty = Ty::from_ast_opt(
self.db,
&self.module,
self.impl_block.as_ref(),
stmt.type_ref(),
)?;
let decl_ty = self.insert_type_vars(decl_ty);
let ty = if let Some(expr) = stmt.initializer() {
let expr_ty = self.infer_expr(expr, &Expectation::has_type(decl_ty))?;
@ -921,19 +958,26 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
let function = Function::new(def_id); // TODO: consts also need inference
let scopes = function.scopes(db);
let module = function.module(db)?;
let mut ctx = InferenceContext::new(db, scopes, module);
let impl_block = function.impl_block(db)?;
let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
let syntax = function.syntax(db);
let node = syntax.borrowed();
if let Some(param_list) = node.param_list() {
if let Some(self_param) = param_list.self_param() {
let self_type = if let Some(impl_block) = function.impl_block(db)? {
let self_type = if let Some(impl_block) = &ctx.impl_block {
if let Some(type_ref) = self_param.type_ref() {
let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
ctx.insert_type_vars(ty)
} else {
let ty = Ty::from_hir(db, &ctx.module, impl_block.target())?;
// TODO this should be handled by desugaring during HIR conversion
let ty = Ty::from_hir(
db,
&ctx.module,
ctx.impl_block.as_ref(),
impl_block.target(),
)?;
let ty = match self_param.flavor() {
ast::SelfParamFlavor::Owned => ty,
ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
@ -961,7 +1005,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
continue;
};
let ty = if let Some(type_ref) = param.type_ref() {
let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
ctx.insert_type_vars(ty)
} else {
// missing type annotation
@ -972,7 +1016,7 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
}
let ret_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
ctx.insert_type_vars(ty)
} else {
Ty::unit()

View file

@ -2,5 +2,5 @@
[34; 38) 'self': &S
[40; 61) '{ ... }': ()
[88; 109) '{ ... }': ()
[98; 102) 'self': &[unknown]
[75; 79) 'self': &[unknown]
[98; 102) 'self': &S
[75; 79) 'self': &S