Skip to content

Fix / Enhancement for Omitted Object Literals #1229

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 21, 2020
131 changes: 121 additions & 10 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8682,12 +8682,36 @@ export class Compiler extends DiagnosticEmitter {
var values = expression.values;
var members = classReference.members;
var hasErrors = false;
var exprs = new Array<ExpressionRef>(numNames + 2);
var exprs = new Array<ExpressionRef>();
var flow = this.currentFlow;
var tempLocal = isManaged
? flow.getAutoreleaseLocal(classReference.type)
: flow.getTempLocal(classReference.type);
assert(numNames == values.length);

// Assume all class fields will be omitted, and add them to our omitted list
var omittedClassFieldMembers = new Map();
if (members) {
for (let memberKey of members.keys()) {
let member = members.get(memberKey);
if (member && member.kind == ElementKind.FIELD) {
omittedClassFieldMembers.set(member.name, '');
}
}
}

// Define a function to add a new expression on our Object literal
let storeObjectLiteralField = (fieldInstance: Field, fieldType: Type, valueExpr: ExpressionRef) => {
exprs.push(this.module.store( // TODO: handle setters as well
fieldType.byteSize,
this.module.local_get(tempLocal.index, this.options.nativeSizeType),
valueExpr,
fieldType.toNativeType(),
fieldInstance.memoryOffset
));
};

// Iterate through the members definted in our expression
for (let i = 0, k = numNames; i < k; ++i) {
let member = members ? members.get(names[i].text) : null;
if (!member || member.kind != ElementKind.FIELD) {
Expand All @@ -8700,27 +8724,114 @@ export class Compiler extends DiagnosticEmitter {
}
let fieldInstance = <Field>member;
let fieldType = fieldInstance.type;
exprs[i + 1] = this.module.store( // TODO: handle setters as well
fieldType.byteSize,
this.module.local_get(tempLocal.index, this.options.nativeSizeType),
this.compileExpression(values[i], fieldInstance.type, Constraints.CONV_IMPLICIT),
fieldType.toNativeType(),
fieldInstance.memoryOffset
storeObjectLiteralField(
fieldInstance,
fieldType,
this.compileExpression(values[i], fieldInstance.type, Constraints.CONV_IMPLICIT)
);

// This member is no longer omitted, so delete from our omitted fields
omittedClassFieldMembers.delete(member.name);
}
this.currentType = classReference.type.nonNullableType;
if (hasErrors) return module.unreachable();

// Iterate through the remaining omittedClassFieldMembers.
if (members) {
for(let omittedClassFieldMemberKey of omittedClassFieldMembers.keys()) {
let member = members.get(omittedClassFieldMemberKey);

if(member) {

let fieldInstance = <Field>member;
let fieldType = fieldInstance.type;

if (fieldType.classReference) {
// TODO: Check if it is a class, with a default value (constructor with no params).
// TODO: Check if it can be null, and set to null

// Otherwise, error
this.error(
DiagnosticCode.Object_literal_is_missing_class_member_fields_that_must_be_defined,
expression.range, classReference.toString()
);
hasErrors = true;
continue;
}

switch(fieldType.kind) {
// i32 Types
case TypeKind.I8:
case TypeKind.I16:
case TypeKind.I32:
case TypeKind.U8:
case TypeKind.U16:
case TypeKind.U32:
case TypeKind.USIZE:
case TypeKind.ISIZE:
case TypeKind.BOOL: {
storeObjectLiteralField(
fieldInstance,
fieldType,
this.module.i32(0)
);
continue;
}

// i64 Types
case TypeKind.I64:
case TypeKind.U64: {
storeObjectLiteralField(
fieldInstance,
fieldType,
this.module.i64(0)
);
continue;
}

// f32 Types
case TypeKind.F32: {
storeObjectLiteralField(
fieldInstance,
fieldType,
this.module.f32(0)
);
continue;
}

// f64 Types
case TypeKind.F64: {
storeObjectLiteralField(
fieldInstance,
fieldType,
this.module.f64(0)
);
continue;
}
default: {}
}
}

// Otherwise, error
this.error(
DiagnosticCode.Object_literal_is_missing_class_member_fields_that_must_be_defined,
expression.range, classReference.toString()
);
hasErrors = true;
}
}
if (hasErrors) return module.unreachable();

// allocate a new instance first and assign 'this' to the temp. local
exprs[0] = module.local_set(
exprs.unshift(module.local_set(
tempLocal.index,
isManaged
? this.makeRetain(this.makeAllocation(classReference))
: this.makeAllocation(classReference)
);
));

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

if (!isManaged) flow.freeTempLocal(tempLocal);
this.currentType = classReference.type;
Expand Down
2 changes: 2 additions & 0 deletions src/diagnosticMessages.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export enum DiagnosticCode {
_0_is_not_a_valid_operator = 224,
Expression_cannot_be_represented_by_a_type = 225,
Expression_resolves_to_unusual_type_0 = 226,
Object_literal_is_missing_class_member_fields_that_must_be_defined = 227,
Type_0_is_cyclic_Module_will_include_deferred_garbage_collection = 900,
Importing_the_table_disables_some_indirect_call_optimizations = 901,
Exporting_the_table_disables_some_indirect_call_optimizations = 902,
Expand Down Expand Up @@ -194,6 +195,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 224: return "'{0}' is not a valid operator.";
case 225: return "Expression cannot be represented by a type.";
case 226: return "Expression resolves to unusual type '{0}'.";
case 227: return "Object literal is missing class member fields that must be defined";
case 900: return "Type '{0}' is cyclic. Module will include deferred garbage collection.";
case 901: return "Importing the table disables some indirect call optimizations.";
case 902: return "Exporting the table disables some indirect call optimizations.";
Expand Down
1 change: 1 addition & 0 deletions src/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"'{0}' is not a valid operator.": 224,
"Expression cannot be represented by a type.": 225,
"Expression resolves to unusual type '{0}'.": 226,
"Object literal is missing class member fields that must be defined": 227,

"Type '{0}' is cyclic. Module will include deferred garbage collection.": 900,
"Importing the table disables some indirect call optimizations.": 901,
Expand Down
5 changes: 5 additions & 0 deletions tests/compiler/std/object-literal-omitted.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"asc_flags": [
"--runtime full"
]
}
Loading