mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[typer] Track return type in FunctionType
Rather than having a special FunctionCall type that deduces the return type, change the FunctionType to include the return type. This return type is inferred as part of unification.
This commit is contained in:
@@ -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<string, BuiltInType | null>;
|
||||
// TODO(gsn): Why do Objects have a `functionType`? Oh, this the constructor.
|
||||
// Let's rename to constructor?
|
||||
functionType: FunctionSignature | null;
|
||||
};
|
||||
|
||||
|
||||
@@ -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<Type>;
|
||||
};
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user