From 76e6eff110688b9a8cdbe23956ca6cc24dd60cdb Mon Sep 17 00:00:00 2001 From: Mofei Zhang Date: Thu, 23 Mar 2023 15:08:17 -0400 Subject: [PATCH] [hir][typer] infer polymorphic types from PropertyLoad and PropertyCall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Expand Hindley Milner type inference to infer dependent types. Say `t` is a typevar and `t'` is some type (a built-in type, phi node, or another typevar). Our type equations are as follows (please edit/correct notation 😅) - type substitution: `t = t'`, - ~~dependent~~ polymorphic property load: `t = t'.prop` - polymorphic function call `t = fnCall{returnType}` - ~~dependent property call: `t = t'.prop` (only if t'.prop is a function type)~~ - ~~dependent return type: `t = t'.[[returntype]]`~~ --- compiler/forget/src/HIR/Environment.ts | 30 +++++++++++-------- .../forget/src/TypeInference/InferTypes.ts | 16 ++++++---- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/compiler/forget/src/HIR/Environment.ts b/compiler/forget/src/HIR/Environment.ts index 487900d013..d41e044713 100644 --- a/compiler/forget/src/HIR/Environment.ts +++ b/compiler/forget/src/HIR/Environment.ts @@ -7,7 +7,7 @@ import { FunctionType, IdentifierId, makeIdentifierId, - Type, + ObjectType, ValueKind, } from "./HIR"; import { BUILTIN_HOOKS, Hook } from "./Hooks"; @@ -75,19 +75,23 @@ export class Environment { }; } - getPropertyType(receiver: Type, property: string): BuiltInType | null { - if (receiver.kind === "Object" || receiver.kind === "Function") { - const { shapeId } = receiver; - if (shapeId !== null) { - const shape = BUILTIN_SHAPES.get(shapeId); - invariant( - shape !== undefined, - `[HIR] Forget internal error: cannot resolve shape ${shapeId}` - ); - return shape.properties.get(property) ?? null; - } + getPropertyType( + receiver: ObjectType | FunctionType, + property: string + ): BuiltInType | null { + const { shapeId } = receiver; + if (shapeId !== null) { + // If an object or function has a shapeId, it must have been assigned + // by Forget (and be present in a builtin or user-defined registry) + const shape = BUILTIN_SHAPES.get(shapeId); + invariant( + shape !== undefined, + `[HIR] Forget internal error: cannot resolve shape ${shapeId}` + ); + return shape.properties.get(property) ?? null; + } else { + return null; } - return null; } getFunctionSignature(type: FunctionType): FunctionSignature | null { diff --git a/compiler/forget/src/TypeInference/InferTypes.ts b/compiler/forget/src/TypeInference/InferTypes.ts index 8508658a38..e4ac142231 100644 --- a/compiler/forget/src/TypeInference/InferTypes.ts +++ b/compiler/forget/src/TypeInference/InferTypes.ts @@ -231,13 +231,17 @@ class Unifier { unify(tA: Type, tB: Type | PolyType): void { if (tB.kind === "Property") { const objectType = this.get(tB.object); - const propertyType = this.env.getPropertyType( - objectType, - tB.propertyName - ); - if (propertyType !== null) { - this.unify(tA, propertyType); + if (objectType.kind === "Object" || objectType.kind === "Function") { + const propertyType = this.env.getPropertyType( + objectType, + tB.propertyName + ); + if (propertyType !== null) { + this.unify(tA, propertyType); + } } + // 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);