Make let statements kind of work

This commit is contained in:
Florian Diebold 2018-12-23 13:22:29 +01:00
parent 5d60937090
commit 93ffbf80c6
5 changed files with 53 additions and 8 deletions

View File

@ -243,8 +243,23 @@ impl InferenceContext {
self.type_for.insert(LocalSyntaxPtr::new(node), ty);
}
fn unify(&mut self, _ty1: &Ty, _ty2: &Ty) -> bool {
unimplemented!()
fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> {
if *ty1 == Ty::Unknown {
return Some(ty2.clone());
}
if *ty2 == Ty::Unknown {
return Some(ty1.clone());
}
if ty1 == ty2 {
return Some(ty1.clone());
}
// TODO implement actual unification
return None;
}
fn unify_with_coercion(&mut self, ty1: &Ty, ty2: &Ty) -> Option<Ty> {
// TODO implement coercion
self.unify(ty1, ty2)
}
fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Option<Ty> {
@ -280,9 +295,8 @@ impl InferenceContext {
} else {
Ty::Unknown
};
if self.unify(&if_ty, &else_ty) {
// TODO actually, need to take the 'more specific' type (not unknown, never, ...)
if_ty
if let Some(ty) = self.unify(&if_ty, &else_ty) {
ty
} else {
// TODO report diagnostic
Ty::Unknown
@ -455,9 +469,23 @@ impl InferenceContext {
for stmt in node.statements() {
match stmt {
ast::Stmt::LetStmt(stmt) => {
if let Some(expr) = stmt.initializer() {
self.infer_expr(expr);
}
let decl_ty = if let Some(type_ref) = stmt.type_ref() {
Ty::new(type_ref)
} else {
Ty::Unknown
};
let ty = if let Some(expr) = stmt.initializer() {
// TODO pass expectation
let expr_ty = self.infer_expr(expr);
self.unify_with_coercion(&expr_ty, &decl_ty)
.unwrap_or(decl_ty)
} else {
decl_ty
};
if let Some(pat) = stmt.pat() {
self.write_ty(pat.syntax(), ty);
};
}
ast::Stmt::ExprStmt(expr_stmt) => {
if let Some(expr) = expr_stmt.expr() {

View File

@ -0,0 +1,5 @@
fn test() {
let a = 1isize;
let b: usize = 1;
let c = b;
}

View File

@ -0,0 +1,7 @@
[51; 52) '1': [unknown]
[10; 70) '{ ...= b; }': ()
[24; 30) '1isize': [unknown]
[20; 21) 'a': [unknown]
[62; 63) 'c': usize
[66; 67) 'b': usize
[40; 41) 'b': usize

View File

@ -1561,6 +1561,10 @@ impl<'a> LetStmt<'a> {
super::child_opt(self)
}
pub fn type_ref(self) -> Option<TypeRef<'a>> {
super::child_opt(self)
}
pub fn initializer(self) -> Option<Expr<'a>> {
super::child_opt(self)
}

View File

@ -499,6 +499,7 @@ Grammar(
),
"LetStmt": ( options: [
["pat", "Pat"],
["type_ref", "TypeRef"],
["initializer", "Expr"],
]),
"Condition": (