[typer] Use opaque TypeId to number types

This commit is contained in:
Sathya Gunasekaran
2022-12-20 14:55:52 +00:00
parent 549f5a4af6
commit c130bcc9c2
2 changed files with 36 additions and 20 deletions
+18 -3
View File
@@ -460,17 +460,32 @@ export type ObjectType = { kind: "Object"; properties: Map<string, Type> };
export type PropType = { kind: "Prop"; objectType: Type; name: string };
export type TypeVar = {
kind: "Type";
name: string;
id: TypeId;
};
export type PolyType = {
kind: "Poly";
};
/**
* Simulated opaque type for TypeId to prevent using normal numbers as ids
* accidentally.
*/
const opaqueTypeId = Symbol();
export type TypeId = number & { [opaqueTypeId]: "IdentifierId" };
export function makeTypeId(id: number): TypeId {
invariant(
id >= 0 && Number.isInteger(id),
"Expected instruction id to be a non-negative integer"
);
return id as TypeId;
}
let typeCounter = 0;
export function makeType(): TypeVar {
return {
kind: "Type",
name: `t${typeCounter++}`, //TODO(gsn): Use a TypeID here
id: makeTypeId(typeCounter++),
};
}
@@ -488,7 +503,7 @@ export function typeEquals(tA: Type, tB: Type): boolean {
function typeVarEquals(tA: Type, tB: Type): boolean {
if (tA.kind === "Type" && tB.kind === "Type") {
return tA.name === tB.name;
return tA.id === tB.id;
}
return false;
}
+18 -17
View File
@@ -3,13 +3,14 @@ import invariant from "invariant";
import {
HIRFunction,
Instruction,
LValue,
makeType,
Place,
PropType,
Type,
typeEquals,
TypeId,
TypeVar,
Place,
LValue,
} from "./HIR";
import { eachInstructionOperand } from "./visitors";
@@ -210,7 +211,7 @@ function assignTypeForLvalue(
);
}
type Substitution = Map<string, Type>;
type Substitution = Map<TypeId, Type>;
class Unifier {
substitutions: Substitution = new Map();
@@ -231,13 +232,13 @@ class Unifier {
}
bindVariableTo(v: TypeVar, type: Type): void {
if (this.substitutions.has(v.name)) {
this.unify(this.substitutions.get(v.name)!, type);
if (this.substitutions.has(v.id)) {
this.unify(this.substitutions.get(v.id)!, type);
return;
}
if (type.kind === "Type" && this.substitutions.has(type.name)) {
this.unify(v, this.substitutions.get(type.name)!);
if (type.kind === "Type" && this.substitutions.has(type.id)) {
this.unify(v, this.substitutions.get(type.id)!);
return;
}
@@ -250,14 +251,14 @@ class Unifier {
throw new Error("cycle detected");
}
this.substitutions.set(v.name, type);
this.substitutions.set(v.id, type);
}
bindToProp(type: TypeVar, prop: PropType) {
let object = prop.objectType;
if (object.kind === "Type" && this.substitutions.has(object.name)) {
object = this.substitutions.get(object.name)!;
if (object.kind === "Type" && this.substitutions.has(object.id)) {
object = this.substitutions.get(object.id)!;
}
if (object.kind === "Object") {
@@ -270,14 +271,14 @@ class Unifier {
return;
}
this.substitutions.set(type.name, prop);
this.substitutions.set(type.id, prop);
}
occursCheck(v: TypeVar, type: Type): boolean {
if (typeEquals(v, type)) return true;
if (type.kind === "Type" && this.substitutions.has(type.name)) {
return this.occursCheck(v, this.substitutions.get(type.name)!);
if (type.kind === "Type" && this.substitutions.has(type.id)) {
return this.occursCheck(v, this.substitutions.get(type.id)!);
}
if (type.kind === "Object") {
@@ -297,8 +298,8 @@ class Unifier {
}
if (type.kind === "Type") {
if (this.substitutions.has(type.name)) {
return this.get(this.substitutions.get(type.name)!);
if (this.substitutions.has(type.id)) {
return this.get(this.substitutions.get(type.id)!);
} else {
return type;
}
@@ -308,8 +309,8 @@ class Unifier {
}
generalize(objectType: Type, name: Array<string> | null): Type | null {
if (objectType.kind === "Type" && this.substitutions.has(objectType.name)) {
objectType = this.substitutions.get(objectType.name)!;
if (objectType.kind === "Type" && this.substitutions.has(objectType.id)) {
objectType = this.substitutions.get(objectType.id)!;
}
if (