diff --git a/src/language/formatting/safe-ds-formatter.ts b/src/language/formatting/safe-ds-formatter.ts index 85b24662b..77e60c6c3 100644 --- a/src/language/formatting/safe-ds-formatter.ts +++ b/src/language/formatting/safe-ds-formatter.ts @@ -313,7 +313,7 @@ export class SafeDsFormatter extends AbstractFormatter { const formatter = this.getNodeFormatter(node); if (annotationCallsOrEmpty(node).length > 0) { - if (node.static) { + if (node.isStatic) { formatter.keyword('static').prepend(newLine()); } else { formatter.keyword('attr').prepend(newLine()); @@ -421,7 +421,7 @@ export class SafeDsFormatter extends AbstractFormatter { const formatter = this.getNodeFormatter(node); if (annotationCallsOrEmpty(node).length > 0) { - if (node.static) { + if (node.isStatic) { formatter.keyword('static').prepend(newLine()); } else { formatter.keyword('fun').prepend(newLine()); @@ -550,7 +550,7 @@ export class SafeDsFormatter extends AbstractFormatter { const formatter = this.getNodeFormatter(node); if (annotationCallsOrEmpty(node).length === 0) { - if (node.variadic) { + if (node.isVariadic) { formatter.property('name').prepend(oneSpace()); } } else { diff --git a/src/language/grammar/safe-ds.langium b/src/language/grammar/safe-ds.langium index 0d8e74438..6c7fa01e9 100644 --- a/src/language/grammar/safe-ds.langium +++ b/src/language/grammar/safe-ds.langium @@ -11,12 +11,12 @@ interface SdsAnnotatedObject extends SdsObject { } interface SdsAbstractCall extends SdsObject { - argumentList: SdsArgumentList + argumentList: SdsArgumentList } interface SdsDeclaration extends SdsAnnotatedObject { annotationCallList?: SdsAnnotationCallList - name: string + name: string } interface SdsLocalVariable extends SdsDeclaration {} @@ -156,7 +156,7 @@ SdsUnannotatedModuleMember returns SdsModuleMember: ; interface SdsAnnotation extends SdsCallable, SdsModuleMember { - constraintList?: SdsConstraintList + constraintList?: SdsConstraintList } fragment SdsAnnotationFragment: @@ -166,10 +166,10 @@ fragment SdsAnnotationFragment: ; interface SdsClass extends SdsCallable, SdsClassMember, SdsModuleMember, SdsNamedTypeDeclaration { - typeParameterList?: SdsTypeParameterList - parentTypeList?: SdsParentTypeList + typeParameterList?: SdsTypeParameterList + parentTypeList?: SdsParentTypeList constraintList?: SdsConstraintList - body?: SdsClassBody + body?: SdsClassBody } fragment SdsClassFragment: @@ -183,7 +183,7 @@ fragment SdsClassFragment: ; interface SdsParentTypeList extends SdsObject { - parentTypes: SdsType[] + parentTypes: SdsType[] } SdsParentTypeList returns SdsParentTypeList: @@ -194,7 +194,7 @@ SdsParentTypeList returns SdsParentTypeList: ; interface SdsClassBody extends SdsObject { - members: SdsClassMember[] + members: SdsClassMember[] } SdsClassBody returns SdsClassBody: @@ -222,7 +222,7 @@ SdsAnnotatedClassMember returns SdsClassMember: SdsEnumFragment | {SdsFunction.annotationCallList=current} - static?='static'? + isStatic?='static'? SdsFunctionFragment ) ; @@ -238,24 +238,24 @@ SdsUnannotatedClassMember returns SdsClassMember: SdsEnumFragment | {SdsFunction} - static?='static'? + isStatic?='static'? SdsFunctionFragment ; interface SdsAttribute extends SdsClassMember { - static: boolean - ^type?: SdsType + isStatic: boolean + ^type?: SdsType } fragment SdsAttributeFragment: - static?='static'? + isStatic?='static'? 'attr' name=ID (':' ^type=SdsType)? ; interface SdsEnum extends SdsNamedTypeDeclaration, SdsClassMember, SdsModuleMember { - body?: SdsEnumBody + body?: SdsEnumBody } fragment SdsEnumFragment: @@ -265,7 +265,7 @@ fragment SdsEnumFragment: ; interface SdsEnumBody extends SdsObject { - variants: SdsEnumVariant[] + variants: SdsEnumVariant[] } SdsEnumBody returns SdsEnumBody: @@ -273,8 +273,8 @@ SdsEnumBody returns SdsEnumBody: ; interface SdsEnumVariant extends SdsCallable, SdsNamedTypeDeclaration { - typeParameterList?: SdsTypeParameterList - constraintList?: SdsConstraintList + typeParameterList?: SdsTypeParameterList + constraintList?: SdsConstraintList } SdsEnumVariant returns SdsEnumVariant: @@ -286,10 +286,10 @@ SdsEnumVariant returns SdsEnumVariant: ; interface SdsFunction extends SdsCallable, SdsClassMember, SdsModuleMember { - static: boolean - typeParameterList?: SdsTypeParameterList - resultList?: SdsResultList - constraintList?: SdsConstraintList + isStatic: boolean + typeParameterList?: SdsTypeParameterList + resultList?: SdsResultList + constraintList?: SdsConstraintList } fragment SdsFunctionFragment: @@ -302,7 +302,7 @@ fragment SdsFunctionFragment: ; interface SdsPipeline extends SdsModuleMember { - body: SdsBlock + body: SdsBlock } fragment SdsPipelineFragment: @@ -312,9 +312,9 @@ fragment SdsPipelineFragment: ; interface SdsSegment extends SdsCallable, SdsModuleMember { - visibility?: string - resultList?: SdsResultList - body: SdsBlock + visibility?: string + resultList?: SdsResultList + body: SdsBlock } fragment SdsSegmentFragment: @@ -334,7 +334,7 @@ fragment SdsSegmentFragment: interface SdsAnnotationCallList extends SdsAnnotatedObject {} interface SdsAnnotationCall extends SdsAbstractCall { - annotation?: @SdsAnnotation + annotation?: @SdsAnnotation } SdsAnnotationCall returns SdsAnnotationCall: @@ -355,7 +355,7 @@ SdsAnnotationCallArgument returns SdsArgument: // ----------------------------------------------------------------------------- interface SdsConstraintList extends SdsObject { - constraints: SdsConstraint[] + constraints: SdsConstraint[] } SdsConstraintList returns SdsConstraintList: @@ -376,9 +376,9 @@ SdsConstraint returns SdsConstraint: ; interface SdsTypeParameterConstraint extends SdsConstraint { - leftOperand: @SdsTypeParameter - operator: string - rightOperand: SdsType + leftOperand: @SdsTypeParameter + operator: string + rightOperand: SdsType } SdsTypeParameterConstraint returns SdsTypeParameterConstraint: @@ -397,11 +397,11 @@ SdsTypeParameterConstraintOperator returns string: // ----------------------------------------------------------------------------- interface SdsCallable extends SdsObject { - parameterList?: SdsParameterList + parameterList?: SdsParameterList } interface SdsParameterList extends SdsObject { - parameters: SdsParameter[] + parameters: SdsParameter[] } SdsParameterList returns SdsParameterList: @@ -416,21 +416,21 @@ SdsParameterList returns SdsParameterList: ; interface SdsParameter extends SdsLocalVariable { - variadic: boolean - ^type?: SdsType - defaultValue?: SdsExpression + isVariadic: boolean + ^type?: SdsType + defaultValue?: SdsExpression } SdsParameter returns SdsParameter: annotationCalls+=SdsAnnotationCall* - variadic?='vararg'? + isVariadic?='vararg'? name=ID (':' ^type=SdsType)? ('=' defaultValue=SdsExpression)? ; interface SdsResultList extends SdsObject { - results: SdsResult[] + results: SdsResult[] } SdsResultList returns SdsResultList: @@ -441,7 +441,7 @@ SdsResultList returns SdsResultList: interface SdsAbstractResult extends SdsDeclaration {} interface SdsResult extends SdsAbstractResult { - ^type?: SdsType + ^type?: SdsType } SdsResult returns SdsResult: @@ -458,7 +458,7 @@ SdsResult returns SdsResult: interface SdsStatement extends SdsObject {} interface SdsBlock extends SdsObject { - statements: SdsStatement[] + statements: SdsStatement[] } SdsBlock returns SdsBlock: @@ -471,8 +471,8 @@ SdsStatement returns SdsStatement: ; interface SdsAssignment extends SdsStatement { - assigneeList?: SdsAssigneeList - expression?: SdsExpression + assigneeList?: SdsAssigneeList + expression?: SdsExpression } SdsAssignment returns SdsAssignment: @@ -480,7 +480,7 @@ SdsAssignment returns SdsAssignment: ; interface SdsAssigneeList extends SdsObject { - assignees: SdsAssignee[] + assignees: SdsAssignee[] } SdsAssigneeList returns SdsAssigneeList: @@ -504,7 +504,7 @@ SdsAssignee returns SdsAssignee: ; interface SdsExpressionStatement extends SdsStatement { - expression: SdsExpression + expression: SdsExpression } SdsExpressionStatement returns SdsExpressionStatement: @@ -525,11 +525,11 @@ SdsExpression returns SdsExpression: interface SdsLambda extends SdsCallable, SdsExpression {} interface SdsBlockLambda extends SdsLambda { - body: SdsBlock + body: SdsBlock } interface SdsExpressionLambda extends SdsLambda { - result: SdsExpression + result: SdsExpression } SdsLambda returns SdsExpression: @@ -565,14 +565,14 @@ SdsBlockLambdaAssignee returns SdsAssignee: ; interface SdsInfixOperation extends SdsExpression { - leftOperand: SdsExpression - operator: string - rightOperand: SdsExpression + leftOperand: SdsExpression + operator: string + rightOperand: SdsExpression } interface SdsPrefixOperation extends SdsExpression { - operand: SdsExpression - operator: string + operand: SdsExpression + operator: string } SdsOrExpression returns SdsExpression: @@ -665,18 +665,18 @@ SdsUnaryOperation returns SdsExpression: ; interface SdsChainedExpression extends SdsExpression { - receiver: SdsExpression + receiver: SdsExpression } interface SdsCall extends SdsAbstractCall, SdsChainedExpression {} interface SdsIndexedAccess extends SdsChainedExpression { - index: SdsExpression + index: SdsExpression } interface SdsMemberAccess extends SdsChainedExpression { - nullSafe: boolean - member: SdsReference + isNullSafe: boolean + member: SdsReference } SdsChainedExpression returns SdsExpression: @@ -689,14 +689,14 @@ SdsChainedExpression returns SdsExpression: '[' index=SdsExpression ']' | {SdsMemberAccess.receiver=current} - (nullSafe?='?')? + (isNullSafe?='?')? '.' - member=SdsReference* + member=SdsReference )* ; interface SdsArgumentList extends SdsObject { - arguments: SdsArgument[] + arguments: SdsArgument[] } SdsCallArgumentList returns SdsArgumentList: @@ -711,8 +711,8 @@ SdsCallArgumentList returns SdsArgumentList: ; interface SdsArgument extends SdsExpression { - parameter?: @SdsParameter - value: SdsExpression + parameter?: @SdsParameter + value: SdsExpression } SdsCallArgument returns SdsArgument: @@ -737,7 +737,7 @@ SdsLiteral returns SdsLiteral: ; interface SdsBoolean extends SdsLiteral { - value: boolean + value: boolean } SdsBoolean returns SdsBoolean: @@ -748,7 +748,7 @@ SdsBoolean returns SdsBoolean: interface SdsNumber extends SdsLiteral {} interface SdsFloat extends SdsNumber { - value: number + value: number } SdsFloat returns SdsFloat: @@ -756,7 +756,7 @@ SdsFloat returns SdsFloat: ; interface SdsInt extends SdsNumber { - value: number + value: number } SdsInt returns SdsInt: @@ -770,7 +770,7 @@ SdsNull returns SdsNull: ; interface SdsString extends SdsLiteral { - value: string + value: string } SdsString returns SdsString: @@ -778,7 +778,7 @@ SdsString returns SdsString: ; interface SdsReference extends SdsExpression { - target: @SdsDeclaration + target: @SdsDeclaration } SdsReference returns SdsReference: @@ -786,7 +786,7 @@ SdsReference returns SdsReference: ; interface SdsParenthesizedExpression extends SdsExpression { - expression: SdsExpression + expression: SdsExpression } SdsParenthesizedExpression returns SdsParenthesizedExpression: @@ -794,7 +794,7 @@ SdsParenthesizedExpression returns SdsParenthesizedExpression: ; interface SdsTemplateString extends SdsExpression { - expressions: SdsExpression[] + expressions: SdsExpression[] } SdsTemplateString returns SdsTemplateString: @@ -805,7 +805,7 @@ SdsTemplateString returns SdsTemplateString: ; interface SdsTemplateStringPart extends SdsLiteral { - value: string + value: string } interface SdsTemplateStringStart extends SdsTemplateStringPart {} @@ -839,8 +839,8 @@ interface SdsType extends SdsObject {} interface SdsNamedTypeDeclaration extends SdsDeclaration {} interface SdsMemberType extends SdsType { - member: SdsNamedType - receiver: SdsType + member: SdsNamedType + receiver: SdsType } SdsType returns SdsType: @@ -855,7 +855,7 @@ SdsPrimaryType returns SdsType: ; interface SdsCallableType extends SdsCallable, SdsType { - resultList: SdsResultList + resultList: SdsResultList } SdsCallableType returns SdsCallableType: @@ -864,7 +864,7 @@ SdsCallableType returns SdsCallableType: ; interface SdsLiteralType extends SdsType { - literalList: SdsLiteralList + literalList: SdsLiteralList } SdsLiteralType returns SdsLiteralType: @@ -887,19 +887,19 @@ SdsLiteralList returns SdsLiteralList: ; interface SdsNamedType extends SdsType { - declaration: @SdsNamedTypeDeclaration - typeArgumentList?: SdsTypeArgumentList - nullable: boolean + declaration: @SdsNamedTypeDeclaration + typeArgumentList?: SdsTypeArgumentList + isNullable: boolean } SdsNamedType returns SdsNamedType: declaration=[SdsNamedTypeDeclaration:ID] typeArgumentList=SdsTypeArgumentList? - (nullable?='?' )? + (isNullable?='?' )? ; interface SdsUnionType extends SdsType { - typeArgumentList: SdsTypeArgumentList + typeArgumentList: SdsTypeArgumentList } SdsUnionType returns SdsUnionType: @@ -930,7 +930,7 @@ SdsParentType returns SdsType: ; interface SdsTypeParameterList extends SdsObject { - typeParameters: SdsTypeParameter[] + typeParameters: SdsTypeParameter[] } SdsTypeParameterList returns SdsTypeParameterList: @@ -945,7 +945,7 @@ SdsTypeParameterList returns SdsTypeParameterList: ; interface SdsTypeParameter extends SdsNamedTypeDeclaration { - variance?: string + variance?: string } SdsTypeParameter returns SdsTypeParameter: @@ -959,7 +959,7 @@ SdsTypeParameterVariance returns string: ; interface SdsTypeArgumentList extends SdsObject { - typeArguments: SdsTypeArgument[] + typeArguments: SdsTypeArgument[] } SdsTypeArgumentList returns SdsTypeArgumentList: @@ -970,8 +970,8 @@ SdsTypeArgumentList returns SdsTypeArgumentList: ; interface SdsTypeArgument extends SdsObject { - typeParameter?: @SdsTypeParameter - value: SdsTypeArgumentValue + typeParameter?: @SdsTypeParameter + value: SdsTypeArgumentValue } SdsTypeArgument returns SdsTypeArgument: @@ -982,7 +982,7 @@ SdsTypeArgument returns SdsTypeArgument: interface SdsTypeArgumentValue extends SdsObject {} interface SdsTypeProjection extends SdsTypeArgumentValue { - ^type: SdsType + ^type: SdsType } SdsTypeArgumentValue returns SdsTypeArgumentValue: @@ -995,7 +995,7 @@ SdsTypeArgumentValue returns SdsTypeArgumentValue: // ----------------------------------------------------------------------------- interface SdsSchema extends SdsModuleMember { - columnList: SdsColumnList + columnList: SdsColumnList } fragment SdsSchemaFragment: @@ -1005,7 +1005,7 @@ fragment SdsSchemaFragment: ; interface SdsColumnList extends SdsObject { - columns: SdsColumn[] + columns: SdsColumn[] } SdsColumnList returns SdsColumnList: @@ -1013,8 +1013,8 @@ SdsColumnList returns SdsColumnList: ; interface SdsColumn extends SdsObject { - columnName: SdsString - columnType: SdsType + columnName: SdsString + columnType: SdsType } SdsColumn returns SdsColumn: diff --git a/src/language/helpers/checks.ts b/src/language/helpers/checks.ts index f1fef942c..f9fe22b4d 100644 --- a/src/language/helpers/checks.ts +++ b/src/language/helpers/checks.ts @@ -16,9 +16,9 @@ export const isStatic = (node: SdsClassMember): boolean => { if (isSdsClass(node) || isSdsEnum(node)) { return true; } else if (isSdsAttribute(node)) { - return node.static; + return node.isStatic; } else if (isSdsFunction(node)) { - return node.static; + return node.isStatic; } else { /* c8 ignore next 2 */ return false; diff --git a/src/language/typing/model.ts b/src/language/typing/model.ts index 61b092432..d791bdba7 100644 --- a/src/language/typing/model.ts +++ b/src/language/typing/model.ts @@ -1,14 +1,12 @@ -// package com.larsreimann.safeds.staticAnalysis.typing -// -// import com.larsreimann.safeds.emf.containingEnumOrNull -// import com.larsreimann.safeds.naming.qualifiedNameOrNull -// import com.larsreimann.safeds.safeDS.SdsAbstractDeclaration -// import com.larsreimann.safeds.safeDS.SdsClass -// import com.larsreimann.safeds.safeDS.SdsEnum -// import com.larsreimann.safeds.safeDS.SdsEnumVariant -// import org.eclipse.xtext.naming.QualifiedName - -import { SdsClass, SdsDeclaration, SdsEnum, SdsEnumVariant } from '../generated/ast.js'; +import { + isSdsNull, + SdsCallable, + SdsClass, + SdsDeclaration, + SdsEnum, + SdsEnumVariant, + SdsLiteral, +} from '../generated/ast.js'; /* c8 ignore start */ export abstract class Type { @@ -21,11 +19,149 @@ export abstract class Type { abstract toString(): string; } +export class CallableType extends Type { + override isNullable: boolean = false; + + constructor( + readonly callable: SdsCallable, + readonly inputType: NamedTupleType, + readonly outputType: NamedTupleType, + ) { + super(); + } + + getParameterTypeByPosition(position: number): Type | undefined { + return this.inputType.getTypeOfEntryByPosition(position); + } + + override copyWithNullability(_isNullable: boolean): CallableType { + return this; + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof CallableType)) { + return false; + } + + return ( + other.callable === this.callable && + other.inputType.equals(this.inputType) && + other.outputType.equals(this.outputType) + ); + } + + override toString(): string { + return `${this.inputType} -> ${this.outputType}`; + } +} + +export class LiteralType extends Type { + override readonly isNullable: boolean; + + constructor(readonly values: SdsLiteral[]) { + super(); + + this.isNullable = values.some(isSdsNull); + } + + override copyWithNullability(isNullable: boolean): LiteralType { + if (isNullable && !this.isNullable) { + throw Error('Not implemented'); + } else if (!isNullable && this.isNullable) { + throw Error('Not implemented'); + } else { + return this; + } + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof LiteralType)) { + return false; + } + + throw Error('Not implemented'); + } + + override toString(): string { + throw Error('Not implemented'); + } +} + +export class NamedTupleType extends Type { + override readonly isNullable = false; + + constructor(readonly entries: NamedTupleEntry[]) { + super(); + } + + getTypeOfEntryByPosition(position: number): Type | undefined { + return this.entries[position]?.type; + } + + override copyWithNullability(_isNullable: boolean): NamedTupleType { + return this; + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof NamedTupleType)) { + return false; + } + + if (other.entries.length !== this.entries.length) { + return false; + } + + for (let i = 0; i < this.entries.length; i++) { + const otherEntry = other.entries[i]; + const entry = this.entries[i]; + + if (!entry.equals(otherEntry)) { + return false; + } + } + + return true; + } + + override toString(): string { + return `(${this.entries.join(', ')})`; + } +} + +export class NamedTupleEntry { + constructor( + readonly name: string, + readonly type: Type, + ) {} + + toString(): string { + return `${this.name}: ${this.type}`; + } + + equals(other: NamedTupleEntry): boolean { + return this.name === other.name && this.type.equals(other.type); + } +} + export abstract class NamedType extends Type { - protected constructor(private readonly sdsDeclaration: SdsDeclaration) { + protected constructor(readonly sdsDeclaration: SdsDeclaration) { super(); } + abstract override copyWithNullability(isNullable: boolean): NamedType; + override toString(): string { if (this.isNullable) { return `${this.sdsDeclaration.name}?`; @@ -33,8 +169,6 @@ export abstract class NamedType extends Type { return this.sdsDeclaration.name; } } - - // TODO: toQualifiedString(): string that uses qualified names instead of simple names } export class ClassType extends NamedType { @@ -45,7 +179,7 @@ export class ClassType extends NamedType { super(sdsClass); } - override copyWithNullability(isNullable: boolean): Type { + override copyWithNullability(isNullable: boolean): ClassType { return new ClassType(this.sdsClass, isNullable); } @@ -70,7 +204,7 @@ export class EnumType extends NamedType { super(sdsEnum); } - override copyWithNullability(isNullable: boolean): Type { + override copyWithNullability(isNullable: boolean): EnumType { return new EnumType(this.sdsEnum, isNullable); } @@ -95,7 +229,7 @@ export class EnumVariantType extends NamedType { super(sdsEnumVariant); } - override copyWithNullability(isNullable: boolean): Type { + override copyWithNullability(isNullable: boolean): EnumVariantType { return new EnumVariantType(this.sdsEnumVariant, isNullable); } @@ -110,130 +244,134 @@ export class EnumVariantType extends NamedType { return other.sdsEnumVariant === this.sdsEnumVariant && other.isNullable === this.isNullable; } +} + +/** + * A type that represents an actual class, enum, or enum variant instead of an instance of it. + */ +export class StaticType extends Type { + override readonly isNullable = false; + + constructor(readonly instanceType: NamedType) { + super(); + } + + override copyWithNullability(_isNullable: boolean): StaticType { + return this; + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof StaticType)) { + return false; + } + + return other.instanceType.equals(this.instanceType); + } + + override toString(): string { + return `$type<${this.instanceType}>`; + } +} + +export class UnionType extends Type { + override readonly isNullable = false; + + constructor(readonly possibleTypes: Type[]) { + super(); + } + + override copyWithNullability(_isNullable: boolean): UnionType { + return this; + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof UnionType)) { + return false; + } + + if (other.possibleTypes.length !== this.possibleTypes.length) { + return false; + } + + return other.possibleTypes.every((otherPossibleType) => + this.possibleTypes.some((possibleType) => possibleType.equals(otherPossibleType)), + ); + } - // override fun toSimpleString() = buildString { - // sdsEnumVariant.containingEnumOrNull()?.let { append("${it.name}.") } - // append(sdsEnumVariant.name) - // // nullability - // } + override toString(): string { + return `union<${this.possibleTypes.join(', ')}>`; + } } -// class RecordType(resultToType: List>) : Type() { -// private val resultToType = resultToType.toMap() -// -// override val isNullable = false -// override fun setIsNullableOnCopy(isNullable: boolean) = this -// -// override fun toString(): String { -// val types = resultToType.entries.joinToString { (name, type) -> "$name: $type" } -// return "($types)" -// } -// -// override fun toSimpleString(): String { -// val types = resultToType.entries.joinToString { (name, type) -> "$name: ${type.toSimpleString()}" } -// return "($types)" -// } -// -// override fun equals(other: Any?): boolean { -// if (this === other) return true -// if (javaClass != other?.javaClass) return false -// -// other as RecordType -// -// if (resultToType != other.resultToType) return false -// if (isNullable != other.isNullable) return false -// -// return true -// } -// -// override fun hashCode(): Int { -// var result = resultToType.hashCode() -// result = 31 * result + isNullable.hashCode() -// return result -// } -// } -// -// data class CallableType(val parameters: List, val results: List) : Type() { -// override val isNullable = false -// override fun setIsNullableOnCopy(isNullable: boolean) = this -// -// override fun toString(): String { -// val parameters = parameters.joinToString() -// val results = results.joinToString() -// -// return "($parameters) -> ($results)" -// } -// -// override fun toSimpleString(): String { -// val parameters = parameters.joinToString { it.toSimpleString() } -// val results = results.joinToString { it.toSimpleString() } -// -// return "($parameters) -> ($results)" -// } -// } -// -// -// LiteralType -// -// } -// -// data class UnionType(val possibleTypes: Set) : Type() { -// override val isNullable = false -// override fun setIsNullableOnCopy(isNullable: boolean) = this -// -// override fun toString(): String { -// return "union<${possibleTypes.joinToString()}>" -// } -// -// override fun toSimpleString(): String { -// return "union<${possibleTypes.joinToString { it.toSimpleString() }}>" -// } -// } -// -// data class VariadicType(val elementType: Type) : Type() { -// override val isNullable = false -// override fun setIsNullableOnCopy(isNullable: boolean) = this -// -// override fun toString(): String { -// return "vararg<$elementType>" -// } -// -// override fun toSimpleString(): String { -// return "vararg<${elementType.toSimpleString()}>" -// } -// } -// -// data class ParameterisedType( -// val sdsAbstractNamedTypeDeclaration: SdsAbstractDeclaration, -// val kind: String, -// ) : Type() { -// override val isNullable = false -// override fun setIsNullableOnCopy(isNullable: boolean) = this -// -// override fun toString(): String { -// return "::$kind" -// } -// -// override fun toSimpleString(): String { -// return "::$kind" -// } -// } - -class UnresolvedTypeClass extends Type { +export class VariadicType extends Type { + override readonly isNullable = false; + + constructor(readonly elementType: Type) { + super(); + } + + override copyWithNullability(_isNullable: boolean): VariadicType { + return this; + } + + override equals(other: Type): boolean { + if (other === this) { + return true; + } + + if (!(other instanceof VariadicType)) { + return false; + } + + return other.elementType.equals(this.elementType); + } + + override toString(): string { + return `vararg<${this.elementType}>`; + } +} + +class UnknownTypeClass extends Type { readonly isNullable = false; - copyWithNullability(_isNullable: boolean): Type { + copyWithNullability(_isNullable: boolean): UnknownTypeClass { + return this; + } + + override equals(other: Type): boolean { + return other instanceof UnknownTypeClass; + } + + toString(): string { + return '$Unknown'; + } +} + +export const UnknownType = new UnknownTypeClass(); + +class NotImplementedTypeClass extends Type { + override readonly isNullable = false; + + copyWithNullability(_isNullable: boolean): NotImplementedTypeClass { return this; } override equals(other: Type): boolean { - return other instanceof UnresolvedTypeClass; + return other instanceof NotImplementedTypeClass; } toString(): string { - return '$Unresolved'; + return '$NotImplemented'; } } -export const UnresolvedType = new UnresolvedTypeClass(); +export const NotImplementedType = new NotImplementedTypeClass(); /* c8 ignore stop */ diff --git a/src/language/typing/safe-ds-type-computer.ts b/src/language/typing/safe-ds-type-computer.ts index 1d1f22b80..142708c3f 100644 --- a/src/language/typing/safe-ds-type-computer.ts +++ b/src/language/typing/safe-ds-type-computer.ts @@ -1,28 +1,85 @@ -import { AstNode, AstNodeLocator, getDocument, WorkspaceCache } from 'langium'; +import { AstNode, AstNodeLocator, getContainerOfType, getDocument, WorkspaceCache } from 'langium'; import { SafeDsServices } from '../safe-ds-module.js'; import { SafeDsCoreClasses } from '../builtins/safe-ds-core-classes.js'; -import { ClassType, Type, UnresolvedType } from './model.js'; import { + CallableType, + ClassType, + EnumType, + EnumVariantType, + NamedTupleEntry, + NamedTupleType, + NamedType, + NotImplementedType, + StaticType, + Type, + UnionType, + UnknownType, + VariadicType, +} from './model.js'; +import { + isSdsAnnotation, + isSdsArgument, isSdsAssignee, + isSdsAssignment, + isSdsAttribute, + isSdsBlockLambda, isSdsBoolean, + isSdsCall, + isSdsCallable, + isSdsCallableType, + isSdsClass, isSdsDeclaration, + isSdsEnum, + isSdsEnumVariant, isSdsExpression, + isSdsExpressionLambda, isSdsFloat, + isSdsFunction, + isSdsIndexedAccess, + isSdsInfixOperation, isSdsInt, + isSdsLambda, + isSdsLiteralType, + isSdsMemberAccess, + isSdsMemberType, + isSdsNamedType, + isSdsNamedTypeDeclaration, isSdsNull, + isSdsParameter, + isSdsParenthesizedExpression, + isSdsPipeline, + isSdsPrefixOperation, + isSdsReference, + isSdsResult, + isSdsSegment, isSdsString, isSdsTemplateString, isSdsType, - isSdsTypeArgument, isSdsTypeProjection, + isSdsUnionType, + isSdsYield, SdsAssignee, + SdsCall, + SdsCallableType, SdsClass, SdsDeclaration, SdsExpression, + SdsFunction, + SdsInfixOperation, + SdsParameter, + SdsPrefixOperation, + SdsReference, + SdsSegment, SdsType, } from '../generated/ast.js'; +import { + assigneesOrEmpty, + blockLambdaResultsOrEmpty, + parametersOrEmpty, + resultsOrEmpty, + typeArgumentsOrEmpty, +} from '../helpers/shortcuts.js'; -/* c8 ignore start */ export class SafeDsTypeComputer { readonly astNodeLocator: AstNodeLocator; readonly coreClasses: SafeDsCoreClasses; @@ -38,7 +95,7 @@ export class SafeDsTypeComputer { computeType(node: AstNode | undefined): Type { if (!node) { - return UnresolvedType; + return UnknownType; } const documentUri = getDocument(node).uri.toString(); @@ -47,6 +104,21 @@ export class SafeDsTypeComputer { return this.typeCache.get(key, () => this.doComputeType(node)); } + // fun SdsAbstractObject.hasPrimitiveType(): Boolean { + // val type = type() + // if (type !is ClassType) { + // return false + // } + // + // val qualifiedName = type.sdsClass.qualifiedNameOrNull() + // return qualifiedName in setOf( + // StdlibClasses.Boolean, + // StdlibClasses.Float, + // StdlibClasses.Int, + // StdlibClasses.String, + // ) + // } + private doComputeType(node: AstNode): Type { if (isSdsAssignee(node)) { return this.computeTypeOfAssignee(node); @@ -56,23 +128,124 @@ export class SafeDsTypeComputer { return this.computeTypeOfExpression(node); } else if (isSdsType(node)) { return this.computeTypeOfType(node); - } else if (isSdsTypeArgument(node)) { - return UnresolvedType; - // return this.computeType(node.value); } else if (isSdsTypeProjection(node)) { - return UnresolvedType; - // return this.computeTypeOfType(node.type); - } else { - return this.Any(); + return this.computeTypeOfType(node.type); + } /* c8 ignore start */ else { + return UnknownType; + } /* c8 ignore stop */ + } + + private computeTypeOfAssignee(node: SdsAssignee): Type { + const containingAssignment = getContainerOfType(node, isSdsAssignment); + if (!containingAssignment) { + /* c8 ignore next 2 */ + return UnknownType; + } + + const nodePosition = node.$containerIndex ?? -1; + const expressionType = this.computeType(containingAssignment?.expression); + if (expressionType instanceof NamedTupleType) { + return expressionType.getTypeOfEntryByPosition(nodePosition) ?? UnknownType; + } else if (nodePosition === 0) { + return expressionType; } + + return UnknownType; + } + + private computeTypeOfDeclaration(node: SdsDeclaration): Type { + if (isSdsAnnotation(node)) { + const parameterEntries = parametersOrEmpty(node.parameterList).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it.type)), + ); + + return new CallableType(node, new NamedTupleType(parameterEntries), new NamedTupleType([])); + } else if (isSdsAttribute(node)) { + return this.computeType(node.type); + } else if (isSdsClass(node)) { + return new ClassType(node, false); + } else if (isSdsEnum(node)) { + return new EnumType(node, false); + } else if (isSdsEnumVariant(node)) { + return new EnumVariantType(node, false); + } else if (isSdsFunction(node)) { + return this.computeTypeOfCallableWithManifestTypes(node); + } else if (isSdsParameter(node)) { + return this.computeTypeOfParameter(node); + } else if (isSdsPipeline(node)) { + return UnknownType; + } else if (isSdsResult(node)) { + return this.computeType(node.type); + } else if (isSdsSegment(node)) { + return this.computeTypeOfCallableWithManifestTypes(node); + } /* c8 ignore start */ else { + return UnknownType; + } /* c8 ignore stop */ } - private computeTypeOfAssignee(_node: SdsAssignee): Type { - return UnresolvedType; + private computeTypeOfCallableWithManifestTypes(node: SdsFunction | SdsSegment | SdsCallableType): Type { + const parameterEntries = parametersOrEmpty(node.parameterList).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it.type)), + ); + const resultEntries = resultsOrEmpty(node.resultList).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it.type)), + ); + + return new CallableType(node, new NamedTupleType(parameterEntries), new NamedTupleType(resultEntries)); } - private computeTypeOfDeclaration(_node: SdsDeclaration): Type { - return UnresolvedType; + private computeTypeOfParameter(node: SdsParameter): Type { + // Manifest type + if (node.type) { + const manifestParameterType = this.computeType(node.type); + if (node.isVariadic) { + return new VariadicType(manifestParameterType); + } else { + return manifestParameterType; + } + } + + // Infer type from context + const containingCallable = getContainerOfType(node, isSdsCallable); + if (!isSdsLambda(containingCallable)) { + return UnknownType; + } + + const containerOfLambda = containingCallable.$container; + + // Lambda passed as argument + /* c8 ignore start */ + if (isSdsArgument(containerOfLambda)) { + // val containerType = when (val container = callable.eContainer()) { + // is SdsArgument -> container.parameterOrNull()?.inferType(context) + // } + // + // return when (containerType) { + // is CallableType -> containerType.parameters.getOrElse(thisIndex) { Any(context) } + // else -> Any(context) + // } + + return NotImplementedType; + } + /* c8 ignore stop */ + + // Yielded lambda + else if (isSdsAssignment(containerOfLambda)) { + const firstAssignee = assigneesOrEmpty(containerOfLambda)[0]; + if (!isSdsYield(firstAssignee)) { + return UnknownType; + } + + const resultType = this.computeType(firstAssignee.result?.ref); + if (!(resultType instanceof CallableType)) { + return UnknownType; + } + + const parameterPosition = node.$containerIndex ?? -1; + return resultType.getParameterTypeByPosition(parameterPosition) ?? UnknownType; + } + + return UnknownType; } private computeTypeOfExpression(node: SdsExpression): Type { @@ -84,382 +257,299 @@ export class SafeDsTypeComputer { } else if (isSdsInt(node)) { return this.Int(); } else if (isSdsNull(node)) { - return this.Nothing(true); + return this.NothingOrNull(); } else if (isSdsString(node)) { return this.String(); } else if (isSdsTemplateString(node)) { return this.String(); } - return UnresolvedType; + // Recursive cases + else if (isSdsArgument(node)) { + return this.computeType(node.value); + } else if (isSdsCall(node)) { + return this.computeTypeOfCall(node); + } else if (isSdsBlockLambda(node)) { + const parameterEntries = parametersOrEmpty(node.parameterList).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it)), + ); + const resultEntries = blockLambdaResultsOrEmpty(node).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it)), + ); + + return new CallableType(node, new NamedTupleType(parameterEntries), new NamedTupleType(resultEntries)); + } else if (isSdsExpressionLambda(node)) { + const parameterEntries = parametersOrEmpty(node.parameterList).map( + (it) => new NamedTupleEntry(it.name, this.computeType(it)), + ); + const resultEntries = [new NamedTupleEntry('result', this.computeType(node.result))]; + + return new CallableType(node, new NamedTupleType(parameterEntries), new NamedTupleType(resultEntries)); + } else if (isSdsIndexedAccess(node)) { + const receiverType = this.computeType(node.receiver); + if (receiverType instanceof VariadicType) { + return receiverType.elementType; + } else { + return UnknownType; + } + } else if (isSdsInfixOperation(node)) { + switch (node.operator) { + // Boolean operators + case 'or': + case 'and': + return this.Boolean(); + + // Equality operators + case '==': + case '!=': + case '===': + case '!==': + return this.Boolean(); + + // Comparison operators + case '<': + case '<=': + case '>=': + case '>': + return this.Boolean(); + + // Arithmetic operators + case '+': + case '-': + case '*': + case '/': + return this.computeTypeOfArithmeticInfixOperation(node); + + // Elvis operator + case '?:': + return this.computeTypeOfElvisOperation(node); + + // Unknown operator + /* c8 ignore next 2 */ + default: + return UnknownType; + } + } else if (isSdsMemberAccess(node)) { + const memberType = this.computeType(node.member); + return memberType.copyWithNullability(node.isNullSafe || memberType.isNullable); + } else if (isSdsParenthesizedExpression(node)) { + return this.computeType(node.expression); + } else if (isSdsPrefixOperation(node)) { + switch (node.operator) { + case 'not': + return this.Boolean(); + case '-': + return this.computeTypeOfArithmeticPrefixOperation(node); + + // Unknown operator + /* c8 ignore next 2 */ + default: + return UnknownType; + } + } else if (isSdsReference(node)) { + return this.computeTypeOfReference(node); + } /* c8 ignore start */ else { + return UnknownType; + } /* c8 ignore stop */ } - private computeTypeOfType(_node: SdsType): Type { - return UnresolvedType; - } + private computeTypeOfCall(node: SdsCall): Type { + const receiverType = this.computeType(node.receiver); - private cachedAny: Type = UnresolvedType; + if (receiverType instanceof CallableType) { + if (!isSdsAnnotation(receiverType.callable)) { + return receiverType.outputType; + } + } else if (receiverType instanceof StaticType) { + const instanceType = receiverType.instanceType; + const declaration = instanceType.sdsDeclaration; - private Any(): Type { - if (this.cachedAny === UnresolvedType) { - this.cachedAny = this.createCoreType(this.coreClasses.Any); + if (isSdsClass(declaration) || isSdsEnumVariant(declaration)) { + return instanceType; + } } - return this.cachedAny; - } - - private cachedBoolean: Type = UnresolvedType; - private Boolean(): Type { - if (this.cachedBoolean === UnresolvedType) { - this.cachedBoolean = this.createCoreType(this.coreClasses.Boolean); - } - return this.cachedBoolean; + return UnknownType; } - private cachedFloat: Type = UnresolvedType; + private computeTypeOfArithmeticInfixOperation(node: SdsInfixOperation): Type { + const leftOperandType = this.computeType(node.leftOperand); + const rightOperandType = this.computeType(node.rightOperand); - private Float(): Type { - if (this.cachedFloat === UnresolvedType) { - this.cachedFloat = this.createCoreType(this.coreClasses.Float); + if (leftOperandType === this.Int() && rightOperandType === this.Int()) { + return this.Int(); + } else { + return this.Float(); } - return this.cachedFloat; } - private cachedInt: Type = UnresolvedType; - - private Int(): Type { - if (this.cachedInt === UnresolvedType) { - this.cachedInt = this.createCoreType(this.coreClasses.Int); + private computeTypeOfElvisOperation(node: SdsInfixOperation): Type { + const leftOperandType = this.computeType(node.leftOperand); + if (leftOperandType.isNullable) { + /* c8 ignore next 3 */ + const rightOperandType = this.computeType(node.rightOperand); + return this.lowestCommonSupertype(leftOperandType.copyWithNullability(false), rightOperandType); + } else { + return leftOperandType; } - return this.cachedInt; } - private cachedNullableNothing: Type = UnresolvedType; - private cachedNothing: Type = UnresolvedType; + private computeTypeOfArithmeticPrefixOperation(node: SdsPrefixOperation): Type { + const leftOperandType = this.computeType(node.operand); - private Nothing(isNullable: boolean): Type { - if (isNullable) { - if (this.cachedNullableNothing === UnresolvedType) { - this.cachedNullableNothing = this.createCoreType(this.coreClasses.Nothing, true); - } - return this.cachedNullableNothing; + if (leftOperandType === this.Int()) { + return this.Int(); } else { - if (this.cachedNothing === UnresolvedType) { - this.cachedNothing = this.createCoreType(this.coreClasses.Nothing); - } - return this.cachedNothing; + return this.Float(); } } - private cachedString: Type = UnresolvedType; + private computeTypeOfReference(node: SdsReference): Type { + const target = node.target.ref; + const instanceType = this.computeType(target); - private String(): Type { - if (this.cachedString === UnresolvedType) { - this.cachedString = this.createCoreType(this.coreClasses.String); - } - return this.cachedString; - } - - private createCoreType(coreClass: SdsClass | undefined, isNullable: boolean = false): Type { - if (coreClass) { - return new ClassType(coreClass, isNullable); + if (isSdsNamedTypeDeclaration(target) && instanceType instanceof NamedType) { + return new StaticType(instanceType.copyWithNullability(false)); } else { - return UnresolvedType; + return instanceType; } } -} - -/* c8 ignore stop */ -/* -fun SdsAbstractObject.hasPrimitiveType(): Boolean { - val type = type() - if (type !is ClassType) { - return false + private computeTypeOfType(node: SdsType): Type { + if (isSdsCallableType(node)) { + return this.computeTypeOfCallableWithManifestTypes(node); + } else if (isSdsLiteralType(node)) { + /* c8 ignore next */ + return NotImplementedType; + } else if (isSdsMemberType(node)) { + return this.computeType(node.member); + } else if (isSdsNamedType(node)) { + return this.computeType(node.declaration.ref).copyWithNullability(node.isNullable); + } else if (isSdsUnionType(node)) { + const typeArguments = typeArgumentsOrEmpty(node.typeArgumentList); + return new UnionType(typeArguments.map((typeArgument) => this.computeType(typeArgument.value))); + } /* c8 ignore start */ else { + return UnknownType; + } /* c8 ignore stop */ } - val qualifiedName = type.sdsClass.qualifiedNameOrNull() - return qualifiedName in setOf( - StdlibClasses.Boolean, - StdlibClasses.Float, - StdlibClasses.Int, - StdlibClasses.String, - ) -} + // ----------------------------------------------------------------------------------------------------------------- + // Helpers + // ----------------------------------------------------------------------------------------------------------------- -private fun SdsAbstractAssignee.inferTypeForAssignee(context: EObject): Type { - return when { - this.eIsProxy() -> UnresolvedType - this is SdsBlockLambdaResult || this is SdsPlaceholder || this is SdsYield -> { - val assigned = assignedOrNull() ?: return Nothing(context) - assigned.inferType(context) - } - else -> Any(context) + /* c8 ignore start */ + private lowestCommonSupertype(..._types: Type[]): Type { + return NotImplementedType; } -} -@OptIn(ExperimentalSdsApi::class) -private fun SdsAbstractDeclaration.inferTypeForDeclaration(context: EObject): Type { - return when { - this.eIsProxy() -> UnresolvedType - this is SdsAttribute -> type.inferTypeForType(context) - this is SdsClass -> { - val typeParametersTypes = this.typeParametersOrEmpty() - .map { it.inferTypeForDeclaration(context) } - .filterIsInstance() - - ClassType(this, typeParametersTypes, isNullable = false) - } - this is SdsEnum -> EnumType(this, isNullable = false) - this is SdsEnumVariant -> EnumVariantType(this, isNullable = false) - this is SdsFunction -> CallableType( - parametersOrEmpty().map { it.inferTypeForDeclaration(context) }, - resultsOrEmpty().map { it.inferTypeForDeclaration(context) }, - ) - this is SdsParameter -> { - // Declared parameter type - if (this.type != null) { - val declaredParameterType = this.type.inferTypeForType(context) - return when { - this.isVariadic -> VariadicType(declaredParameterType) - else -> declaredParameterType - } - } - - // Inferred lambda parameter type - val callable = this.closestAncestorOrNull() - val thisIndex = callable.parametersOrEmpty().indexOf(this) - if (callable is SdsAbstractLambda) { - val containerType = when (val container = callable.eContainer()) { - is SdsArgument -> container.parameterOrNull()?.inferType(context) - is SdsAssignment -> - container - .yieldsOrEmpty() - .find { it.assignedOrNull() == callable } - ?.result - ?.inferType(context) - else -> null - } - - return when (containerType) { - is CallableType -> containerType.parameters.getOrElse(thisIndex) { Any(context) } - else -> Any(context) - } - } + /* c8 ignore stop */ + + // private fun lowestCommonSupertype(context: EObject, types: List): Type { + // if (types.isEmpty()) { + // return Nothing(context) + // } + // + // val unwrappedTypes = unwrapUnionTypes(types) + // val isNullable = unwrappedTypes.any { it.isNullable } + // var candidate = unwrappedTypes.first().setIsNullableOnCopy(isNullable) + // + // while (!isLowestCommonSupertype(candidate, unwrappedTypes)) { + // candidate = when (candidate) { + // is CallableType -> Any(context, candidate.isNullable) + // is ClassType -> { + // val superClass = candidate.sdsClass.superClasses().firstOrNull() + // ?: return Any(context, candidate.isNullable) + // + // ClassType(superClass, typeParametersTypes, candidate.isNullable) + // } + // is EnumType -> Any(context, candidate.isNullable) + // is EnumVariantType -> { + // val containingEnum = candidate.sdsEnumVariant.containingEnumOrNull() + // ?: return Any(context, candidate.isNullable) + // EnumType(containingEnum, candidate.isNullable) + // } + // is RecordType -> Any(context, candidate.isNullable) + // // TODO: Correct ? + // is UnionType -> throw AssertionError("Union types should have been unwrapped.") + // UnresolvedType -> Any(context, candidate.isNullable) + // is VariadicType -> Any(context, candidate.isNullable) + // } + // } + // + // return candidate + // } + // + // private fun unwrapUnionTypes(types: List): List { + // return types.flatMap { + // when (it) { + // is UnionType -> it.possibleTypes + // else -> listOf(it) + // } + // } + // } + // + // private fun isLowestCommonSupertype(candidate: Type, otherTypes: List): Boolean { + // if (candidate is ClassType && candidate.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any) { + // return true + // } + // + // return otherTypes.all { it.isSubstitutableFor(candidate) } + // } + + // ----------------------------------------------------------------------------------------------------------------- + // Builtin types + // ----------------------------------------------------------------------------------------------------------------- + + private cachedBoolean: Type = UnknownType; - // We don't know better - return Any(context) + private Boolean(): Type { + if (this.cachedBoolean === UnknownType) { + this.cachedBoolean = this.createCoreType(this.coreClasses.Boolean); } - this is SdsResult -> type.inferTypeForType(context) - // For now all Schema placeholders are of type 'ParameterisedType(::$SchemaType)' - this is SdsSchemaPlaceholder -> ParameterisedType(this, SdsKind.SchemaKind.toString()) - this is SdsStep -> CallableType( - parametersOrEmpty().map { it.inferTypeForDeclaration(context) }, - resultsOrEmpty().map { it.inferTypeForDeclaration(context) }, - ) - // Todo: resolve TypeParameter for "non kind" TypeParameter too - this is SdsTypeParameter && this.kind != null -> ParameterisedType(this, kind) - else -> Any(context) + return this.cachedBoolean; } -} -private fun SdsAbstractExpression.inferTypeExpression(context: EObject): Type { - return when { - // Terminal cases - this.eIsProxy() -> UnresolvedType - this is SdsBoolean -> Boolean(context) - this is SdsFloat -> Float(context) - this is SdsInt -> Int(context) - this is SdsNull -> Nothing(context, isNullable = true) - this is SdsString -> String(context) - this is SdsTemplateString -> String(context) + private cachedFloat: Type = UnknownType; - // Recursive cases - this is SdsArgument -> this.value.inferTypeExpression(context) - this is SdsBlockLambda -> CallableType( - this.parametersOrEmpty().map { it.inferTypeForDeclaration(context) }, - blockLambdaResultsOrEmpty().map { it.inferTypeForAssignee(context) }, - ) - this is SdsCall -> when (val callable = callableOrNull()) { - is SdsClass -> { - val typeParametersTypes = callable.typeParametersOrEmpty() - .map { it.inferTypeForDeclaration(context) } - .filterIsInstance() - - ClassType(callable, typeParametersTypes, isNullable = false) - } - is SdsCallableType -> { - val results = callable.resultsOrEmpty() - when (results.size) { - 1 -> results.first().inferTypeForDeclaration(context) - else -> RecordType(results.map { it.name to it.inferTypeForDeclaration(context) }) - } - } - is SdsFunction -> { - val results = callable.resultsOrEmpty() - when (results.size) { - 1 -> results.first().inferTypeForDeclaration(context) - else -> RecordType(results.map { it.name to it.inferTypeForDeclaration(context) }) - } - } - is SdsBlockLambda -> { - val results = callable.blockLambdaResultsOrEmpty() - when (results.size) { - 1 -> results.first().inferTypeForAssignee(context) - else -> RecordType(results.map { it.name to it.inferTypeForAssignee(context) }) - } - } - is SdsEnumVariant -> { - EnumVariantType(callable, isNullable = false) - } - is SdsExpressionLambda -> { - callable.result.inferTypeExpression(context) - } - is SdsStep -> { - val results = callable.resultsOrEmpty() - when (results.size) { - 1 -> results.first().inferTypeForDeclaration(context) - else -> RecordType(results.map { it.name to it.inferTypeForDeclaration(context) }) - } - } - else -> Any(context) - } - this is SdsExpressionLambda -> CallableType( - this.parametersOrEmpty().map { it.inferTypeForDeclaration(context) }, - listOf(result.inferTypeExpression(context)), - ) - this is SdsIndexedAccess -> { - when (val receiverType = this.receiver.inferTypeExpression(context)) { - is UnresolvedType -> UnresolvedType - is VariadicType -> receiverType.elementType - else -> Nothing(context) - } - } - this is SdsInfixOperation -> when (operator) { - "<", "<=", ">=", ">" -> Boolean(context) - "==", "!=" -> Boolean(context) - "===", "!==" -> Boolean(context) - "or", "and" -> Boolean(context) - "+", "-", "*", "/" -> when { - this.leftOperand.inferTypeExpression(context) == Int(context) && - this.rightOperand.inferTypeExpression(context) == Int(context) -> Int(context) - else -> Float(context) - } - "?:" -> { - val leftOperandType = this.leftOperand.inferTypeExpression(context) - if (leftOperandType.isNullable) { - lowestCommonSupertype( - context, - listOf( - leftOperandType.setIsNullableOnCopy(isNullable = false), - this.rightOperand.inferTypeExpression(context), - ), - ) - } else { - leftOperandType - } - } - else -> Nothing(context) - } - this is SdsMemberAccess -> { - val memberType = this.member.inferTypeExpression(context) - memberType.setIsNullableOnCopy(this.isNullSafe || memberType.isNullable) - } - this is SdsParenthesizedExpression -> this.expression.inferTypeExpression(context) - this is SdsPrefixOperation -> when (operator) { - "not" -> Boolean(context) - "-" -> when (this.operand.inferTypeExpression(context)) { - Int(context) -> Int(context) - else -> Float(context) - } - else -> Nothing(context) + private Float(): Type { + if (this.cachedFloat === UnknownType) { + this.cachedFloat = this.createCoreType(this.coreClasses.Float); } - this is SdsReference -> this.declaration.inferType(context) - this is SdsSchemaReference -> this.type.inferTypeForType(context) - else -> Any(context) + return this.cachedFloat; } -} -private fun SdsAbstractType.inferTypeForType(context: EObject): Type { - return when { - this.eIsProxy() -> UnresolvedType - this is SdsCallableType -> CallableType( - this.parametersOrEmpty().map { it.inferTypeForDeclaration(context) }, - this.resultsOrEmpty().map { it.inferTypeForDeclaration(context) }, - ) - this is SdsMemberType -> { - this.member.inferTypeForType(context) - } - this is SdsNamedType -> { - this.declaration.inferTypeForDeclaration(context).setIsNullableOnCopy(this.isNullable) - } - this is SdsParenthesizedType -> { - this.type.inferTypeForType(context) - } - this is SdsSchemaType -> { - this.declaration.inferTypeForDeclaration(context) - } - this is SdsUnionType -> { - UnionType(this.typeArgumentsOrEmpty().map { it.value.inferType(context) }.toSet()) - } - else -> Any(context) - } -} + private cachedInt: Type = UnknownType; -private fun lowestCommonSupertype(context: EObject, types: List): Type { - if (types.isEmpty()) { - return Nothing(context) + private Int(): Type { + if (this.cachedInt === UnknownType) { + this.cachedInt = this.createCoreType(this.coreClasses.Int); + } + return this.cachedInt; } - val unwrappedTypes = unwrapUnionTypes(types) - val isNullable = unwrappedTypes.any { it.isNullable } - var candidate = unwrappedTypes.first().setIsNullableOnCopy(isNullable) - - while (!isLowestCommonSupertype(candidate, unwrappedTypes)) { - candidate = when (candidate) { - is CallableType -> Any(context, candidate.isNullable) - is ClassType -> { - val superClass = candidate.sdsClass.superClasses().firstOrNull() - ?: return Any(context, candidate.isNullable) - - val typeParametersTypes = superClass.typeParametersOrEmpty() - .map { it.inferTypeForDeclaration(context) } - .filterIsInstance() + private cachedNothingOrNull: Type = UnknownType; - ClassType(superClass, typeParametersTypes, candidate.isNullable) - } - is EnumType -> Any(context, candidate.isNullable) - is EnumVariantType -> { - val containingEnum = candidate.sdsEnumVariant.containingEnumOrNull() - ?: return Any(context, candidate.isNullable) - EnumType(containingEnum, candidate.isNullable) - } - is RecordType -> Any(context, candidate.isNullable) - // TODO: Correct ? - is ParameterisedType -> Any(context, candidate.isNullable) - is UnionType -> throw AssertionError("Union types should have been unwrapped.") - UnresolvedType -> Any(context, candidate.isNullable) - is VariadicType -> Any(context, candidate.isNullable) + private NothingOrNull(): Type { + if (this.cachedNothingOrNull === UnknownType) { + this.cachedNothingOrNull = this.createCoreType(this.coreClasses.Nothing, true); } + return this.cachedNothingOrNull; } - return candidate -} + private cachedString: Type = UnknownType; -private fun unwrapUnionTypes(types: List): List { - return types.flatMap { - when (it) { - is UnionType -> it.possibleTypes - else -> listOf(it) + private String(): Type { + if (this.cachedString === UnknownType) { + this.cachedString = this.createCoreType(this.coreClasses.String); } + return this.cachedString; } -} -private fun isLowestCommonSupertype(candidate: Type, otherTypes: List): Boolean { - if (candidate is ClassType && candidate.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any) { - return true + private createCoreType(coreClass: SdsClass | undefined, isNullable: boolean = false): Type { + if (coreClass) { + return new ClassType(coreClass, isNullable); + } /* c8 ignore start */ else { + return UnknownType; + } /* c8 ignore stop */ } - - return otherTypes.all { it.isSubstitutableFor(candidate) } } - */ diff --git a/src/language/typing/typeConformance.ts b/src/language/typing/typeConformance.ts new file mode 100644 index 000000000..35f42f6dc --- /dev/null +++ b/src/language/typing/typeConformance.ts @@ -0,0 +1,141 @@ +// package com.larsreimann.safeds.staticAnalysis.typing +// +// import com.larsreimann.safeds.constant.kind +// import com.larsreimann.safeds.emf.variantsOrEmpty +// import com.larsreimann.safeds.naming.qualifiedNameOrNull +// import com.larsreimann.safeds.staticAnalysis.classHierarchy.isSubtypeOf +// import com.larsreimann.safeds.stdlibAccess.StdlibClasses +// import com.larsreimann.safeds.utils.ExperimentalSdsApi +// +// fun Type.isSubstitutableFor(other: Type, resultIfUnresolved: Boolean = false): Boolean { +// if (other == UnresolvedType) { +// return resultIfUnresolved +// } +// +// return when (this) { +// is CallableType -> this.isSubstitutableFor(other) +// is ClassType -> this.isSubstitutableFor(other) +// is EnumType -> this.isSubstitutableFor(other) +// is EnumVariantType -> this.isSubstitutableFor(other) +// is ParameterisedType -> this.isSubstitutableFor(other) +// is UnionType -> this.isSubstitutableFor(other) +// is VariadicType -> this.isSubstitutableFor(other) +// is RecordType -> false +// UnresolvedType -> resultIfUnresolved +// } +// } +// +// private fun CallableType.isSubstitutableFor(other: Type): Boolean { +// return when (val unwrappedOther = unwrapVariadicType(other)) { +// is CallableType -> { +// // TODO: We need to compare names of parameters & results and can allow additional optional parameters +// +// // Sizes must match (too strict requirement -> should be loosened later) +// if (this.parameters.size != unwrappedOther.parameters.size || this.results.size != this.results.size) { +// return false +// } +// +// // Actual parameters must be supertypes of expected parameters (contravariance) +// this.parameters.zip(unwrappedOther.parameters).forEach { (thisParameter, otherParameter) -> +// if (!otherParameter.isSubstitutableFor(thisParameter)) { +// return false +// } +// } +// +// // Expected results must be subtypes of expected results (covariance) +// this.results.zip(unwrappedOther.results).forEach { (thisResult, otherResult) -> +// if (!thisResult.isSubstitutableFor(otherResult)) { +// return false +// } +// } +// +// true +// } +// is ClassType -> { +// unwrappedOther.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any +// } +// is UnionType -> { +// unwrappedOther.possibleTypes.any { this.isSubstitutableFor(it) } +// } +// else -> false +// } +// } +// +// private fun ClassType.isSubstitutableFor(other: Type): Boolean { +// return when (val unwrappedOther = unwrapVariadicType(other)) { +// is ClassType -> { +// (!this.isNullable || unwrappedOther.isNullable) && this.sdsClass.isSubtypeOf(unwrappedOther.sdsClass) +// } +// is UnionType -> { +// unwrappedOther.possibleTypes.any { this.isSubstitutableFor(it) } +// } +// else -> false +// } +// } +// +// private fun EnumType.isSubstitutableFor(other: Type): Boolean { +// return when (val unwrappedOther = unwrapVariadicType(other)) { +// is ClassType -> { +// (!this.isNullable || unwrappedOther.isNullable) && +// unwrappedOther.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any +// } +// is EnumType -> { +// (!this.isNullable || unwrappedOther.isNullable) && this.sdsEnum == unwrappedOther.sdsEnum +// } +// is UnionType -> { +// unwrappedOther.possibleTypes.any { this.isSubstitutableFor(it) } +// } +// else -> false +// } +// } +// +// private fun EnumVariantType.isSubstitutableFor(other: Type): Boolean { +// return when (val unwrappedOther = unwrapVariadicType(other)) { +// is ClassType -> { +// (!this.isNullable || unwrappedOther.isNullable) && +// unwrappedOther.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any +// } +// is EnumType -> { +// (!this.isNullable || unwrappedOther.isNullable) && +// this.sdsEnumVariant in unwrappedOther.sdsEnum.variantsOrEmpty() +// } +// is EnumVariantType -> { +// (!this.isNullable || unwrappedOther.isNullable) && this.sdsEnumVariant == unwrappedOther.sdsEnumVariant +// } +// is UnionType -> unwrappedOther.possibleTypes.any { this.isSubstitutableFor(it) } +// else -> false +// } +// } +// +// @OptIn(ExperimentalSdsApi::class) +// private fun ParameterisedType.isSubstitutableFor(other: Type): Boolean { +// return when (other) { +// is ParameterisedType -> (!this.isNullable || other.isNullable) && this.kind() == other.kind() +// else -> false +// } +// } +// +// /** +// * A [UnionType] can be substituted for another type of all its possible types can be substituted for the other type. +// */ +// private fun UnionType.isSubstitutableFor(other: Type): Boolean { +// return this.possibleTypes.all { it.isSubstitutableFor(other) } +// } +// +// private fun VariadicType.isSubstitutableFor(other: Type): Boolean { +// return when (other) { +// is ClassType -> other.sdsClass.qualifiedNameOrNull() == StdlibClasses.Any +// is VariadicType -> this.elementType.isSubstitutableFor(other) +// else -> false +// } +// } +// +// /** +// * Returns the elementType of a [VariadicType] or, otherwise, the type itself. +// */ +// private fun unwrapVariadicType(type: Type): Type { +// return when (type) { +// is VariadicType -> type.elementType +// else -> type +// } +// } diff --git a/src/language/validation/other/declarations/parameterLists.ts b/src/language/validation/other/declarations/parameterLists.ts index f7851aabb..e2458e5d8 100644 --- a/src/language/validation/other/declarations/parameterLists.ts +++ b/src/language/validation/other/declarations/parameterLists.ts @@ -11,7 +11,7 @@ export const parameterListMustNotHaveOptionalAndVariadicParameters = ( ) => { const hasOptional = node.parameters.find((p) => p.defaultValue); if (hasOptional) { - const variadicRequiredParameters = node.parameters.filter((p) => p.variadic && !p.defaultValue); + const variadicRequiredParameters = node.parameters.filter((p) => p.isVariadic && !p.defaultValue); for (const variadic of variadicRequiredParameters) { accept('error', 'A callable with optional parameters must not have a variadic parameter.', { @@ -31,7 +31,7 @@ export const parameterListMustNotHaveRequiredParametersAfterOptionalParameters = for (const parameter of node.parameters) { if (parameter.defaultValue) { foundOptional = true; - } else if (foundOptional && !parameter.variadic) { + } else if (foundOptional && !parameter.isVariadic) { accept('error', 'After the first optional parameter all parameters must be optional.', { node: parameter, property: 'name', @@ -52,7 +52,7 @@ export const parameterListVariadicParameterMustBeLast = (node: SdsParameterList, }); } - if (parameter.variadic) { + if (parameter.isVariadic) { foundVariadic = true; } } diff --git a/src/language/validation/other/declarations/parameters.ts b/src/language/validation/other/declarations/parameters.ts index 064fd74bd..473db1763 100644 --- a/src/language/validation/other/declarations/parameters.ts +++ b/src/language/validation/other/declarations/parameters.ts @@ -4,7 +4,7 @@ import { ValidationAcceptor } from 'langium'; export const CODE_PARAMETER_VARIADIC_AND_OPTIONAL = 'parameter/variadic-and-optional'; export const parameterMustNotBeVariadicAndOptional = (node: SdsParameter, accept: ValidationAcceptor) => { - if (node.variadic && node.defaultValue) { + if (node.isVariadic && node.defaultValue) { accept('error', 'Variadic parameters must not be optional.', { node, property: 'name', diff --git a/src/language/validation/other/types/callableTypes.ts b/src/language/validation/other/types/callableTypes.ts index 28058acde..fba81efac 100644 --- a/src/language/validation/other/types/callableTypes.ts +++ b/src/language/validation/other/types/callableTypes.ts @@ -6,7 +6,7 @@ export const CODE_CALLABLE_TYPE_NO_OPTIONAL_PARAMETERS = 'callable-type/no-optio export const callableTypeMustNotHaveOptionalParameters = (node: SdsCallableType, accept: ValidationAcceptor): void => { for (const parameter of parametersOrEmpty(node.parameterList)) { - if (parameter.defaultValue && !parameter.variadic) { + if (parameter.defaultValue && !parameter.isVariadic) { accept('error', 'A callable type must not have optional parameters.', { node: parameter, property: 'defaultValue', diff --git a/tests/helpers/location.ts b/tests/helpers/location.ts index ef18fc5ed..9e0d41a48 100644 --- a/tests/helpers/location.ts +++ b/tests/helpers/location.ts @@ -47,7 +47,7 @@ export const isLocationEqual = (location1: Location, location2: Location): boole }; /** - * Find the AstNode at the given location. It must fill the range exactly. + * Find the AstNode at the given location. It must either fill the entire range or have a name node that does. * * @param services The services to use. * @param location The location of the node to find. @@ -73,7 +73,7 @@ export const getNodeByLocation = (services: SafeDsServices, location: Location): }); } - for (const node of streamAllContents(root, { range: location.range })) { + for (const node of streamAllContents(root)) { // Entire node matches the range const actualRange = node.$cstNode?.range; if (actualRange && isRangeEqual(actualRange, location.range)) { diff --git a/tests/resources/typing/assignees/block lambda results/main.sdstest b/tests/resources/typing/assignees/block lambda results/main.sdstest new file mode 100644 index 000000000..a8ace56be --- /dev/null +++ b/tests/resources/typing/assignees/block lambda results/main.sdstest @@ -0,0 +1,23 @@ +package tests.typing.assignees.blockLambdaResults + +fun f() -> (r1: Int, r2: Float, r3: String) + +segment mySegment() -> (r: Int) { + () { + // $TEST$ equivalence_class assignedValue + // $TEST$ equivalence_class assignedValue + yield »r« = »1«; + }; + + () { + // $TEST$ serialization Int + // $TEST$ serialization $Unknown + yield »r«, yield »s« = 1; + }; + + () { + // $TEST$ serialization Int + // $TEST$ serialization String + yield »r«, _, yield »s« = f(); + }; +} diff --git a/tests/resources/typing/assignees/placeholders/main.sdstest b/tests/resources/typing/assignees/placeholders/main.sdstest new file mode 100644 index 000000000..f091e8e32 --- /dev/null +++ b/tests/resources/typing/assignees/placeholders/main.sdstest @@ -0,0 +1,21 @@ +package tests.typing.assignees.placeholders + +fun f() -> (r1: Int, r2: Float, r3: String) + +segment mySegment1() -> (r: Int) { + // $TEST$ equivalence_class assignedValue + // $TEST$ equivalence_class assignedValue + val »r« = »1«; +} + +segment mySegment2() -> (r: Int, s: String) { + // $TEST$ serialization Int + // $TEST$ serialization $Unknown + val »r«, val »s« = 1; +} + +segment mySegment3() -> (r: Int, s: String) { + // $TEST$ serialization Int + // $TEST$ serialization String + val »r«, _, val »s« = f(); +} diff --git a/tests/resources/typing/assignees/yields/main.sdstest b/tests/resources/typing/assignees/yields/main.sdstest new file mode 100644 index 000000000..21f442a3e --- /dev/null +++ b/tests/resources/typing/assignees/yields/main.sdstest @@ -0,0 +1,21 @@ +package tests.typing.assignees.yields + +fun f() -> (r1: Int, r2: Float, r3: String) + +segment mySegment1() -> (r: Int) { + // $TEST$ equivalence_class assignedValue + // $TEST$ equivalence_class assignedValue + »yield r«, _ = »1«; // the wildcards prevents the marker from matching the entire assignee list +} + +segment mySegment2() -> (r: Int, s: String) { + // $TEST$ serialization Int + // $TEST$ serialization $Unknown + »yield r«, »yield s« = 1; +} + +segment mySegment3() -> (r: Int, s: String) { + // $TEST$ serialization Int + // $TEST$ serialization String + »yield r«, _, »yield s« = f(); +} diff --git a/tests/resources/typing/declarations/annotations/main.sdstest b/tests/resources/typing/declarations/annotations/main.sdstest new file mode 100644 index 000000000..2c3c7a752 --- /dev/null +++ b/tests/resources/typing/declarations/annotations/main.sdstest @@ -0,0 +1,10 @@ +package tests.typing.declarations.annotations + +// $TEST$ serialization () -> () +annotation »myAnnotation1« + +// $TEST$ serialization (p1: Int, p2: String) -> () +annotation »myAnnotation3«(p1: Int, p2: String) + +// $TEST$ serialization (p1: $Unknown) -> () +annotation »myAnnotation5«(p1) diff --git a/tests/resources/typing/declarations/attributes/main.sdstest b/tests/resources/typing/declarations/attributes/main.sdstest new file mode 100644 index 000000000..48c8c0a1f --- /dev/null +++ b/tests/resources/typing/declarations/attributes/main.sdstest @@ -0,0 +1,17 @@ +package tests.typing.declarations.attributes + +class C { + // $TEST$ serialization $Unknown + attr »a« + + // $TEST$ equivalence_class instanceAttribute + // $TEST$ equivalence_class instanceAttribute + attr »b«: »Int« + + // $TEST$ serialization $Unknown + static attr »c« + + // $TEST$ equivalence_class staticAttribute + // $TEST$ equivalence_class staticAttribute + static attr »d«: »Int« +} diff --git a/tests/resources/typing/declarations/classes/main.sdstest b/tests/resources/typing/declarations/classes/main.sdstest new file mode 100644 index 000000000..17c8bbeb3 --- /dev/null +++ b/tests/resources/typing/declarations/classes/main.sdstest @@ -0,0 +1,7 @@ +package tests.typing.declarations.classes + +// $TEST$ serialization MyClass1 +class »MyClass1« + +// $TEST$ serialization MyClass2 +class »MyClass2« diff --git a/tests/resources/typing/declarations/enum variants/main.sdstest b/tests/resources/typing/declarations/enum variants/main.sdstest new file mode 100644 index 000000000..a3dbfa674 --- /dev/null +++ b/tests/resources/typing/declarations/enum variants/main.sdstest @@ -0,0 +1,9 @@ +package tests.typing.declarations.enumVariants + +enum MyEnum { + // $TEST$ serialization MyEnumVariant1 + »MyEnumVariant1« + + // $TEST$ serialization MyEnumVariant2 + »MyEnumVariant2« +} diff --git a/tests/resources/typing/declarations/enums/main.sdstest b/tests/resources/typing/declarations/enums/main.sdstest new file mode 100644 index 000000000..e1297fb1d --- /dev/null +++ b/tests/resources/typing/declarations/enums/main.sdstest @@ -0,0 +1,7 @@ +package tests.typing.declarations.enums + +// $TEST$ serialization MyEnum1 +enum »MyEnum1« + +// $TEST$ serialization MyEnum2 +enum »MyEnum2« diff --git a/tests/resources/typing/declarations/functions/main.sdstest b/tests/resources/typing/declarations/functions/main.sdstest new file mode 100644 index 000000000..7b4c02a25 --- /dev/null +++ b/tests/resources/typing/declarations/functions/main.sdstest @@ -0,0 +1,16 @@ +package tests.typing.declarations.functions + +// $TEST$ serialization () -> () +fun »myFunction1«() + +// $TEST$ serialization () -> (r1: Int, r2: String) +fun »myFunction2«() -> (r1: Int, r2: String) + +// $TEST$ serialization (p1: Int, p2: String) -> () +fun »myFunction3«(p1: Int, p2: String) + +// $TEST$ serialization (p1: Int, p2: String) -> (r1: Int, r2: String) +fun »myFunction4«(p1: Int, p2: String) -> (r1: Int, r2: String) + +// $TEST$ serialization (p1: $Unknown) -> (r1: $Unknown) +fun »myFunction5«(p1) -> (r1) diff --git a/tests/resources/typing/declarations/parameters/of annotations/main.sdstest b/tests/resources/typing/declarations/parameters/of annotations/main.sdstest new file mode 100644 index 000000000..ebf0930ae --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of annotations/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.declarations.parameters.ofAnnotations + +// $TEST$ equivalence_class parameterType +// $TEST$ equivalence_class parameterType +annotation MyAnnotation1(»p«: »Int«) + +// $TEST$ serialization vararg +annotation MyAnnotation2(vararg »p«: String) + +// $TEST$ serialization $Unknown +annotation MyAnnotation3(»p«) diff --git a/tests/resources/typing/declarations/parameters/of block lambdas/skip-that are passed as argument.sdstest b/tests/resources/typing/declarations/parameters/of block lambdas/skip-that are passed as argument.sdstest new file mode 100644 index 000000000..9e165397c --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of block lambdas/skip-that are passed as argument.sdstest @@ -0,0 +1,26 @@ +package tests.typing.declarations.parameters.ofBlockLambdas + +// $TEST$ equivalence_class parameterType1 +fun higherOrderFunction1(param: (a: »String«) -> ()) +fun higherOrderFunction2(param: () -> ()) +fun normalFunction(param: Int) + +segment mySegment() { + // $TEST$ equivalence_class parameterType1 + higherOrderFunction1((»p«) {}); + + // $TEST$ equivalence_class parameterType1 + higherOrderFunction1(param = (»p«) {}); + + // $TEST$ serialization $Unknown + higherOrderFunction2((»p«) {}); + + // $TEST$ serialization $Unknown + higherOrderFunction2(param = (»p«) {}); + + // $TEST$ serialization $Unknown + normalFunction((»p«) {}); + + // $TEST$ serialization $Unknown + normalFunction(param = (»p«) {}); +} diff --git a/tests/resources/typing/declarations/parameters/of block lambdas/that are isolated.sdstest b/tests/resources/typing/declarations/parameters/of block lambdas/that are isolated.sdstest new file mode 100644 index 000000000..0fa3e694c --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of block lambdas/that are isolated.sdstest @@ -0,0 +1,6 @@ +package tests.typing.declarations.parameters.ofBlockLambdas + +segment mySegment() { + // $TEST$ serialization $Unknown + (»p«) {}; +} diff --git a/tests/resources/typing/declarations/parameters/of block lambdas/that are yielded.sdstest b/tests/resources/typing/declarations/parameters/of block lambdas/that are yielded.sdstest new file mode 100644 index 000000000..74818c8d5 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of block lambdas/that are yielded.sdstest @@ -0,0 +1,17 @@ +package tests.typing.declarations.parameters.ofBlockLambdas + +segment mySegment() -> ( + // $TEST$ equivalence_class parameterType2 + r: (p: »String«) -> (), + s: () -> (), + t: Int, +) { + // $TEST$ equivalence_class parameterType2 + yield r = (»p«) {}; + + // $TEST$ serialization $Unknown + yield s = (»p«) {}; + + // $TEST$ serialization $Unknown + yield t = (»p«) {}; +} diff --git a/tests/resources/typing/declarations/parameters/of block lambdas/with manifest types.sdstest b/tests/resources/typing/declarations/parameters/of block lambdas/with manifest types.sdstest new file mode 100644 index 000000000..3e481344e --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of block lambdas/with manifest types.sdstest @@ -0,0 +1,10 @@ +package tests.typing.declarations.parameters.ofBlockLambdas + +segment mySegment() { + // $TEST$ equivalence_class parameterType3 + // $TEST$ equivalence_class parameterType3 + (»p«: »Int«) {}; + + // $TEST$ serialization vararg + (vararg »p«: String) {}; +} diff --git a/tests/resources/typing/declarations/parameters/of callable types/main.sdstest b/tests/resources/typing/declarations/parameters/of callable types/main.sdstest new file mode 100644 index 000000000..716f12cb9 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of callable types/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.declarations.parameters.ofCallableTypes + +// $TEST$ equivalence_class parameterType +// $TEST$ equivalence_class parameterType +annotation MyAnnotation1(f: (»p«: »Int«) -> ()) + +// $TEST$ serialization vararg +annotation MyAnnotation2(f: (vararg »p«: String) -> ()) + +// $TEST$ serialization $Unknown +annotation MyAnnotation3(f: (»p«) -> ()) diff --git a/tests/resources/typing/declarations/parameters/of classes/main.sdstest b/tests/resources/typing/declarations/parameters/of classes/main.sdstest new file mode 100644 index 000000000..1ad48613e --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of classes/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.declarations.parameters.ofClasses + +// $TEST$ equivalence_class parameterType +// $TEST$ equivalence_class parameterType +class MyClass1(»p«: »Int«) + +// $TEST$ serialization vararg +class MyClass2(vararg »p«: String) + +// $TEST$ serialization $Unknown +class MyClass3(»p«) diff --git a/tests/resources/typing/declarations/parameters/of enum variants/main.sdstest b/tests/resources/typing/declarations/parameters/of enum variants/main.sdstest new file mode 100644 index 000000000..208ce02a5 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of enum variants/main.sdstest @@ -0,0 +1,13 @@ +package tests.typing.declarations.parameters.ofEnumVariants + +enum MyEnum { + // $TEST$ equivalence_class parameterType + // $TEST$ equivalence_class parameterType + MyEnumVariant1(»p«: »Int«) + + // $TEST$ serialization vararg + MyEnumVariant2(vararg »p«: String) + + // $TEST$ serialization $Unknown + MyEnumVariant3(»p«) +} diff --git a/tests/resources/typing/declarations/parameters/of expression lambdas/skip-that are passed as argument.sdstest b/tests/resources/typing/declarations/parameters/of expression lambdas/skip-that are passed as argument.sdstest new file mode 100644 index 000000000..ecfc233fe --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of expression lambdas/skip-that are passed as argument.sdstest @@ -0,0 +1,26 @@ +package tests.typing.declarations.parameters.ofExpressionLambdas + +// $TEST$ equivalence_class parameterType1 +fun higherOrderFunction1(param: (a: »String«) -> r: String) +fun higherOrderFunction2(param: () -> r: String) +fun normalFunction(param: Int) + +segment mySegment() { + // $TEST$ equivalence_class parameterType1 + higherOrderFunction1((»p«) -> ""); + + // $TEST$ equivalence_class parameterType1 + higherOrderFunction1(param = (»p«) -> ""); + + // $TEST$ serialization $Unknown + higherOrderFunction2((»p«) -> ""); + + // $TEST$ serialization $Unknown + higherOrderFunction2(param = (»p«) -> ""); + + // $TEST$ serialization $Unknown + normalFunction((»p«) -> ""); + + // $TEST$ serialization $Unknown + normalFunction(param = (»p«) -> ""); +} diff --git a/tests/resources/typing/declarations/parameters/of expression lambdas/that are isolated.sdstest b/tests/resources/typing/declarations/parameters/of expression lambdas/that are isolated.sdstest new file mode 100644 index 000000000..a4460a231 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of expression lambdas/that are isolated.sdstest @@ -0,0 +1,6 @@ +package tests.typing.declarations.parameters.ofExpressionLambdas + +segment mySegment() { + // $TEST$ serialization $Unknown + (»p«) -> 1; +} diff --git a/tests/resources/typing/declarations/parameters/of expression lambdas/that are yielded.sdstest b/tests/resources/typing/declarations/parameters/of expression lambdas/that are yielded.sdstest new file mode 100644 index 000000000..b4c92b7b4 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of expression lambdas/that are yielded.sdstest @@ -0,0 +1,17 @@ +package tests.typing.declarations.parameters.ofExpressionLambdas + +segment mySegment() -> ( + // $TEST$ equivalence_class parameterType2 + r: (p: »String«) -> r: String, + s: () -> r: String, + t: Int, +) { + // $TEST$ equivalence_class parameterType2 + yield r = (»p«) -> true; + + // $TEST$ serialization $Unknown + yield s = (»p«) -> true; + + // $TEST$ serialization $Unknown + yield t = (»p«) -> true; +} diff --git a/tests/resources/typing/declarations/parameters/of expression lambdas/with manifest types.sdstest b/tests/resources/typing/declarations/parameters/of expression lambdas/with manifest types.sdstest new file mode 100644 index 000000000..0e9c1fad3 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of expression lambdas/with manifest types.sdstest @@ -0,0 +1,10 @@ +package tests.typing.declarations.parameters.ofExpressionLambdas + +segment mySegment() { + // $TEST$ equivalence_class parameterType3 + // $TEST$ equivalence_class parameterType3 + (»p«: »Int«) -> 1; + + // $TEST$ serialization vararg + (vararg »p«: String) -> 1; +} diff --git a/tests/resources/typing/declarations/parameters/of functions/main.sdstest b/tests/resources/typing/declarations/parameters/of functions/main.sdstest new file mode 100644 index 000000000..2374778db --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of functions/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.declarations.parameters.ofFunctions + +// $TEST$ equivalence_class parameterType +// $TEST$ equivalence_class parameterType +fun myFunction1(»p«: »Int«) + +// $TEST$ serialization vararg +fun myFunction2(vararg »p«: String) + +// $TEST$ serialization $Unknown +fun myFunction3(»p«) diff --git a/tests/resources/typing/declarations/parameters/of segments/main.sdstest b/tests/resources/typing/declarations/parameters/of segments/main.sdstest new file mode 100644 index 000000000..25e9217d6 --- /dev/null +++ b/tests/resources/typing/declarations/parameters/of segments/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.declarations.parameters.ofSegments + +// $TEST$ equivalence_class parameterType +// $TEST$ equivalence_class parameterType +segment mySegment1(»p«: »Int«) {} + +// $TEST$ serialization vararg +segment mySegment2(vararg »p«: String) {} + +// $TEST$ serialization $Unknown +segment mySegment3(»p«) {} diff --git a/tests/resources/typing/declarations/pipelines/main.sdstest b/tests/resources/typing/declarations/pipelines/main.sdstest new file mode 100644 index 000000000..b971899a6 --- /dev/null +++ b/tests/resources/typing/declarations/pipelines/main.sdstest @@ -0,0 +1,4 @@ +package tests.typing.declarations.pipelines + +// $TEST$ serialization $Unknown +pipeline »myPipeline« {} diff --git a/tests/resources/typing/declarations/results/main.sdstest b/tests/resources/typing/declarations/results/main.sdstest new file mode 100644 index 000000000..fe03bfa52 --- /dev/null +++ b/tests/resources/typing/declarations/results/main.sdstest @@ -0,0 +1,14 @@ +package tests.typing.declarations.results + +// $TEST$ equivalence_class functionResult +// $TEST$ equivalence_class functionResult +fun myFun() -> (»r«: »String«) + +segment mySegment( + // $TEST$ equivalence_class callableTypeResult + // $TEST$ equivalence_class callableTypeResult + p: () -> (»r«: »String«) + +// $TEST$ equivalence_class segmentResult +// $TEST$ equivalence_class segmentResult +) -> (»r«: »String«) {} diff --git a/tests/resources/typing/declarations/segments/main.sdstest b/tests/resources/typing/declarations/segments/main.sdstest new file mode 100644 index 000000000..7c1d4b10b --- /dev/null +++ b/tests/resources/typing/declarations/segments/main.sdstest @@ -0,0 +1,16 @@ +package tests.typing.declarations.segments + +// $TEST$ serialization () -> () +segment »mySegment1«() {} + +// $TEST$ serialization () -> (r1: Int, r2: String) +segment »mySegment2«() -> (r1: Int, r2: String) {} + +// $TEST$ serialization (p1: Int, p2: String) -> () +segment »mySegment3«(p1: Int, p2: String) {} + +// $TEST$ serialization (p1: Int, p2: String) -> (r1: Int, r2: String) +segment »mySegment4«(p1: Int, p2: String) -> (r1: Int, r2: String) {} + +// $TEST$ serialization (p1: $Unknown) -> (r1: $Unknown) +segment »mySegment5«(p1) -> (r1) {} diff --git a/tests/resources/typing/expressions/arguments/main.sdstest b/tests/resources/typing/expressions/arguments/main.sdstest new file mode 100644 index 000000000..8efa9e45f --- /dev/null +++ b/tests/resources/typing/expressions/arguments/main.sdstest @@ -0,0 +1,40 @@ +package tests.typing.expressions.arguments + +fun f(p: Any?) + +pipeline myPipeline { + // $TEST$ equivalence_class boolean + // $TEST$ equivalence_class boolean + // $TEST$ equivalence_class boolean + »true«; + f(»true«); + f(»p = true«); + + // $TEST$ equivalence_class float + // $TEST$ equivalence_class float + // $TEST$ equivalence_class float + »1.0«; + f(»1.0«); + f(»p = 1.0«); + + // $TEST$ equivalence_class int + // $TEST$ equivalence_class int + // $TEST$ equivalence_class int + »1«; + f(»1«); + f(»p = 1«); + + // $TEST$ equivalence_class null + // $TEST$ equivalence_class null + // $TEST$ equivalence_class null + »null«; + f(»null«); + f(»p = null«); + + // $TEST$ equivalence_class string + // $TEST$ equivalence_class string + // $TEST$ equivalence_class string + »""«; + f(»""«); + f(»p = ""«); +} diff --git a/tests/resources/typing/expressions/block lambdas/skip-that are passed as argument.sdstest b/tests/resources/typing/expressions/block lambdas/skip-that are passed as argument.sdstest new file mode 100644 index 000000000..7c3f9096d --- /dev/null +++ b/tests/resources/typing/expressions/block lambdas/skip-that are passed as argument.sdstest @@ -0,0 +1,40 @@ +package tests.typing.expressions.blockLambdas + +fun higherOrderFunction1(param: (p: String) -> (r: Int, s: String)) +fun higherOrderFunction2(param: () -> ()) +fun normalFunction(param: Int) + +segment mySegment() { + // $TEST$ serialization (p: String) -> (r: Int, s: String) + higherOrderFunction1(»(p) { + yield r = 1; + yield s = ""; + }«); + + // $TEST$ serialization (p: String) -> (r: Int, s: $Unknown) + higherOrderFunction1(param = »(p) { + yield r, yield s = 1; + }«); + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: String) + higherOrderFunction2(»(p) { + yield r = 1; + yield s = ""; + }«); + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: $Unknown) + higherOrderFunction2(param = »(p) { + yield r, yield s = 1; + }«); + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: String) + normalFunction(»(p) { + yield r = 1; + yield s = ""; + }«); + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: $Unknown) + normalFunction(param = »(p) { + yield r, yield s = 1; + }«); +} diff --git a/tests/resources/typing/expressions/block lambdas/that are isolated.sdstest b/tests/resources/typing/expressions/block lambdas/that are isolated.sdstest new file mode 100644 index 000000000..79085cb78 --- /dev/null +++ b/tests/resources/typing/expressions/block lambdas/that are isolated.sdstest @@ -0,0 +1,13 @@ +package tests.typing.expressions.blockLambdas + +segment mySegment() { + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: $Unknown) + »(p) { + yield r, yield s = 1; + }«; + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: $Unknown) + val f = »(p) { + yield r, yield s = 1; + }«; +} diff --git a/tests/resources/typing/expressions/block lambdas/that are yielded.sdstest b/tests/resources/typing/expressions/block lambdas/that are yielded.sdstest new file mode 100644 index 000000000..f331c8afc --- /dev/null +++ b/tests/resources/typing/expressions/block lambdas/that are yielded.sdstest @@ -0,0 +1,24 @@ +package tests.typing.expressions.blockLambdas + +segment mySegment() -> ( + r: (p: String) -> (r: Int, s: String), + s: () -> (), + t: Int, +) { + // $TEST$ serialization (p: String) -> (r: Int, s: String) + yield r = »(p) { + yield r = 1; + yield s = ""; + }«; + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: String) + yield s = »(p) { + yield r = 1; + yield s = ""; + }«; + + // $TEST$ serialization (p: $Unknown) -> (r: Int, s: $Unknown) + yield t = »(p) { + yield r, yield s = 1; + }«; +} diff --git a/tests/resources/typing/expressions/block lambdas/with manifest types.sdstest b/tests/resources/typing/expressions/block lambdas/with manifest types.sdstest new file mode 100644 index 000000000..09fdbed82 --- /dev/null +++ b/tests/resources/typing/expressions/block lambdas/with manifest types.sdstest @@ -0,0 +1,14 @@ +package tests.typing.expressions.blockLambdas + +segment mySegment() { + // $TEST$ serialization (p: Int) -> (r: Int, s: String) + »(p: Int) { + yield r = 1; + yield s = ""; + }«; + + // $TEST$ serialization (p: vararg) -> (r: Int, s: $Unknown) + »(vararg p: String) { + yield r, yield s = 1; + }«; +} diff --git a/tests/resources/typing/expressions/calls/of annotations/main.sdstest b/tests/resources/typing/expressions/calls/of annotations/main.sdstest new file mode 100644 index 000000000..a5f06c078 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of annotations/main.sdstest @@ -0,0 +1,8 @@ +package tests.typing.expressions.calls.ofAnnotations + +annotation MyAnnotation + +pipeline myPipeline { + // $TEST$ serialization $Unknown + »MyAnnotation()«; +} diff --git a/tests/resources/typing/expressions/calls/of block lambdas/main.sdstest b/tests/resources/typing/expressions/calls/of block lambdas/main.sdstest new file mode 100644 index 000000000..c6c4b418c --- /dev/null +++ b/tests/resources/typing/expressions/calls/of block lambdas/main.sdstest @@ -0,0 +1,14 @@ +package tests.typing.expressions.calls.ofBlockLambdas + +pipeline myPipeline { + // $TEST$ serialization (r: String) + »(() { + yield r = ""; + })()«; + + // $TEST$ serialization (r: String, s: Int) + »(() { + yield r = ""; + yield s = 1; + })()«; +} diff --git a/tests/resources/typing/expressions/calls/of callable types/main.sdstest b/tests/resources/typing/expressions/calls/of callable types/main.sdstest new file mode 100644 index 000000000..032cbec00 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of callable types/main.sdstest @@ -0,0 +1,12 @@ +package tests.typing.expressions.calls.ofCallableTypes + +segment mySegment( + p1: () -> r: String, + p2: () -> (r: String, s: Int) +) { + // $TEST$ serialization (r: String) + »p1()«; + + // $TEST$ serialization (r: String, s: Int) + »p2()«; +} diff --git a/tests/resources/typing/expressions/calls/of classes/main.sdstest b/tests/resources/typing/expressions/calls/of classes/main.sdstest new file mode 100644 index 000000000..c38dbc76d --- /dev/null +++ b/tests/resources/typing/expressions/calls/of classes/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.expressions.calls.ofClasses + +class C() + +pipeline myPipeline { + // $TEST$ serialization C + »C()«; + + // $TEST$ serialization $Unknown + »C()()«; +} diff --git a/tests/resources/typing/expressions/calls/of enum variants/main.sdstest b/tests/resources/typing/expressions/calls/of enum variants/main.sdstest new file mode 100644 index 000000000..860194613 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of enum variants/main.sdstest @@ -0,0 +1,13 @@ +package tests.typing.expressions.calls.ofEnumVariants + +enum E { + V +} + +pipeline myPipeline { + // $TEST$ serialization V + »E.V()«; + + // $TEST$ serialization $Unknown + »E.V()()«; +} diff --git a/tests/resources/typing/expressions/calls/of expression lambdas/main.sdstest b/tests/resources/typing/expressions/calls/of expression lambdas/main.sdstest new file mode 100644 index 000000000..7866aa463 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of expression lambdas/main.sdstest @@ -0,0 +1,6 @@ +package tests.typing.expressions.calls.ofExpressionLambdas + +pipeline myPipeline { + // $TEST$ serialization (result: Int) + »(() -> 1)()«; +} diff --git a/tests/resources/typing/expressions/calls/of functions/main.sdstest b/tests/resources/typing/expressions/calls/of functions/main.sdstest new file mode 100644 index 000000000..e044b7e0a --- /dev/null +++ b/tests/resources/typing/expressions/calls/of functions/main.sdstest @@ -0,0 +1,12 @@ +package tests.typing.expressions.calls.ofFunctions + +fun f1() -> r: String +fun f2() -> (r: String, s: Int) + +pipeline myPipeline { + // $TEST$ serialization (r: String) + »f1()«; + + // $TEST$ serialization (r: String, s: Int) + »f2()«; +} diff --git a/tests/resources/typing/expressions/calls/of non-callable/main.sdstest b/tests/resources/typing/expressions/calls/of non-callable/main.sdstest new file mode 100644 index 000000000..373cefb48 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of non-callable/main.sdstest @@ -0,0 +1,8 @@ +package tests.typing.expressions.calls.ofNonCallables + +enum MyEnum + +pipeline myPipeline { + // $TEST$ serialization $Unknown + »MyEnum()«; +} diff --git a/tests/resources/typing/expressions/calls/of segments/main.sdstest b/tests/resources/typing/expressions/calls/of segments/main.sdstest new file mode 100644 index 000000000..99f805821 --- /dev/null +++ b/tests/resources/typing/expressions/calls/of segments/main.sdstest @@ -0,0 +1,17 @@ +package tests.typing.expressions.calls.ofSegments + +segment s1() -> r: String{ + yield r = ""; +} +segment s2() -> (r: String, s: Int) { + yield r = ""; + yield s = 1; +} + +pipeline myPipeline { + // $TEST$ serialization (r: String) + »s1()«; + + // $TEST$ serialization (r: String, s: Int) + »s2()«; +} diff --git a/tests/resources/typing/expressions/calls/unresolved/main.sdstest b/tests/resources/typing/expressions/calls/unresolved/main.sdstest new file mode 100644 index 000000000..a88fb7f02 --- /dev/null +++ b/tests/resources/typing/expressions/calls/unresolved/main.sdstest @@ -0,0 +1,6 @@ +package tests.typing.expressions.calls.ofUnresolved + +pipeline myPipeline { + // $TEST$ serialization $Unknown + »unresolved()«; +} diff --git a/tests/resources/typing/expressions/expression lambdas/skip-that are passed as argument.sdstest b/tests/resources/typing/expressions/expression lambdas/skip-that are passed as argument.sdstest new file mode 100644 index 000000000..462e259d9 --- /dev/null +++ b/tests/resources/typing/expressions/expression lambdas/skip-that are passed as argument.sdstest @@ -0,0 +1,25 @@ +package tests.typing.expressions.expressionLambdas + +fun higherOrderFunction1(param: (p: String) -> (r: Int)) +fun higherOrderFunction2(param: () -> ()) +fun normalFunction(param: Int) + +segment mySegment() { + // $TEST$ serialization (p: String) -> (result: Int) + higherOrderFunction1(»(p) -> 1«); + + // $TEST$ serialization (p: String) -> (result: Int) + higherOrderFunction1(param = »(p) -> 1«); + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + higherOrderFunction2(»(p) -> 1«); + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + higherOrderFunction2(param = »(p) -> 1«); + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + normalFunction(»(p) -> 1«); + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + normalFunction(param = »(p) -> 1«); +} diff --git a/tests/resources/typing/expressions/expression lambdas/that are isolated.sdstest b/tests/resources/typing/expressions/expression lambdas/that are isolated.sdstest new file mode 100644 index 000000000..cb801ba2b --- /dev/null +++ b/tests/resources/typing/expressions/expression lambdas/that are isolated.sdstest @@ -0,0 +1,9 @@ +package tests.typing.expressions.expressionLambdas + +segment mySegment() { + // $TEST$ serialization (p: $Unknown) -> (result: Int) + »(p) -> 1«; + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + val f = »(p) -> 1«; +} diff --git a/tests/resources/typing/expressions/expression lambdas/that are yielded.sdstest b/tests/resources/typing/expressions/expression lambdas/that are yielded.sdstest new file mode 100644 index 000000000..d21d5f414 --- /dev/null +++ b/tests/resources/typing/expressions/expression lambdas/that are yielded.sdstest @@ -0,0 +1,16 @@ +package tests.typing.expressions.expressionLambdas + +segment mySegment() -> ( + r: (p: String) -> (), + s: () -> (), + t: Int, +) { + // $TEST$ serialization (p: String) -> (result: Int) + yield r = »(p) -> 1«; + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + yield s = »(p) -> 1«; + + // $TEST$ serialization (p: $Unknown) -> (result: Int) + yield t = »(p) -> 1«; +} diff --git a/tests/resources/typing/expressions/expression lambdas/with manifest types.sdstest b/tests/resources/typing/expressions/expression lambdas/with manifest types.sdstest new file mode 100644 index 000000000..64f8355a7 --- /dev/null +++ b/tests/resources/typing/expressions/expression lambdas/with manifest types.sdstest @@ -0,0 +1,9 @@ +package tests.typing.expressions.expressionLambdas + +segment mySegment() { + // $TEST$ serialization (p: Int) -> (result: Int) + »(p: Int) -> 1«; + + // $TEST$ serialization (p: vararg) -> (result: Int) + »(vararg p: String) -> 1«; +} diff --git a/tests/resources/typing/expressions/indexed accesses/main.sdstest b/tests/resources/typing/expressions/indexed accesses/main.sdstest new file mode 100644 index 000000000..a4a495889 --- /dev/null +++ b/tests/resources/typing/expressions/indexed accesses/main.sdstest @@ -0,0 +1,17 @@ +package tests.typing.expressions.indexedAccesses + +// $TEST$ equivalence_class elementType +segment mySegment1(vararg params: »Int«) { + // $TEST$ equivalence_class elementType + »params[0]«; +} + +segment mySegment2(params: String) { + // $TEST$ serialization $Unknown + »params[0]«; +} + +segment mySegment3() { + // $TEST$ serialization $Unknown + »unresolved[0]«; +} diff --git a/tests/resources/typing/expressions/member accesses/to enum variants/main.sdstest b/tests/resources/typing/expressions/member accesses/to enum variants/main.sdstest new file mode 100644 index 000000000..160c880f0 --- /dev/null +++ b/tests/resources/typing/expressions/member accesses/to enum variants/main.sdstest @@ -0,0 +1,10 @@ +package tests.typing.expressions.references.toEnumVariants + +enum MyEnum { + MyEnumVariant +} + +pipeline myPipeline { + // $TEST$ serialization $type + »MyEnum.MyEnumVariant«; +} diff --git a/tests/resources/typing/expressions/member accesses/to nested classes/main.sdstest b/tests/resources/typing/expressions/member accesses/to nested classes/main.sdstest new file mode 100644 index 000000000..69ea9fcfa --- /dev/null +++ b/tests/resources/typing/expressions/member accesses/to nested classes/main.sdstest @@ -0,0 +1,10 @@ +package tests.typing.expressions.memberAccesses.toNestedClasses + +class MyClass { + class MyNestedClass +} + +pipeline myPipeline { + // $TEST$ serialization $type + »MyClass.MyNestedClass«; +} diff --git a/tests/resources/typing/expressions/member accesses/to nested enums/main.sdstest b/tests/resources/typing/expressions/member accesses/to nested enums/main.sdstest new file mode 100644 index 000000000..9c2ed18c8 --- /dev/null +++ b/tests/resources/typing/expressions/member accesses/to nested enums/main.sdstest @@ -0,0 +1,10 @@ +package tests.typing.expressions.memberAccesses.toNestedEnums + +class MyClass { + enum MyNestedEnum +} + +pipeline myPipeline { + // $TEST$ serialization $type + »MyClass.MyNestedEnum«; +} diff --git a/tests/resources/typing/expressions/member accesses/to other/main.sdstest b/tests/resources/typing/expressions/member accesses/to other/main.sdstest new file mode 100644 index 000000000..32058b9f4 --- /dev/null +++ b/tests/resources/typing/expressions/member accesses/to other/main.sdstest @@ -0,0 +1,21 @@ +package tests.typing.expressions.memberAccesses.toOther + +class C { + // $TEST$ equivalence_class nonNullableMember + static attr »nonNullableMember«: Int + + // $TEST$ equivalence_class nullableMember + static attr »nullableMember«: Any? +} + +pipeline myPipeline { + // $TEST$ equivalence_class nonNullableMember + »C.nonNullableMember«; + // $TEST$ equivalence_class nullableMember + »C.nullableMember«; + + // $TEST$ serialization Int? + »C?.nonNullableMember«; + // $TEST$ serialization Any? + »C?.nullableMember«; +} diff --git a/tests/resources/typing/expressions/member accesses/unresolved/main.sdstest b/tests/resources/typing/expressions/member accesses/unresolved/main.sdstest new file mode 100644 index 000000000..60aa0b8f2 --- /dev/null +++ b/tests/resources/typing/expressions/member accesses/unresolved/main.sdstest @@ -0,0 +1,11 @@ +package tests.typing.expressions.memberAccesses.unresolved + +class C + +pipeline myPipeline { + // $TEST$ serialization $Unknown + »C.unresolved«; + + // $TEST$ serialization $Unknown + »C?.unresolved«; +} diff --git a/tests/resources/typing/expressions/operations/arithmetic/main.sdstest b/tests/resources/typing/expressions/operations/arithmetic/main.sdstest new file mode 100644 index 000000000..99d6c7b8e --- /dev/null +++ b/tests/resources/typing/expressions/operations/arithmetic/main.sdstest @@ -0,0 +1,36 @@ +package tests.typing.operations.arithmetic + +pipeline myPipeline { + // $TEST$ serialization Int + val additionIntInt = »1 + 1«; + // $TEST$ serialization Int + val subtractionIntInt = »1 - 1«; + // $TEST$ serialization Int + val multiplicationIntInt = »1 * 1«; + // $TEST$ serialization Int + val divisionIntInt = »1 / 1«; + // $TEST$ serialization Int + val negationInt = »-1«; + + // $TEST$ serialization Float + val additionIntFloat = »1 + 1.0«; + // $TEST$ serialization Float + val subtractionIntFloat = »1 - 1.0«; + // $TEST$ serialization Float + val multiplicationIntFloat = »1 * 1.0«; + // $TEST$ serialization Float + val divisionIntFloat = »1 / 1.0«; + // $TEST$ serialization Float + val negationFloat = »-1.0«; + + // $TEST$ serialization Float + val additionInvalid = »true + true«; + // $TEST$ serialization Float + val subtractionInvalid = »true - true«; + // $TEST$ serialization Float + val multiplicationInvalid = »true * true«; + // $TEST$ serialization Float + val divisionInvalid = »true / true«; + // $TEST$ serialization Float + val negationInvalid = »-true«; +} diff --git a/tests/resources/typing/expressions/operations/comparison/main.sdstest b/tests/resources/typing/expressions/operations/comparison/main.sdstest new file mode 100644 index 000000000..50186b978 --- /dev/null +++ b/tests/resources/typing/expressions/operations/comparison/main.sdstest @@ -0,0 +1,21 @@ +package tests.typing.operations.comparison + +pipeline myPipeline { + // $TEST$ serialization Boolean + val lessThan = »1 < 1«; + // $TEST$ serialization Boolean + val lessThanOrEquals = »1 <= 1«; + // $TEST$ serialization Boolean + val greaterThanOrEquals = »1 >= 1«; + // $TEST$ serialization Boolean + val greaterThan = »1 > 1«; + + // $TEST$ serialization Boolean + val lessThanInvalid = »true < true«; + // $TEST$ serialization Boolean + val lessThanOrEqualsInvalid = »true <= true«; + // $TEST$ serialization Boolean + val greaterThanOrEqualsInvalid = »true >= true«; + // $TEST$ serialization Boolean + val greaterThanInvalid = »true > true«; +} diff --git a/tests/resources/typing/expressions/operations/elvis/non nullable left operand.sdstest b/tests/resources/typing/expressions/operations/elvis/non nullable left operand.sdstest new file mode 100644 index 000000000..a7d726e3c --- /dev/null +++ b/tests/resources/typing/expressions/operations/elvis/non nullable left operand.sdstest @@ -0,0 +1,18 @@ +package tests.typing.operations.elvis + +fun intOrNull() -> a: Int? + +pipeline elvisWithNonNullableLeftOperand { + // $TEST$ equivalence_class leftOperand + »1«; + // $TEST$ equivalence_class leftOperand + »1 ?: intOrNull()«; + // $TEST$ equivalence_class leftOperand + »1 ?: 1«; + // $TEST$ equivalence_class leftOperand + »1 ?: 1.0«; + // $TEST$ equivalence_class leftOperand + »1 ?: ""«; + // $TEST$ equivalence_class leftOperand + »1 ?: null«; +} diff --git a/tests/resources/typing/expressions/operations/elvis/skip-nullable left operand.sdstest b/tests/resources/typing/expressions/operations/elvis/skip-nullable left operand.sdstest new file mode 100644 index 000000000..16b711ee4 --- /dev/null +++ b/tests/resources/typing/expressions/operations/elvis/skip-nullable left operand.sdstest @@ -0,0 +1,19 @@ +package tests.typing.operations.elvis + +fun intOrNull() -> a: Int? +fun stringOrNull() -> s: String? + +pipeline elvisWithNullableLeftOperand { + // $TEST$ serialization Int? + »intOrNull() ?: intOrNull()«; + // $TEST$ serialization Int? + »intOrNull() ?: null«; + // $TEST$ serialization Int + »intOrNull() ?: 1«; + // $TEST$ serialization Number + »intOrNull() ?: 1.0«; + // $TEST$ serialization Any + »intOrNull() ?: ""«; + // $TEST$ serialization Any? + »intOrNull() ?: stringOrNull()«; +} diff --git a/tests/resources/typing/expressions/operations/equality/main.sdstest b/tests/resources/typing/expressions/operations/equality/main.sdstest new file mode 100644 index 000000000..5635da94f --- /dev/null +++ b/tests/resources/typing/expressions/operations/equality/main.sdstest @@ -0,0 +1,13 @@ +package tests.typing.operations.equality + +pipeline myPipeline { + // $TEST$ serialization Boolean + val equals = (»1 == 1«); + // $TEST$ serialization Boolean + val notEquals = (»1 != 1«); + + // $TEST$ serialization Boolean + val strictlyEquals = (»1 === 1«); + // $TEST$ serialization Boolean + val notStrictlyEquals = (»1 !== 1«); +} diff --git a/tests/resources/typing/expressions/operations/logical/main.sdstest b/tests/resources/typing/expressions/operations/logical/main.sdstest new file mode 100644 index 000000000..146f7e0c9 --- /dev/null +++ b/tests/resources/typing/expressions/operations/logical/main.sdstest @@ -0,0 +1,17 @@ +package tests.typing.operations.logical + +pipeline myPipeline { + // $TEST$ serialization Boolean + val conjunction = »true and true«; + // $TEST$ serialization Boolean + val disjunction = »true or true«; + // $TEST$ serialization Boolean + val negation = »not true«; + + // $TEST$ serialization Boolean + val conjunctionInvalid = »1 and 1«; + // $TEST$ serialization Boolean + val disjunctionInvalid = »1.0 or 1.0«; + // $TEST$ serialization Boolean + val negationInvalid = »not "true"«; +} diff --git a/tests/resources/typing/expressions/parenthesized expressions/main.sdstest b/tests/resources/typing/expressions/parenthesized expressions/main.sdstest new file mode 100644 index 000000000..7695ced74 --- /dev/null +++ b/tests/resources/typing/expressions/parenthesized expressions/main.sdstest @@ -0,0 +1,23 @@ +package tests.typing.expressions.parenthesizedExpressions + +pipeline myPipeline { + // $TEST$ equivalence_class boolean + // $TEST$ equivalence_class boolean + »(»true«)«; + + // $TEST$ equivalence_class float + // $TEST$ equivalence_class float + »(»1.0«)«; + + // $TEST$ equivalence_class int + // $TEST$ equivalence_class int + »(»1«)«; + + // $TEST$ equivalence_class null + // $TEST$ equivalence_class null + »(»null«)«; + + // $TEST$ equivalence_class string + // $TEST$ equivalence_class string + »(»""«)«; +} diff --git a/tests/resources/typing/expressions/references/to global classes/main.sdstest b/tests/resources/typing/expressions/references/to global classes/main.sdstest new file mode 100644 index 000000000..1d2be92c8 --- /dev/null +++ b/tests/resources/typing/expressions/references/to global classes/main.sdstest @@ -0,0 +1,8 @@ +package tests.typing.expressions.references.toGlobalClasses + +class MyClass + +pipeline myPipeline { + // $TEST$ serialization $type + »MyClass«; +} diff --git a/tests/resources/typing/expressions/references/to global enums/main.sdstest b/tests/resources/typing/expressions/references/to global enums/main.sdstest new file mode 100644 index 000000000..03b517568 --- /dev/null +++ b/tests/resources/typing/expressions/references/to global enums/main.sdstest @@ -0,0 +1,8 @@ +package tests.typing.expressions.references.toGlobalEnums + +enum MyEnum + +pipeline myPipeline { + // $TEST$ serialization $type + »MyEnum«; +} diff --git a/tests/resources/typing/expressions/references/to other/main.sdstest b/tests/resources/typing/expressions/references/to other/main.sdstest new file mode 100644 index 000000000..e284e171b --- /dev/null +++ b/tests/resources/typing/expressions/references/to other/main.sdstest @@ -0,0 +1,13 @@ +package tests.typing.expressions.references.toOther + +segment mySegment( + // $TEST$ equivalence_class p1 + »p1«: Int, + // $TEST$ equivalence_class p2 + »p2«: String +) { + // $TEST$ equivalence_class p1 + »p1«; + // $TEST$ equivalence_class p2 + »p2«; +} diff --git a/tests/resources/typing/expressions/references/unresolved/main.sdstest b/tests/resources/typing/expressions/references/unresolved/main.sdstest new file mode 100644 index 000000000..7d51fa351 --- /dev/null +++ b/tests/resources/typing/expressions/references/unresolved/main.sdstest @@ -0,0 +1,6 @@ +package tests.typing.expressions.references.unresolved + +pipeline myPipeline { + // $TEST$ serialization $Unknown + »unresolved«; +} diff --git a/tests/resources/typing/skip-assignees/blockLambdaResults.sdstest b/tests/resources/typing/skip-assignees/blockLambdaResults.sdstest deleted file mode 100644 index 06803536f..000000000 --- a/tests/resources/typing/skip-assignees/blockLambdaResults.sdstest +++ /dev/null @@ -1,10 +0,0 @@ -package tests.typingassignees.blockLambdaResults - -fun f(p: Any) - -pipeline myPipeline { - f(() { - yield r = 1; - yield s = ""; - }); -} diff --git a/tests/resources/typing/skip-assignees/placeholders.sdstest b/tests/resources/typing/skip-assignees/placeholders.sdstest deleted file mode 100644 index 52a255f6e..000000000 --- a/tests/resources/typing/skip-assignees/placeholders.sdstest +++ /dev/null @@ -1,8 +0,0 @@ -package tests.typingassignees.placeholders - -fun f(p: Any) - -pipeline myPipeline { - val a = 1; - val b = ""; -} diff --git a/tests/resources/typing/skip-assignees/yields.sdstest b/tests/resources/typing/skip-assignees/yields.sdstest deleted file mode 100644 index ca40b830b..000000000 --- a/tests/resources/typing/skip-assignees/yields.sdstest +++ /dev/null @@ -1,8 +0,0 @@ -package tests.typingassignees.yields - -fun f(p: Any) - -step myStep() -> (r: Int, s: String) { - yield r = 1; - yield s = ""; -} diff --git a/tests/resources/typing/skip-declarations/attributes.sdstest b/tests/resources/typing/skip-declarations/attributes.sdstest deleted file mode 100644 index ac6208b01..000000000 --- a/tests/resources/typing/skip-declarations/attributes.sdstest +++ /dev/null @@ -1,5 +0,0 @@ -package tests.typingdeclarations.attributes - -class C { - attr a: Int -} diff --git a/tests/resources/typing/skip-declarations/classes.sdstest b/tests/resources/typing/skip-declarations/classes.sdstest deleted file mode 100644 index 97d8dab9f..000000000 --- a/tests/resources/typing/skip-declarations/classes.sdstest +++ /dev/null @@ -1,3 +0,0 @@ -package tests.typingdeclarations.classes - -class C diff --git a/tests/resources/typing/skip-declarations/enumVariants.sdstest b/tests/resources/typing/skip-declarations/enumVariants.sdstest deleted file mode 100644 index 782f9c0f0..000000000 --- a/tests/resources/typing/skip-declarations/enumVariants.sdstest +++ /dev/null @@ -1,7 +0,0 @@ -package tests.typingdeclarations.enumVariants - -enum E { - V -} - -step myStep(v: E.V) {} diff --git a/tests/resources/typing/skip-declarations/enums.sdstest b/tests/resources/typing/skip-declarations/enums.sdstest deleted file mode 100644 index d8e049653..000000000 --- a/tests/resources/typing/skip-declarations/enums.sdstest +++ /dev/null @@ -1,5 +0,0 @@ -package tests.typingdeclarations.enums - -enum E - -step myStep(e: E) {} diff --git a/tests/resources/typing/skip-declarations/functions.sdstest b/tests/resources/typing/skip-declarations/functions.sdstest deleted file mode 100644 index e1440dff3..000000000 --- a/tests/resources/typing/skip-declarations/functions.sdstest +++ /dev/null @@ -1,3 +0,0 @@ -package tests.typingdeclarations.functions - -fun f(a: Int, b: String) -> (r: String, s: Int) diff --git a/tests/resources/typing/skip-declarations/parameters.sdstest b/tests/resources/typing/skip-declarations/parameters.sdstest deleted file mode 100644 index 4110f271d..000000000 --- a/tests/resources/typing/skip-declarations/parameters.sdstest +++ /dev/null @@ -1,17 +0,0 @@ -package tests.typingdeclarations.parameters - -fun f(parameter: (a: String) -> r: String) - -step myStepWithNormalParameter(a: Int, b: String) {} -step myStepWithVariadicParameter(vararg param: Int) {} - -step myStepWithLambdas() -> ( - r: (a: String) -> r: String, - s: (a: String) -> r: String -) { - f((a) -> ""); - f((b) { yield r = ""; }); - - yield r = (c) -> ""; - yield s = (d) { yield r = ""; }; -} diff --git a/tests/resources/typing/skip-declarations/results.sdstest b/tests/resources/typing/skip-declarations/results.sdstest deleted file mode 100644 index 04efa63f2..000000000 --- a/tests/resources/typing/skip-declarations/results.sdstest +++ /dev/null @@ -1,6 +0,0 @@ -package tests.typingdeclarations.results - -step myStep() -> (r: Int, s: String) { - yield r = 1; - yield s = ""; -} diff --git a/tests/resources/typing/skip-declarations/steps.sdstest b/tests/resources/typing/skip-declarations/steps.sdstest deleted file mode 100644 index 891a36fd2..000000000 --- a/tests/resources/typing/skip-declarations/steps.sdstest +++ /dev/null @@ -1,6 +0,0 @@ -package tests.typingdeclarations.steps - -step s(a: Int, b: String) -> (r: String, s: Int) { - yield r = ""; - yield s = 1; -} diff --git a/tests/resources/typing/skip-expressions/arguments.sdstest b/tests/resources/typing/skip-expressions/arguments.sdstest deleted file mode 100644 index 484674139..000000000 --- a/tests/resources/typing/skip-expressions/arguments.sdstest +++ /dev/null @@ -1,8 +0,0 @@ -package tests.typingexpressions.parenthesizedExpressions - -fun f(x: Any?) - -pipeline myPipeline { - f(1); - f(x = ""); -} diff --git a/tests/resources/typing/skip-expressions/blockLambdas.sdstest b/tests/resources/typing/skip-expressions/blockLambdas.sdstest deleted file mode 100644 index 0b48112d5..000000000 --- a/tests/resources/typing/skip-expressions/blockLambdas.sdstest +++ /dev/null @@ -1,49 +0,0 @@ -package tests.typingexpressions.blockLambdas - -fun f( - parameter: (a: String, b: Int) -> (r: String, s: Int) -) - -step lambdasWithExplicitParameterTypes() -> ( - result: (a: String, b: Int) -> (r: String, s: Int) -) { - val myLambda = (a: Int, b: String) { - yield r = 1; - yield s = ""; - }; - yield result = (a: Int, b: String) { - yield r = 1; - yield s = ""; - }; - f( - (a: Int, b: String) { - yield r = 1; - yield s = ""; - } - ); -} - -step lambdasWithExplicitVariadicType() { - val myLambda = (a: Int, vararg b: String) { - yield r = 1; - yield s = ""; - }; -} - -step yieldedLambda() -> ( - result: (a: String, b: Int) -> (r: String, s: Int) -) { - yield result = (a, b) { - yield r = 1; - yield s = ""; - }; -} - -step argumentLambda() { - f( - (a, b) { - yield r = 1; - yield s = ""; - } - ); -} diff --git a/tests/resources/typing/skip-expressions/calls.sdstest b/tests/resources/typing/skip-expressions/calls.sdstest deleted file mode 100644 index 2e323bf9d..000000000 --- a/tests/resources/typing/skip-expressions/calls.sdstest +++ /dev/null @@ -1,37 +0,0 @@ -package tests.typingexpressions.calls - -class C() -enum E { - V(a: Int) -} -fun f1() -> r: String -fun f2() -> (r: String, s: Int) -step s1() -> r: String{ - yield r = ""; -} -step s2() -> (r: String, s: Int) { - yield r = ""; - yield s = 1; -} - -step mySteps( - p1: () -> r: String, - p2: () -> (r: String, s: Int) -) { - val classCall = C(); - val callableTypeCall1 = p1(); - val callableTypeCall2 = p2(); - val enumVariantCall = E.V(1); - val functionCall1 = f1(); - val functionCall2 = f2(); - val blockLambdaCall1 = (() { - yield r = ""; - })(); - val blockLambdaCall2 = (() { - yield r = ""; - yield s = 1; - })(); - val expressionLambdaCall = (() -> 1)(); - val stepCall1 = s1(); - val stepCall2 = s2(); -} diff --git a/tests/resources/typing/skip-expressions/expressionLambdas.sdstest b/tests/resources/typing/skip-expressions/expressionLambdas.sdstest deleted file mode 100644 index 158bddc91..000000000 --- a/tests/resources/typing/skip-expressions/expressionLambdas.sdstest +++ /dev/null @@ -1,27 +0,0 @@ -package tests.typingexpressions.expressionLambdas - -fun f( - parameter: (a: String, b: Int) -> r: String -) - -step lambdasWithExplicitParameterTypes() -> ( - result: (a: String, b: Int) -> r: String -) { - val myLambda = (a: Int, b: String) -> 1; - yield result = (a: Int, b: String) -> 1; - f((a: Int, b: String) -> 1); -} - -step lambdasWithExplicitVariadicType() { - val myLambda = (a: Int, vararg b: String) -> 1; -} - -step yieldedLambda() -> ( - result: (a: String, b: Int) -> r: String -) { - yield result = (a, b) -> 1; -} - -step argumentLambda() { - f((a, b) -> 1); -} diff --git a/tests/resources/typing/skip-expressions/indexedAccesses.sdstest b/tests/resources/typing/skip-expressions/indexedAccesses.sdstest deleted file mode 100644 index 572a7b24d..000000000 --- a/tests/resources/typing/skip-expressions/indexedAccesses.sdstest +++ /dev/null @@ -1,17 +0,0 @@ -package tests.typingexpressions.indexedAccesses - -step myStep1(vararg params: Int) { - params[0]; -} - -step myStep2(vararg params: String) { - params[0]; -} - -step myStep3(params: String) { - params[0]; -} - -step myStep4() { - unresolved[0]; -} diff --git a/tests/resources/typing/skip-expressions/memberAccesses.sdstest b/tests/resources/typing/skip-expressions/memberAccesses.sdstest deleted file mode 100644 index 7d6d1da03..000000000 --- a/tests/resources/typing/skip-expressions/memberAccesses.sdstest +++ /dev/null @@ -1,19 +0,0 @@ -package tests.typingexpressions.memberAccesses - -class C { - static attr a: Int - static attr b: String - static attr c: Any? -} - -pipeline myPipeline { - C.a; - C.b; - C.c; - C.unresolved; - - C?.a; - C?.b; - C?.c; - C?.unresolved; -} diff --git a/tests/resources/typing/skip-expressions/operations/arithmetic.sdstest b/tests/resources/typing/skip-expressions/operations/arithmetic.sdstest deleted file mode 100644 index 8bc95c317..000000000 --- a/tests/resources/typing/skip-expressions/operations/arithmetic.sdstest +++ /dev/null @@ -1,21 +0,0 @@ -package tests.typingoperations.arithmetic - -pipeline myPipeline { - val additionIntInt = (1 + 1); - val subtractionIntInt = (1 - 1); - val multiplicationIntInt = (1 * 1); - val divisionIntInt = (1 / 1); - val negationInt = (-1); - - val additionIntFloat = (1 + 1.0); - val subtractionIntFloat = (1 - 1.0); - val multiplicationIntFloat = (1 * 1.0); - val divisionIntFloat = (1 / 1.0); - val negationFloat = (-1.0); - - val additionInvalid = (true + true); - val subtractionInvalid = (true - true); - val multiplicationInvalid = (true * true); - val divisionInvalid = (true / true); - val negationInvalid = (-true); -} diff --git a/tests/resources/typing/skip-expressions/operations/comparison.sdstest b/tests/resources/typing/skip-expressions/operations/comparison.sdstest deleted file mode 100644 index a4200c411..000000000 --- a/tests/resources/typing/skip-expressions/operations/comparison.sdstest +++ /dev/null @@ -1,12 +0,0 @@ -package tests.typingoperations.comparison - -pipeline myPipeline { - val lessThan = (1 < 1); - val lessThanOrEquals = (1 <= 1); - val greaterThanOrEquals = (1 >= 1); - val greaterThan = (1 > 1); - val lessThanInvalid = (true < true); - val lessThanOrEqualsInvalid = (true <= true); - val greaterThanOrEqualsInvalid = (true >= true); - val greaterThanInvalid = (true > true); -} diff --git a/tests/resources/typing/skip-expressions/operations/elvis.sdstest b/tests/resources/typing/skip-expressions/operations/elvis.sdstest deleted file mode 100644 index 9616e92fb..000000000 --- a/tests/resources/typing/skip-expressions/operations/elvis.sdstest +++ /dev/null @@ -1,21 +0,0 @@ -package tests.typingoperations.elvis - -fun intOrNull() -> a: Int? -fun stringOrNull() -> s: String? - -pipeline elvisWithNonNullableLeftOperand { - 1 ?: intOrNull(); - 1 ?: 1; - 1 ?: 1.0; - 1 ?: ""; - 1 ?: null; -} - -pipeline elvisWithNullableLeftOperand { - val intOrNullElseIntOrNull = intOrNull() ?: intOrNull(); - val intOrNullElseNull = intOrNull() ?: null; - val intOrNullElseInt = intOrNull() ?: 1; - val intOrNullElseFloat = intOrNull() ?: 1.0; - val intOrNullElseString = intOrNull() ?: ""; - val intOrNullElseStringOrNull = intOrNull() ?: stringOrNull(); -} diff --git a/tests/resources/typing/skip-expressions/operations/equality.sdstest b/tests/resources/typing/skip-expressions/operations/equality.sdstest deleted file mode 100644 index 6278e2b63..000000000 --- a/tests/resources/typing/skip-expressions/operations/equality.sdstest +++ /dev/null @@ -1,6 +0,0 @@ -package tests.typingoperations.equality - -pipeline myPipeline { - val equals = (1 == 1); - val notEquals = (1 != 1); -} diff --git a/tests/resources/typing/skip-expressions/operations/logical.sdstest b/tests/resources/typing/skip-expressions/operations/logical.sdstest deleted file mode 100644 index e789df0d9..000000000 --- a/tests/resources/typing/skip-expressions/operations/logical.sdstest +++ /dev/null @@ -1,10 +0,0 @@ -package tests.typingoperations.logical - -pipeline myPipeline { - val conjunction = (true and true); - val disjunction = (true or true); - val negation = (not true); - val conjunctionInvalid = (1 and 1); - val disjunctionInvalid = (1.0 or 1.0); - val negationInvalid = (not "true"); -} diff --git a/tests/resources/typing/skip-expressions/operations/strictEquality.sdstest b/tests/resources/typing/skip-expressions/operations/strictEquality.sdstest deleted file mode 100644 index 7663b79cb..000000000 --- a/tests/resources/typing/skip-expressions/operations/strictEquality.sdstest +++ /dev/null @@ -1,6 +0,0 @@ -package tests.typingoperations.strictEquality - -pipeline myPipeline { - val strictlyEquals = (1 === 1); - val notStrictlyEquals = (1 !== 1); -} diff --git a/tests/resources/typing/skip-expressions/parenthesizedExpressions.sdstest b/tests/resources/typing/skip-expressions/parenthesizedExpressions.sdstest deleted file mode 100644 index 435022bff..000000000 --- a/tests/resources/typing/skip-expressions/parenthesizedExpressions.sdstest +++ /dev/null @@ -1,6 +0,0 @@ -package tests.typingexpressions.parenthesizedExpressions - -pipeline myPipeline { - (1); - (""); -} diff --git a/tests/resources/typing/skip-expressions/references.sdstest b/tests/resources/typing/skip-expressions/references.sdstest deleted file mode 100644 index 7f3a1899f..000000000 --- a/tests/resources/typing/skip-expressions/references.sdstest +++ /dev/null @@ -1,10 +0,0 @@ -package tests.typingexpressions.references - -pipeline myPipeline { - val a = 1; - val b = ""; - - a; - b; - unresolved; -} diff --git a/tests/resources/typing/skip-types/callableTypes.sdstest b/tests/resources/typing/skip-types/callableTypes.sdstest deleted file mode 100644 index 46d98e37b..000000000 --- a/tests/resources/typing/skip-types/callableTypes.sdstest +++ /dev/null @@ -1,3 +0,0 @@ -package tests.typingtypes.callableTypes - -fun myFun(f: (p1: Int, p2: String) -> (r1: Int, r2: String)) diff --git a/tests/resources/typing/skip-types/memberTypes.sdstest b/tests/resources/typing/skip-types/memberTypes.sdstest deleted file mode 100644 index e4b635cd9..000000000 --- a/tests/resources/typing/skip-types/memberTypes.sdstest +++ /dev/null @@ -1,9 +0,0 @@ -package tests.typingtypes.memberTypes - -enum MyEnum { - MyVariant1 - MyVariant2 -} - -fun nonNullableMemberTypes(a: MyEnum.MyVariant1, b: MyEnum.MyVariant2) -fun nullableMemberTypes(a: MyEnum.MyVariant1?, b: MyEnum.MyVariant2?) diff --git a/tests/resources/typing/skip-types/namedTypes.sdstest b/tests/resources/typing/skip-types/namedTypes.sdstest deleted file mode 100644 index 8f64311b6..000000000 --- a/tests/resources/typing/skip-types/namedTypes.sdstest +++ /dev/null @@ -1,4 +0,0 @@ -package tests.typingtypes.namedTypes - -fun nonNullableNamedTypes(a: Int, b: String) -fun nullableNamedTypes(a: Int?, b: String?) diff --git a/tests/resources/typing/skip-types/parenthesizedTypes.sdstest b/tests/resources/typing/skip-types/parenthesizedTypes.sdstest deleted file mode 100644 index c35d55b35..000000000 --- a/tests/resources/typing/skip-types/parenthesizedTypes.sdstest +++ /dev/null @@ -1,3 +0,0 @@ -package tests.typingtypes.parenthesizedTypes - -fun myFun(a: (Int), b: (String)) diff --git a/tests/resources/typing/skip-types/unionTypes.sdstest b/tests/resources/typing/skip-types/unionTypes.sdstest deleted file mode 100644 index 9850bd075..000000000 --- a/tests/resources/typing/skip-types/unionTypes.sdstest +++ /dev/null @@ -1,3 +0,0 @@ -package tests.typingtypes.unionTypes - -fun myFun(a: union) diff --git a/tests/resources/typing/types/callable types/main.sdstest b/tests/resources/typing/types/callable types/main.sdstest new file mode 100644 index 000000000..d38058e65 --- /dev/null +++ b/tests/resources/typing/types/callable types/main.sdstest @@ -0,0 +1,16 @@ +package tests.typing.types.callableTypes + +// $TEST$ serialization () -> () +fun myFunction1(f: »() -> ()«) + +// $TEST$ serialization () -> (r1: Int, r2: String) +fun myFunction2(f: »() -> (r1: Int, r2: String)«) + +// $TEST$ serialization (p1: Int, p2: String) -> () +fun myFunction3(f: »(p1: Int, p2: String) -> ()«) + +// $TEST$ serialization (p1: Int, p2: String) -> (r1: Int, r2: String) +fun myFunction4(f: »(p1: Int, p2: String) -> (r1: Int, r2: String)«) + +// $TEST$ serialization (p1: $Unknown) -> (r1: $Unknown) +fun myFunction5(f: »(p1) -> (r1)«) diff --git a/tests/resources/typing/types/member types/main.sdstest b/tests/resources/typing/types/member types/main.sdstest new file mode 100644 index 000000000..637055d12 --- /dev/null +++ b/tests/resources/typing/types/member types/main.sdstest @@ -0,0 +1,36 @@ +package tests.typing.types.memberTypes + +class MyClass { + // $TEST$ equivalence_class myNestedClass + class »MyNestedClass« + + // $TEST$ equivalence_class myNestedEnum + enum »MyNestedEnum« +} + +enum MyEnum { + // $TEST$ equivalence_class myEnumVariant + »MyEnumVariant« +} + +fun nonNullableMemberTypes( + // $TEST$ equivalence_class myNestedClass + a: »MyClass.MyNestedClass«, + // $TEST$ equivalence_class myNestedEnum + b: »MyClass.MyNestedEnum«, + // $TEST$ equivalence_class myEnumVariant + d: »MyEnum.MyEnumVariant«, + // $TEST$ serialization $Unknown + e: »MyEnum.unresolved«, +) + +fun nullableMemberTypes( + // $TEST$ serialization MyNestedClass? + a: »MyClass.MyNestedClass?«, + // $TEST$ serialization MyNestedEnum? + b: »MyClass.MyNestedEnum?«, + // $TEST$ serialization MyEnumVariant? + d: »MyEnum.MyEnumVariant?«, + // $TEST$ serialization $Unknown + e: »MyEnum.unresolved?«, +) diff --git a/tests/resources/typing/types/named types/main.sdstest b/tests/resources/typing/types/named types/main.sdstest new file mode 100644 index 000000000..7447e4fcd --- /dev/null +++ b/tests/resources/typing/types/named types/main.sdstest @@ -0,0 +1,23 @@ +package tests.typing.types.namedTypes + +class MyClass + +enum MyEnum + +fun nonNullableNamedTypes( + // $TEST$ serialization MyClass + a: »MyClass«, + // $TEST$ serialization MyEnum + b: »MyEnum«, + // $TEST$ serialization $Unknown + c: »unresolved«, +) + +fun nullableNamedTypes( + // $TEST$ serialization MyClass? + a: »MyClass?«, + // $TEST$ serialization MyEnum? + b: »MyEnum?«, + // $TEST$ serialization $Unknown + c: »unresolved?«, +) diff --git a/tests/resources/typing/types/union types/main.sdstest b/tests/resources/typing/types/union types/main.sdstest new file mode 100644 index 000000000..92d0edb66 --- /dev/null +++ b/tests/resources/typing/types/union types/main.sdstest @@ -0,0 +1,7 @@ +package tests.typing.types.unionTypes + +// $TEST$ serialization union<> +fun myFunction(a: »union<>«) + +// $TEST$ serialization union +fun myFunction(a: »union«)