Skip to content

Commit

Permalink
Add tests, squash bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
drew-y committed Sep 17, 2024
1 parent 3189b4e commit f35d72d
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 58 deletions.
67 changes: 21 additions & 46 deletions src/__tests__/compiler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,52 +31,27 @@ describe("E2E Compiler Pipeline", () => {
const mod = await compile(kitchenSink);
const instance = getWasmInstance(mod);
t.expect(mod.validate(), "Module is valid");
const test1 = getWasmFn("test1", instance);
const test2 = getWasmFn("test2", instance);
const test3 = getWasmFn("test3", instance);
const test4 = getWasmFn("test4", instance);
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);
const test10 = getWasmFn("test10", instance);
const test11 = getWasmFn("test11", instance);
const test12 = getWasmFn("test12", instance);
assert(test1, "Test1 exists");
assert(test2, "Test2 exists");
assert(test3, "Test3 exists");
assert(test4, "Test4 exists");
assert(test5, "Test5 exists");
assert(test6, "Test6 exists");
assert(test7, "Test7 exists");
assert(test8, "Test8 exists");
assert(test9, "Test9 exists");
assert(test10, "Test10 exists");
assert(test11, "Test11 exists");
assert(test12, "Test12 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);
t.expect(test10(), "test 10 returns correct value").toEqual(12);
t.expect(test11(), "test 11 returns correct value").toEqual(4);

// Modules
t.expect(test12(), "test 12 returns correct value").toEqual(597);
const tests = (expectedValues: unknown[]) =>
expectedValues.forEach((v, i) => {
const test = getWasmFn(`test${i + 1}`, instance);
assert(test, `Test${i + 1} exists`);
t.expect(test(), `test ${i + 1} returns correct value`).toEqual(v);
});

tests([
13, // Static method resolution tests
1,
2,
52,
52, // Match based type narrowing (and basic gc)
21,
-1,
143, // Generic type test
7.5, // Generic object type test
12,
4,
597, // Modules
]);
});

test("Compiler can do tco", async (t) => {
Expand Down
16 changes: 16 additions & 0 deletions src/__tests__/fixtures/e2e-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ use m1::m2::{ test as hi }
pub fn test12()
hi()
impl<T> VecGeneric<T>
fn add(self, v: VecGeneric<T>) -> VecGeneric<T>
VecGeneric<T> { x: self.x + v.x, y: self.y + v.y, z: self.z + v.z }
pub fn do_work(self, v: VecGeneric<T>) -> VecGeneric<T>
let b = self.add(v)
b
// Test generic impls, should return 9
pub fn test13()
let a = VecGeneric<i32> { x: 1, y: 2, z: 3 }
let b = VecGeneric<i32> { x: 4, y: 5, z: 6 }
let c = a.do_work(b)
c.z // 9
`;

export const tcoText = `
Expand Down
9 changes: 8 additions & 1 deletion src/semantics/check-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,14 @@ const checkCallTypes = (call: Call): Call | ObjectLiteral => {
call.args = call.args.map(checkTypes);

if (!call.fn) {
throw new Error(`Could not resolve fn ${call.fnName} at ${call.location}`);
const params = call.args
.toArray()
.map((arg) => getExprType(arg)?.name.value)
.join(", ");

throw new Error(
`Could not resolve fn ${call.fnName}(${params}) at ${call.location}`
);
}

if (!call.type) {
Expand Down
2 changes: 2 additions & 0 deletions src/semantics/resolution/resolve-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export const resolveImpl = (
}

if (targetType?.isObjectType() && targetType.typeParameters?.length) {
// Apply impl to existing generic instances
targetType.genericInstances?.forEach((obj) => resolveImpl(impl, obj));
return impl;
}

Expand Down
1 change: 1 addition & 0 deletions src/semantics/resolution/resolve-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const resolveDsArrayTypeTypes = (arr: DsArrayType): DsArrayType => {
};

const resolveTypeAliasTypes = (alias: TypeAlias): TypeAlias => {
if (alias.type) return alias;
alias.typeExpr = resolveTypes(alias.typeExpr);
alias.type = getExprType(alias.typeExpr);
return alias;
Expand Down
1 change: 0 additions & 1 deletion src/syntax-objects/fn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ export class Fn extends ScopedNamedEntity {
return new Fn({
...super.getCloneOpts(parent),
id: `${this.id}#${this.#iteration++}`,
variables: this.variables,
returnTypeExpr: this.returnTypeExpr?.clone(),
parameters: this.#parameters.clone(),
typeParameters: this.#typeParams.clone(),
Expand Down
2 changes: 1 addition & 1 deletion src/syntax-objects/scoped-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Expr } from "./expr.js";
import { LexicalContext } from "./lib/lexical-context.js";
import { Syntax, SyntaxMetadata } from "./syntax.js";

export type ScopedEntity = Expr & {
export type ScopedEntity = Syntax & {
lexicon: LexicalContext;
};

Expand Down
5 changes: 3 additions & 2 deletions src/syntax-objects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Id, Identifier } from "./identifier.js";
import { getIdStr } from "./lib/get-id-str.js";
import { LexicalContext } from "./lib/lexical-context.js";
import { Implementation } from "./implementation.js";
import { ScopedEntity } from "./scoped-entity.js";

export type Type =
| PrimitiveType
Expand Down Expand Up @@ -162,9 +163,9 @@ export class TupleType extends BaseType {

export type ObjectField = { name: string; typeExpr: Expr; type?: Type };

export class ObjectType extends BaseType {
export class ObjectType extends BaseType implements ScopedEntity {
readonly kindOfType = "object";
namespace: LexicalContext = new LexicalContext();
lexicon: LexicalContext = new LexicalContext();
typeParameters?: Identifier[];
appliedTypeArgs?: Type[];
genericInstances?: ObjectType[];
Expand Down
29 changes: 22 additions & 7 deletions src/syntax-objects/variable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Expr } from "./expr.js";
import { Child } from "./lib/child.js";
import { NamedEntity, NamedEntityOpts } from "./named-entity.js";
import { Type } from "./types.js";

Expand All @@ -10,8 +11,8 @@ export class Variable extends NamedEntity {
originalType?: Type;
inferredType?: Type;
annotatedType?: Type;
typeExpr?: Expr;
initializer: Expr;
#typeExpr = new Child<Expr | undefined>(undefined, this);
#initializer: Child<Expr>;
requiresCast = false;

constructor(
Expand All @@ -26,9 +27,23 @@ export class Variable extends NamedEntity {
this.isMutable = opts.isMutable;
this.type = opts.type;
this.typeExpr = opts.typeExpr;
if (this.typeExpr) this.typeExpr.parent = this;
this.initializer = opts.initializer;
this.initializer.parent = this;
this.#initializer = new Child(opts.initializer, this);
}

get typeExpr(): Expr | undefined {
return this.#typeExpr.value;
}

set typeExpr(value: Expr | undefined) {
this.#typeExpr.value = value;
}

get initializer(): Expr {
return this.#initializer.value;
}

set initializer(value: Expr) {
this.#initializer.value = value;
}

getIndex(): number {
Expand Down Expand Up @@ -59,8 +74,8 @@ export class Variable extends NamedEntity {
return new Variable({
...super.getCloneOpts(parent),
isMutable: this.isMutable,
initializer: this.initializer,
typeExpr: this.typeExpr?.clone(),
initializer: this.#initializer.clone(),
typeExpr: this.#typeExpr.clone(),
});
}
}
11 changes: 11 additions & 0 deletions std/operators.void
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,14 @@ pub def_wasm_operator('+', add, f32, f32)
pub def_wasm_operator('-', sub, f32, f32)
pub def_wasm_operator('*', mul, f32, f32)
pub def_wasm_operator('/', div, f32, f32)

pub def_wasm_operator('<', lt, f64, bool)
pub def_wasm_operator('>', gt, f64, bool)
pub def_wasm_operator('<=', le, f64, bool)
pub def_wasm_operator('>=', ge, f64, bool)
pub def_wasm_operator('==', eq, f64, bool)
pub def_wasm_operator('not', ne, f64, bool)
pub def_wasm_operator('+', add, f64, f64)
pub def_wasm_operator('-', sub, f64, f64)
pub def_wasm_operator('*', mul, f64, f64)
pub def_wasm_operator('/', div, f64, f64)

0 comments on commit f35d72d

Please sign in to comment.