diff --git a/compiler/forget/src/HIR/ObjectShape.ts b/compiler/forget/src/HIR/ObjectShape.ts index e5790bbe9a..2c59e01ba2 100644 --- a/compiler/forget/src/HIR/ObjectShape.ts +++ b/compiler/forget/src/HIR/ObjectShape.ts @@ -28,6 +28,7 @@ function addFunction( addShape(registry, shapeId, properties, fn); return { kind: "Function", + return: fn.returnType, shapeId, }; } @@ -63,7 +64,10 @@ export type FunctionSignature = { }; export type ObjectShape = { + // TODO(gsn): When can the key be null here? properties: Map; + // TODO(gsn): Why do Objects have a `functionType`? Oh, this the constructor. + // Let's rename to constructor? functionType: FunctionSignature | null; }; diff --git a/compiler/forget/src/HIR/Types.ts b/compiler/forget/src/HIR/Types.ts index 9e17dd086d..ee472ce6cd 100644 --- a/compiler/forget/src/HIR/Types.ts +++ b/compiler/forget/src/HIR/Types.ts @@ -9,7 +9,13 @@ import { Hook } from "./Hooks"; export type BuiltInType = PrimitiveType | FunctionType | ObjectType; -export type Type = BuiltInType | HookType | PhiType | TypeVar | PolyType; +export type Type = + | BuiltInType + | HookType + | PhiType + | TypeVar + | PolyType + | PropType; export type PrimitiveType = { kind: "Primitive" }; export type HookType = { kind: "Hook"; @@ -30,6 +36,7 @@ export type HookType = { export type FunctionType = { kind: "Function"; shapeId: string | null; + return: Type; }; export type ObjectType = { @@ -48,7 +55,11 @@ export type PhiType = { kind: "Phi"; operands: Array; }; - +export type PropType = { + kind: "Property"; + object: Type; + propertyName: string; +}; /** * Simulated opaque type for TypeId to prevent using normal numbers as ids * accidentally. @@ -109,7 +120,10 @@ function objectTypeEquals(tA: Type, tB: Type): boolean { } function funcTypeEquals(tA: Type, tB: Type): boolean { - return typeKindCheck(tA, tB, "Function"); + if (tA.kind !== "Function" || tB.kind !== "Function") { + return false; + } + return typeEquals(tA.return, tB.return); } function hookTypeEquals(tA: Type, tB: Type): boolean { diff --git a/compiler/forget/src/TypeInference/InferTypes.ts b/compiler/forget/src/TypeInference/InferTypes.ts index 6227d3a6c7..242938a640 100644 --- a/compiler/forget/src/TypeInference/InferTypes.ts +++ b/compiler/forget/src/TypeInference/InferTypes.ts @@ -63,25 +63,12 @@ function apply(func: HIRFunction, unifier: Unifier): void { } } -type FunctionCallType = { - kind: "FunctionCall"; - returnType: TypeVar; -}; - -type PolyType = - | { - kind: "Property"; - object: Type; - propertyName: string; - } - | FunctionCallType; - type TypeEquation = { left: Type; - right: Type | PolyType; + right: Type; }; -function equation(left: Type, right: Type | PolyType): TypeEquation { +function equation(left: Type, right: Type): TypeEquation { return { left, right, @@ -165,7 +152,7 @@ function* generateInstructionTypes( if (hook !== null) { type = { kind: "Hook", definition: hook }; } else { - type = { kind: "Function", shapeId: null }; + type = { kind: "Function", shapeId: null, return: left }; } yield equation(value.callee.identifier.type, type); break; @@ -193,9 +180,11 @@ function* generateInstructionTypes( case "MethodCall": { const returnType = makeType(); yield equation(value.property.identifier.type, { - kind: "FunctionCall", - returnType, + kind: "Function", + return: returnType, + shapeId: null, }); + yield equation(left, returnType); } } @@ -210,18 +199,7 @@ class Unifier { this.env = env; } - unifyFunctionCall(tA: Type, tB: FunctionCallType): void { - const propertyType = this.get(tA); - if (propertyType.kind === "Function") { - const fn = this.env.getFunctionSignature(propertyType); - const returnType = fn?.returnType ?? null; - if (returnType !== null) { - this.unify(tB.returnType, returnType); - } - } - } - - unify(tA: Type, tB: Type | PolyType): void { + unify(tA: Type, tB: Type): void { if (tB.kind === "Property") { const objectType = this.get(tB.object); if (objectType.kind === "Object" || objectType.kind === "Function") { @@ -236,9 +214,6 @@ class Unifier { // We do not error if tB is not a known object or function (even if it // is a primitive), since JS implicit conversion to objects return; - } else if (tB.kind === "FunctionCall") { - this.unifyFunctionCall(tA, tB); - return; } if (typeEquals(tA, tB)) { @@ -254,6 +229,11 @@ class Unifier { this.bindVariableTo(tB, tA); return; } + + if (tB.kind === "Function" && tA.kind === "Function") { + this.unify(tA.return, tB.return); + return; + } } bindVariableTo(v: TypeVar, type: Type): void { @@ -298,6 +278,10 @@ class Unifier { return type.operands.some((o) => this.occursCheck(v, o)); } + if (type.kind === "Function") { + return this.occursCheck(v, type.return); + } + return false; }