Resolve the Self type
This commit is contained in:
parent
d4db61b9a1
commit
538147bf94
3 changed files with 71 additions and 24 deletions
|
|
@ -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_,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue