Skip to content

Commit

Permalink
frontend: Fix bytecode generation for is-patterns in condition
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Jan 27, 2025
1 parent 814c4e1 commit 267c271
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 19 deletions.
23 changes: 5 additions & 18 deletions dora-frontend/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use dora_parser::ast::CmpOp;
use dora_parser::{ast, Span};

use self::bytecode::BytecodeBuilder;
use self::expr::{gen_expr, gen_expr_bin_cmp, gen_fatal_error, gen_intrinsic_bin, gen_method_bin};
use self::expr::{
gen_expr, gen_expr_bin_cmp, gen_expr_condition, gen_fatal_error, gen_intrinsic_bin,
gen_method_bin,
};
use crate::sema::{
emit_as_bytecode_operation, new_identity_type_params, AnalysisData, CallType,
ClassDefinitionId, ConstDefinitionId, ContextFieldId, EnumDefinitionId, FctDefinition,
Expand Down Expand Up @@ -1317,23 +1320,7 @@ impl<'a> AstBytecodeGen<'a> {

self.push_scope();

if let Some((is_expr, cond)) = is_pattern_check(&expr.cond) {
let value_reg = gen_expr(self, &is_expr.value, DataDest::Alloc);
let value_ty = self.ty(is_expr.value.id());
self.setup_pattern_vars(&is_expr.pattern);
self.destruct_pattern(&is_expr.pattern, value_reg, value_ty, Some(else_lbl));
self.free_if_temp(value_reg);

if let Some(cond) = cond {
let cond_reg = gen_expr(self, cond, DataDest::Alloc);
self.builder.emit_jump_if_false(cond_reg, else_lbl);
self.free_if_temp(cond_reg);
}
} else {
let cond_reg = gen_expr(self, &expr.cond, DataDest::Alloc);
self.builder.emit_jump_if_false(cond_reg, else_lbl);
self.free_if_temp(cond_reg);
}
gen_expr_condition(self, &expr.cond, else_lbl);

gen_expr(self, &expr.then_block, DataDest::Reg(dest));

Expand Down
31 changes: 30 additions & 1 deletion dora-frontend/src/generator/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use dora_bytecode::{BytecodeType, BytecodeTypeArray, FunctionId, Location, Regis
use dora_parser::ast::{self, CmpOp};
use dora_parser::Span;

use crate::generator::{bty_array_from_ty, register_bty_from_ty, AstBytecodeGen, DataDest};
use crate::generator::{bty_array_from_ty, register_bty_from_ty, AstBytecodeGen, DataDest, Label};
use crate::sema::{FctDefinition, FctParent, Intrinsic, Sema};
use crate::ty::{SourceType, SourceTypeArray};

Expand Down Expand Up @@ -39,6 +39,35 @@ pub(super) fn gen_expr(g: &mut AstBytecodeGen, expr: &ast::ExprData, dest: DataD
}
}

pub(super) fn gen_expr_condition(g: &mut AstBytecodeGen, expr: &ast::ExprData, false_lbl: Label) {
expr.to_bin();
if let Some(bin_expr) = expr.to_bin_and() {
if let Some(is_expr) = bin_expr.lhs.to_is() {
let value_reg = gen_expr(g, &is_expr.value, DataDest::Alloc);
let value_ty = g.ty(is_expr.value.id());
g.setup_pattern_vars(&is_expr.pattern);
g.destruct_pattern(&is_expr.pattern, value_reg, value_ty, Some(false_lbl));
g.free_if_temp(value_reg);
} else {
let cond_reg = gen_expr(g, &expr, DataDest::Alloc);
g.builder.emit_jump_if_false(cond_reg, false_lbl);
g.free_if_temp(cond_reg);
}

gen_expr_condition(g, &bin_expr.rhs, false_lbl);
} else if let Some(is_expr) = expr.to_is() {
let value_reg = gen_expr(g, &is_expr.value, DataDest::Alloc);
let value_ty = g.ty(is_expr.value.id());
g.setup_pattern_vars(&is_expr.pattern);
g.destruct_pattern(&is_expr.pattern, value_reg, value_ty, Some(false_lbl));
g.free_if_temp(value_reg);
} else {
let cond_reg = gen_expr(g, &expr, DataDest::Alloc);
g.builder.emit_jump_if_false(cond_reg, false_lbl);
g.free_if_temp(cond_reg);
}
}

pub(super) fn gen_intrinsic_bin(
g: &mut AstBytecodeGen,
intrinsic: Intrinsic,
Expand Down
13 changes: 13 additions & 0 deletions tests/language/pattern-if5.dora
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
fn main() {
assert(myf(Some[Int](1), Some[Int](2), Some[Int](3)) == 6);
assert(myf(Some[Int](1), Some[Int](2), Some[Int](0)) == 0);
assert(myf(Some[Int](1), Some[Int](-2), Some[Int](3)) == 0);
}

fn myf(x: Option[Int], y: Option[Int], z: Option[Int]): Int {
if x is Some(x) && y is Some(y) && z is Some(z) && x > 0 && y > 0 && z > 0 {
x + y + z
} else {
0
}
}

0 comments on commit 267c271

Please sign in to comment.