Skip to content

Commit 8729b81

Browse files
committed
progress
1 parent 0a08a7f commit 8729b81

File tree

3 files changed

+154
-31
lines changed

3 files changed

+154
-31
lines changed

src/ir/lowering/expressions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ pub(crate) fn lower_path(
913913
// expression can only be used in a match, so we return the variant discriminant.
914914
if info.extra.is_empty() {
915915
projection.push(PlaceElem::GetVariant);
916-
type_idx = fn_builder.builder.ir.get_u64_ty();
916+
type_idx = fn_builder.builder.ir.get_u32_ty();
917917
ty = fn_builder.builder.get_type(type_idx).clone();
918918
}
919919
// if extra is not empty it means its a method call

src/ir/lowering/statements.rs

+152-29
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use tracing::{debug, instrument};
33
use crate::{
44
ast::{
55
common::TypeName,
6-
expressions::{Expression, IfExpr, MatchCaseExpr, MatchExpr},
6+
expressions::{Expression, IfExpr, MatchCaseExpr, MatchExpr, ValueExpr},
77
statements::{self, AssignStmt, ForStmt, LetStmt, LetStmtTarget, ReturnStmt, WhileStmt},
88
types::TypeDescriptor,
99
},
1010
ir::{
11-
BasicBlock, ConstData, ConstKind, ConstValue, Mutability, Operand, Place, PlaceElem,
12-
Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, Type,
13-
ValueTree,
11+
BasicBlock, ConstData, ConstKind, ConstValue, Local, LocalKind, Mutability, Operand, Place,
12+
PlaceElem, Rvalue, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind,
13+
Type, ValueTree,
1414
lowering::{
1515
Symbol,
1616
expressions::{lower_expression, lower_value_expr},
@@ -333,24 +333,20 @@ fn lower_match(builder: &mut FnIrBuilder, info: &MatchExpr) -> Result<(), Loweri
333333
let (discriminator, discriminator_type_idx, _disc_span) =
334334
lower_expression(builder, &info.expr, None)?;
335335

336-
let local = builder.add_temp_local(builder.builder.ir.get_bool_ty());
336+
let local = builder.add_temp_local(discriminator_type_idx);
337337
let place = Place {
338338
local,
339339
projection: vec![],
340340
};
341341

342342
builder.statements.push(Statement {
343343
span: None,
344-
kind: StatementKind::Assign(place.clone(), discriminator),
344+
kind: StatementKind::Assign(place.clone(), discriminator.clone()),
345345
});
346346

347-
// keep idx to change terminator
348-
let current_block_idx = builder.body.basic_blocks.len();
349-
350-
let outer_scope_locals = builder.name_to_local.clone();
351-
352-
// flush current block
353347
let statements = std::mem::take(&mut builder.statements);
348+
// keep idx to change terminator
349+
let cond_block_idx = builder.body.basic_blocks.len();
354350
builder.body.basic_blocks.push(BasicBlock {
355351
statements,
356352
terminator: Box::new(Terminator {
@@ -365,16 +361,39 @@ fn lower_match(builder: &mut FnIrBuilder, info: &MatchExpr) -> Result<(), Loweri
365361

366362
let mut is_enum_match: Option<Option<TypeName>> = None;
367363

368-
for variant in &info.variants {
369-
let mut variant_scope_locals = outer_scope_locals.clone();
364+
let outer_scope_locals = builder.name_to_local.clone();
365+
let outer_scope_local_exists = builder.local_exists.clone();
366+
367+
for variant in info.variants.iter() {
368+
debug!("lowering variant");
369+
// keep idx for switch targets
370+
let current_block_idx = builder.body.basic_blocks.len();
371+
targets.push(current_block_idx);
372+
373+
let statements = std::mem::take(&mut builder.statements);
374+
builder.body.basic_blocks.push(BasicBlock {
375+
statements,
376+
terminator: Box::new(Terminator {
377+
span: None,
378+
kind: TerminatorKind::Unreachable,
379+
}),
380+
});
370381

371382
match &variant.case {
372383
MatchCaseExpr::Value(value_expr) => {
373-
let value = lower_value_expr(builder, value_expr, None)?;
374-
target_conds.push(value);
384+
let idx = match value_expr {
385+
ValueExpr::ConstBool(v, _) => (*v) as u32,
386+
ValueExpr::ConstChar(v, _) => (*v) as u32,
387+
ValueExpr::ConstInt(v, _) => (*v) as u32,
388+
ValueExpr::ConstFloat(_, _) => todo!(),
389+
ValueExpr::ConstStr(_, _) => todo!(),
390+
ValueExpr::Path(_) => todo!("todo: bind variable to other?"),
391+
};
392+
target_conds.push(ValueTree::Leaf(ConstValue::U32(idx)));
375393
is_enum_match = Some(None);
376394
}
377395
MatchCaseExpr::Enum(enum_match_expr) => {
396+
debug!("lowering enum variant {}", enum_match_expr.name.name.name);
378397
if let Some(None) = is_enum_match {
379398
panic!("enum on a non enum match")
380399
}
@@ -419,21 +438,83 @@ fn lower_match(builder: &mut FnIrBuilder, info: &MatchExpr) -> Result<(), Loweri
419438
.get(&enum_match_expr.variant.name)
420439
.expect("variant not found");
421440

422-
let variant_value = Rvalue::Use(Operand::Const(ConstData {
423-
ty: builder.builder.ir.get_u32_ty(),
424-
span: enum_match_expr.span,
425-
data: ConstKind::Value(ValueTree::Leaf(ConstValue::U32(variant_idx as u32))),
426-
}));
441+
let variant_value = ValueTree::Leaf(ConstValue::U32(variant_idx as u32));
427442

428-
target_conds.push((variant_value, builder.builder.ir.get_u32_ty()));
429-
}
430-
}
443+
target_conds.push(variant_value);
431444

432-
// todo: add locals from destructure, on each enum match block add the value extraction on the start of block.
445+
// todo: add locals from destructure, on each enum match block add the value extraction on the start of block.
433446

434-
// keep idx for switch targets
435-
targets.push(builder.body.basic_blocks.len());
436-
let current_block_idx = builder.body.basic_blocks.len();
447+
let enum_place = match &discriminator {
448+
Rvalue::Use(operand) => match operand {
449+
Operand::Place(place) => {
450+
let mut place = place.clone(); // this place should have the GetVariant projection, remove it.
451+
let popped = place.projection.pop();
452+
assert_eq!(popped, Some(PlaceElem::GetVariant));
453+
place
454+
}
455+
Operand::Const(_) => todo!(),
456+
},
457+
Rvalue::LogicOp(_, _) => todo!(),
458+
Rvalue::BinaryOp(_, _) => todo!(),
459+
Rvalue::UnaryOp(_, _) => todo!(),
460+
Rvalue::Ref(mutability, place) => todo!(),
461+
Rvalue::Cast(operand, index, _span) => todo!(),
462+
};
463+
464+
for field_value in &enum_match_expr.field_values {
465+
debug!("lowering variant field {}", field_value.name);
466+
let field_idx = *adt_body.variants[variant_idx]
467+
.field_names
468+
.get(&field_value.name)
469+
.expect("field not found");
470+
let ty_idx = adt_body.variants[variant_idx].fields[field_idx].ty;
471+
472+
let field_local_idx = builder.body.locals.len();
473+
builder
474+
.name_to_local
475+
.insert(field_value.name.clone(), field_local_idx);
476+
builder.local_exists.insert(field_local_idx);
477+
478+
let field_local = Local::new(
479+
Some(field_value.span),
480+
LocalKind::Temp,
481+
ty_idx,
482+
Some(field_value.name.clone()),
483+
false,
484+
);
485+
486+
builder.body.locals.push(field_local);
487+
builder.local_exists.insert(field_local_idx);
488+
489+
let field_place = Place {
490+
local: field_local_idx,
491+
projection: Vec::new(),
492+
};
493+
494+
// todo: maybe add a "mut ref" keyword to be able to modify the field in the match
495+
496+
let enum_field_place = {
497+
let mut place = enum_place.clone();
498+
place.projection.push(PlaceElem::Variant(variant_idx));
499+
place.projection.push(PlaceElem::Field(field_idx));
500+
place
501+
};
502+
503+
builder.statements.push(Statement {
504+
span: Some(enum_match_expr.span),
505+
kind: StatementKind::Assign(
506+
field_place,
507+
Rvalue::Use(Operand::Place(enum_field_place)),
508+
),
509+
});
510+
511+
builder.statements.push(Statement {
512+
span: Some(enum_match_expr.span),
513+
kind: StatementKind::StorageLive(field_local_idx),
514+
});
515+
}
516+
}
517+
}
437518

438519
for stmt in &variant.block {
439520
get_locals(builder, stmt)?;
@@ -456,9 +537,51 @@ fn lower_match(builder: &mut FnIrBuilder, info: &MatchExpr) -> Result<(), Loweri
456537
targets_last_block.push(last_then_block_idx);
457538

458539
builder.name_to_local = outer_scope_locals.clone();
540+
builder.local_exists = outer_scope_local_exists.clone();
459541
}
460542

461-
todo!()
543+
// todo: add otherwise block
544+
545+
// otherwise block
546+
// todo: maybe its not needed if user adds a catch all.
547+
// todo: identify catch all, maybe path
548+
let statements = std::mem::take(&mut builder.statements);
549+
let otherwise_block_idx = builder.body.basic_blocks.len();
550+
builder.body.basic_blocks.push(BasicBlock {
551+
statements,
552+
terminator: Box::new(Terminator {
553+
span: None,
554+
kind: TerminatorKind::Unreachable,
555+
}),
556+
});
557+
targets.push(otherwise_block_idx);
558+
559+
let targets = SwitchTargets {
560+
values: target_conds,
561+
targets,
562+
};
563+
564+
let kind = TerminatorKind::SwitchInt {
565+
discriminator: Operand::Place(place),
566+
targets,
567+
};
568+
builder.body.basic_blocks[cond_block_idx].terminator.kind = kind;
569+
builder.name_to_local = outer_scope_locals;
570+
571+
let next_block_idx = builder.body.basic_blocks.len();
572+
573+
for blockidx in &targets_last_block {
574+
if matches!(
575+
builder.body.basic_blocks[*blockidx].terminator.kind,
576+
TerminatorKind::Unreachable
577+
) {
578+
builder.body.basic_blocks[*blockidx].terminator.kind = TerminatorKind::Goto {
579+
target: next_block_idx,
580+
};
581+
}
582+
}
583+
584+
Ok(())
462585
}
463586

464587
#[instrument(level = "debug", skip_all)]

src/ir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ pub struct Place {
264264
}
265265

266266
/// A element of the place projection.
267-
#[derive(Debug, Clone)]
267+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
268268
pub enum PlaceElem {
269269
/// Dereference
270270
Deref,

0 commit comments

Comments
 (0)