Skip to content

Commit 53e314c

Browse files
authored
Improve compilation of object literals (#1229)
1 parent 106a4b0 commit 53e314c

8 files changed

+3906
-7
lines changed

src/compiler.ts

+87-7
Original file line numberDiff line numberDiff line change
@@ -8682,12 +8682,26 @@ export class Compiler extends DiagnosticEmitter {
86828682
var values = expression.values;
86838683
var members = classReference.members;
86848684
var hasErrors = false;
8685-
var exprs = new Array<ExpressionRef>(numNames + 2);
8685+
var exprs = new Array<ExpressionRef>();
86868686
var flow = this.currentFlow;
86878687
var tempLocal = isManaged
86888688
? flow.getAutoreleaseLocal(classReference.type)
86898689
: flow.getTempLocal(classReference.type);
86908690
assert(numNames == values.length);
8691+
8692+
// Assume all class fields will be omitted, and add them to our omitted list
8693+
let omittedClassFieldMembers = new Set<string>();
8694+
if (members) {
8695+
for (let _keys = Map_keys(members), i = 0, k = _keys.length; i < k; ++i) {
8696+
let memberKey = _keys[i];
8697+
let member = assert(members.get(memberKey));
8698+
if (member !== null && member.kind == ElementKind.FIELD) {
8699+
omittedClassFieldMembers.add(member.name);
8700+
}
8701+
}
8702+
}
8703+
8704+
// Iterate through the members defined in our expression
86918705
for (let i = 0, k = numNames; i < k; ++i) {
86928706
let member = members ? members.get(names[i].text) : null;
86938707
if (!member || member.kind != ElementKind.FIELD) {
@@ -8700,27 +8714,93 @@ export class Compiler extends DiagnosticEmitter {
87008714
}
87018715
let fieldInstance = <Field>member;
87028716
let fieldType = fieldInstance.type;
8703-
exprs[i + 1] = this.module.store( // TODO: handle setters as well
8717+
8718+
let expr = this.compileExpression(values[i], fieldType, Constraints.CONV_IMPLICIT | Constraints.WILL_RETAIN);
8719+
if (isManaged && fieldType.isManaged && !this.skippedAutoreleases.has(expr)) {
8720+
expr = this.makeRetain(expr);
8721+
}
8722+
exprs.push(this.module.store( // TODO: handle setters as well
87048723
fieldType.byteSize,
87058724
this.module.local_get(tempLocal.index, this.options.nativeSizeType),
8706-
this.compileExpression(values[i], fieldInstance.type, Constraints.CONV_IMPLICIT),
8725+
expr,
87078726
fieldType.toNativeType(),
87088727
fieldInstance.memoryOffset
8709-
);
8728+
));
8729+
8730+
// This member is no longer omitted, so delete from our omitted fields
8731+
omittedClassFieldMembers.delete(member.name);
87108732
}
87118733
this.currentType = classReference.type.nonNullableType;
87128734
if (hasErrors) return module.unreachable();
87138735

8736+
// Iterate through the remaining omittedClassFieldMembers.
8737+
if (members) {
8738+
8739+
for (let _values = Set_values(omittedClassFieldMembers), j = 0, l = _values.length; j < l; ++j) {
8740+
let omittedMemberKey = _values[j];
8741+
let member = assert(members.get(omittedMemberKey));
8742+
8743+
let fieldInstance = <Field>member;
8744+
let fieldType = fieldInstance.type;
8745+
8746+
if (fieldType.is(TypeFlags.REFERENCE) && fieldType.classReference !== null) {
8747+
// TODO: Check if it is a class, with a default value (constructor with no params).
8748+
if (!fieldType.is(TypeFlags.NULLABLE)) {
8749+
this.error(
8750+
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
8751+
expression.range, "<object>", classReference.toString()
8752+
);
8753+
hasErrors = true;
8754+
continue;
8755+
}
8756+
}
8757+
8758+
switch(fieldType.kind) {
8759+
// Number Types (and Number alias types)
8760+
case TypeKind.I8:
8761+
case TypeKind.I16:
8762+
case TypeKind.I32:
8763+
case TypeKind.U8:
8764+
case TypeKind.U16:
8765+
case TypeKind.U32:
8766+
case TypeKind.USIZE:
8767+
case TypeKind.ISIZE:
8768+
case TypeKind.BOOL:
8769+
case TypeKind.I64:
8770+
case TypeKind.U64:
8771+
case TypeKind.F32:
8772+
case TypeKind.F64: {
8773+
exprs.push(this.module.store( // TODO: handle setters as well
8774+
fieldType.byteSize,
8775+
this.module.local_get(tempLocal.index, this.options.nativeSizeType),
8776+
this.makeZero(fieldType),
8777+
fieldType.toNativeType(),
8778+
fieldInstance.memoryOffset
8779+
));
8780+
continue;
8781+
}
8782+
}
8783+
8784+
// Otherwise, error
8785+
this.error(
8786+
DiagnosticCode.Property_0_is_missing_in_type_1_but_required_in_type_2,
8787+
expression.range, "<object>", classReference.toString()
8788+
);
8789+
hasErrors = true;
8790+
}
8791+
}
8792+
if (hasErrors) return module.unreachable();
8793+
87148794
// allocate a new instance first and assign 'this' to the temp. local
8715-
exprs[0] = module.local_set(
8795+
exprs.unshift(module.local_set(
87168796
tempLocal.index,
87178797
isManaged
87188798
? this.makeRetain(this.makeAllocation(classReference))
87198799
: this.makeAllocation(classReference)
8720-
);
8800+
));
87218801

87228802
// once all field values have been set, return 'this'
8723-
exprs[exprs.length - 1] = module.local_get(tempLocal.index, this.options.nativeSizeType);
8803+
exprs.push(module.local_get(tempLocal.index, this.options.nativeSizeType));
87248804

87258805
if (!isManaged) flow.freeTempLocal(tempLocal);
87268806
this.currentType = classReference.type;

src/diagnosticMessages.generated.ts

+2
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ export enum DiagnosticCode {
150150
Namespace_0_has_no_exported_member_1 = 2694,
151151
Required_type_parameters_may_not_follow_optional_type_parameters = 2706,
152152
Duplicate_property_0 = 2718,
153+
Property_0_is_missing_in_type_1_but_required_in_type_2 = 2741,
153154
Type_0_has_no_call_signatures = 2757,
154155
File_0_not_found = 6054,
155156
Numeric_separators_are_not_allowed_here = 6188,
@@ -304,6 +305,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
304305
case 2694: return "Namespace '{0}' has no exported member '{1}'.";
305306
case 2706: return "Required type parameters may not follow optional type parameters.";
306307
case 2718: return "Duplicate property '{0}'.";
308+
case 2741: return "Property '{0}' is missing in type '{1}' but required in type '{2}'.";
307309
case 2757: return "Type '{0}' has no call signatures.";
308310
case 6054: return "File '{0}' not found.";
309311
case 6188: return "Numeric separators are not allowed here.";

src/diagnosticMessages.json

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
"Namespace '{0}' has no exported member '{1}'.": 2694,
147147
"Required type parameters may not follow optional type parameters.": 2706,
148148
"Duplicate property '{0}'.": 2718,
149+
"Property '{0}' is missing in type '{1}' but required in type '{2}'.": 2741,
149150
"Type '{0}' has no call signatures.": 2757,
150151

151152
"File '{0}' not found.": 6054,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"asc_flags": [
3+
"--runtime full"
4+
]
5+
}

0 commit comments

Comments
 (0)