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 174e267fb..a0e58619d 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 @@ -737,11 +737,74 @@ export class SafeDsTypeComputer { } /* c8 ignore stop */ } + // ----------------------------------------------------------------------------------------------------------------- + // Supertypes + // ----------------------------------------------------------------------------------------------------------------- + + /** + * Returns the supertype of the given `type` that is declared by the given `clazz`. If no such supertype exists, + * `undefined` is returned. Type parameters on parent types get substituted. + */ + computeSupertypeOfClass(type: ClassType | undefined, clazz: SdsClass | undefined): ClassType | undefined { + if (!type || !clazz) { + return undefined; + } + + return stream([type], this.streamSupertypes(type)).find((it) => it.declaration === clazz); + } + + /** + * Returns a stream of all declared supertypes of the given type. Direct ancestors are returned first, followed by + * their ancestors and so on. The given type is never included in the stream. + * + * Compared to `ClassHierarchy.streamSuperTypes`, this method cannot be used to detect cycles in the inheritance + * hierarchy. However, it can handle type parameters on parent types and substitute them accordingly. + */ + streamSupertypes(type: ClassType | undefined): Stream { + if (!type) { + return EMPTY_STREAM; + } + + return stream(this.supertypesGenerator(type)); + } + + private *supertypesGenerator(type: ClassType): Generator { + // Compared to `ClassHierarchy.superclassesGenerator`, we already include the given type in the list of visited + // elements, since this method here is not used to detect cycles. + const visited = new Set([type.declaration]); + let current = this.parentClassType(type); + while (current && !visited.has(current.declaration)) { + yield current; + visited.add(current.declaration); + current = this.parentClassType(current); + } + + const Any = this.coreTypes.Any; + if (Any instanceof ClassType && !visited.has(Any.declaration)) { + yield Any; + } + } + + /** + * Tries to evaluate the first parent type of the class to a `ClassType` and returns it if successful. Type + * parameters get substituted. If there is no parent type or the parent type is not a class, `undefined` is + * returned. + */ + private parentClassType(type: ClassType | undefined): ClassType | undefined { + const [firstParentTypeNode] = getParentTypes(type?.declaration); + const firstParentType = this.computeType(firstParentTypeNode, type?.substitutions); + + if (firstParentType instanceof ClassType) { + return firstParentType; + } + return undefined; + } + // ----------------------------------------------------------------------------------------------------------------- // Lowest common supertype // ----------------------------------------------------------------------------------------------------------------- - lowestCommonSupertype(...types: Type[]): Type { + private lowestCommonSupertype(...types: Type[]): Type { // Simplify types const simplifiedTypes = this.simplifyTypes(types); @@ -902,69 +965,6 @@ export class SafeDsTypeComputer { private Any(isNullable: boolean): Type { return isNullable ? this.coreTypes.AnyOrNull : this.coreTypes.Any; } - - // ----------------------------------------------------------------------------------------------------------------- - // Supertypes - // ----------------------------------------------------------------------------------------------------------------- - - /** - * Returns the supertype of the given `type` that is declared by the given `clazz`. If no such supertype exists, - * `undefined` is returned. Type parameters on parent types get substituted. - */ - computeSupertypeOfClass(type: ClassType | undefined, clazz: SdsClass | undefined): ClassType | undefined { - if (!type || !clazz) { - return undefined; - } - - return stream([type], this.streamSupertypes(type)).find((it) => it.declaration === clazz); - } - - /** - * Returns a stream of all declared supertypes of the given type. Direct ancestors are returned first, followed by - * their ancestors and so on. The given type is never included in the stream. - * - * Compared to `ClassHierarchy.streamSuperTypes`, this method cannot be used to detect cycles in the inheritance - * hierarchy. However, it can handle type parameters on parent types and substitute them accordingly. - */ - streamSupertypes(type: ClassType | undefined): Stream { - if (!type) { - return EMPTY_STREAM; - } - - return stream(this.supertypesGenerator(type)); - } - - private *supertypesGenerator(type: ClassType): Generator { - // Compared to `ClassHierarchy.superclassesGenerator`, we already include the given type in the list of visited - // elements, since this method here is not used to detect cycles. - const visited = new Set([type.declaration]); - let current = this.parentClassType(type); - while (current && !visited.has(current.declaration)) { - yield current; - visited.add(current.declaration); - current = this.parentClassType(current); - } - - const Any = this.coreTypes.Any; - if (Any instanceof ClassType && !visited.has(Any.declaration)) { - yield Any; - } - } - - /** - * Tries to evaluate the first parent type of the class to a `ClassType` and returns it if successful. Type - * parameters get substituted. If there is no parent type or the parent type is not a class, `undefined` is - * returned. - */ - private parentClassType(type: ClassType | undefined): ClassType | undefined { - const [firstParentTypeNode] = getParentTypes(type?.declaration); - const firstParentType = this.computeType(firstParentTypeNode, type?.substitutions); - - if (firstParentType instanceof ClassType) { - return firstParentType; - } - return undefined; - } } interface GroupTypesResult { diff --git a/packages/safe-ds-lang/tests/language/typing/type computer/lowestCommonSupertype.test.ts b/packages/safe-ds-lang/tests/language/typing/type computer/lowestCommonSupertype.test.ts deleted file mode 100644 index c775ee2b8..000000000 --- a/packages/safe-ds-lang/tests/language/typing/type computer/lowestCommonSupertype.test.ts +++ /dev/null @@ -1,393 +0,0 @@ -import { streamAllContents } from 'langium'; -import { NodeFileSystem } from 'langium/node'; -import { describe, it } from 'vitest'; -import { - isSdsClass, - isSdsEnum, - isSdsEnumVariant, - isSdsFunction, - isSdsModule, -} from '../../../../src/language/generated/ast.js'; -import { - createSafeDsServicesWithBuiltins, - getModuleMembers, - getTypeParameters, -} from '../../../../src/language/index.js'; -import { - BooleanConstant, - FloatConstant, - IntConstant, - NullConstant, -} from '../../../../src/language/partialEvaluation/model.js'; -import { - ClassType, - LiteralType, - NamedTupleType, - StaticType, - Type, - UnionType, - UnknownType, -} from '../../../../src/language/typing/model.js'; -import { getNodeOfType } from '../../../helpers/nodeFinder.js'; -import { AssertionError } from 'assert'; - -const services = (await createSafeDsServicesWithBuiltins(NodeFileSystem)).SafeDs; -const coreTypes = services.types.CoreTypes; -const typeComputer = services.types.TypeComputer; - -const code = ` - fun func() -> () - - class Class1 - class Class2 sub Class1 - class Class3 - - enum Enum1 { - Variant1 - Variant2 - } - enum Enum2 { - Variant3 - } -`; -const module = await getNodeOfType(services, code, isSdsModule); -const func = getModuleMembers(module).find(isSdsFunction)!; -const callableType = typeComputer.computeType(func); - -const classes = getModuleMembers(module).filter(isSdsClass); -const class1 = classes[0]; -const class2 = classes[1]; -const class3 = classes[2]; -const classType1 = typeComputer.computeType(class1) as ClassType; -const classType2 = typeComputer.computeType(class2) as ClassType; -const classType3 = typeComputer.computeType(class3) as ClassType; - -const enums = getModuleMembers(module).filter(isSdsEnum); -const enum1 = enums[0]; -const enum2 = enums[1]; -const enumType1 = typeComputer.computeType(enum1); -const enumType2 = typeComputer.computeType(enum2); - -const enumVariants = streamAllContents(module).filter(isSdsEnumVariant).toArray(); -const enumVariant1 = enumVariants[0]; -const enumVariant2 = enumVariants[1]; -const enumVariant3 = enumVariants[2]; -const enumVariantType1 = typeComputer.computeType(enumVariant1); -const enumVariantType2 = typeComputer.computeType(enumVariant2); -const enumVariantType3 = typeComputer.computeType(enumVariant3); - -const typeParameter1 = getTypeParameters(class3)[0]; -const typeParameterType1 = typeComputer.computeType(typeParameter1); - -const tests: LowestCommonSupertypeTest[] = [ - // No types (after simplification) - { - types: [], - expected: coreTypes.Nothing, - }, - { - types: [new LiteralType()], - expected: coreTypes.Nothing, - }, - { - types: [new UnionType()], - expected: coreTypes.Nothing, - }, - - // Singular type (after simplification) - { - types: [callableType], - expected: callableType, - }, - { - types: [new LiteralType(new IntConstant(1n))], - expected: new LiteralType(new IntConstant(1n)), - }, - { - types: [new NamedTupleType()], - expected: new NamedTupleType(), - }, - { - types: [classType1], - expected: classType1, - }, - { - types: [enumType1], - expected: enumType1, - }, - { - types: [enumVariantType1], - expected: enumVariantType1, - }, - { - types: [typeParameterType1], - expected: typeParameterType1, - }, - { - types: [new StaticType(classType1)], - expected: new StaticType(classType1), - }, - { - types: [UnknownType], - expected: UnknownType, - }, - - // Simplification - { - types: [ - new UnionType( - new UnionType(new LiteralType(NullConstant), new LiteralType(NullConstant)), - new UnionType(new LiteralType(NullConstant), new LiteralType(NullConstant)), - ), - ], - expected: coreTypes.NothingOrNull, - }, - { - types: [new LiteralType(new IntConstant(1n)), new LiteralType(new FloatConstant(1.5))], - expected: new LiteralType(new IntConstant(1n), new FloatConstant(1.5)), - }, - { - types: [enumType1, new LiteralType()], - expected: enumType1, - }, - { - types: [enumType1, new LiteralType(NullConstant)], - expected: enumType1.updateNullability(true), - }, - - // Types with no clear lowest common supertype - { - types: [new LiteralType(new IntConstant(1n)), new StaticType(classType1)], - expected: UnknownType, - }, - { - types: [new LiteralType(new IntConstant(1n)), UnknownType], - expected: UnknownType, - }, - - // Types where we don't bother computing the lowest common supertype since they don't occur in legal code - { - types: [new LiteralType(new IntConstant(1n)), callableType], - expected: UnknownType, - }, - { - types: [new LiteralType(new IntConstant(1n)), new NamedTupleType()], - expected: UnknownType, - }, - { - types: [new LiteralType(new IntConstant(1n)), typeParameterType1], - expected: UnknownType, - }, - - // Incompatible types - { - types: [classType1, enumType1], - expected: coreTypes.Any, - }, - { - types: [classType1.updateNullability(true), enumType1], - expected: coreTypes.AnyOrNull, - }, - - { - types: [classType1, enumVariantType1], - expected: coreTypes.Any, - }, - { - types: [classType1.updateNullability(true), enumType1], - expected: coreTypes.AnyOrNull, - }, - - { - types: [enumType1, new LiteralType(new BooleanConstant(true))], - expected: coreTypes.Any, - }, - { - types: [enumType1.updateNullability(true), new LiteralType(new BooleanConstant(true))], - expected: coreTypes.AnyOrNull, - }, - - { - types: [enumVariantType1, new LiteralType(new BooleanConstant(true))], - expected: coreTypes.Any, - }, - { - types: [enumVariantType1.updateNullability(true), new LiteralType(new BooleanConstant(true))], - expected: coreTypes.AnyOrNull, - }, - - // TODO: continue here (check excel table) - - // Class type & class type - { - types: [classType1, classType1], - expected: classType1, - }, - { - types: [classType1, classType2], - expected: classType1, - }, - { - types: [classType1, classType3], - expected: coreTypes.Any, - }, - { - types: [classType1.updateNullability(true), classType1], - expected: classType1.updateNullability(true), - }, - { - types: [classType1.updateNullability(true), classType2], - expected: classType1.updateNullability(true), - }, - { - types: [classType1.updateNullability(true), classType3], - expected: coreTypes.AnyOrNull, - }, - - // Class type & literal type - { - types: [classType1, new LiteralType()], - expected: classType1, - }, - { - types: [coreTypes.Int, new LiteralType(new IntConstant(1n))], - expected: coreTypes.Int, - }, - { - types: [coreTypes.String, new LiteralType(new IntConstant(1n))], - expected: coreTypes.Any, - }, - { - types: [classType1.updateNullability(true), new LiteralType()], - expected: classType1.updateNullability(true), - }, - { - types: [coreTypes.Int.updateNullability(true), new LiteralType(new IntConstant(1n))], - expected: coreTypes.Int.updateNullability(true), - }, - { - types: [coreTypes.String.updateNullability(true), new LiteralType(new IntConstant(1n))], - expected: coreTypes.AnyOrNull, - }, - { - types: [classType1, new LiteralType(NullConstant)], - expected: classType1.updateNullability(true), - }, - { - types: [coreTypes.Int, new LiteralType(new IntConstant(1n), NullConstant)], - expected: coreTypes.Int.updateNullability(true), - }, - { - types: [coreTypes.String, new LiteralType(new IntConstant(1n), NullConstant)], - expected: coreTypes.AnyOrNull, - }, - { - types: [coreTypes.Nothing, new LiteralType(new IntConstant(1n))], - expected: new LiteralType(new IntConstant(1n)), - }, - { - types: [coreTypes.NothingOrNull, new LiteralType(new IntConstant(1n))], - expected: new LiteralType(new IntConstant(1n), NullConstant), - }, - - // Enum type & enum type - { - types: [enumType1, enumType1], - expected: enumType1, - }, - { - types: [enumType1, enumType2], - expected: coreTypes.Any, - }, - { - types: [enumType1.updateNullability(true), enumType1], - expected: enumType1.updateNullability(true), - }, - { - types: [enumType1.updateNullability(true), enumType2], - expected: coreTypes.AnyOrNull, - }, - - // Enum type & enum variant type - { - types: [enumType1, enumVariantType1], - expected: enumType1, - }, - { - types: [enumType2, enumVariantType1], - expected: coreTypes.Any, - }, - { - types: [enumType1.updateNullability(true), enumVariantType1], - expected: enumType1.updateNullability(true), - }, - { - types: [enumType2.updateNullability(true), enumVariantType1], - expected: coreTypes.AnyOrNull, - }, - - // Enum variant type & enum variant type - { - types: [enumVariantType1, enumVariantType1], - expected: enumVariantType1, - }, - { - types: [enumVariantType1, enumVariantType2], - expected: enumType1, - }, - { - types: [enumVariantType1, enumVariantType3], - expected: coreTypes.Any, - }, - { - types: [enumVariantType1.updateNullability(true), enumVariantType1], - expected: enumVariantType1.updateNullability(true), - }, - { - types: [enumVariantType1.updateNullability(true), enumVariantType2], - expected: enumType1.updateNullability(true), - }, - { - types: [enumVariantType1.updateNullability(true), enumVariantType3], - expected: coreTypes.AnyOrNull, - }, - - // Literal type & literal type - { - types: [new LiteralType(new BooleanConstant(true)), new LiteralType(new IntConstant(1n))], - expected: new LiteralType(new BooleanConstant(true), new IntConstant(1n)), - }, - { - types: [new LiteralType(new BooleanConstant(true)), new LiteralType(NullConstant)], - expected: new LiteralType(new BooleanConstant(true), NullConstant), - }, -]; - -describe.each(tests)('lowestCommonSupertype', ({ types, expected }) => { - it(`should return the lowest common supertype [${types}]`, () => { - const actual = typeComputer.lowestCommonSupertype(...types); - - if (!actual.equals(expected)) { - throw new AssertionError({ - message: 'Incorrect lowest common supertype.', - expected: expected.toString(), - actual: actual.toString(), - }); - } - }); -}); - -/** - * A test case for {@link lowestCommonSupertype}. - */ -interface LowestCommonSupertypeTest { - /** - * The types to compute the lowest common supertype of. - */ - types: Type[]; - - /** - * The expected lowest common supertype. - */ - expected: Type; -} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and class type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and class type/main.sdstest new file mode 100644 index 000000000..664b22b6a --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and class type/main.sdstest @@ -0,0 +1,34 @@ +package tests.typing.lowestCommonSupertype.classTypeAndClassType + +class C +class D sub C +class E + +segment mySegment( + c: C, + cOrNull: C?, + d: D, + dOrNull: D?, + e: E, + eOrNull: E?, +) { + // $TEST$ serialization List + »[c, c]«; + + // $TEST$ serialization List + »[c, cOrNull]«; + + + // $TEST$ serialization List + »[c, d]«; + + // $TEST$ serialization List + »[c, dOrNull]«; + + + // $TEST$ serialization List + »[c, e]«; + + // $TEST$ serialization List + »[c, eOrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and literal type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and literal type/main.sdstest new file mode 100644 index 000000000..93b2dfb47 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/class type and literal type/main.sdstest @@ -0,0 +1,50 @@ +package tests.typing.lowestCommonSupertype.classTypeAndLiteralType + +class C + +segment mySegment( + c: C, + cOrNull: C?, + int: Int, + intOrNull: Int?, + number: Number, + numberOrNull: Number?, + string: String, + stringOrNull: String?, + nothing: Nothing, + nothingOrNull: Nothing?, +) { + // $TEST$ serialization List + »[1, c]«; + + // $TEST$ serialization List + »[1, cOrNull]«; + + + // $TEST$ serialization List + »[1, int]«; + + // $TEST$ serialization List + »[1, intOrNull]«; + + + // $TEST$ serialization List + »[1, number]«; + + // $TEST$ serialization List + »[1, numberOrNull]«; + + + // $TEST$ serialization List + »[1, string]«; + + // $TEST$ serialization List + »[1, stringOrNull]«; + + + // $TEST$ serialization List> + »[1, nothing]«; + + // $TEST$ serialization List> + »[1, nothingOrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum type/main.sdstest new file mode 100644 index 000000000..a25495d25 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum type/main.sdstest @@ -0,0 +1,24 @@ +package tests.typing.lowestCommonSupertype.enumTypeAndEnumType + +enum E1 +enum E2 + +segment mySegment( + e1: E1, + e1OrNull: E1?, + e2: E2, + e2OrNull: E2? +) { + // $TEST$ serialization List + »[e1, e1]«; + + // $TEST$ serialization List + »[e1, e1OrNull]«; + + + // $TEST$ serialization List + »[e1, e2]«; + + // $TEST$ serialization List + »[e1, e2OrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum variant type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum variant type/main.sdstest new file mode 100644 index 000000000..0f2a8f8c7 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum type and enum variant type/main.sdstest @@ -0,0 +1,29 @@ +package tests.typing.lowestCommonSupertype.enumTypeAndEnumVariantType + +enum E1 { + V1 +} +enum E2 { + V2 +} + +segment mySegment( + e1: E1, + v1: E1.V1, + v1OrNull: E1.V1?, + v2: E2.V2, + v2OrNull: E2.V2? +) { + // $TEST$ serialization List + »[e1, v1]«; + + // $TEST$ serialization List + »[e1, v1OrNull]«; + + + // $TEST$ serialization List + »[e1, v2]«; + + // $TEST$ serialization List + »[e1, v2OrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum variant type and enum variant type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum variant type and enum variant type/main.sdstest new file mode 100644 index 000000000..b36f3ae8c --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/enum variant type and enum variant type/main.sdstest @@ -0,0 +1,38 @@ +package tests.typing.lowestCommonSupertype.enumVariantTypeAndEnumVariantType + +enum E1 { + V1 + V2 +} +enum E3 { + V3 +} + +segment mySegment( + v1: E1.V1, + v1OrNull: E1.V1?, + v2: E1.V2, + v2OrNull: E1.V2?, + v3: E3.V3, + v3OrNull: E3.V3? +) { + // $TEST$ serialization List + »[v1, v1]«; + + // $TEST$ serialization List + »[v1, v1OrNull]«; + + + // $TEST$ serialization List + »[v1, v2]«; + + // $TEST$ serialization List + »[v1, v2OrNull]«; + + + // $TEST$ serialization List + »[v1, v3]«; + + // $TEST$ serialization List + »[v1, v3OrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/incompatible types/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/incompatible types/main.sdstest new file mode 100644 index 000000000..34d6a4924 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/incompatible types/main.sdstest @@ -0,0 +1,39 @@ +package tests.typing.lowestCommonSupertype.incompatibleTypes + +class C() +enum E { + V +} + +segment mySegment( + e: E, + eOrNull: E?, + vOrNull: E.V? +) { + // $TEST$ serialization List + »[C(), e]«; + + // $TEST$ serialization List + »[C(), eOrNull]«; + + + // $TEST$ serialization List + »[C(), E.V]«; + + // $TEST$ serialization List + »[C(), vOrNull]«; + + + // $TEST$ serialization List + »[1, e]«; + + // $TEST$ serialization List + »[1, eOrNull]«; + + + // $TEST$ serialization List + »[1, E.V]«; + + // $TEST$ serialization List + »[1, vOrNull]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/literal type and literal type/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/literal type and literal type/main.sdstest new file mode 100644 index 000000000..e69766be3 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/literal type and literal type/main.sdstest @@ -0,0 +1,9 @@ +package tests.typing.lowestCommonSupertype.literalTypeAndLiteralType + +segment mySegment() { + // $TEST$ serialization List> + »[true, 1]«; + + // $TEST$ serialization List> + »[true, null]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/no types after simplification/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/no types after simplification/main.sdstest new file mode 100644 index 000000000..9b35a2f7e --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/no types after simplification/main.sdstest @@ -0,0 +1,18 @@ +package tests.typing.lowestCommonSupertype.noTypesAfterSimplification + +segment mySegment( + p1: literal<>, + p2: union<>, +) { + // $TEST$ serialization List + »[]«; + + // $TEST$ serialization List + »[p1]«; + + // $TEST$ serialization List + »[p2]«; + + // $TEST$ serialization List + »[p1, p2]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/simplification/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/simplification/main.sdstest new file mode 100644 index 000000000..942901e0f --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/simplification/main.sdstest @@ -0,0 +1,20 @@ +package tests.typing.lowestCommonSupertype.simplification + +class C() + +segment mySegment( + p1: union, literal>, + p2: literal<> +) { + // $TEST$ serialization List + »[p1, p1]«; + + // $TEST$ serialization List> + »[1, 1.5]«; + + // $TEST$ serialization List + »[C(), p2]«; + + // $TEST$ serialization List + »[C(), null]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/singular type after simplification/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/singular type after simplification/main.sdstest new file mode 100644 index 000000000..4418b16de --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/singular type after simplification/main.sdstest @@ -0,0 +1,36 @@ +package tests.typing.lowestCommonSupertype.singularTypeAfterSimplification + +class C() +enum E { + V +} + +@Pure fun f() -> (r1: Int, r2: Int) + +segment mySegment( + p1: E +) { + // $TEST$ serialization List<() -> ()> + »[() {}]«; + + // $TEST$ serialization List> + »[1]«; + + // $TEST$ serialization List<(r1: Int, r2: Int)> + »[f()]«; + + // $TEST$ serialization List + »[C()]«; + + // $TEST$ serialization List + »[p1]«; + + // $TEST$ serialization List + »[E.V]«; + + // $TEST$ serialization List<$type> + »[C]«; + + // $TEST$ serialization List<$unknown> + »[unknown]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/unknown supertype/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/unknown supertype/main.sdstest new file mode 100644 index 000000000..d4d020f91 --- /dev/null +++ b/packages/safe-ds-lang/tests/resources/typing/lowest common supertype/unknown supertype/main.sdstest @@ -0,0 +1,23 @@ +package tests.typing.lowestCommonSupertype.unknownSupertype + +class C +@Pure fun f() -> (r1: Int, r2: Int) + +segment mySegment() { + // These types really don't have common supertype + + // $TEST$ serialization List<$unknown> + »[1, C]«; + + // $TEST$ serialization List<$unknown> + »[1, unknown]«; + + + // These types don't occur in legal code when we compute the lowest common supertype, so we don't handle them better + + // $TEST$ serialization List<$unknown> + »[1, f]«; + + // $TEST$ serialization List<$unknown> + »[1, f()]«; +} diff --git a/packages/safe-ds-lang/tests/resources/typing/simplification/replace empty literal types with Nothing/main.sdstest b/packages/safe-ds-lang/tests/resources/typing/simplification/replace empty literal types with Nothing/main.sdstest index 4b74dc11a..01740bae0 100644 --- a/packages/safe-ds-lang/tests/resources/typing/simplification/replace empty literal types with Nothing/main.sdstest +++ b/packages/safe-ds-lang/tests/resources/typing/simplification/replace empty literal types with Nothing/main.sdstest @@ -4,9 +4,3 @@ class C( // $TEST$ serialization Nothing p1: »literal<>« ) - -class D { - attr a: T - - @Pure fun f(p: T = a) -}