@samitouri / QOS-React-2 / commits / 76e6eff110

[hir][typer] infer polymorphic types from PropertyLoad and PropertyCall

--- 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]]`~~

Mofei Zhang committed Mar 23, 2023 at 15:08 UTC 76e6eff110688b9a8cdbe23956ca6cc24dd60cdb
2 files changed +27 -19
compiler/forget/src/HIR/Environment.ts
+17 -13
@@ -7,7 +7,7 @@ import {
7 FunctionType,
8 IdentifierId,
9 makeIdentifierId,
10 - Type,
10 + ObjectType,
11 ValueKind,
12 } from "./HIR";
13 import { BUILTIN_HOOKS, Hook } from "./Hooks";
@@ -75,19 +75,23 @@ export class Environment {
75 };
76 }
77
78 - getPropertyType(receiver: Type, property: string): BuiltInType | null {
79 - if (receiver.kind === "Object" || receiver.kind === "Function") {
80 - const { shapeId } = receiver;
81 - if (shapeId !== null) {
82 - const shape = BUILTIN_SHAPES.get(shapeId);
83 - invariant(
84 - shape !== undefined,
85 - `[HIR] Forget internal error: cannot resolve shape ${shapeId}`
86 - );
87 - return shape.properties.get(property) ?? null;
88 - }
78 + getPropertyType(
79 + receiver: ObjectType | FunctionType,
80 + property: string
81 + ): BuiltInType | null {
82 + const { shapeId } = receiver;
83 + if (shapeId !== null) {
84 + // If an object or function has a shapeId, it must have been assigned
85 + // by Forget (and be present in a builtin or user-defined registry)
86 + const shape = BUILTIN_SHAPES.get(shapeId);
87 + invariant(
88 + shape !== undefined,
89 + `[HIR] Forget internal error: cannot resolve shape ${shapeId}`
90 + );
91 + return shape.properties.get(property) ?? null;
92 + } else {
93 + return null;
94 }
90 - return null;
95 }
96
97 getFunctionSignature(type: FunctionType): FunctionSignature | null {
compiler/forget/src/TypeInference/InferTypes.ts
+10 -6
@@ -231,13 +231,17 @@ class Unifier {
231 unify(tA: Type, tB: Type | PolyType): void {
232 if (tB.kind === "Property") {
233 const objectType = this.get(tB.object);
234 - const propertyType = this.env.getPropertyType(
235 - objectType,
236 - tB.propertyName
237 - );
238 - if (propertyType !== null) {
239 - this.unify(tA, propertyType);
234 + if (objectType.kind === "Object" || objectType.kind === "Function") {
235 + const propertyType = this.env.getPropertyType(
236 + objectType,
237 + tB.propertyName
238 + );
239 + if (propertyType !== null) {
240 + this.unify(tA, propertyType);
241 + }
242 }
243 + // We do not error if tB is not a known object or function (even if it
244 + // is a primitive), since JS implicit conversion to objects
245 return;
246 } else if (tB.kind === "FunctionCall") {
247 this.unifyFunctionCall(tA, tB);