diff --git a/src/program.ts b/src/program.ts index adedcf2caf..e3c183a096 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1213,11 +1213,9 @@ export class Program extends DiagnosticEmitter { let basePrototype = thisPrototype.basePrototype; let interfacePrototypes = thisPrototype.interfacePrototypes; if (basePrototype) { - assert(!interfacePrototypes); this.markVirtuals(thisPrototype, basePrototype); } if (interfacePrototypes) { - assert(!basePrototype); for (let j = 0, l = interfacePrototypes.length; j < l; ++j) { this.markVirtuals(thisPrototype, interfacePrototypes[j]); } diff --git a/tests/compiler/class-implements.json b/tests/compiler/class-implements.json new file mode 100644 index 0000000000..b1da366ff4 --- /dev/null +++ b/tests/compiler/class-implements.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "--runtime none" + ] +} \ No newline at end of file diff --git a/tests/compiler/class-implements.optimized.wat b/tests/compiler/class-implements.optimized.wat new file mode 100644 index 0000000000..28eafbd5a4 --- /dev/null +++ b/tests/compiler/class-implements.optimized.wat @@ -0,0 +1,112 @@ +(module + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $none_=>_none (func)) + (memory $0 1) + (data (i32.const 1024) "&\00\00\00\01\00\00\00\01\00\00\00&\00\00\00c\00l\00a\00s\00s\00-\00i\00m\00p\00l\00e\00m\00e\00n\00t\00s\00.\00t\00s") + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $class-implements/A i32 (i32.const 3)) + (global $class-implements/C i32 (i32.const 5)) + (export "memory" (memory $0)) + (export "A" (global $class-implements/A)) + (export "A#foo" (func $class-implements/A#foo)) + (export "A#constructor" (func $class-implements/A#constructor)) + (export "C" (global $class-implements/C)) + (export "C#foo" (func $class-implements/C#foo)) + (start $~start) + (func $~lib/rt/stub/__alloc (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.tee $3 + i32.const 16 + i32.add + local.tee $1 + memory.size + local.tee $4 + i32.const 16 + i32.shl + local.tee $2 + i32.gt_u + if + local.get $4 + local.get $1 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + local.tee $2 + local.get $4 + local.get $2 + i32.gt_s + select + memory.grow + i32.const 0 + i32.lt_s + if + local.get $2 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $1 + global.set $~lib/rt/stub/offset + local.get $3 + i32.const 16 + i32.sub + local.tee $1 + i32.const 16 + i32.store + local.get $1 + i32.const 1 + i32.store offset=4 + local.get $1 + local.get $0 + i32.store offset=8 + local.get $1 + i32.const 0 + i32.store offset=12 + local.get $3 + ) + (func $class-implements/A#constructor (param $0 i32) (result i32) + local.get $0 + if (result i32) + local.get $0 + else + i32.const 3 + call $~lib/rt/stub/__alloc + end + ) + (func $class-implements/A#foo (param $0 i32) (result i32) + i32.const 1 + ) + (func $class-implements/C#foo (param $0 i32) (result i32) + i32.const 2 + ) + (func $~start + i32.const 1088 + global.set $~lib/rt/stub/offset + i32.const 0 + call $class-implements/A#constructor + drop + i32.const 5 + call $~lib/rt/stub/__alloc + i32.eqz + if + i32.const 6 + call $~lib/rt/stub/__alloc + drop + end + ) +) diff --git a/tests/compiler/class-implements.ts b/tests/compiler/class-implements.ts new file mode 100644 index 0000000000..d284e80068 --- /dev/null +++ b/tests/compiler/class-implements.ts @@ -0,0 +1,20 @@ +interface I { + foo(): i32; +} + +export class A implements I { + foo(): i32 { return 1; } +} + +var a = new A(); +assert(a.foo() === 1); + +class B { +} + +export class C extends B implements I { + foo(): i32 { return 2; } +} + +var c = new C(); +assert(c.foo() === 2); diff --git a/tests/compiler/class-implements.untouched.wat b/tests/compiler/class-implements.untouched.wat new file mode 100644 index 0000000000..b7ab1b4de0 --- /dev/null +++ b/tests/compiler/class-implements.untouched.wat @@ -0,0 +1,229 @@ +(module + (type $i32_=>_i32 (func (param i32) (result i32))) + (type $none_=>_none (func)) + (type $i32_=>_none (func (param i32))) + (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) + (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) + (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) + (memory $0 1) + (data (i32.const 16) "&\00\00\00\01\00\00\00\01\00\00\00&\00\00\00c\00l\00a\00s\00s\00-\00i\00m\00p\00l\00e\00m\00e\00n\00t\00s\00.\00t\00s\00") + (table $0 1 funcref) + (global $~lib/rt/stub/startOffset (mut i32) (i32.const 0)) + (global $~lib/rt/stub/offset (mut i32) (i32.const 0)) + (global $class-implements/a (mut i32) (i32.const 0)) + (global $class-implements/c (mut i32) (i32.const 0)) + (global $~lib/heap/__heap_base i32 (i32.const 72)) + (global $class-implements/A i32 (i32.const 3)) + (global $class-implements/C i32 (i32.const 5)) + (export "memory" (memory $0)) + (export "A" (global $class-implements/A)) + (export "A#foo" (func $class-implements/A#foo)) + (export "A#constructor" (func $class-implements/A#constructor)) + (export "C" (global $class-implements/C)) + (export "C#foo" (func $class-implements/C#foo)) + (start $~start) + (func $~lib/rt/stub/maybeGrowMemory (param $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + memory.size + local.set $1 + local.get $1 + i32.const 16 + i32.shl + local.set $2 + local.get $0 + local.get $2 + i32.gt_u + if + local.get $0 + local.get $2 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + local.set $3 + local.get $1 + local.tee $4 + local.get $3 + local.tee $5 + local.get $4 + local.get $5 + i32.gt_s + select + local.set $4 + local.get $4 + memory.grow + i32.const 0 + i32.lt_s + if + local.get $3 + memory.grow + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + local.get $0 + global.set $~lib/rt/stub/offset + ) + (func $~lib/rt/stub/__alloc (param $0 i32) (param $1 i32) (result i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + local.get $0 + i32.const 1073741808 + i32.gt_u + if + unreachable + end + global.get $~lib/rt/stub/offset + i32.const 16 + i32.add + local.set $2 + local.get $0 + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + local.tee $3 + i32.const 16 + local.tee $4 + local.get $3 + local.get $4 + i32.gt_u + select + local.set $5 + local.get $2 + local.get $5 + i32.add + call $~lib/rt/stub/maybeGrowMemory + local.get $2 + i32.const 16 + i32.sub + local.set $6 + local.get $6 + local.get $5 + i32.store + i32.const 1 + drop + local.get $6 + i32.const 1 + i32.store offset=4 + local.get $6 + local.get $1 + i32.store offset=8 + local.get $6 + local.get $0 + i32.store offset=12 + local.get $2 + ) + (func $~lib/rt/stub/__retain (param $0 i32) (result i32) + local.get $0 + ) + (func $class-implements/A#constructor (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 3 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $class-implements/A#foo (param $0 i32) (result i32) + i32.const 1 + ) + (func $class-implements/B#constructor (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 6 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + ) + (func $class-implements/C#constructor (param $0 i32) (result i32) + local.get $0 + i32.eqz + if + i32.const 0 + i32.const 5 + call $~lib/rt/stub/__alloc + call $~lib/rt/stub/__retain + local.set $0 + end + local.get $0 + call $class-implements/B#constructor + local.set $0 + local.get $0 + ) + (func $class-implements/C#foo (param $0 i32) (result i32) + i32.const 2 + ) + (func $start:class-implements + global.get $~lib/heap/__heap_base + i32.const 15 + i32.add + i32.const 15 + i32.const -1 + i32.xor + i32.and + global.set $~lib/rt/stub/startOffset + global.get $~lib/rt/stub/startOffset + global.set $~lib/rt/stub/offset + i32.const 0 + call $class-implements/A#constructor + global.set $class-implements/a + global.get $class-implements/a + call $class-implements/A#foo + i32.const 1 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 10 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/C#constructor + global.set $class-implements/c + global.get $class-implements/c + call $class-implements/C#foo + i32.const 2 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 32 + i32.const 20 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + ) + (func $~start + call $start:class-implements + ) +)