Generalize
This commit is contained in:
Родитель
51737eb68b
Коммит
42787bbeb9
|
@ -3,31 +3,11 @@
|
|||
import { Set, Map, OrderedSet } from "immutable";
|
||||
|
||||
import { TypeGraph } from "./TypeGraph";
|
||||
import { Type, UnionType, IntersectionType } from "./Type";
|
||||
import { Type, UnionType, IntersectionType, setOperationMembersRecursively } from "./Type";
|
||||
import { assert, defined } from "./Support";
|
||||
import { TypeRef, GraphRewriteBuilder, StringTypeMapping } from "./TypeBuilder";
|
||||
import { unifyTypes, UnifyUnionBuilder } from "./UnifyClasses";
|
||||
|
||||
function unionMembersRecursively(union: UnionType): OrderedSet<Type> {
|
||||
let processedUnions = Set<UnionType>();
|
||||
let members = OrderedSet<Type>();
|
||||
|
||||
function addMembers(u: UnionType): void {
|
||||
if (processedUnions.has(u)) return;
|
||||
processedUnions = processedUnions.add(u);
|
||||
u.members.forEach(t => {
|
||||
if (t instanceof UnionType) {
|
||||
addMembers(t);
|
||||
} else {
|
||||
members = members.add(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addMembers(union);
|
||||
return members;
|
||||
}
|
||||
|
||||
export function flattenUnions(
|
||||
graph: TypeGraph,
|
||||
stringTypeMapping: StringTypeMapping,
|
||||
|
@ -55,7 +35,7 @@ export function flattenUnions(
|
|||
const groups: Type[][] = [];
|
||||
let foundIntersection: boolean = false;
|
||||
nonCanonicalUnions.forEach(u => {
|
||||
const members = unionMembersRecursively(u);
|
||||
const members = setOperationMembersRecursively(u)[0];
|
||||
assert(!members.isEmpty(), "We can't have an empty union");
|
||||
if (members.some(m => m instanceof IntersectionType)) {
|
||||
foundIntersection = true;
|
||||
|
|
|
@ -30,7 +30,8 @@ import {
|
|||
GenericClassProperty,
|
||||
TypeKind,
|
||||
combineTypeAttributesOfTypes,
|
||||
ObjectType
|
||||
ObjectType,
|
||||
setOperationMembersRecursively
|
||||
} from "./Type";
|
||||
import { assert, defined, panic } from "./Support";
|
||||
import {
|
||||
|
@ -40,25 +41,8 @@ import {
|
|||
makeTypeAttributesInferred
|
||||
} from "./TypeAttributes";
|
||||
|
||||
function intersectionMembersRecursively(intersection: IntersectionType): [OrderedSet<Type>, TypeAttributes] {
|
||||
const types: Type[] = [];
|
||||
let attributes = emptyTypeAttributes;
|
||||
function process(t: Type): void {
|
||||
if (t instanceof IntersectionType) {
|
||||
attributes = combineTypeAttributes(attributes, t.getAttributes());
|
||||
t.members.forEach(process);
|
||||
} else if (t.kind !== "any") {
|
||||
types.push(t);
|
||||
} else {
|
||||
attributes = combineTypeAttributes(attributes, t.getAttributes());
|
||||
}
|
||||
}
|
||||
process(intersection);
|
||||
return [OrderedSet(types), attributes];
|
||||
}
|
||||
|
||||
function canResolve(t: IntersectionType): boolean {
|
||||
const members = intersectionMembersRecursively(t)[0];
|
||||
const members = setOperationMembersRecursively(t)[0];
|
||||
if (members.size <= 1) return true;
|
||||
return members.every(m => !(m instanceof UnionType) || m.isCanonical);
|
||||
}
|
||||
|
@ -236,7 +220,7 @@ class IntersectionAccumulator
|
|||
return panic("There shouldn't be a none type");
|
||||
},
|
||||
_anyType => {
|
||||
return panic("The any type should have been filtered out in intersectionMembersRecursively");
|
||||
return panic("The any type should have been filtered out in setOperationMembersRecursively");
|
||||
},
|
||||
nullType => this.addUnionSet(OrderedSet([nullType])),
|
||||
boolType => this.addUnionSet(OrderedSet([boolType])),
|
||||
|
@ -416,7 +400,7 @@ export function resolveIntersections(graph: TypeGraph, stringTypeMapping: String
|
|||
forwardingRef: TypeRef
|
||||
): TypeRef {
|
||||
assert(types.size === 1);
|
||||
const [members, intersectionAttributes] = intersectionMembersRecursively(defined(types.first()));
|
||||
const [members, intersectionAttributes] = setOperationMembersRecursively(defined(types.first()));
|
||||
if (members.isEmpty()) {
|
||||
const t = builder.getPrimitiveType("any", forwardingRef);
|
||||
builder.addAttributes(t, intersectionAttributes);
|
||||
|
|
29
src/Type.ts
29
src/Type.ts
|
@ -5,7 +5,7 @@ import { OrderedSet, OrderedMap, Collection, Set, is, hash } from "immutable";
|
|||
import { defined, panic, assert, assertNever } from "./Support";
|
||||
import { TypeRef, TypeReconstituter } from "./TypeBuilder";
|
||||
import { TypeNames, namesTypeAttributeKind } from "./TypeNames";
|
||||
import { TypeAttributes, combineTypeAttributes } from "./TypeAttributes";
|
||||
import { TypeAttributes, combineTypeAttributes, emptyTypeAttributes } from "./TypeAttributes";
|
||||
|
||||
export type PrimitiveStringTypeKind = "string" | "date" | "time" | "date-time";
|
||||
export type PrimitiveTypeKind = "none" | "any" | "null" | "bool" | "integer" | "double" | PrimitiveStringTypeKind;
|
||||
|
@ -568,6 +568,33 @@ export class UnionType extends SetOperationType {
|
|||
}
|
||||
}
|
||||
|
||||
export function setOperationMembersRecursively<T extends SetOperationType>(
|
||||
setOperation: T
|
||||
): [OrderedSet<Type>, TypeAttributes] {
|
||||
const kind = setOperation.kind;
|
||||
const includeAny = kind !== "intersection";
|
||||
let processedSetOperations = Set<T>();
|
||||
let members = OrderedSet<Type>();
|
||||
let attributes = emptyTypeAttributes;
|
||||
|
||||
function process(t: Type): void {
|
||||
if (t.kind === kind) {
|
||||
const so = t as T;
|
||||
if (processedSetOperations.has(so)) return;
|
||||
processedSetOperations = processedSetOperations.add(so);
|
||||
attributes = combineTypeAttributes(attributes, t.getAttributes());
|
||||
so.members.forEach(process);
|
||||
} else if (includeAny || t.kind !== "any") {
|
||||
members = members.add(t);
|
||||
} else {
|
||||
attributes = combineTypeAttributes(attributes, t.getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
process(setOperation);
|
||||
return [members, attributes];
|
||||
}
|
||||
|
||||
export function combineTypeAttributesOfTypes(types: Collection<any, Type>): TypeAttributes {
|
||||
return combineTypeAttributes(
|
||||
types
|
||||
|
|
Загрузка…
Ссылка в новой задаче