Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dc4a387
feat(mir): activate SwitchKind::TypeTag for class-type match arms
antoniosarosi Apr 7, 2026
0f43b6e
feat(bytecode): fused Instruction::IsType replaces CmpOp::InstanceOf
antoniosarosi Apr 7, 2026
d32147f
feat(ast): remove instanceof keyword from AST onwards with E0098 diag…
antoniosarosi Apr 7, 2026
21b210d
Merge branch 'canary' into unify-instanceof-with-typetag
antoniosarosi Apr 8, 2026
d365605
fix(emit): skip discriminant for single-arm exhaustive switches
antoniosarosi Apr 8, 2026
98ae8f5
fix(mir): route null literal patterns through TypeTag switch path
antoniosarosi Apr 8, 2026
9c0bc05
fix(mir): skip last-arm pattern test in exhaustive match chains
antoniosarosi Apr 8, 2026
119a7e9
feat(emit,mir): TypeTag switch for catch arms, is_type debug names, 4…
antoniosarosi Apr 9, 2026
000d742
Merge branch 'canary' into unify-instanceof-with-typetag
antoniosarosi Apr 9, 2026
3fdc183
refactor(mir): remove duplicate try_lower_catch_as_switch, fix instan…
antoniosarosi Apr 9, 2026
f18902f
fix(emit): eliminate redundant copy/pop on last arm of if-else switch
antoniosarosi Apr 9, 2026
b6183d3
refactor(emit): re-load discriminant per arm in if-else switch
antoniosarosi Apr 9, 2026
e6bcbee
feat(emit): short-circuit &&/|| via JumpIfFalse peek instruction
antoniosarosi Apr 10, 2026
2fbc43b
fix(emit): allow PhiLike promotion through ShortCircuit terminators
antoniosarosi Apr 10, 2026
9c302ed
chore(tests): accept InitField snapshots in ignored assignment tests
antoniosarosi Apr 10, 2026
905f6a7
refactor(tests): inline all exception catch bytecode snapshots
antoniosarosi Apr 10, 2026
66217d4
fix(mir): dead-eliminate unused ShortCircuit destinations
antoniosarosi Apr 10, 2026
be33e97
Merge branch 'canary' into unify-instanceof-with-typetag
antoniosarosi Apr 10, 2026
a37370e
chore(tests): regenerate bytecode snapshots after canary merge
antoniosarosi Apr 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions baml_language/crates/baml_compiler2_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,6 @@ pub enum BinaryOp {
BitXor,
Shl,
Shr,
Instanceof,
/// Null coalescing: `a ?? b` — returns `a` if non-null, else `b`.
NullCoalesce,
}
Expand All @@ -660,7 +659,6 @@ impl std::fmt::Display for BinaryOp {
BinaryOp::BitXor => "^",
BinaryOp::Shl => "<<",
BinaryOp::Shr => ">>",
BinaryOp::Instanceof => "instanceof",
BinaryOp::NullCoalesce => "??",
};
write!(f, "{s}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,11 @@ impl LoweringContext {
SyntaxKind::CARET => op = Some(BinaryOp::BitXor),
SyntaxKind::LESS_LESS => op = Some(BinaryOp::Shl),
SyntaxKind::GREATER_GREATER => op = Some(BinaryOp::Shr),
SyntaxKind::KW_INSTANCEOF => op = Some(BinaryOp::Instanceof),
SyntaxKind::KW_INSTANCEOF => {
self.diags
.push(LoweringDiagnostic::InstanceofRemoved { span });
return self.alloc_expr(Expr::Missing, node.text_range());
}
SyntaxKind::QUESTION_QUESTION => op = Some(BinaryOp::NullCoalesce),
SyntaxKind::QUESTION if op.is_none() => {
// Two consecutive QUESTION tokens = null coalescing (??)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub enum LoweringDiagnostic {

/// A byte string literal contains an invalid escape sequence.
InvalidByteStringEscape { message: String, span: TextRange },

/// The `instanceof` operator was used; it has been removed. Use `match` instead.
InstanceofRemoved { span: TextRange },
Comment thread
antoniosarosi marked this conversation as resolved.
}

impl LoweringDiagnostic {
Expand Down Expand Up @@ -183,6 +186,12 @@ impl LoweringDiagnostic {
*span,
"invalid escape",
),
LoweringDiagnostic::InstanceofRemoved { span } => (
DiagnosticId::InstanceofRemoved,
"`instanceof` is no longer supported. Use a `match` expression for type checking instead.".to_string(),
*span,
"use `match` instead",
),
};

Diagnostic::error(id, message)
Expand Down
22 changes: 10 additions & 12 deletions baml_language/crates/baml_compiler2_emit/src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,12 @@ impl<'ctx, 'obj> StackifyCodegen<'ctx, 'obj> {
exhaustive: bool,
name_map: &std::collections::HashMap<i64, &str>,
) {
// Single exhaustive arm: no comparison needed, skip the discriminant entirely.
if exhaustive && arms.len() == 1 {
self.emit_jump_unless_fallthrough(arms[0].1);
return;
}

self.emit_operand_pull(discriminant);

let num_arms = arms.len();
Expand Down Expand Up @@ -1840,15 +1846,11 @@ impl PullSink for StackifyCodegen<'_, '_> {
}

fn is_type(&mut self, ty: &Ty) -> Result<(), Self::Error> {
// Emit instanceof check for nominal class checks.
if let Ty::Class(tn, _) | Ty::TypeAlias(tn, _) = ty {
let class_name_str = tn.display_name.as_str();
if let Some(&class_obj_idx) = self.class_object_indices.get(class_name_str) {
let class_const =
self.add_constant(ConstValue::Object(ObjectIndex::from_raw(class_obj_idx)));
let inst = self.emit(Instruction::LoadConst(class_const));
self.set_operand(inst, OperandMeta::Const(class_name_str.to_string()));
self.emit(Instruction::CmpOp(CmpOp::InstanceOf));
let c = self.add_constant(ConstValue::Object(ObjectIndex::from_raw(class_obj_idx)));
self.emit(Instruction::IsType(c));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
} else {
self.emit(Instruction::Pop(1));
let idx = self.add_constant(ConstValue::Bool(false));
Expand All @@ -1858,7 +1860,6 @@ impl PullSink for StackifyCodegen<'_, '_> {
return Ok(());
}

// Primitive and builtin runtime kinds use type tags.
let type_tag = match ty {
Ty::Int { .. } => Some(baml_type::typetag::INT),
Ty::String { .. } => Some(baml_type::typetag::STRING),
Expand All @@ -1880,11 +1881,8 @@ impl PullSink for StackifyCodegen<'_, '_> {
};

if let Some(tag) = type_tag {
self.emit(Instruction::TypeTag);
let idx = self.add_constant(ConstValue::Int(tag));
let inst = self.emit(Instruction::LoadConst(idx));
self.set_operand(inst, OperandMeta::Const(tag.to_string()));
self.emit(Instruction::CmpOp(CmpOp::Eq));
let c = self.add_constant(ConstValue::Int(tag));
self.emit(Instruction::IsType(c));
} else {
self.emit(Instruction::Pop(1));
let idx = self.add_constant(ConstValue::Bool(false));
Expand Down
2 changes: 1 addition & 1 deletion baml_language/crates/baml_compiler2_mir/src/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ pub enum Rvalue {

/// Extract runtime type tag from any value: `type_tag(_1)`
///
/// Used for jump table dispatch on union types (instanceof patterns).
/// Used for jump table dispatch on union types (type patterns in match).
/// Type tags are global constants:
/// - Primitives: `int=0`, `string=1`, `bool=2`, `null=3`, `float=4`
/// - Classes: assigned unique IDs starting at 100
Expand Down
Loading
Loading