From 3ff542d5f6873d6c80b0f197e4c2998039c0d168 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Wed, 7 Feb 2024 17:00:50 +0100 Subject: [PATCH] feat: remove unneeded entries from union types --- .../language/typing/safe-ds-type-computer.ts | 31 ++++++++++- .../main.sdstest | 4 +- .../member accesses/to other/main.sdstest | 2 +- .../main.sdstest | 53 +++++++++++++++++++ 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 packages/safe-ds-lang/tests/resources/typing/simplification/remove unneeded entries from union types/main.sdstest diff --git a/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts b/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts index ba6fcf9ad..872ff3f9a 100644 --- a/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts +++ b/packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts @@ -657,10 +657,39 @@ export class SafeDsTypeComputer { } private simplifyUnionType(type: UnionType): Type { + // Handle empty union types if (isEmpty(type.possibleTypes)) { return this.coreTypes.Nothing; + } + + // Simplify possible types + const newPossibleTypes = type.possibleTypes.map((it) => this.simplifyType(it)); + + // Remove types that are subtypes of others. We do this back-to-front to keep the first occurrence of duplicate + // types. It's also makes splicing easier. + for (let i = newPossibleTypes.length - 1; i >= 0; i--) { + const currentType = newPossibleTypes[i]!; + + for (let j = 0; j < newPossibleTypes.length; j++) { + if (i === j) { + continue; + } + + let otherType = newPossibleTypes[j]!; + otherType = otherType.updateNullability(currentType.isNullable || otherType.isNullable); + + if (this.typeChecker.isAssignableTo(currentType, otherType)) { + newPossibleTypes.splice(j, 1, otherType); // Update nullability + newPossibleTypes.splice(i, 1); + break; + } + } + } + + if (newPossibleTypes.length === 1) { + return newPossibleTypes[0]!; } else { - return type; + return new UnionType(...newPossibleTypes); } } diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/on class with type parameters/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/on class with type parameters/main.sdstest index f96eeb0e2..219a73191 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/on class with type parameters/main.sdstest +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/on class with type parameters/main.sdstest @@ -39,7 +39,7 @@ segment mySegment1(p: C) { »nullableC()?.nonNullableMember«; // $TEST$ serialization Int? »nullableC()?.nullableMember«; - // $TEST$ serialization union<() -> (r: Int), literal> + // $TEST$ serialization union<() -> (r: Int), Nothing?> »nullableC()?.method«; } @@ -71,6 +71,6 @@ segment mySegment2(p: D) { »nullableD()?.nonNullableMember«; // $TEST$ serialization Int? »nullableD()?.nullableMember«; - // $TEST$ serialization union<() -> (r: Int), literal> + // $TEST$ serialization union<() -> (r: Int), Nothing?> »nullableD()?.method«; } diff --git a/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/to other/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/to other/main.sdstest index d855a00cc..f77c49001 100644 --- a/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/to other/main.sdstest +++ b/packages/safe-ds-lang/tests/resources/typing/expressions/member accesses/to other/main.sdstest @@ -40,6 +40,6 @@ pipeline myPipeline { »nullableC()?.nonNullableMember«; // $TEST$ equivalence_class nullableMember »nullableC()?.nullableMember«; - // $TEST$ serialization union<() -> (r: Int), literal> + // $TEST$ serialization union<() -> (r: Int), Nothing?> »nullableC()?.method«; } diff --git a/packages/safe-ds-lang/tests/resources/typing/simplification/remove unneeded entries from union types/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/simplification/remove unneeded entries from union types/main.sdstest new file mode 100644 index 000000000..2432ae362 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/simplification/remove unneeded entries from union types/main.sdstest @@ -0,0 +1,53 @@ +package tests.typing.simplification.removeUnneededEntriesFromUnionTypes + +class C( + // $TEST$ serialization Int + p1: »union«, + + // $TEST$ serialization union + p2: »union«, + + + // $TEST$ serialization Number + p3: »union«, + + // $TEST$ serialization Number + p4: »union«, + + // $TEST$ serialization Number? + p5: »union«, + + // $TEST$ serialization Any + p6: »union«, + + // $TEST$ serialization Any + p7: »union«, + + // $TEST$ serialization Any? + p8: »union«, + + + // $TEST$ serialization union + p9: »union«, + + // $TEST$ serialization union + p10: »union«, + + // $TEST$ serialization union + p11: »union«, + + // $TEST$ serialization union + p12: »union«, + + // $TEST$ serialization Any + p13: »union«, + + // $TEST$ serialization Any? + p14: »union«, + + // $TEST$ serialization Any + p15: »union«, + + // $TEST$ serialization Any? + p16: »union«, +)