Skip to content

Commit

Permalink
Merge pull request #81 from baszalmstra/fix/struct_init
Browse files Browse the repository at this point in the history
fix: struct initialization fix for non constants
  • Loading branch information
Wodann committed Jan 13, 2020
2 parents 473f480 + f3d7a76 commit a204e63
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 25 deletions.
11 changes: 0 additions & 11 deletions crates/mun_codegen/src/ir/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::ir::try_convert_any_to_basic;
use crate::IrDatabase;
use inkwell::types::{BasicTypeEnum, StructType};
use inkwell::values::{BasicValueEnum, StructValue};

pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) -> StructType {
let struct_type = db.struct_ty(s);
Expand All @@ -21,13 +20,3 @@ pub(super) fn gen_struct_decl(db: &impl IrDatabase, s: hir::Struct) -> StructTyp
}
struct_type
}

/// Constructs a struct literal value of type `s`.
pub(super) fn gen_named_struct_lit(
db: &impl IrDatabase,
s: hir::Struct,
values: &[BasicValueEnum],
) -> StructValue {
let struct_ty = db.struct_ty(s);
struct_ty.const_named_struct(values)
}
26 changes: 17 additions & 9 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use inkwell::{
};
use std::{collections::HashMap, mem, sync::Arc};

use crate::ir::adt::gen_named_struct_lit;
use inkwell::basic_block::BasicBlock;
use inkwell::values::PointerValue;
use inkwell::values::{AggregateValueEnum, PointerValue};

struct LoopInfo {
break_values: Vec<(
Expand Down Expand Up @@ -218,9 +217,19 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
fn gen_struct_alloc(
&mut self,
hir_struct: hir::Struct,
args: &[BasicValueEnum],
args: Vec<BasicValueEnum>,
) -> BasicValueEnum {
let struct_lit = gen_named_struct_lit(self.db, hir_struct, &args);
// Construct the struct literal
let struct_ty = self.db.struct_ty(hir_struct);
let mut value: AggregateValueEnum = struct_ty.get_undef().into();
for (i, arg) in args.into_iter().enumerate() {
value = self
.builder
.build_insert_value(value, arg, i as u32, "init")
.expect("Failed to initialize struct field.");
}
let struct_lit = value.into_struct_value();

match hir_struct.data(self.db).memory_kind {
hir::StructMemoryKind::Value => struct_lit.into(),
hir::StructMemoryKind::GC => {
Expand All @@ -229,8 +238,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
let struct_ptr: PointerValue = self
.builder
.build_malloc(struct_ir_ty, &hir_struct.name(self.db).to_string());
let struct_value = gen_named_struct_lit(self.db, hir_struct, &args);
self.builder.build_store(struct_ptr, struct_value);
self.builder.build_store(struct_ptr, struct_lit);
struct_ptr.into()
}
}
Expand All @@ -249,7 +257,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
.map(|field| self.gen_expr(field.expr).expect("expected a field value"))
.collect();

self.gen_struct_alloc(hir_struct, &fields)
self.gen_struct_alloc(hir_struct, fields)
}

/// Generates IR for a named tuple literal, e.g. `Foo(1.23, 4)`
Expand All @@ -261,14 +269,14 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
.map(|expr| self.gen_expr(*expr).expect("expected a field value"))
.collect();

self.gen_struct_alloc(hir_struct, &args)
self.gen_struct_alloc(hir_struct, args)
}

/// Generates IR for a unit struct literal, e.g `Foo`
fn gen_unit_struct_lit(&mut self, type_expr: ExprId) -> BasicValueEnum {
let struct_ty = self.infer[type_expr].clone();
let hir_struct = struct_ty.as_struct().unwrap(); // Can only really get here if the type is a struct
self.gen_struct_alloc(hir_struct, &[])
self.gen_struct_alloc(hir_struct, Vec::new())
}

/// Generates IR for the specified block expression.
Expand Down
29 changes: 29 additions & 0 deletions crates/mun_codegen/src/snapshots/test__field_crash.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: crates/mun_codegen/src/test.rs
expression: "struct(gc) Foo { a: int };\n\nfn main(c:int):int {\n let b = Foo { a: c + 5 }\n b.a\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"

%Foo = type { i64 }

define i64 @main(i64) {
body:
%b = alloca %Foo*
%c = alloca i64
store i64 %0, i64* %c
%c1 = load i64, i64* %c
%add = add i64 %c1, 5
%init = insertvalue %Foo undef, i64 %add, 0
%malloccall = tail call i8* @malloc(i32 ptrtoint (i64* getelementptr (i64, i64* null, i32 1) to i32))
%Foo = bitcast i8* %malloccall to %Foo*
store %Foo %init, %Foo* %Foo
store %Foo* %Foo, %Foo** %b
%deref = load %Foo*, %Foo** %b
%Foo.a = getelementptr inbounds %Foo, %Foo* %deref, i32 0, i32 0
%a = load i64, i64* %Foo.a
ret i64 %a
}

declare noalias i8* @malloc(i32)

13 changes: 9 additions & 4 deletions crates/mun_codegen/src/snapshots/test__struct_test.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: crates/mun_codegen/src/test.rs
expression: "struct Bar(float, int, bool, Foo);\nstruct Foo { a: int };\nstruct Baz;\nfn foo() {\n let a: Foo = Foo { a: 5 };\n let b: Bar = Bar(1.23, 4, true, a);\n let c: Baz = Baz;\n}"
expression: "struct(value) Bar(float, int, bool, Foo);\nstruct(value) Foo { a: int };\nstruct(value) Baz;\nfn foo() {\n let a: Foo = Foo { a: 5 };\n let b: Bar = Bar(1.23, a.a, true, a);\n let c: Baz = Baz;\n}"
---
; ModuleID = 'main.mun'
source_filename = "main.mun"
Expand All @@ -15,9 +15,14 @@ body:
%b = alloca %Bar
%a = alloca %Foo
store %Foo { i64 5 }, %Foo* %a
%a1 = load %Foo, %Foo* %a
store %Bar { double 1.230000e+00, i64 4, i1 true, %Foo %a1 }, %Bar* %b
store %Baz zeroinitializer, %Baz* %c
%Foo.a = getelementptr inbounds %Foo, %Foo* %a, i32 0, i32 0
%a1 = load i64, i64* %Foo.a
%a2 = load %Foo, %Foo* %a
%init = insertvalue %Bar { double 1.230000e+00, i64 undef, i1 undef, %Foo undef }, i64 %a1, 1
%init3 = insertvalue %Bar %init, i1 true, 2
%init4 = insertvalue %Bar %init3, %Foo %a2, 3
store %Bar %init4, %Bar* %b
store %Baz undef, %Baz* %c
ret void
}

16 changes: 15 additions & 1 deletion crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ fn struct_test() {
struct(value) Baz;
fn foo() {
let a: Foo = Foo { a: 5 };
let b: Bar = Bar(1.23, 4, true, a);
let b: Bar = Bar(1.23, a.a, true, a);
let c: Baz = Baz;
}
"#,
Expand Down Expand Up @@ -416,6 +416,20 @@ fn field_expr() {
)
}

#[test]
fn field_crash() {
test_snapshot_unoptimized(
r#"
struct(gc) Foo { a: int };
fn main(c:int):int {
let b = Foo { a: c + 5 }
b.a
}
"#,
)
}

#[test]
fn gc_struct() {
test_snapshot_unoptimized(
Expand Down
15 changes: 15 additions & 0 deletions crates/mun_runtime/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,18 @@ fn fields() {
);
assert_invoke_eq!(bool, true, driver, "main", 48);
}

#[test]
fn field_crash() {
let mut driver = TestDriver::new(
r#"
struct(gc) Foo { a: int };
fn main(c:int):int {
let b = Foo { a: c + 5 }
b.a
}
"#,
);
assert_invoke_eq!(i64, 15, driver, "main", 10);
}

0 comments on commit a204e63

Please sign in to comment.