M fml/src/typeck.rs +31 -2
@@ 126,6 126,20 @@ impl Tck {
}
self.unify(symtbl, a_o, b_o)
}
+ (Struct(body1), Struct(body2)) => {
+ for (nm, t1) in body1.iter() {
+ let t2 = body2[nm];
+ self.unify(symtbl, *t1, t2)?;
+ }
+ // Now we just do it again the other way around
+ // which is a dumb but effective way of making sure
+ // struct2 doesn't have any fields that struct1 doesn't.
+ for (nm, t2) in body2.iter() {
+ let t1 = body1[nm];
+ self.unify(symtbl, t1, *t2)?;
+ }
+ Ok(())
+ }
(TypeParam(s1), TypeParam(s2)) if s1 == s2 => Ok(()),
// If no previous attempts to unify were successful, raise an error
(a, b) => Err(format!("Conflict between {:?} and {:?}", a, b)),
@@ 186,7 200,6 @@ impl Tck {
.map(|t| self.instantiate(named_types, t))
.collect();
TypeInfo::Named(s.clone(), inst_args)
- //todo!("Double check this is correct")
}
Type::Generic(s) => {
// If we know this is is a particular generic, match wiht it
@@ 459,7 472,23 @@ fn typecheck_expr(
Ok(rettype_var)
}
- StructCtor { body: _ } => todo!("Struct ctor"),
+ StructCtor { body } => {
+ let body_types: Result<HashMap<_, _>, _> = body
+ .iter()
+ .map(|(name, expr)| {
+ // ? in map doesn't work too well...
+ match typecheck_expr(tck, symtbl, expr) {
+ Ok(t) => Ok((name.to_string(), t)),
+ Err(s) => Err(s),
+ }
+ })
+ .collect();
+ let body_types = body_types?;
+ let struct_type = TypeInfo::Struct(body_types);
+ let typeid = tck.insert(struct_type);
+ tck.set_expr_type(expr, typeid);
+ Ok(typeid)
+ }
TypeCtor { name, body } => {
let named_type = symtbl.get_type(name).expect("Unknown type constructor");
println!("Got type named {}: is {:?}", name, named_type);
M fml/tests/main.rs +13 -0
@@ 99,3 99,16 @@ fn test_struct1() {
let src = include_str!("test_struct1.gt");
let _output = fml::compile("test_struct1.gt", src);
}
+
+#[test]
+fn test_struct2() {
+ let src = include_str!("test_struct2.gt");
+ let _output = fml::compile("test_struct2.gt", src);
+}
+
+#[test]
+#[should_panic]
+fn test_struct3() {
+ let src = include_str!("test_struct3.gt");
+ let _output = fml::compile("test_struct3.gt", src);
+}
A => fml/tests/test_struct1.gt +19 -0
@@ 0,0 1,19 @@
+
+type Foo = struct
+ a: I32,
+ b: Bool
+end
+
+fn id(x: @T): @T =
+ x
+end
+
+
+fn main(): I32 =
+ let f1: Foo = id($Foo(struct {
+ a = 3,
+ b = false
+ }))
+ let f2: struct a: I32, b: Bool end = id(struct { a = 3, b = false })
+ 3
+end
A => fml/tests/test_struct2.gt +22 -0
@@ 0,0 1,22 @@
+
+type Foo = struct
+ a: I32,
+ b: Bool
+end
+
+fn thing(i: I32): Foo =
+ $Foo(struct {
+ a = i,
+ b = false,
+ })
+end
+
+
+fn main(): I32 =
+ let f1: Foo = $Foo(struct {
+ a = 3,
+ b = false
+ })
+ let f2: Foo = thing(4)
+ 3
+end
A => fml/tests/test_struct3.gt +21 -0
@@ 0,0 1,21 @@
+
+type Foo = struct
+ a: I32,
+ b: Bool
+end
+
+fn thing(i: I32): Foo =
+ $Foo(struct {
+ a = i,
+ b = false,
+ })
+end
+
+
+fn main(): I32 =
+ let f1: Foo = $Foo(struct {
+ a = 3,
+ })
+ let f2: Foo = thing(4)
+ 3
+end