From 1e062fb1a7d7cf0e49adc1365111cad665d4bc87 Mon Sep 17 00:00:00 2001 From: Drew Youngwerth Date: Mon, 9 Sep 2024 16:48:36 -0700 Subject: [PATCH] Add test, fix bug --- src/__tests__/compiler.test.ts | 29 +++++++------ src/__tests__/fixtures/e2e-file.ts | 43 ++++++++++++------- src/assembler.ts | 4 +- src/semantics/check-types.ts | 2 +- .../resolution/resolve-object-type.ts | 4 +- src/syntax-objects/syntax.ts | 1 + src/syntax-objects/types.ts | 19 ++++---- 7 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/__tests__/compiler.test.ts b/src/__tests__/compiler.test.ts index adf144d6..4e7f8d5b 100644 --- a/src/__tests__/compiler.test.ts +++ b/src/__tests__/compiler.test.ts @@ -1,7 +1,6 @@ import { e2eVoidText, - gcVoidText, - genericsText, + kitchenSink, goodTypeInferenceText, tcoText, } from "./fixtures/e2e-file.js"; @@ -28,8 +27,8 @@ describe("E2E Compiler Pipeline", () => { t.expect(fn(), "Main function returns correct value").toEqual(55n); }); - test("Compiler can compile gc objects and map correct fns", async (t) => { - const mod = await compile(gcVoidText); + test("Compiler kitchen sink", async (t) => { + const mod = await compile(kitchenSink); const instance = getWasmInstance(mod); t.expect(mod.validate(), "Module is valid"); const test1 = getWasmFn("test1", instance); @@ -39,6 +38,8 @@ describe("E2E Compiler Pipeline", () => { const test5 = getWasmFn("test5", instance); const test6 = getWasmFn("test6", instance); const test7 = getWasmFn("test7", instance); + const test8 = getWasmFn("test8", instance); + const test9 = getWasmFn("test9", instance); assert(test1, "Test1 exists"); assert(test2, "Test2 exists"); assert(test3, "Test3 exists"); @@ -46,13 +47,25 @@ describe("E2E Compiler Pipeline", () => { assert(test5, "Test5 exists"); assert(test6, "Test6 exists"); assert(test7, "Test7 exists"); + assert(test8, "Test8 exists"); + assert(test9, "Test9 exists"); + + // Static method resolution tests t.expect(test1(), "test 1 returns correct value").toEqual(13); t.expect(test2(), "test 2 returns correct value").toEqual(1); t.expect(test3(), "test 3 returns correct value").toEqual(2); t.expect(test4(), "test 4 returns correct value").toEqual(52); + + // Match based type narrowing (and basic gc) t.expect(test5(), "test 5 returns correct value").toEqual(52); t.expect(test6(), "test 6 returns correct value").toEqual(21); t.expect(test7(), "test 7 returns correct value").toEqual(-1); + + // Generic type test + t.expect(test8(), "test 8 returns correct value").toEqual(143); + + // Generic object type test + t.expect(test9(), "test 9 returns correct value").toEqual(7.5); }); test("Compiler can do tco", async (t) => { @@ -61,12 +74,4 @@ describe("E2E Compiler Pipeline", () => { const did = spy.mock.calls.some((call) => call[1].startsWith("fib")); t.expect(did); }); - - test("Generic fn compilation", async (t) => { - const mod = await compile(genericsText); - const instance = getWasmInstance(mod); - const main = getWasmFn("main", instance); - assert(main, "Main exists"); - t.expect(main(), "main 1 returns correct value").toEqual(143); - }); }); diff --git a/src/__tests__/fixtures/e2e-file.ts b/src/__tests__/fixtures/e2e-file.ts index 5077ed7c..934dcaa8 100644 --- a/src/__tests__/fixtures/e2e-file.ts +++ b/src/__tests__/fixtures/e2e-file.ts @@ -12,7 +12,7 @@ pub fn main() `; -export const gcVoidText = ` +export const kitchenSink = ` use std::all obj Vec { @@ -90,6 +90,32 @@ pub fn test6() pub fn test7() let vec = Bitly { x: 52, y: 2, z: 21 } get_num_from_vec_sub_obj(vec) + +type DSArrayI32 = DSArray + +// Test generic functions, should return 143 +pub fn test8() + let arr2 = ds_array_init(10) + arr2.set(0, 1.5) + arr2.get(0) + + let arr: DSArrayI32 = ds_array_init(10) + arr.set(9, 143) + arr.get(9) + +obj VecGeneric { + x: T, + y: T, + z: T +} + +// Test generic object initialization, should return 7.5 +pub fn test9() + let vec = VecGeneric { x: 7, y: 2, z: 3 } + vec.x + + let vec2 = VecGeneric { x: 7.5, y: 2.5, z: 3.5 } + vec2.x `; export const tcoText = ` @@ -119,18 +145,3 @@ fn fib_alias(n: i32, a: i64, b: i64) -> i64 pub fn main() -> i64 fib(10, 0i64, 1i64) `; - -export const genericsText = ` -use std::all - -type DSArrayI32 = DSArray - -pub fn main() - let arr2 = ds_array_init(10) - arr2.set(0, 1.5) - arr2.get(0) - - let arr: DSArrayI32 = ds_array_init(10) - arr.set(9, 143) - arr.get(9) -`; diff --git a/src/assembler.ts b/src/assembler.ts index 33ca8ebf..8d81254b 100644 --- a/src/assembler.ts +++ b/src/assembler.ts @@ -446,8 +446,8 @@ const buildObjectType = (opts: CompileExprOpts, obj: ObjectType): TypeRef => { name: field.name, })), ], - supertype: obj.parentObj - ? binaryenTypeToHeapType(mapBinaryenType(opts, obj.parentObj)) + supertype: obj.parentObjType + ? binaryenTypeToHeapType(mapBinaryenType(opts, obj.parentObjType)) : undefined, }); diff --git a/src/semantics/check-types.ts b/src/semantics/check-types.ts index 159ab0e5..9e9413f7 100644 --- a/src/semantics/check-types.ts +++ b/src/semantics/check-types.ts @@ -282,7 +282,7 @@ const checkObjectType = (obj: ObjectType): ObjectType => { }); if (obj.parentObjExpr) { - assertValidExtension(obj, obj.parentObj); + assertValidExtension(obj, obj.parentObjType); } return obj; diff --git a/src/semantics/resolution/resolve-object-type.ts b/src/semantics/resolution/resolve-object-type.ts index 61157b14..a740abb7 100644 --- a/src/semantics/resolution/resolve-object-type.ts +++ b/src/semantics/resolution/resolve-object-type.ts @@ -24,9 +24,9 @@ export const resolveObjectTypeTypes = ( if (obj.parentObjExpr) { const parentType = getExprType(obj.parentObjExpr); - obj.parentObj = parentType?.isObjectType() ? parentType : undefined; + obj.parentObjType = parentType?.isObjectType() ? parentType : undefined; } else { - obj.parentObj = voidBaseObject; + obj.parentObjType = voidBaseObject; } return obj; diff --git a/src/syntax-objects/syntax.ts b/src/syntax-objects/syntax.ts index 7e677120..be101e3d 100644 --- a/src/syntax-objects/syntax.ts +++ b/src/syntax-objects/syntax.ts @@ -116,6 +116,7 @@ export abstract class Syntax { }; } + /** Clone this object (Implementations should not carry over resolved type expression) */ abstract clone(parent?: Expr): Expr; /** Should emit in compliance with core language spec */ diff --git a/src/syntax-objects/types.ts b/src/syntax-objects/types.ts index e3ede42f..20bfb007 100644 --- a/src/syntax-objects/types.ts +++ b/src/syntax-objects/types.ts @@ -167,7 +167,7 @@ export class ObjectType extends BaseType { genericInstances?: ObjectType[]; fields: ObjectField[]; parentObjExpr?: Expr; - parentObj?: ObjectType; + parentObjType?: ObjectType; /** Type used for locals, globals, function return type */ binaryenType?: number; @@ -184,7 +184,7 @@ export class ObjectType extends BaseType { this.fields.forEach((field) => { field.typeExpr.parent = this; }); - this.parentObj = opts.parentObj; + this.parentObjType = opts.parentObj; this.parentObjExpr = opts.parentObjExpr; this.typeParameters = opts.typeParameters; } @@ -212,8 +212,7 @@ export class ObjectType extends BaseType { typeExpr: field.typeExpr.clone(), type: field.type?.clone(), })), - parentObj: this.parentObj, - parentObjExpr: this.parentObj?.clone(), + parentObjExpr: this.parentObjExpr?.clone(), typeParameters: this.typeParameters, }); } @@ -223,8 +222,8 @@ export class ObjectType extends BaseType { return true; } - if (this.parentObj) { - return this.parentObj.extends(ancestor); + if (this.parentObjType) { + return this.parentObjType.extends(ancestor); } return false; @@ -241,8 +240,8 @@ export class ObjectType extends BaseType { getAncestorIds(start: number[] = []): number[] { start.push(this.idNum); - if (this.parentObj) { - return this.parentObj.getAncestorIds(start); + if (this.parentObjType) { + return this.parentObjType.getAncestorIds(start); } return start; } @@ -256,8 +255,8 @@ export class ObjectType extends BaseType { return start; } - if (this.parentObj) { - return this.parentObj.extensionDistance(ancestor, start + 1); + if (this.parentObjType) { + return this.parentObjType.extensionDistance(ancestor, start + 1); } throw new Error(`${this.name} does not extend ${ancestor.name}`);