feat: add expression statements and assign expressions

This commit is contained in:
2026-04-21 23:18:13 +02:00
parent 3fe307eff8
commit 68ec14e541
7 changed files with 190 additions and 5 deletions
+70
View File
@@ -390,6 +390,14 @@ impl Sema {
span: stmt.span,
}
}
StmtKind::Expression { expr } => {
let typed_expr = self.analyze_expr(expr);
TypedStmt {
kind: TypedStmtKind::Expression { expr: typed_expr },
span: stmt.span,
}
}
}
}
@@ -518,6 +526,31 @@ impl Sema {
span: expr.span,
}
}
ExprKind::Assign { lval, rval } => {
let typed_rval = self.analyze_expr(rval);
let typed_lval = self.analyze_expr(lval);
match &typed_lval.kind {
TypedExprKind::Identifier { .. } => {}
_ => self.errors.push(SemanticError::new(
"invalid left-hand side of assignment",
lval.span,
)),
}
if let Err(e) = self.unify(&typed_lval.ty, &typed_rval.ty) {
self.errors.push(SemanticError::new(e, expr.span));
}
TypedExpr {
ty: typed_rval.ty.clone(),
kind: TypedExprKind::Assign {
lval: Box::new(typed_lval),
rval: Box::new(typed_rval),
},
span: expr.span,
}
}
}
}
@@ -586,6 +619,9 @@ impl Sema {
ty: self.apply_subst(&ty),
initializer: initializer.map(|e| self.apply_subst_expr(e)),
},
TypedStmtKind::Expression { expr } => TypedStmtKind::Expression {
expr: self.apply_subst_expr(expr),
},
};
TypedStmt { kind, span }
@@ -610,6 +646,10 @@ impl Sema {
lhs: Box::new(self.apply_subst_expr(*lhs)),
rhs: Box::new(self.apply_subst_expr(*rhs)),
},
TypedExprKind::Assign { lval, rval } => TypedExprKind::Assign {
lval: Box::new(self.apply_subst_expr(*lval)),
rval: Box::new(self.apply_subst_expr(*rval)),
},
};
TypedExpr { kind, ty, span }
@@ -863,4 +903,34 @@ mod test {
let src = "fn test() { let a; }";
assert!(analyze(src).is_err());
}
#[test]
fn valid_expression_stmt() {
let src = "fn test() { 5 + 5; }";
assert!(analyze(src).is_ok());
}
#[test]
fn valid_assignment() {
let src = "fn test() { let a = 5; a = 10; }";
assert!(analyze(src).is_ok());
}
#[test]
fn invalid_assignment_type() {
let src = "fn test() { let a: i32 = 5; a = true; }";
let errors = analyze(src).unwrap_err();
assert!(errors.iter().any(|e| e.message.contains("type mismatch")));
}
#[test]
fn invalid_lvalue() {
let src = "fn test() { 5 = 10; }";
let errors = analyze(src).unwrap_err();
assert!(
errors
.iter()
.any(|e| e.message.contains("invalid left-hand side of assignment"))
);
}
}