diff --git a/src/program.ts b/src/program.ts index c333b36054..3a9dfb09a0 100644 --- a/src/program.ts +++ b/src/program.ts @@ -3007,10 +3007,30 @@ export abstract class DeclaredElement extends Element { isCompatibleOverride(base: DeclaredElement): bool { var self: DeclaredElement = this; // TS var kind = self.kind; + var checkCompatibleOverride = false; if (kind == base.kind) { switch (kind) { + case ElementKind.FUNCTION_PROTOTYPE : { + let selfFunction = this.program.resolver.resolveFunction(self, null); + if (!selfFunction) return false; + let baseFunction = this.program.resolver.resolveFunction(base, null); + if (!baseFunction) return false; + self = selfFunction; + base = baseFunction; + checkCompatibleOverride = true; + // fall-through + } case ElementKind.FUNCTION: { - return (self).signature.isAssignableTo((base).signature); + return (self).signature.isAssignableTo((base).signature, checkCompatibleOverride); + } + case ElementKind.PROPERTY_PROTOTYPE: { + let selfProperty = this.program.resolver.resolveProperty(self); + if (!selfProperty) return false; + let baseProperty = this.program.resolver.resolveProperty(base); + if (!baseProperty) return false; + self = selfProperty; + base = baseProperty; + // fall-through } case ElementKind.PROPERTY: { let selfProperty = self; @@ -3018,7 +3038,7 @@ export abstract class DeclaredElement extends Element { let selfGetter = selfProperty.getterInstance; let baseGetter = baseProperty.getterInstance; if (selfGetter) { - if (!baseGetter || !selfGetter.signature.isAssignableTo(baseGetter.signature)) { + if (!baseGetter || !selfGetter.signature.isAssignableTo(baseGetter.signature, true)) { return false; } } else if (baseGetter) { @@ -3027,7 +3047,7 @@ export abstract class DeclaredElement extends Element { let selfSetter = selfProperty.setterInstance; let baseSetter = baseProperty.setterInstance; if (selfSetter) { - if (!baseSetter || !selfSetter.signature.isAssignableTo(baseSetter.signature)) { + if (!baseSetter || !selfSetter.signature.isAssignableTo(baseSetter.signature, true)) { return false; } } else if (baseSetter) { @@ -3035,6 +3055,10 @@ export abstract class DeclaredElement extends Element { } return true; } + // TODO: Implement properties overriding fields and vice-versa. Challenge is that anything overridable requires + // a virtual stub, but fields aren't functions. Either all (such) fields should become property-like, with a + // getter and a setter that can participate as a virtual stub, or it's allowed one-way, with fields integrated + // into what can be a virtual stub as get=load and set=store, then not necessarily with own accessor functions. } } return false; @@ -4294,6 +4318,11 @@ export class Class extends TypedElement { ); } + /** Tests if this is an interface. */ + get isInterface(): bool { + return this.kind == ElementKind.INTERFACE; + } + /** Constructs a new class. */ constructor( /** Name incl. type parameters, i.e. `Foo`. */ diff --git a/src/types.ts b/src/types.ts index 5c6c071b96..9a2f0361d6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -502,6 +502,27 @@ export class Type { return this.kind == target.kind; } + /** Tests if this type can extend or implement the given type. */ + canExtendOrImplement(base: Type): bool { + // Both must be class types + var thisClass = this.getClass(); + var baseClass = base.getClass(); + if (!thisClass || !baseClass) return false; + // Both types must be either managed or unmanaged + if (this.isManaged != base.isManaged) return false; + // Both types must be either internal or external references + if (this.isInternalReference) { + if (!base.isInternalReference) return false; + } else if (this.isExternalReference) { + if (!base.isExternalReference) return false; + } else { + return false; + } + // Interfaces can only extend interfaces + if (thisClass.isInterface && !baseClass.isInterface) return false; + return true; + } + /** Determines the common denominator type of two types, if there is any. */ static commonDenominator(left: Type, right: Type, signednessIsImportant: bool): Type | null { if (right.isAssignableTo(left, signednessIsImportant)) return left; @@ -926,17 +947,27 @@ export class Signature { } /** Tests if a value of this function type is assignable to a target of the specified function type. */ - isAssignableTo(target: Signature): bool { - - // check `this` type + isAssignableTo(target: Signature, checkCompatibleOverride: bool = false): bool { var thisThisType = this.thisType; var targetThisType = target.thisType; - if (thisThisType) { - if (!targetThisType || !thisThisType.isAssignableTo(targetThisType)) { + if (!checkCompatibleOverride) { + // check exact `this` type + if (thisThisType) { + if (!targetThisType || !thisThisType.isAssignableTo(targetThisType)) { + return false; + } + } else if (targetThisType) { + return false; + } + } else { + // check kind of `this` type + if (thisThisType) { + if (!targetThisType || !thisThisType.canExtendOrImplement(targetThisType)) { + return false; + } + } else if (targetThisType) { return false; } - } else if (targetThisType) { - return false; } // check rest parameter diff --git a/tests/compiler/class-implements.debug.wat b/tests/compiler/class-implements.debug.wat index 930954ad61..7406a835b8 100644 --- a/tests/compiler/class-implements.debug.wat +++ b/tests/compiler/class-implements.debug.wat @@ -1,6 +1,6 @@ (module - (type $i32_i32_=>_none (func (param i32 i32))) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_i32_=>_none (func (param i32 i32))) (type $i32_=>_none (func (param i32))) (type $none_=>_none (func)) (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) @@ -25,10 +25,15 @@ (global $~lib/native/ASC_LOW_MEMORY_LIMIT i32 (i32.const 0)) (global $class-implements/a (mut i32) (i32.const 0)) (global $class-implements/c (mut i32) (i32.const 0)) + (global $class-implements/d (mut i32) (i32.const 0)) + (global $class-implements/e (mut i32) (i32.const 0)) + (global $class-implements/f (mut i32) (i32.const 0)) + (global $class-implements/g (mut i32) (i32.const 0)) + (global $class-implements/h (mut i32) (i32.const 0)) (global $~lib/rt/__rtti_base i32 (i32.const 480)) - (global $~lib/memory/__data_end i32 (i32.const 540)) - (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16924)) - (global $~lib/memory/__heap_base i32 (i32.const 16924)) + (global $~lib/memory/__data_end i32 (i32.const 572)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16956)) + (global $~lib/memory/__heap_base i32 (i32.const 16956)) (memory $0 1) (data (i32.const 12) "<\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e\00\00\00\00\00") (data (i32.const 76) "<\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00 \00\00\00~\00l\00i\00b\00/\00r\00t\00/\00i\00t\00c\00m\00s\00.\00t\00s\00\00\00\00\00\00\00\00\00\00\00\00\00") @@ -39,7 +44,7 @@ (data (i32.const 320) "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") (data (i32.const 348) "<\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00t\00l\00s\00f\00.\00t\00s\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00") (data (i32.const 412) "<\00\00\00\00\00\00\00\00\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\00\00\00\00\00\00") - (data (i32.const 480) "\07\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\06\00\00\00 \00\00\00\00\00\00\00") + (data (i32.const 480) "\0b\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\06\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\07\00\00\00 \00\00\00\07\00\00\00") (table $0 1 1 funcref) (elem $0 (i32.const 1)) (export "memory" (memory $0)) @@ -2122,6 +2127,89 @@ (func $class-implements/C#foo (param $this i32) (result i32) i32.const 2 ) + (func $class-implements/D#foo (param $this i32) (result i32) + i32.const 3 + ) + (func $class-implements/F#foo (param $this i32) (result i32) + i32.const 4 + ) + (func $class-implements/I#foo (param $this i32) (result i32) + unreachable + ) + (func $class-implements/D#foo@virtual (param $0 i32) (result i32) + (local $1 i32) + block $default + block $case0 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + local.set $1 + local.get $1 + i32.const 10 + i32.eq + br_if $case0 + br $default + end + local.get $0 + call $class-implements/F#foo + return + end + local.get $0 + call $class-implements/D#foo + ) + (func $class-implements/I#foo@virtual (param $0 i32) (result i32) + (local $1 i32) + block $default + block $case3 + block $case2 + block $case1 + block $case0 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + local.set $1 + local.get $1 + i32.const 3 + i32.eq + br_if $case0 + local.get $1 + i32.const 5 + i32.eq + br_if $case1 + local.get $1 + i32.const 7 + i32.eq + br_if $case2 + local.get $1 + i32.const 9 + i32.eq + br_if $case2 + local.get $1 + i32.const 10 + i32.eq + br_if $case3 + br $default + end + local.get $0 + call $class-implements/A#foo + return + end + local.get $0 + call $class-implements/C#foo + return + end + local.get $0 + call $class-implements/D#foo + return + end + local.get $0 + call $class-implements/F#foo + return + end + unreachable + ) (func $~lib/rt/__visit_globals (param $0 i32) (local $1 i32) global.get $class-implements/a @@ -2138,6 +2226,41 @@ local.get $0 call $~lib/rt/itcms/__visit end + global.get $class-implements/d + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $class-implements/e + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $class-implements/f + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $class-implements/g + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end + global.get $class-implements/h + local.tee $1 + if + local.get $1 + local.get $0 + call $~lib/rt/itcms/__visit + end i32.const 224 local.get $0 call $~lib/rt/itcms/__visit @@ -2158,26 +2281,38 @@ ) (func $~lib/rt/__visit_members (param $0 i32) (param $1 i32) block $invalid - block $class-implements/B - block $class-implements/C - block $class-implements/I - block $class-implements/A - block $~lib/arraybuffer/ArrayBufferView - block $~lib/string/String - block $~lib/arraybuffer/ArrayBuffer - local.get $0 - i32.const 8 - i32.sub - i32.load $0 - br_table $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $class-implements/A $class-implements/I $class-implements/C $class-implements/B $invalid + block $class-implements/F + block $class-implements/E + block $class-implements/J + block $class-implements/D + block $class-implements/B + block $class-implements/C + block $class-implements/I + block $class-implements/A + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + br_table $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $class-implements/A $class-implements/I $class-implements/C $class-implements/B $class-implements/D $class-implements/J $class-implements/E $class-implements/F $invalid + end + return + end + return + end + local.get $0 + local.get $1 + call $~lib/arraybuffer/ArrayBufferView~visit + return + end + return end return end return end - local.get $0 - local.get $1 - call $~lib/arraybuffer/ArrayBufferView~visit return end return @@ -2198,8 +2333,8 @@ global.get $~lib/memory/__data_end i32.lt_s if - i32.const 16944 - i32.const 16992 + i32.const 16976 + i32.const 17024 i32.const 1 i32.const 1 call $~lib/builtins/abort @@ -2249,7 +2384,7 @@ if i32.const 0 i32.const 432 - i32.const 10 + i32.const 14 i32.const 1 call $~lib/builtins/abort unreachable @@ -2270,7 +2405,112 @@ if i32.const 0 i32.const 432 - i32.const 20 + i32.const 24 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/D#constructor + global.set $class-implements/d + global.get $class-implements/d + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $class-implements/D#foo@virtual + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 432 + i32.const 31 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/E#constructor + global.set $class-implements/e + global.get $class-implements/e + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $class-implements/D#foo@virtual + i32.const 3 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 432 + i32.const 37 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/F#constructor + global.set $class-implements/f + global.get $class-implements/f + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $class-implements/F#foo + i32.const 4 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 432 + i32.const 44 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/F#constructor + global.set $class-implements/g + global.get $class-implements/g + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $class-implements/D#foo@virtual + i32.const 4 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 432 + i32.const 47 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + i32.const 0 + call $class-implements/F#constructor + global.set $class-implements/h + global.get $class-implements/h + local.set $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + i32.store $0 + local.get $0 + call $class-implements/I#foo@virtual + i32.const 4 + i32.eq + i32.eqz + if + i32.const 0 + i32.const 432 + i32.const 50 i32.const 1 call $~lib/builtins/abort unreachable @@ -2369,4 +2609,98 @@ global.set $~lib/memory/__stack_pointer local.get $1 ) + (func $class-implements/D#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store $0 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 7 + call $~lib/rt/itcms/__new + local.tee $this + i32.store $0 + end + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $class-implements/E#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store $0 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 9 + call $~lib/rt/itcms/__new + local.tee $this + i32.store $0 + end + global.get $~lib/memory/__stack_pointer + local.get $this + call $class-implements/D#constructor + local.tee $this + i32.store $0 + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) + (func $class-implements/F#constructor (param $this i32) (result i32) + (local $1 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + call $~stack_check + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store $0 + local.get $this + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.const 10 + call $~lib/rt/itcms/__new + local.tee $this + i32.store $0 + end + global.get $~lib/memory/__stack_pointer + local.get $this + call $class-implements/D#constructor + local.tee $this + i32.store $0 + local.get $this + local.set $1 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $1 + ) ) diff --git a/tests/compiler/class-implements.release.wat b/tests/compiler/class-implements.release.wat index 7545bad8a7..154645f85d 100644 --- a/tests/compiler/class-implements.release.wat +++ b/tests/compiler/class-implements.release.wat @@ -1,11 +1,11 @@ (module (type $none_=>_none (func)) - (type $i32_i32_=>_none (func (param i32 i32))) (type $i32_=>_i32 (func (param i32) (result i32))) + (type $i32_i32_=>_none (func (param i32 i32))) + (type $none_=>_i32 (func (result i32))) (type $i32_=>_none (func (param i32))) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) (type $i32_i32_i32_=>_none (func (param i32 i32 i32))) - (type $none_=>_i32 (func (result i32))) (import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32))) (global $~lib/rt/itcms/total (mut i32) (i32.const 0)) (global $~lib/rt/itcms/threshold (mut i32) (i32.const 0)) @@ -19,7 +19,12 @@ (global $~lib/rt/tlsf/ROOT (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/memory/__stack_pointer (mut i32) (i32.const 17948)) + (global $class-implements/d (mut i32) (i32.const 0)) + (global $class-implements/e (mut i32) (i32.const 0)) + (global $class-implements/f (mut i32) (i32.const 0)) + (global $class-implements/g (mut i32) (i32.const 0)) + (global $class-implements/h (mut i32) (i32.const 0)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 17980)) (memory $0 1) (data (i32.const 1036) "<") (data (i32.const 1048) "\01\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e") @@ -33,8 +38,8 @@ (data (i32.const 1384) "\01\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00t\00l\00s\00f\00.\00t\00s") (data (i32.const 1436) "<") (data (i32.const 1448) "\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") - (data (i32.const 1504) "\07\00\00\00 \00\00\00\00\00\00\00 ") - (data (i32.const 1532) " \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\06\00\00\00 ") + (data (i32.const 1504) "\0b\00\00\00 \00\00\00\00\00\00\00 ") + (data (i32.const 1532) " \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\06\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\00\00\00\00 \00\00\00\07\00\00\00 \00\00\00\07") (export "memory" (memory $0)) (start $~start) (func $~lib/rt/itcms/visitRoots @@ -52,6 +57,36 @@ local.get $0 call $byn-split-outlined-A$~lib/rt/itcms/__visit end + global.get $class-implements/d + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end + global.get $class-implements/e + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end + global.get $class-implements/f + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end + global.get $class-implements/g + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end + global.get $class-implements/h + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end i32.const 1248 call $byn-split-outlined-A$~lib/rt/itcms/__visit i32.const 1056 @@ -625,10 +660,10 @@ if unreachable end - i32.const 17952 + i32.const 17984 i32.const 0 i32.store $0 - i32.const 19520 + i32.const 19552 i32.const 0 i32.store $0 loop $for-loop|0 @@ -639,7 +674,7 @@ local.get $0 i32.const 2 i32.shl - i32.const 17952 + i32.const 17984 i32.add i32.const 0 i32.store $0 offset=4 @@ -657,7 +692,7 @@ i32.add i32.const 2 i32.shl - i32.const 17952 + i32.const 17984 i32.add i32.const 0 i32.store $0 offset=96 @@ -675,13 +710,13 @@ br $for-loop|0 end end - i32.const 17952 - i32.const 19524 + i32.const 17984 + i32.const 19556 memory.size $0 i32.const 16 i32.shl call $~lib/rt/tlsf/addMemory - i32.const 17952 + i32.const 17984 global.set $~lib/rt/tlsf/ROOT ) (func $~lib/rt/itcms/step (result i32) @@ -766,7 +801,7 @@ local.set $0 loop $while-continue|0 local.get $0 - i32.const 17948 + i32.const 17980 i32.lt_u if local.get $0 @@ -866,7 +901,7 @@ unreachable end local.get $0 - i32.const 17948 + i32.const 17980 i32.lt_u if local.get $0 @@ -889,7 +924,7 @@ i32.const 4 i32.add local.tee $0 - i32.const 17948 + i32.const 17980 i32.ge_u if global.get $~lib/rt/tlsf/ROOT @@ -1243,30 +1278,42 @@ ) (func $~lib/rt/__visit_members (param $0 i32) block $invalid - block $class-implements/B - block $class-implements/C - block $class-implements/I - block $class-implements/A - block $~lib/arraybuffer/ArrayBufferView - block $~lib/string/String - block $~lib/arraybuffer/ArrayBuffer - local.get $0 - i32.const 8 - i32.sub - i32.load $0 - br_table $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $class-implements/A $class-implements/I $class-implements/C $class-implements/B $invalid + block $class-implements/F + block $class-implements/E + block $class-implements/J + block $class-implements/D + block $class-implements/B + block $class-implements/C + block $class-implements/I + block $class-implements/A + block $~lib/arraybuffer/ArrayBufferView + block $~lib/string/String + block $~lib/arraybuffer/ArrayBuffer + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + br_table $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $class-implements/A $class-implements/I $class-implements/C $class-implements/B $class-implements/D $class-implements/J $class-implements/E $class-implements/F $invalid + end + return + end + return + end + local.get $0 + i32.load $0 + local.tee $0 + if + local.get $0 + call $byn-split-outlined-A$~lib/rt/itcms/__visit + end + return + end + return end return end return end - local.get $0 - i32.load $0 - local.tee $0 - if - local.get $0 - call $byn-split-outlined-A$~lib/rt/itcms/__visit - end return end return @@ -1288,7 +1335,7 @@ global.set $~lib/memory/__stack_pointer block $folding-inner0 global.get $~lib/memory/__stack_pointer - i32.const 1564 + i32.const 1596 i32.lt_s br_if $folding-inner0 global.get $~lib/memory/__stack_pointer @@ -1298,7 +1345,7 @@ memory.size $0 i32.const 16 i32.shl - i32.const 17948 + i32.const 17980 i32.sub i32.const 1 i32.shr_u @@ -1332,7 +1379,7 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1564 + i32.const 1596 i32.lt_s br_if $folding-inner0 global.get $~lib/memory/__stack_pointer @@ -1358,7 +1405,7 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1564 + i32.const 1596 i32.lt_s br_if $folding-inner0 global.get $~lib/memory/__stack_pointer @@ -1376,7 +1423,7 @@ i32.sub global.set $~lib/memory/__stack_pointer global.get $~lib/memory/__stack_pointer - i32.const 1564 + i32.const 1596 i32.lt_s br_if $folding-inner0 global.get $~lib/memory/__stack_pointer @@ -1407,19 +1454,255 @@ global.get $~lib/memory/__stack_pointer global.get $class-implements/c i32.store $0 + i32.const 0 + call $class-implements/D#constructor + global.set $class-implements/d + block $__inlined_func$class-implements/D#foo@virtual (result i32) + global.get $~lib/memory/__stack_pointer + global.get $class-implements/d + local.tee $0 + i32.store $0 + i32.const 4 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + i32.const 10 + i32.eq + br_if $__inlined_func$class-implements/D#foo@virtual + drop + i32.const 3 + end + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1456 + i32.const 31 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1596 + i32.lt_s + br_if $folding-inner0 + global.get $~lib/memory/__stack_pointer + local.tee $0 + i32.const 0 + i32.store $0 + local.get $0 + i32.const 9 + call $~lib/rt/itcms/__new + local.tee $0 + i32.store $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + call $class-implements/D#constructor + local.tee $0 + i32.store $0 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $0 + global.set $class-implements/e + block $__inlined_func$class-implements/D#foo@virtual9 (result i32) + global.get $~lib/memory/__stack_pointer + global.get $class-implements/e + local.tee $0 + i32.store $0 + i32.const 4 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + i32.const 10 + i32.eq + br_if $__inlined_func$class-implements/D#foo@virtual9 + drop + i32.const 3 + end + i32.const 3 + i32.ne + if + i32.const 0 + i32.const 1456 + i32.const 37 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $class-implements/F#constructor + global.set $class-implements/f + global.get $~lib/memory/__stack_pointer + global.get $class-implements/f + i32.store $0 + call $class-implements/F#constructor + global.set $class-implements/g + block $__inlined_func$class-implements/D#foo@virtual15 (result i32) + global.get $~lib/memory/__stack_pointer + global.get $class-implements/g + local.tee $0 + i32.store $0 + i32.const 4 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + i32.const 10 + i32.eq + br_if $__inlined_func$class-implements/D#foo@virtual15 + drop + i32.const 3 + end + i32.const 4 + i32.ne + if + i32.const 0 + i32.const 1456 + i32.const 47 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + call $class-implements/F#constructor + global.set $class-implements/h + global.get $~lib/memory/__stack_pointer + global.get $class-implements/h + local.tee $0 + i32.store $0 + block $__inlined_func$class-implements/I#foo@virtual + block $default20 + block $case3 + block $case2 + block $case1 + block $case021 + local.get $0 + i32.const 8 + i32.sub + i32.load $0 + i32.const 3 + i32.sub + br_table $case021 $default20 $case1 $default20 $case2 $default20 $case2 $case3 $default20 + end + i32.const 1 + local.set $0 + br $__inlined_func$class-implements/I#foo@virtual + end + i32.const 2 + local.set $0 + br $__inlined_func$class-implements/I#foo@virtual + end + i32.const 3 + local.set $0 + br $__inlined_func$class-implements/I#foo@virtual + end + i32.const 4 + local.set $0 + br $__inlined_func$class-implements/I#foo@virtual + end + unreachable + end + local.get $0 + i32.const 4 + i32.ne + if + i32.const 0 + i32.const 1456 + i32.const 50 + i32.const 1 + call $~lib/builtins/abort + unreachable + end global.get $~lib/memory/__stack_pointer i32.const 4 i32.add global.set $~lib/memory/__stack_pointer return end - i32.const 17968 - i32.const 18016 + i32.const 18000 + i32.const 18048 i32.const 1 i32.const 1 call $~lib/builtins/abort unreachable ) + (func $class-implements/D#constructor (param $0 i32) (result i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1596 + i32.lt_s + if + i32.const 18000 + i32.const 18048 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + i32.const 0 + i32.store $0 + local.get $0 + i32.eqz + if + global.get $~lib/memory/__stack_pointer + i32.const 7 + call $~lib/rt/itcms/__new + local.tee $0 + i32.store $0 + end + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $0 + ) + (func $class-implements/F#constructor (result i32) + (local $0 i32) + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.sub + global.set $~lib/memory/__stack_pointer + global.get $~lib/memory/__stack_pointer + i32.const 1596 + i32.lt_s + if + i32.const 18000 + i32.const 18048 + i32.const 1 + i32.const 1 + call $~lib/builtins/abort + unreachable + end + global.get $~lib/memory/__stack_pointer + local.tee $0 + i32.const 0 + i32.store $0 + local.get $0 + i32.const 10 + call $~lib/rt/itcms/__new + local.tee $0 + i32.store $0 + global.get $~lib/memory/__stack_pointer + local.get $0 + call $class-implements/D#constructor + local.tee $0 + i32.store $0 + global.get $~lib/memory/__stack_pointer + i32.const 4 + i32.add + global.set $~lib/memory/__stack_pointer + local.get $0 + ) (func $byn-split-outlined-A$~lib/rt/itcms/__visit (param $0 i32) (local $1 i32) (local $2 i32) @@ -1465,7 +1748,7 @@ i32.load $0 offset=8 i32.eqz local.get $1 - i32.const 17948 + i32.const 17980 i32.lt_u i32.and i32.eqz diff --git a/tests/compiler/class-implements.ts b/tests/compiler/class-implements.ts index ec039b7367..cc6bfca763 100644 --- a/tests/compiler/class-implements.ts +++ b/tests/compiler/class-implements.ts @@ -2,6 +2,10 @@ interface I { foo(): i32; } +interface J { + foo(): i32; +} + class A implements I { foo(): i32 { return 1; } } @@ -18,3 +22,29 @@ class C extends B implements I { var c = new C(); assert(c.foo() == 2); + +class D implements I, J { + foo(): i32 { return 3; } +} + +let d = new D(); +assert(d.foo() == 3); + +class E extends D implements I { +} + +let e = new E(); +assert(e.foo() == 3); + +class F extends D implements I { + foo(): i32 { return 4; } +} + +let f = new F(); +assert(f.foo() == 4); + +let g:D = new F(); +assert(g.foo() == 4); + +let h:I = new F(); +assert(h.foo() == 4);