Skip to content

Commit 839aa13

Browse files
author
Willem Wyndham
committed
Type checking improved, but virtual table needs work
1 parent 5fb758f commit 839aa13

File tree

4 files changed

+152
-216
lines changed

4 files changed

+152
-216
lines changed

Diff for: src/compiler.ts

+124-44
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ import {
8282
IndexSignature,
8383
File,
8484
mangleInternalName,
85-
Interface
85+
Interface,
86+
TypedElement,
87+
FieldPrototype,
88+
DeclaredElement
8689
} from "./program";
8790

8891
import {
@@ -2953,49 +2956,7 @@ export class Compiler extends DiagnosticEmitter {
29532956
fromType.toString(),
29542957
toType.toString());
29552958
} else {
2956-
const _interface = (<Interface>toType.classReference!);
2957-
let _class = fromType.classReference!;
2958-
let incorrectMethods = _interface.checkClass(_class);
2959-
if (incorrectMethods.length == 0) {
2960-
_interface.implementers.add(fromType.classReference!);
2961-
} else {
2962-
this.error(
2963-
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
2964-
reportNode.range,
2965-
fromType.toString(),
2966-
toType.toString());
2967-
let missingMethods = false;
2968-
// tslint:disable-next-line: as-types
2969-
for (let i: i32 = 0; i < incorrectMethods.length; i++) {
2970-
const ifunc = incorrectMethods[i];
2971-
if (_class.members == null || !_class.members.has(ifunc.name)) {
2972-
if (!missingMethods) {
2973-
missingMethods = true;
2974-
this.error(
2975-
DiagnosticCode.Class_0_incorrectly_implements_interface_1,
2976-
_class.identifierNode.range,
2977-
fromType.toString(),
2978-
toType.toString()
2979-
);
2980-
}
2981-
this.error(
2982-
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
2983-
_class.identifierNode.range,
2984-
ifunc.name,
2985-
fromType.toString(),
2986-
toType.toString()
2987-
);
2988-
} else {
2989-
let otherFunc = _class.members.get(ifunc.name)!;
2990-
this.error(
2991-
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
2992-
otherFunc.identifierNode.range,
2993-
_class.name + "." + otherFunc.name,
2994-
_interface.name + "." + ifunc.name);
2995-
}
2996-
}
2997-
}
2998-
2959+
this.checkInterfaceImplementation(toType, fromType, reportNode);
29992960
}
30002961
}
30012962
else if (!fromType.isAssignableTo(toType)) {
@@ -9312,6 +9273,125 @@ export class Compiler extends DiagnosticEmitter {
93129273
module.removeFunction(func.internalName);
93139274
return module.addFunction(func.internalName, typeRef, null, body);
93149275
}
9276+
9277+
checkInterfaceImplementation(toType: Type, fromType: Type, reportNode: Node): void {
9278+
const _interface = (<Interface>toType.classReference!);
9279+
const _class = fromType.classReference!;
9280+
var imems: Map<string, Element>;
9281+
var mems: Map<string, Element>;
9282+
if (_interface.prototype.instanceMembers == null) {
9283+
return;
9284+
} else {
9285+
imems = _interface.prototype.instanceMembers;
9286+
if (_class.prototype.instanceMembers == null) {
9287+
// All members missing
9288+
9289+
return;
9290+
} else {
9291+
mems = _class.prototype.instanceMembers;
9292+
}
9293+
}
9294+
var error = false;
9295+
var incorrectMember = false;
9296+
for (const [name, imem] of imems.entries()) {
9297+
error = error || incorrectMember;
9298+
incorrectMember = true;
9299+
let mem = mems.get(name);
9300+
if (mem == null) {
9301+
// Error!
9302+
this.error(
9303+
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
9304+
_class.identifierNode.range,
9305+
name,
9306+
_class.name,
9307+
_interface.name
9308+
);
9309+
continue;
9310+
}
9311+
if (imem.kind != mem.kind) {
9312+
// Interfaces can't have properties
9313+
if (!(mem.kind == ElementKind.PROPERTY_PROTOTYPE && imem.kind == ElementKind.FIELD_PROTOTYPE)) {
9314+
this.error(
9315+
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
9316+
(<DeclaredElement>mem).declaration.range,
9317+
mem.name,
9318+
name);
9319+
continue;
9320+
}
9321+
// Error
9322+
}
9323+
let from: Type = Type.void, to: Type = Type.void;
9324+
switch (mem.kind){
9325+
case ElementKind.FIELD_PROTOTYPE: {
9326+
from = this.resolver.resolveType((<FieldPrototype>mem).typeNode!, _class)!;
9327+
to = this.resolver.resolveType((<FieldPrototype>imem).typeNode!, _interface)!;
9328+
break;
9329+
}
9330+
case ElementKind.FUNCTION_PROTOTYPE: {
9331+
let func = (<FunctionPrototype>mem);
9332+
mem.parent = _class;
9333+
imem.parent = _interface;
9334+
from = this.resolver.resolveType(func.functionTypeNode, func, _class.contextualTypeArguments)!;//, ReportMode.REPORT, false)!.type;
9335+
to = this.resolver.resolveType((<FunctionPrototype>imem).functionTypeNode, imem, _interface.contextualTypeArguments, ReportMode.REPORT)!;
9336+
break;
9337+
}
9338+
case ElementKind.PROPERTY_PROTOTYPE: {
9339+
const property = <PropertyPrototype> mem;
9340+
const iproperty = <FieldPrototype> imem;
9341+
if (!iproperty.is(CommonFlags.READONLY)) {
9342+
if (property.setterPrototype == null) {
9343+
this.error(
9344+
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
9345+
_class.identifierNode.range,
9346+
"set " + name,
9347+
_class.name,
9348+
_interface.name
9349+
);
9350+
error = true;
9351+
// Error
9352+
break;
9353+
}
9354+
}
9355+
if (property.getterPrototype == null) {
9356+
this.error(
9357+
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
9358+
_class.identifierNode.range,
9359+
"get " + name,
9360+
_class.name,
9361+
_interface.name
9362+
);
9363+
continue;
9364+
// Error
9365+
}
9366+
from = this.resolver.resolveType(property.getterPrototype.functionTypeNode, property.getterPrototype, _class.contextualTypeArguments, ReportMode.REPORT)!;
9367+
to = this.resolver.resolveType((<FieldPrototype>imem).typeNode!, _interface)!;
9368+
}
9369+
default: {
9370+
// Error
9371+
continue;
9372+
}
9373+
}
9374+
if (!from.isAssignableTo(to)) {
9375+
this.error(
9376+
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
9377+
(<DeclaredElement>mem).declaration.range,
9378+
from.toString(),
9379+
to.toString()
9380+
);
9381+
continue;
9382+
// Error
9383+
}
9384+
incorrectMember = false;
9385+
}
9386+
if (error) {
9387+
this.error(
9388+
DiagnosticCode.Class_0_incorrectly_implements_interface_1,
9389+
_class.identifierNode.range,
9390+
fromType.toString(),
9391+
toType.toString()
9392+
);
9393+
}
9394+
}
93159395
}
93169396

93179397
// helpers

Diff for: tests/compiler/interface-fail.ts

+15
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,18 @@ class AnotherBadFoo {}
1717
const aBadFoo: IFoo = new BadFoo();
1818
const anotherBadFoo: IFoo = new AnotherBadFoo();
1919
const intFoo: IFoo = <i32>5;
20+
21+
interface Properties {
22+
val: i32;
23+
}
24+
25+
class BadProps implements Properties {
26+
private _val: i32 = 0;
27+
set val(newVal: i32) {
28+
this._val = newVal;
29+
}
30+
}
31+
32+
const badProp = <Properties> new BadProps();
33+
34+
const val = badProp.val;

Diff for: tests/compiler/interface.optimized.wat

+7-98
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
(module
2-
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
32
(type $FUNCSIG$vi (func (param i32)))
4-
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
5-
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
63
(type $FUNCSIG$v (func))
74
(type $FUNCSIG$ii (func (param i32) (result i32)))
8-
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
95
(memory $0 1)
106
(data (i32.const 8) "\18\00\00\00\01\00\00\00\01\00\00\00\18\00\00\00i\00n\00t\00e\00r\00f\00a\00c\00e\00.\00t\00s")
11-
(table $0 5 funcref)
12-
(elem (i32.const 0) $null $interface/AFoo#foo $interface/AFoo#foo $interface/AFoo#faa $interface/AFoo#faa)
137
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
148
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
159
(global $interface/aFoo (mut i32) (i32.const 0))
1610
(global $interface/sFoo (mut i32) (i32.const 0))
1711
(export "memory" (memory $0))
1812
(start $start)
19-
(func $~lib/rt/stub/maybeGrowMemory (; 1 ;) (type $FUNCSIG$vi) (param $0 i32)
13+
(func $~lib/rt/stub/maybeGrowMemory (; 0 ;) (type $FUNCSIG$vi) (param $0 i32)
2014
(local $1 i32)
2115
(local $2 i32)
2216
local.get $0
@@ -58,7 +52,7 @@
5852
local.get $0
5953
global.set $~lib/rt/stub/offset
6054
)
61-
(func $~lib/rt/stub/__alloc (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
55+
(func $~lib/rt/stub/__alloc (; 1 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
6256
(local $1 i32)
6357
(local $2 i32)
6458
global.get $~lib/rt/stub/offset
@@ -85,48 +79,15 @@
8579
i32.store offset=12
8680
local.get $2
8781
)
88-
(func $interface/passAnInterface (; 3 ;) (type $FUNCSIG$vi) (param $0 i32)
89-
local.get $0
90-
i32.const 1
91-
i32.const 0
92-
local.get $0
93-
i32.const 8
94-
i32.sub
95-
i32.load
96-
call $~virtual
97-
call_indirect (type $FUNCSIG$iii)
98-
i32.const 42
99-
i32.ne
100-
if
101-
i32.const 0
102-
i32.const 24
103-
i32.const 37
104-
i32.const 2
105-
call $~lib/builtins/abort
106-
unreachable
107-
end
108-
local.get $0
109-
i32.const 1
110-
i32.const 3
111-
i32.const 1
82+
(func $interface/passAnInterface (; 2 ;) (type $FUNCSIG$vi) (param $0 i32)
11283
local.get $0
11384
i32.const 8
11485
i32.sub
11586
i32.load
116-
call $~virtual
117-
call_indirect (type $FUNCSIG$iiii)
118-
i32.const 4
119-
i32.ne
120-
if
121-
i32.const 0
122-
i32.const 24
123-
i32.const 38
124-
i32.const 2
125-
call $~lib/builtins/abort
126-
unreachable
127-
end
87+
drop
88+
unreachable
12889
)
129-
(func $start (; 4 ;) (type $FUNCSIG$v)
90+
(func $start (; 3 ;) (type $FUNCSIG$v)
13091
(local $0 i32)
13192
i32.const 48
13293
global.set $~lib/rt/stub/startOffset
@@ -151,59 +112,7 @@
151112
global.get $interface/sFoo
152113
call $interface/passAnInterface
153114
)
154-
(func $interface/AFoo#foo (; 5 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
155-
local.get $0
156-
i32.load
157-
local.get $1
158-
i32.add
159-
)
160-
(func $interface/AFoo#faa (; 6 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
161-
local.get $1
162-
local.get $2
163-
i32.add
164-
)
165-
(func $~virtual (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
166-
block $block$2$break
167-
block $switch$1$case$6
168-
block $switch$1$case$3
169-
local.get $0
170-
br_table $switch$1$case$3 $switch$1$case$6 $block$2$break
171-
end
172-
local.get $1
173-
i32.const 3
174-
i32.eq
175-
if
176-
i32.const 1
177-
return
178-
else
179-
local.get $1
180-
i32.const 4
181-
i32.ne
182-
br_if $block$2$break
183-
i32.const 2
184-
return
185-
end
186-
unreachable
187-
end
188-
local.get $1
189-
i32.const 3
190-
i32.eq
191-
if
192-
i32.const 3
193-
return
194-
else
195-
local.get $1
196-
i32.const 4
197-
i32.eq
198-
if
199-
i32.const 4
200-
return
201-
end
202-
end
203-
end
204-
unreachable
205-
)
206-
(func $null (; 8 ;) (type $FUNCSIG$v)
115+
(func $null (; 4 ;) (type $FUNCSIG$v)
207116
nop
208117
)
209118
)

0 commit comments

Comments
 (0)