diff --git a/.gitignore b/.gitignore index 5333257..3c33de8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ ast.json .env test.void /playground.* +/playground diff --git a/src/assembler.ts b/src/assembler.ts index 2ffb0d9..33ca8eb 100644 --- a/src/assembler.ts +++ b/src/assembler.ts @@ -431,6 +431,7 @@ const buildDSArrayType = (opts: CompileExprOpts, type: DSArrayType) => { /** TODO: Skip building types for object literals that are part of an initializer of an obj */ const buildObjectType = (opts: CompileExprOpts, obj: ObjectType): TypeRef => { if (obj.binaryenType) return obj.binaryenType; + if (obj.typeParameters) return opts.mod.nop(); const mod = opts.mod; const binaryenType = defineStructType(mod, { diff --git a/src/semantics/check-types.ts b/src/semantics/check-types.ts index b3671e9..159ab0e 100644 --- a/src/semantics/check-types.ts +++ b/src/semantics/check-types.ts @@ -270,6 +270,11 @@ const checkVarTypes = (variable: Variable): Variable => { }; const checkObjectType = (obj: ObjectType): ObjectType => { + if (obj.genericInstances) { + obj.genericInstances.forEach(checkTypes); + return obj; + } + obj.fields.forEach((field) => { if (!field.type) { throw new Error(`Unable to determine type for ${field.typeExpr}`); diff --git a/src/semantics/init-entities.ts b/src/semantics/init-entities.ts index 3e95b62..312b52d 100644 --- a/src/semantics/init-entities.ts +++ b/src/semantics/init-entities.ts @@ -291,9 +291,24 @@ const initDSArray = (type: List) => { const initNominalObjectType = (obj: List) => { const hasExtension = obj.optionalIdentifierAt(2)?.is("extends"); + const hasGenerics = obj.at(1)?.isList(); + + const name = hasGenerics + ? obj.listAt(1).identifierAt(0) + : obj.identifierAt(1); + + const typeParameters = hasGenerics + ? obj + .listAt(1) + .listAt(1) + .sliceAsArray(1) + .flatMap((p) => (p.isIdentifier() ? p : [])) + : undefined; + return new ObjectType({ ...obj.metadata, - name: obj.identifierAt(1), + name, + typeParameters, parentObjExpr: hasExtension ? obj.at(3) : undefined, value: extractObjectFields(hasExtension ? obj.listAt(4) : obj.listAt(2)), }); diff --git a/src/semantics/resolution/resolve-object-type.ts b/src/semantics/resolution/resolve-object-type.ts index 9e15a92..61157b1 100644 --- a/src/semantics/resolution/resolve-object-type.ts +++ b/src/semantics/resolution/resolve-object-type.ts @@ -36,6 +36,7 @@ const resolveGenericObjVersion = ( call: Call, type: ObjectType ): ObjectType | undefined => { + if (!call.typeArgs) return; const existing = type.genericInstances?.find((c) => typeArgsMatch(call, c)); if (existing) return existing; return resolveGenericsWithTypeArgs(type, call.typeArgs!); @@ -69,9 +70,9 @@ const resolveGenericsWithTypeArgs = ( newObj.registerEntity(type); }); - const resolvedFn = resolveObjectTypeTypes(newObj); - obj.registerGenericInstance(resolvedFn); - return obj; + const resolvedObj = resolveObjectTypeTypes(newObj); + obj.registerGenericInstance(resolvedObj); + return resolvedObj; }; const typeArgsMatch = (call: Call, candidate: ObjectType): boolean => diff --git a/src/syntax-objects/types.ts b/src/syntax-objects/types.ts index 6aca7dc..e3ede42 100644 --- a/src/syntax-objects/types.ts +++ b/src/syntax-objects/types.ts @@ -176,6 +176,7 @@ export class ObjectType extends BaseType { value: ObjectField[]; parentObjExpr?: Expr; parentObj?: ObjectType; + typeParameters?: Identifier[]; } ) { super(opts); @@ -185,6 +186,7 @@ export class ObjectType extends BaseType { }); this.parentObj = opts.parentObj; this.parentObjExpr = opts.parentObjExpr; + this.typeParameters = opts.typeParameters; } get size() { @@ -212,6 +214,7 @@ export class ObjectType extends BaseType { })), parentObj: this.parentObj, parentObjExpr: this.parentObj?.clone(), + typeParameters: this.typeParameters, }); }