Skip to content

Commit 688dcd2

Browse files
authored
Implicitly inherit from Object (#2559)
BREAKING CHANGE: Constant class ids of `String`, `ArrayBuffer` etc. moved one value up, with `Object` now represented by ID=0.
1 parent a71f649 commit 688dcd2

File tree

272 files changed

+18037
-12313
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

272 files changed

+18037
-12313
lines changed

lib/loader/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ const ID_OFFSET = -8;
33
const SIZE_OFFSET = -4;
44

55
// Runtime ids
6-
const ARRAYBUFFER_ID = 0;
7-
const STRING_ID = 1;
8-
// const ARRAYBUFFERVIEW_ID = 2;
6+
// const OBJECT_ID = 0;
7+
const ARRAYBUFFER_ID = 1;
8+
const STRING_ID = 2;
99

1010
// Runtime type information
1111
const ARRAYBUFFERVIEW = 1 << 0;

lib/loader/tests/build/default.wasm

32 Bytes
Binary file not shown.

lib/loader/tests/build/legacy.wasm

32 Bytes
Binary file not shown.

lib/loader/umd/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ var loader = (function(exports) {
1313
// Runtime header offsets
1414
const ID_OFFSET = -8;
1515
const SIZE_OFFSET = -4; // Runtime ids
16+
// const OBJECT_ID = 0;
1617

17-
const ARRAYBUFFER_ID = 0;
18-
const STRING_ID = 1; // const ARRAYBUFFERVIEW_ID = 2;
19-
// Runtime type information
18+
const ARRAYBUFFER_ID = 1;
19+
const STRING_ID = 2; // Runtime type information
2020

2121
const ARRAYBUFFERVIEW = 1 << 0;
2222
const ARRAY = 1 << 1;

src/bindings/js.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ function isPlainFunction(signature: Signature, mode: Mode): bool {
13361336

13371337
function isPlainObject(clazz: Class): bool {
13381338
// A plain object does not inherit and does not have a constructor or private properties
1339-
if (clazz.base) return false;
1339+
if (clazz.base && !clazz.prototype.implicitlyExtendsObject) return false;
13401340
let members = clazz.members;
13411341
if (members) {
13421342
for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) {

src/bindings/tsd.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ export class TSDBuilder extends ExportsWalker {
230230

231231
isPlainObject(clazz: Class): bool {
232232
// A plain object does not inherit and does not have a constructor or private properties
233-
if (clazz.base) return false;
233+
if (clazz.base && !clazz.prototype.implicitlyExtendsObject) return false;
234234
let members = clazz.members;
235235
if (members) {
236236
for (let _values = Map_values(members), i = 0, k = _values.length; i < k; ++i) {

src/builtins.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,9 @@ export namespace BuiltinNames {
732732
export const String_eq = "~lib/string/String.__eq";
733733
export const String_ne = "~lib/string/String.__ne";
734734
export const String_not = "~lib/string/String.__not";
735+
736+
// std/object.ts
737+
export const Object = "~lib/object/Object";
735738
}
736739

737740
/** Builtin compilation context. */

src/compiler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,7 +1716,7 @@ export class Compiler extends DiagnosticEmitter {
17161716
}
17171717

17181718
// check that super has been called if this is a derived class
1719-
if (classInstance.base && !flow.is(FlowFlags.CallsSuper)) {
1719+
if (classInstance.base && !classInstance.prototype.implicitlyExtendsObject && !flow.is(FlowFlags.CallsSuper)) {
17201720
this.error(
17211721
DiagnosticCode.Constructors_for_derived_classes_must_contain_a_super_call,
17221722
instance.prototype.declaration.range
@@ -5950,7 +5950,7 @@ export class Compiler extends DiagnosticEmitter {
59505950
assert(parent.kind == ElementKind.Class);
59515951
let classInstance = <Class>parent;
59525952
let baseClassInstance = classInstance.base;
5953-
if (!baseClassInstance) {
5953+
if (!baseClassInstance || classInstance.prototype.implicitlyExtendsObject) {
59545954
this.error(
59555955
DiagnosticCode._super_can_only_be_referenced_in_a_derived_class,
59565956
expression.expression.range

src/program.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,14 @@ export class Program extends DiagnosticEmitter {
640640
}
641641
private _regexpInstance: Class | null = null;
642642

643+
/** Gets the standard `Object` prototype. */
644+
get objectPrototype(): ClassPrototype {
645+
let cached = this._objectPrototype;
646+
if (!cached) this._objectPrototype = cached = <ClassPrototype>this.require(CommonNames.Object, ElementKind.ClassPrototype);
647+
return cached;
648+
}
649+
private _objectPrototype: ClassPrototype | null = null;
650+
643651
/** Gets the standard `Object` instance. */
644652
get objectInstance(): Class {
645653
let cached = this._objectInstance;
@@ -1257,10 +1265,11 @@ export class Program extends DiagnosticEmitter {
12571265
}
12581266
}
12591267

1260-
// register ArrayBuffer (id=0), String (id=1), ArrayBufferView (id=2)
1261-
assert(this.arrayBufferInstance.id == 0);
1262-
assert(this.stringInstance.id == 1);
1263-
assert(this.arrayBufferViewInstance.id == 2);
1268+
// register foundational classes with fixed ids
1269+
assert(this.objectInstance.id == 0);
1270+
assert(this.arrayBufferInstance.id == 1);
1271+
assert(this.stringInstance.id == 2);
1272+
assert(this.arrayBufferViewInstance.id == 3);
12641273

12651274
// register classes backing basic types
12661275
this.registerWrapperClass(Type.i8, CommonNames.I8);
@@ -2044,7 +2053,14 @@ export class Program extends DiagnosticEmitter {
20442053
}
20452054

20462055
// remember classes that extend another class
2047-
if (declaration.extendsType) queuedExtends.push(element);
2056+
if (declaration.extendsType) {
2057+
queuedExtends.push(element);
2058+
} else if (
2059+
!element.hasDecorator(DecoratorFlags.Unmanaged) &&
2060+
element.internalName != BuiltinNames.Object
2061+
) {
2062+
element.implicitlyExtendsObject = true;
2063+
}
20482064

20492065
// initialize members
20502066
let memberDeclarations = declaration.members;
@@ -4165,6 +4181,8 @@ export class ClassPrototype extends DeclaredElement {
41654181
instances: Map<string,Class> | null = null;
41664182
/** Classes extending this class. */
41674183
extendees: Set<ClassPrototype> = new Set();
4184+
/** Whether this class implicitly extends `Object`. */
4185+
implicitlyExtendsObject: bool = false;
41684186

41694187
constructor(
41704188
/** Simple name. */

src/resolver.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3121,6 +3121,10 @@ export class Resolver extends DiagnosticEmitter {
31213121
// This is guaranteed to never happen at the entry of the recursion, i.e.
31223122
// where `resolveClass` is called from other code.
31233123
if (pendingClasses.has(base)) anyPending = true;
3124+
3125+
// Implicitly extend `Object` if a derived object
3126+
} else if (prototype.implicitlyExtendsObject) {
3127+
instance.setBase(this.program.objectInstance);
31243128
}
31253129

31263130
// Resolve interfaces if applicable
@@ -3298,13 +3302,15 @@ export class Resolver extends DiagnosticEmitter {
32983302
let memoryOffset: u32 = 0;
32993303
let base = instance.base;
33003304
if (base) {
3305+
let implicitlyExtendsObject = instance.prototype.implicitlyExtendsObject;
33013306
assert(!pendingClasses.has(base));
33023307
let baseMembers = base.members;
33033308
if (baseMembers) {
33043309
// TODO: for (let [baseMemberName, baseMember] of baseMembers) {
33053310
for (let _keys = Map_keys(baseMembers), i = 0, k = _keys.length; i < k; ++i) {
33063311
let memberName = unchecked(_keys[i]);
33073312
let baseMember = assert(baseMembers.get(memberName));
3313+
if (implicitlyExtendsObject && baseMember.is(CommonFlags.Static)) continue;
33083314
let existingMember = instance.getMember(memberName);
33093315
if (existingMember && !this.checkOverrideVisibility(memberName, existingMember, instance, baseMember, base, reportMode)) {
33103316
continue; // keep previous

0 commit comments

Comments
 (0)