Refactor a bit

This commit is contained in:
Florian Diebold 2018-12-29 23:35:57 +01:00
parent 538147bf94
commit 6ab0e292d2

View File

@ -522,6 +522,8 @@ struct InferenceContext<'a, D: HirDatabase> {
impl_block: Option<ImplBlock>,
var_unification_table: InPlaceUnificationTable<TypeVarId>,
type_of: FxHashMap<LocalSyntaxPtr, Ty>,
/// The return type of the function being inferred.
return_ty: Ty,
}
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@ -534,7 +536,8 @@ fn new(
InferenceContext {
type_of: FxHashMap::default(),
var_unification_table: InPlaceUnificationTable::new(),
self_param: None, // set during parameter typing
self_param: None, // set during parameter typing
return_ty: Ty::Unknown, // set in collect_fn_signature
db,
scopes,
module,
@ -555,6 +558,14 @@ fn write_ty(&mut self, node: SyntaxNodeRef, ty: Ty) {
self.type_of.insert(LocalSyntaxPtr::new(node), ty);
}
fn make_ty(&self, type_ref: &TypeRef) -> Cancelable<Ty> {
Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), type_ref)
}
fn make_ty_opt(&self, type_ref: Option<&TypeRef>) -> Cancelable<Ty> {
Ty::from_hir_opt(self.db, &self.module, self.impl_block.as_ref(), type_ref)
}
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
match (ty1, ty2) {
(Ty::Unknown, ..) => true,
@ -952,6 +963,55 @@ fn infer_block(&mut self, node: ast::Block, expected: &Expectation) -> Cancelabl
self.write_ty(node.syntax(), ty.clone());
Ok(ty)
}
fn collect_fn_signature(&mut self, node: ast::FnDef) -> Cancelable<()> {
if let Some(param_list) = node.param_list() {
if let Some(self_param) = param_list.self_param() {
let self_type = if let Some(type_ref) = self_param.type_ref() {
let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
self.insert_type_vars(ty)
} else {
// TODO this should be handled by desugaring during HIR conversion
let ty = self.make_ty_opt(self.impl_block.as_ref().map(|i| i.target()))?;
let ty = match self_param.flavor() {
ast::SelfParamFlavor::Owned => ty,
ast::SelfParamFlavor::Ref => Ty::Ref(Arc::new(ty), Mutability::Shared),
ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
};
self.insert_type_vars(ty)
};
if let Some(self_kw) = self_param.self_kw() {
let self_param = LocalSyntaxPtr::new(self_kw.syntax());
self.self_param = Some(self_param);
self.type_of.insert(self_param, self_type);
}
}
for param in param_list.params() {
let pat = if let Some(pat) = param.pat() {
pat
} else {
continue;
};
let ty = if let Some(type_ref) = param.type_ref() {
let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
self.insert_type_vars(ty)
} else {
// missing type annotation
self.new_type_var()
};
self.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
}
}
self.return_ty = if let Some(type_ref) = node.ret_type().and_then(|n| n.type_ref()) {
let ty = self.make_ty(&TypeRef::from_ast(type_ref))?;
self.insert_type_vars(ty)
} else {
Ty::unit()
};
Ok(())
}
}
pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
@ -964,66 +1024,10 @@ pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceRe
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) = &ctx.impl_block {
if let Some(type_ref) = self_param.type_ref() {
let ty = Ty::from_ast(db, &ctx.module, ctx.impl_block.as_ref(), type_ref)?;
ctx.insert_type_vars(ty)
} else {
// 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),
ast::SelfParamFlavor::MutRef => Ty::Ref(Arc::new(ty), Mutability::Mut),
};
ctx.insert_type_vars(ty)
}
} else {
log::debug!(
"No impl block found, but self param for function {:?}",
def_id
);
ctx.new_type_var()
};
if let Some(self_kw) = self_param.self_kw() {
let self_param = LocalSyntaxPtr::new(self_kw.syntax());
ctx.self_param = Some(self_param);
ctx.type_of.insert(self_param, self_type);
}
}
for param in param_list.params() {
let pat = if let Some(pat) = param.pat() {
pat
} else {
continue;
};
let ty = if let Some(type_ref) = param.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
ctx.new_type_var()
};
ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
}
}
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, ctx.impl_block.as_ref(), type_ref)?;
ctx.insert_type_vars(ty)
} else {
Ty::unit()
};
ctx.collect_fn_signature(node)?;
if let Some(block) = node.body() {
ctx.infer_block(block, &Expectation::has_type(ret_ty))?;
ctx.infer_block(block, &Expectation::has_type(ctx.return_ty.clone()))?;
}
Ok(Arc::new(ctx.resolve_all()))