mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
[compiler] Upstream experimental flow integration (#34121)
all credit on the Flood/ code goes to @mvitousek and @jbrown215, i'm just the one upstreaming it
This commit is contained in:
@@ -0,0 +1,752 @@
|
||||
/**
|
||||
* TypeScript definitions for Flow type JSON representations
|
||||
* Based on the output of /data/sandcastle/boxes/fbsource/fbcode/flow/src/typing/convertTypes.ml
|
||||
*/
|
||||
|
||||
// Base type for all Flow types with a kind field
|
||||
export interface BaseFlowType {
|
||||
kind: string;
|
||||
}
|
||||
|
||||
// Type for representing polarity
|
||||
export type Polarity = 'positive' | 'negative' | 'neutral';
|
||||
|
||||
// Type for representing a name that might be null
|
||||
export type OptionalName = string | null;
|
||||
|
||||
// Open type
|
||||
export interface OpenType extends BaseFlowType {
|
||||
kind: 'Open';
|
||||
}
|
||||
|
||||
// Def type
|
||||
export interface DefType extends BaseFlowType {
|
||||
kind: 'Def';
|
||||
def: DefT;
|
||||
}
|
||||
|
||||
// Eval type
|
||||
export interface EvalType extends BaseFlowType {
|
||||
kind: 'Eval';
|
||||
type: FlowType;
|
||||
destructor: Destructor;
|
||||
}
|
||||
|
||||
// Generic type
|
||||
export interface GenericType extends BaseFlowType {
|
||||
kind: 'Generic';
|
||||
name: string;
|
||||
bound: FlowType;
|
||||
no_infer: boolean;
|
||||
}
|
||||
|
||||
// ThisInstance type
|
||||
export interface ThisInstanceType extends BaseFlowType {
|
||||
kind: 'ThisInstance';
|
||||
instance: InstanceT;
|
||||
is_this: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// ThisTypeApp type
|
||||
export interface ThisTypeAppType extends BaseFlowType {
|
||||
kind: 'ThisTypeApp';
|
||||
t1: FlowType;
|
||||
t2: FlowType;
|
||||
t_list?: Array<FlowType>;
|
||||
}
|
||||
|
||||
// TypeApp type
|
||||
export interface TypeAppType extends BaseFlowType {
|
||||
kind: 'TypeApp';
|
||||
type: FlowType;
|
||||
targs: Array<FlowType>;
|
||||
from_value: boolean;
|
||||
use_desc: boolean;
|
||||
}
|
||||
|
||||
// FunProto type
|
||||
export interface FunProtoType extends BaseFlowType {
|
||||
kind: 'FunProto';
|
||||
}
|
||||
|
||||
// ObjProto type
|
||||
export interface ObjProtoType extends BaseFlowType {
|
||||
kind: 'ObjProto';
|
||||
}
|
||||
|
||||
// NullProto type
|
||||
export interface NullProtoType extends BaseFlowType {
|
||||
kind: 'NullProto';
|
||||
}
|
||||
|
||||
// FunProtoBind type
|
||||
export interface FunProtoBindType extends BaseFlowType {
|
||||
kind: 'FunProtoBind';
|
||||
}
|
||||
|
||||
// Intersection type
|
||||
export interface IntersectionType extends BaseFlowType {
|
||||
kind: 'Intersection';
|
||||
members: Array<FlowType>;
|
||||
}
|
||||
|
||||
// Union type
|
||||
export interface UnionType extends BaseFlowType {
|
||||
kind: 'Union';
|
||||
members: Array<FlowType>;
|
||||
}
|
||||
|
||||
// Maybe type
|
||||
export interface MaybeType extends BaseFlowType {
|
||||
kind: 'Maybe';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
// Optional type
|
||||
export interface OptionalType extends BaseFlowType {
|
||||
kind: 'Optional';
|
||||
type: FlowType;
|
||||
use_desc: boolean;
|
||||
}
|
||||
|
||||
// Keys type
|
||||
export interface KeysType extends BaseFlowType {
|
||||
kind: 'Keys';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
// Annot type
|
||||
export interface AnnotType extends BaseFlowType {
|
||||
kind: 'Annot';
|
||||
type: FlowType;
|
||||
use_desc: boolean;
|
||||
}
|
||||
|
||||
// Opaque type
|
||||
export interface OpaqueType extends BaseFlowType {
|
||||
kind: 'Opaque';
|
||||
opaquetype: {
|
||||
opaque_id: string;
|
||||
underlying_t: FlowType | null;
|
||||
super_t: FlowType | null;
|
||||
opaque_type_args: Array<{
|
||||
name: string;
|
||||
type: FlowType;
|
||||
polarity: Polarity;
|
||||
}>;
|
||||
opaque_name: string;
|
||||
};
|
||||
}
|
||||
|
||||
// Namespace type
|
||||
export interface NamespaceType extends BaseFlowType {
|
||||
kind: 'Namespace';
|
||||
namespace_symbol: {
|
||||
symbol: string;
|
||||
};
|
||||
values_type: FlowType;
|
||||
types_tmap: PropertyMap;
|
||||
}
|
||||
|
||||
// Any type
|
||||
export interface AnyType extends BaseFlowType {
|
||||
kind: 'Any';
|
||||
}
|
||||
|
||||
// StrUtil type
|
||||
export interface StrUtilType extends BaseFlowType {
|
||||
kind: 'StrUtil';
|
||||
op: 'StrPrefix' | 'StrSuffix';
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
remainder?: FlowType;
|
||||
}
|
||||
|
||||
// TypeParam definition
|
||||
export interface TypeParam {
|
||||
name: string;
|
||||
bound: FlowType;
|
||||
polarity: Polarity;
|
||||
default: FlowType | null;
|
||||
}
|
||||
|
||||
// EnumInfo types
|
||||
export type EnumInfo = ConcreteEnum | AbstractEnum;
|
||||
|
||||
export interface ConcreteEnum {
|
||||
kind: 'ConcreteEnum';
|
||||
enum_name: string;
|
||||
enum_id: string;
|
||||
members: Array<string>;
|
||||
representation_t: FlowType;
|
||||
has_unknown_members: boolean;
|
||||
}
|
||||
|
||||
export interface AbstractEnum {
|
||||
kind: 'AbstractEnum';
|
||||
representation_t: FlowType;
|
||||
}
|
||||
|
||||
// CanonicalRendersForm types
|
||||
export type CanonicalRendersForm =
|
||||
| InstrinsicRenders
|
||||
| NominalRenders
|
||||
| StructuralRenders
|
||||
| DefaultRenders;
|
||||
|
||||
export interface InstrinsicRenders {
|
||||
kind: 'InstrinsicRenders';
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface NominalRenders {
|
||||
kind: 'NominalRenders';
|
||||
renders_id: string;
|
||||
renders_name: string;
|
||||
renders_super: FlowType;
|
||||
}
|
||||
|
||||
export interface StructuralRenders {
|
||||
kind: 'StructuralRenders';
|
||||
renders_variant: 'RendersNormal' | 'RendersMaybe' | 'RendersStar';
|
||||
renders_structural_type: FlowType;
|
||||
}
|
||||
|
||||
export interface DefaultRenders {
|
||||
kind: 'DefaultRenders';
|
||||
}
|
||||
|
||||
// InstanceT definition
|
||||
export interface InstanceT {
|
||||
inst: InstType;
|
||||
static: FlowType;
|
||||
super: FlowType;
|
||||
implements: Array<FlowType>;
|
||||
}
|
||||
|
||||
// InstType definition
|
||||
export interface InstType {
|
||||
class_name: string | null;
|
||||
class_id: string;
|
||||
type_args: Array<{
|
||||
name: string;
|
||||
type: FlowType;
|
||||
polarity: Polarity;
|
||||
}>;
|
||||
own_props: PropertyMap;
|
||||
proto_props: PropertyMap;
|
||||
call_t: null | {
|
||||
id: number;
|
||||
call: FlowType;
|
||||
};
|
||||
}
|
||||
|
||||
// DefT types
|
||||
export type DefT =
|
||||
| NumGeneralType
|
||||
| StrGeneralType
|
||||
| BoolGeneralType
|
||||
| BigIntGeneralType
|
||||
| EmptyType
|
||||
| MixedType
|
||||
| NullType
|
||||
| VoidType
|
||||
| SymbolType
|
||||
| FunType
|
||||
| ObjType
|
||||
| ArrType
|
||||
| ClassType
|
||||
| InstanceType
|
||||
| SingletonStrType
|
||||
| NumericStrKeyType
|
||||
| SingletonNumType
|
||||
| SingletonBoolType
|
||||
| SingletonBigIntType
|
||||
| TypeType
|
||||
| PolyType
|
||||
| ReactAbstractComponentType
|
||||
| RendersType
|
||||
| EnumValueType
|
||||
| EnumObjectType;
|
||||
|
||||
export interface NumGeneralType extends BaseFlowType {
|
||||
kind: 'NumGeneral';
|
||||
}
|
||||
|
||||
export interface StrGeneralType extends BaseFlowType {
|
||||
kind: 'StrGeneral';
|
||||
}
|
||||
|
||||
export interface BoolGeneralType extends BaseFlowType {
|
||||
kind: 'BoolGeneral';
|
||||
}
|
||||
|
||||
export interface BigIntGeneralType extends BaseFlowType {
|
||||
kind: 'BigIntGeneral';
|
||||
}
|
||||
|
||||
export interface EmptyType extends BaseFlowType {
|
||||
kind: 'Empty';
|
||||
}
|
||||
|
||||
export interface MixedType extends BaseFlowType {
|
||||
kind: 'Mixed';
|
||||
}
|
||||
|
||||
export interface NullType extends BaseFlowType {
|
||||
kind: 'Null';
|
||||
}
|
||||
|
||||
export interface VoidType extends BaseFlowType {
|
||||
kind: 'Void';
|
||||
}
|
||||
|
||||
export interface SymbolType extends BaseFlowType {
|
||||
kind: 'Symbol';
|
||||
}
|
||||
|
||||
export interface FunType extends BaseFlowType {
|
||||
kind: 'Fun';
|
||||
static: FlowType;
|
||||
funtype: FunTypeObj;
|
||||
}
|
||||
|
||||
export interface ObjType extends BaseFlowType {
|
||||
kind: 'Obj';
|
||||
objtype: ObjTypeObj;
|
||||
}
|
||||
|
||||
export interface ArrType extends BaseFlowType {
|
||||
kind: 'Arr';
|
||||
arrtype: ArrTypeObj;
|
||||
}
|
||||
|
||||
export interface ClassType extends BaseFlowType {
|
||||
kind: 'Class';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
export interface InstanceType extends BaseFlowType {
|
||||
kind: 'Instance';
|
||||
instance: InstanceT;
|
||||
}
|
||||
|
||||
export interface SingletonStrType extends BaseFlowType {
|
||||
kind: 'SingletonStr';
|
||||
from_annot: boolean;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface NumericStrKeyType extends BaseFlowType {
|
||||
kind: 'NumericStrKey';
|
||||
number: string;
|
||||
string: string;
|
||||
}
|
||||
|
||||
export interface SingletonNumType extends BaseFlowType {
|
||||
kind: 'SingletonNum';
|
||||
from_annot: boolean;
|
||||
number: string;
|
||||
string: string;
|
||||
}
|
||||
|
||||
export interface SingletonBoolType extends BaseFlowType {
|
||||
kind: 'SingletonBool';
|
||||
from_annot: boolean;
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export interface SingletonBigIntType extends BaseFlowType {
|
||||
kind: 'SingletonBigInt';
|
||||
from_annot: boolean;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface TypeType extends BaseFlowType {
|
||||
kind: 'Type';
|
||||
type_kind: TypeTKind;
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
export type TypeTKind =
|
||||
| 'TypeAliasKind'
|
||||
| 'TypeParamKind'
|
||||
| 'OpaqueKind'
|
||||
| 'ImportTypeofKind'
|
||||
| 'ImportClassKind'
|
||||
| 'ImportEnumKind'
|
||||
| 'InstanceKind'
|
||||
| 'RenderTypeKind';
|
||||
|
||||
export interface PolyType extends BaseFlowType {
|
||||
kind: 'Poly';
|
||||
tparams: Array<TypeParam>;
|
||||
t_out: FlowType;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ReactAbstractComponentType extends BaseFlowType {
|
||||
kind: 'ReactAbstractComponent';
|
||||
config: FlowType;
|
||||
renders: FlowType;
|
||||
instance: ComponentInstance;
|
||||
component_kind: ComponentKind;
|
||||
}
|
||||
|
||||
export type ComponentInstance =
|
||||
| {kind: 'RefSetterProp'; type: FlowType}
|
||||
| {kind: 'Omitted'};
|
||||
|
||||
export type ComponentKind =
|
||||
| {kind: 'Structural'}
|
||||
| {kind: 'Nominal'; id: string; name: string; types: Array<FlowType> | null};
|
||||
|
||||
export interface RendersType extends BaseFlowType {
|
||||
kind: 'Renders';
|
||||
form: CanonicalRendersForm;
|
||||
}
|
||||
|
||||
export interface EnumValueType extends BaseFlowType {
|
||||
kind: 'EnumValue';
|
||||
enum_info: EnumInfo;
|
||||
}
|
||||
|
||||
export interface EnumObjectType extends BaseFlowType {
|
||||
kind: 'EnumObject';
|
||||
enum_value_t: FlowType;
|
||||
enum_info: EnumInfo;
|
||||
}
|
||||
|
||||
// ObjKind types
|
||||
export type ObjKind =
|
||||
| {kind: 'Exact'}
|
||||
| {kind: 'Inexact'}
|
||||
| {kind: 'Indexed'; dicttype: DictType};
|
||||
|
||||
// DictType definition
|
||||
export interface DictType {
|
||||
dict_name: string | null;
|
||||
key: FlowType;
|
||||
value: FlowType;
|
||||
dict_polarity: Polarity;
|
||||
}
|
||||
|
||||
// ArrType types
|
||||
export type ArrTypeObj = ArrayAT | TupleAT | ROArrayAT;
|
||||
|
||||
export interface ArrayAT {
|
||||
kind: 'ArrayAT';
|
||||
elem_t: FlowType;
|
||||
}
|
||||
|
||||
export interface TupleAT {
|
||||
kind: 'TupleAT';
|
||||
elem_t: FlowType;
|
||||
elements: Array<TupleElement>;
|
||||
min_arity: number;
|
||||
max_arity: number;
|
||||
inexact: boolean;
|
||||
}
|
||||
|
||||
export interface ROArrayAT {
|
||||
kind: 'ROArrayAT';
|
||||
elem_t: FlowType;
|
||||
}
|
||||
|
||||
// TupleElement definition
|
||||
export interface TupleElement {
|
||||
name: string | null;
|
||||
t: FlowType;
|
||||
polarity: Polarity;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
// Flags definition
|
||||
export interface Flags {
|
||||
obj_kind: ObjKind;
|
||||
}
|
||||
|
||||
// Property types
|
||||
export type Property =
|
||||
| FieldProperty
|
||||
| GetProperty
|
||||
| SetProperty
|
||||
| GetSetProperty
|
||||
| MethodProperty;
|
||||
|
||||
export interface FieldProperty {
|
||||
kind: 'Field';
|
||||
type: FlowType;
|
||||
polarity: Polarity;
|
||||
}
|
||||
|
||||
export interface GetProperty {
|
||||
kind: 'Get';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
export interface SetProperty {
|
||||
kind: 'Set';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
export interface GetSetProperty {
|
||||
kind: 'GetSet';
|
||||
get_type: FlowType;
|
||||
set_type: FlowType;
|
||||
}
|
||||
|
||||
export interface MethodProperty {
|
||||
kind: 'Method';
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
// PropertyMap definition
|
||||
export interface PropertyMap {
|
||||
[key: string]: Property; // For other properties in the map
|
||||
}
|
||||
|
||||
// ObjType definition
|
||||
export interface ObjTypeObj {
|
||||
flags: Flags;
|
||||
props: PropertyMap;
|
||||
proto_t: FlowType;
|
||||
call_t: number | null;
|
||||
}
|
||||
|
||||
// FunType definition
|
||||
export interface FunTypeObj {
|
||||
this_t: {
|
||||
type: FlowType;
|
||||
status: ThisStatus;
|
||||
};
|
||||
params: Array<{
|
||||
name: string | null;
|
||||
type: FlowType;
|
||||
}>;
|
||||
rest_param: null | {
|
||||
name: string | null;
|
||||
type: FlowType;
|
||||
};
|
||||
return_t: FlowType;
|
||||
type_guard: null | {
|
||||
inferred: boolean;
|
||||
param_name: string;
|
||||
type_guard: FlowType;
|
||||
one_sided: boolean;
|
||||
};
|
||||
effect: Effect;
|
||||
}
|
||||
|
||||
// ThisStatus types
|
||||
export type ThisStatus =
|
||||
| {kind: 'This_Method'; unbound: boolean}
|
||||
| {kind: 'This_Function'};
|
||||
|
||||
// Effect types
|
||||
export type Effect =
|
||||
| {kind: 'HookDecl'; id: string}
|
||||
| {kind: 'HookAnnot'}
|
||||
| {kind: 'ArbitraryEffect'}
|
||||
| {kind: 'AnyEffect'};
|
||||
|
||||
// Destructor types
|
||||
export type Destructor =
|
||||
| NonMaybeTypeDestructor
|
||||
| PropertyTypeDestructor
|
||||
| ElementTypeDestructor
|
||||
| OptionalIndexedAccessNonMaybeTypeDestructor
|
||||
| OptionalIndexedAccessResultTypeDestructor
|
||||
| ExactTypeDestructor
|
||||
| ReadOnlyTypeDestructor
|
||||
| PartialTypeDestructor
|
||||
| RequiredTypeDestructor
|
||||
| SpreadTypeDestructor
|
||||
| SpreadTupleTypeDestructor
|
||||
| RestTypeDestructor
|
||||
| ValuesTypeDestructor
|
||||
| ConditionalTypeDestructor
|
||||
| TypeMapDestructor
|
||||
| ReactElementPropsTypeDestructor
|
||||
| ReactElementConfigTypeDestructor
|
||||
| ReactCheckComponentConfigDestructor
|
||||
| ReactDRODestructor
|
||||
| MakeHooklikeDestructor
|
||||
| MappedTypeDestructor
|
||||
| EnumTypeDestructor;
|
||||
|
||||
export interface NonMaybeTypeDestructor {
|
||||
kind: 'NonMaybeType';
|
||||
}
|
||||
|
||||
export interface PropertyTypeDestructor {
|
||||
kind: 'PropertyType';
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ElementTypeDestructor {
|
||||
kind: 'ElementType';
|
||||
index_type: FlowType;
|
||||
}
|
||||
|
||||
export interface OptionalIndexedAccessNonMaybeTypeDestructor {
|
||||
kind: 'OptionalIndexedAccessNonMaybeType';
|
||||
index: OptionalIndexedAccessIndex;
|
||||
}
|
||||
|
||||
export type OptionalIndexedAccessIndex =
|
||||
| {kind: 'StrLitIndex'; name: string}
|
||||
| {kind: 'TypeIndex'; type: FlowType};
|
||||
|
||||
export interface OptionalIndexedAccessResultTypeDestructor {
|
||||
kind: 'OptionalIndexedAccessResultType';
|
||||
}
|
||||
|
||||
export interface ExactTypeDestructor {
|
||||
kind: 'ExactType';
|
||||
}
|
||||
|
||||
export interface ReadOnlyTypeDestructor {
|
||||
kind: 'ReadOnlyType';
|
||||
}
|
||||
|
||||
export interface PartialTypeDestructor {
|
||||
kind: 'PartialType';
|
||||
}
|
||||
|
||||
export interface RequiredTypeDestructor {
|
||||
kind: 'RequiredType';
|
||||
}
|
||||
|
||||
export interface SpreadTypeDestructor {
|
||||
kind: 'SpreadType';
|
||||
target: SpreadTarget;
|
||||
operands: Array<SpreadOperand>;
|
||||
operand_slice: Slice | null;
|
||||
}
|
||||
|
||||
export type SpreadTarget =
|
||||
| {kind: 'Value'; make_seal: 'Sealed' | 'Frozen' | 'As_Const'}
|
||||
| {kind: 'Annot'; make_exact: boolean};
|
||||
|
||||
export type SpreadOperand = {kind: 'Type'; type: FlowType} | Slice;
|
||||
|
||||
export interface Slice {
|
||||
kind: 'Slice';
|
||||
prop_map: PropertyMap;
|
||||
generics: Array<string>;
|
||||
dict: DictType | null;
|
||||
reachable_targs: Array<{
|
||||
type: FlowType;
|
||||
polarity: Polarity;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface SpreadTupleTypeDestructor {
|
||||
kind: 'SpreadTupleType';
|
||||
inexact: boolean;
|
||||
resolved_rev: string;
|
||||
unresolved: string;
|
||||
}
|
||||
|
||||
export interface RestTypeDestructor {
|
||||
kind: 'RestType';
|
||||
merge_mode: RestMergeMode;
|
||||
type: FlowType;
|
||||
}
|
||||
|
||||
export type RestMergeMode =
|
||||
| {kind: 'SpreadReversal'}
|
||||
| {kind: 'ReactConfigMerge'; polarity: Polarity}
|
||||
| {kind: 'Omit'};
|
||||
|
||||
export interface ValuesTypeDestructor {
|
||||
kind: 'ValuesType';
|
||||
}
|
||||
|
||||
export interface ConditionalTypeDestructor {
|
||||
kind: 'ConditionalType';
|
||||
distributive_tparam_name: string | null;
|
||||
infer_tparams: string;
|
||||
extends_t: FlowType;
|
||||
true_t: FlowType;
|
||||
false_t: FlowType;
|
||||
}
|
||||
|
||||
export interface TypeMapDestructor {
|
||||
kind: 'ObjectKeyMirror';
|
||||
}
|
||||
|
||||
export interface ReactElementPropsTypeDestructor {
|
||||
kind: 'ReactElementPropsType';
|
||||
}
|
||||
|
||||
export interface ReactElementConfigTypeDestructor {
|
||||
kind: 'ReactElementConfigType';
|
||||
}
|
||||
|
||||
export interface ReactCheckComponentConfigDestructor {
|
||||
kind: 'ReactCheckComponentConfig';
|
||||
props: {
|
||||
[key: string]: Property;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ReactDRODestructor {
|
||||
kind: 'ReactDRO';
|
||||
dro_type:
|
||||
| 'HookReturn'
|
||||
| 'HookArg'
|
||||
| 'Props'
|
||||
| 'ImmutableAnnot'
|
||||
| 'DebugAnnot';
|
||||
}
|
||||
|
||||
export interface MakeHooklikeDestructor {
|
||||
kind: 'MakeHooklike';
|
||||
}
|
||||
|
||||
export interface MappedTypeDestructor {
|
||||
kind: 'MappedType';
|
||||
homomorphic: Homomorphic;
|
||||
distributive_tparam_name: string | null;
|
||||
property_type: FlowType;
|
||||
mapped_type_flags: {
|
||||
variance: Polarity;
|
||||
optional: 'MakeOptional' | 'RemoveOptional' | 'KeepOptionality';
|
||||
};
|
||||
}
|
||||
|
||||
export type Homomorphic =
|
||||
| {kind: 'Homomorphic'}
|
||||
| {kind: 'Unspecialized'}
|
||||
| {kind: 'SemiHomomorphic'; type: FlowType};
|
||||
|
||||
export interface EnumTypeDestructor {
|
||||
kind: 'EnumType';
|
||||
}
|
||||
|
||||
// Union of all possible Flow types
|
||||
export type FlowType =
|
||||
| OpenType
|
||||
| DefType
|
||||
| EvalType
|
||||
| GenericType
|
||||
| ThisInstanceType
|
||||
| ThisTypeAppType
|
||||
| TypeAppType
|
||||
| FunProtoType
|
||||
| ObjProtoType
|
||||
| NullProtoType
|
||||
| FunProtoBindType
|
||||
| IntersectionType
|
||||
| UnionType
|
||||
| MaybeType
|
||||
| OptionalType
|
||||
| KeysType
|
||||
| AnnotType
|
||||
| OpaqueType
|
||||
| NamespaceType
|
||||
| AnyType
|
||||
| StrUtilType;
|
||||
@@ -0,0 +1,131 @@
|
||||
import {CompilerError, SourceLocation} from '..';
|
||||
import {
|
||||
ConcreteType,
|
||||
printConcrete,
|
||||
printType,
|
||||
StructuralValue,
|
||||
Type,
|
||||
VariableId,
|
||||
} from './Types';
|
||||
|
||||
export function unsupportedLanguageFeature(
|
||||
desc: string,
|
||||
loc: SourceLocation,
|
||||
): never {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Typedchecker does not currently support language feature: ${desc}`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
|
||||
export type UnificationError =
|
||||
| {
|
||||
kind: 'TypeUnification';
|
||||
left: ConcreteType<Type>;
|
||||
right: ConcreteType<Type>;
|
||||
}
|
||||
| {
|
||||
kind: 'StructuralUnification';
|
||||
left: StructuralValue;
|
||||
right: ConcreteType<Type>;
|
||||
};
|
||||
|
||||
function printUnificationError(err: UnificationError): string {
|
||||
if (err.kind === 'TypeUnification') {
|
||||
return `${printConcrete(err.left, printType)} is incompatible with ${printConcrete(err.right, printType)}`;
|
||||
} else {
|
||||
return `structural ${err.left.kind} is incompatible with ${printConcrete(err.right, printType)}`;
|
||||
}
|
||||
}
|
||||
|
||||
export function raiseUnificationErrors(
|
||||
errs: null | Array<UnificationError>,
|
||||
loc: SourceLocation,
|
||||
): void {
|
||||
if (errs != null) {
|
||||
if (errs.length === 0) {
|
||||
CompilerError.invariant(false, {
|
||||
reason: 'Should not have array of zero errors',
|
||||
loc,
|
||||
});
|
||||
} else if (errs.length === 1) {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Unable to unify types because ${printUnificationError(errs[0])}`,
|
||||
loc,
|
||||
});
|
||||
} else {
|
||||
const messages = errs
|
||||
.map(err => `\t* ${printUnificationError(err)}`)
|
||||
.join('\n');
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Unable to unify types because:\n${messages}`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function unresolvableTypeVariable(
|
||||
id: VariableId,
|
||||
loc: SourceLocation,
|
||||
): never {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Unable to resolve free variable ${id} to a concrete type`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
|
||||
export function cannotAddVoid(explicit: boolean, loc: SourceLocation): never {
|
||||
if (explicit) {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Undefined is not a valid operand of \`+\``,
|
||||
loc,
|
||||
});
|
||||
} else {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Value may be undefined, which is not a valid operand of \`+\``,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function unsupportedTypeAnnotation(
|
||||
desc: string,
|
||||
loc: SourceLocation,
|
||||
): never {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Typedchecker does not currently support type annotation: ${desc}`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
|
||||
export function checkTypeArgumentArity(
|
||||
desc: string,
|
||||
expected: number,
|
||||
actual: number,
|
||||
loc: SourceLocation,
|
||||
): void {
|
||||
if (expected !== actual) {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Expected ${desc} to have ${expected} type parameters, got ${actual}`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function notAFunction(desc: string, loc: SourceLocation): void {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Cannot call ${desc} because it is not a function`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
|
||||
export function notAPolymorphicFunction(
|
||||
desc: string,
|
||||
loc: SourceLocation,
|
||||
): void {
|
||||
CompilerError.throwInvalidJS({
|
||||
reason: `Cannot call ${desc} with type arguments because it is not a polymorphic function`,
|
||||
loc,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
import {GeneratedSource} from '../HIR';
|
||||
import {assertExhaustive} from '../Utils/utils';
|
||||
import {unsupportedLanguageFeature} from './TypeErrors';
|
||||
import {
|
||||
ConcreteType,
|
||||
ResolvedType,
|
||||
TypeParameter,
|
||||
TypeParameterId,
|
||||
DEBUG,
|
||||
printConcrete,
|
||||
printType,
|
||||
} from './Types';
|
||||
|
||||
export function substitute(
|
||||
type: ConcreteType<ResolvedType>,
|
||||
typeParameters: Array<TypeParameter<ResolvedType>>,
|
||||
typeArguments: Array<ResolvedType>,
|
||||
): ResolvedType {
|
||||
const substMap = new Map<TypeParameterId, ResolvedType>();
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
// TODO: Length checks to make sure type params match up with args
|
||||
const typeParameter = typeParameters[i];
|
||||
const typeArgument = typeArguments[i];
|
||||
substMap.set(typeParameter.id, typeArgument);
|
||||
}
|
||||
const substitutionFunction = (t: ResolvedType): ResolvedType => {
|
||||
// TODO: We really want a stateful mapper or visitor here so that we can model nested polymorphic types
|
||||
if (t.type.kind === 'Generic' && substMap.has(t.type.id)) {
|
||||
const substitutedType = substMap.get(t.type.id)!;
|
||||
return substitutedType;
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'Concrete',
|
||||
type: mapType(substitutionFunction, t.type),
|
||||
platform: t.platform,
|
||||
};
|
||||
};
|
||||
|
||||
const substituted = mapType(substitutionFunction, type);
|
||||
|
||||
if (DEBUG) {
|
||||
let substs = '';
|
||||
for (let i = 0; i < typeParameters.length; i++) {
|
||||
const typeParameter = typeParameters[i];
|
||||
const typeArgument = typeArguments[i];
|
||||
substs += `[${typeParameter.name}${typeParameter.id} := ${printType(typeArgument)}]`;
|
||||
}
|
||||
console.log(
|
||||
`${printConcrete(type, printType)}${substs} = ${printConcrete(substituted, printType)}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {kind: 'Concrete', type: substituted, platform: /* TODO */ 'shared'};
|
||||
}
|
||||
|
||||
export function mapType<T, U>(
|
||||
f: (t: T) => U,
|
||||
type: ConcreteType<T>,
|
||||
): ConcreteType<U> {
|
||||
switch (type.kind) {
|
||||
case 'Mixed':
|
||||
case 'Number':
|
||||
case 'String':
|
||||
case 'Boolean':
|
||||
case 'Void':
|
||||
return type;
|
||||
|
||||
case 'Nullable':
|
||||
return {
|
||||
kind: 'Nullable',
|
||||
type: f(type.type),
|
||||
};
|
||||
|
||||
case 'Array':
|
||||
return {
|
||||
kind: 'Array',
|
||||
element: f(type.element),
|
||||
};
|
||||
|
||||
case 'Set':
|
||||
return {
|
||||
kind: 'Set',
|
||||
element: f(type.element),
|
||||
};
|
||||
|
||||
case 'Map':
|
||||
return {
|
||||
kind: 'Map',
|
||||
key: f(type.key),
|
||||
value: f(type.value),
|
||||
};
|
||||
|
||||
case 'Function':
|
||||
return {
|
||||
kind: 'Function',
|
||||
typeParameters:
|
||||
type.typeParameters?.map(param => ({
|
||||
id: param.id,
|
||||
name: param.name,
|
||||
bound: f(param.bound),
|
||||
})) ?? null,
|
||||
params: type.params.map(f),
|
||||
returnType: f(type.returnType),
|
||||
};
|
||||
|
||||
case 'Component': {
|
||||
return {
|
||||
kind: 'Component',
|
||||
children: type.children != null ? f(type.children) : null,
|
||||
props: new Map([...type.props.entries()].map(([k, v]) => [k, f(v)])),
|
||||
};
|
||||
}
|
||||
|
||||
case 'Generic':
|
||||
return {
|
||||
kind: 'Generic',
|
||||
id: type.id,
|
||||
bound: f(type.bound),
|
||||
};
|
||||
|
||||
case 'Object':
|
||||
return type;
|
||||
|
||||
case 'Tuple':
|
||||
return {
|
||||
kind: 'Tuple',
|
||||
id: type.id,
|
||||
members: type.members.map(f),
|
||||
};
|
||||
|
||||
case 'Structural':
|
||||
return type;
|
||||
|
||||
case 'Enum':
|
||||
case 'Union':
|
||||
case 'Instance':
|
||||
unsupportedLanguageFeature(type.kind, GeneratedSource);
|
||||
|
||||
default:
|
||||
assertExhaustive(type, 'Unknown type kind');
|
||||
}
|
||||
}
|
||||
|
||||
export function diff<R, T>(
|
||||
a: ConcreteType<T>,
|
||||
b: ConcreteType<T>,
|
||||
onChild: (a: T, b: T) => R,
|
||||
onChildMismatch: (child: R, cur: R) => R,
|
||||
onMismatch: (a: ConcreteType<T>, b: ConcreteType<T>, cur: R) => R,
|
||||
init: R,
|
||||
): R {
|
||||
let errors = init;
|
||||
|
||||
// Check if kinds match
|
||||
if (a.kind !== b.kind) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
return errors;
|
||||
}
|
||||
|
||||
// Based on kind, check other properties
|
||||
switch (a.kind) {
|
||||
case 'Mixed':
|
||||
case 'Number':
|
||||
case 'String':
|
||||
case 'Boolean':
|
||||
case 'Void':
|
||||
// Simple types, no further checks needed
|
||||
break;
|
||||
|
||||
case 'Nullable':
|
||||
// Check the nested type
|
||||
errors = onChildMismatch(onChild(a.type, (b as typeof a).type), errors);
|
||||
break;
|
||||
|
||||
case 'Array':
|
||||
case 'Set':
|
||||
// Check the element type
|
||||
errors = onChildMismatch(
|
||||
onChild(a.element, (b as typeof a).element),
|
||||
errors,
|
||||
);
|
||||
break;
|
||||
|
||||
case 'Map':
|
||||
// Check both key and value types
|
||||
errors = onChildMismatch(onChild(a.key, (b as typeof a).key), errors);
|
||||
errors = onChildMismatch(onChild(a.value, (b as typeof a).value), errors);
|
||||
break;
|
||||
|
||||
case 'Function': {
|
||||
const bFunc = b as typeof a;
|
||||
|
||||
// Check type parameters
|
||||
if ((a.typeParameters == null) !== (bFunc.typeParameters == null)) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
|
||||
if (a.typeParameters != null && bFunc.typeParameters != null) {
|
||||
if (a.typeParameters.length !== bFunc.typeParameters.length) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
|
||||
// Type parameters are just numbers, so we can compare them directly
|
||||
for (let i = 0; i < a.typeParameters.length; i++) {
|
||||
if (a.typeParameters[i] !== bFunc.typeParameters[i]) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check parameters
|
||||
if (a.params.length !== bFunc.params.length) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
|
||||
for (let i = 0; i < a.params.length; i++) {
|
||||
errors = onChildMismatch(onChild(a.params[i], bFunc.params[i]), errors);
|
||||
}
|
||||
|
||||
// Check return type
|
||||
errors = onChildMismatch(onChild(a.returnType, bFunc.returnType), errors);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Component': {
|
||||
const bComp = b as typeof a;
|
||||
|
||||
// Check children
|
||||
if (a.children !== bComp.children) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
|
||||
// Check props
|
||||
if (a.props.size !== bComp.props.size) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
|
||||
for (const [k, v] of a.props) {
|
||||
const bProp = bComp.props.get(k);
|
||||
if (bProp == null) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
} else {
|
||||
errors = onChildMismatch(onChild(v, bProp), errors);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Generic': {
|
||||
// Check that the type parameter IDs match
|
||||
if (a.id !== (b as typeof a).id) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Structural': {
|
||||
const bStruct = b as typeof a;
|
||||
|
||||
// Check that the structural IDs match
|
||||
if (a.id !== bStruct.id) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Object': {
|
||||
const bNom = b as typeof a;
|
||||
|
||||
// Check that the nominal IDs match
|
||||
if (a.id !== bNom.id) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Tuple': {
|
||||
const bTuple = b as typeof a;
|
||||
|
||||
// Check that the tuple IDs match
|
||||
if (a.id !== bTuple.id) {
|
||||
errors = onMismatch(a, b, errors);
|
||||
}
|
||||
for (let i = 0; i < a.members.length; i++) {
|
||||
errors = onChildMismatch(
|
||||
onChild(a.members[i], bTuple.members[i]),
|
||||
errors,
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Enum':
|
||||
case 'Instance':
|
||||
case 'Union': {
|
||||
unsupportedLanguageFeature(a.kind, GeneratedSource);
|
||||
}
|
||||
|
||||
default:
|
||||
assertExhaustive(a, 'Unknown type kind');
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
export function filterOptional(t: ResolvedType): ResolvedType {
|
||||
if (t.kind === 'Concrete' && t.type.kind === 'Nullable') {
|
||||
return t.type.type;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
1001
compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts
Normal file
1001
compiler/packages/babel-plugin-react-compiler/src/Flood/Types.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,7 @@ import {
|
||||
} from './ObjectShape';
|
||||
import {Scope as BabelScope, NodePath} from '@babel/traverse';
|
||||
import {TypeSchema} from './TypeSchema';
|
||||
import {FlowTypeEnv} from '../Flood/Types';
|
||||
|
||||
export const ReactElementSymbolSchema = z.object({
|
||||
elementSymbol: z.union([
|
||||
@@ -243,6 +244,12 @@ export const EnvironmentConfigSchema = z.object({
|
||||
*/
|
||||
enableUseTypeAnnotations: z.boolean().default(false),
|
||||
|
||||
/**
|
||||
* Allows specifying a function that can populate HIR with type information from
|
||||
* Flow
|
||||
*/
|
||||
flowTypeProvider: z.nullable(z.function().args(z.string())).default(null),
|
||||
|
||||
/**
|
||||
* Enable a new model for mutability and aliasing inference
|
||||
*/
|
||||
@@ -697,6 +704,8 @@ export class Environment {
|
||||
#hoistedIdentifiers: Set<t.Identifier>;
|
||||
parentFunction: NodePath<t.Function>;
|
||||
|
||||
#flowTypeEnvironment: FlowTypeEnv | null;
|
||||
|
||||
constructor(
|
||||
scope: BabelScope,
|
||||
fnType: ReactFunctionType,
|
||||
@@ -765,6 +774,26 @@ export class Environment {
|
||||
this.parentFunction = parentFunction;
|
||||
this.#contextIdentifiers = contextIdentifiers;
|
||||
this.#hoistedIdentifiers = new Set();
|
||||
|
||||
if (config.flowTypeProvider != null) {
|
||||
this.#flowTypeEnvironment = new FlowTypeEnv();
|
||||
CompilerError.invariant(code != null, {
|
||||
reason:
|
||||
'Expected Environment to be initialized with source code when a Flow type provider is specified',
|
||||
loc: null,
|
||||
});
|
||||
this.#flowTypeEnvironment.init(this, code);
|
||||
} else {
|
||||
this.#flowTypeEnvironment = null;
|
||||
}
|
||||
}
|
||||
|
||||
get typeContext(): FlowTypeEnv {
|
||||
CompilerError.invariant(this.#flowTypeEnvironment != null, {
|
||||
reason: 'Flow type environment not initialized',
|
||||
loc: null,
|
||||
});
|
||||
return this.#flowTypeEnvironment;
|
||||
}
|
||||
|
||||
get isInferredMemoEnabled(): boolean {
|
||||
|
||||
@@ -504,7 +504,7 @@ function canMergeScopes(
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAlwaysInvalidatingType(type: Type): boolean {
|
||||
export function isAlwaysInvalidatingType(type: Type): boolean {
|
||||
switch (type.kind) {
|
||||
case 'Object': {
|
||||
switch (type.shapeId) {
|
||||
|
||||
@@ -78,6 +78,10 @@ export default class DisjointSet<T> {
|
||||
return root;
|
||||
}
|
||||
|
||||
has(item: T): boolean {
|
||||
return this.#entries.has(item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Forces the set into canonical form, ie with all items pointing directly to
|
||||
* their root, and returns a Map representing the mapping of items to their roots.
|
||||
|
||||
@@ -33,12 +33,12 @@ export function assertExhaustive(_: never, errorMsg: string): never {
|
||||
// Modifies @param array in place, retaining only the items where the predicate returns true.
|
||||
export function retainWhere<T>(
|
||||
array: Array<T>,
|
||||
predicate: (item: T) => boolean,
|
||||
predicate: (item: T, index: number) => boolean,
|
||||
): void {
|
||||
let writeIndex = 0;
|
||||
for (let readIndex = 0; readIndex < array.length; readIndex++) {
|
||||
const item = array[readIndex];
|
||||
if (predicate(item) === true) {
|
||||
if (predicate(item, readIndex) === true) {
|
||||
array[writeIndex++] = item;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user