Skip to content

Commit

Permalink
feat: handle cells in type computer
Browse files Browse the repository at this point in the history
  • Loading branch information
lars-reimann committed Oct 31, 2024
1 parent 514b214 commit b168f4a
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class SafeDsCoreTypes {
return this.createCoreType(this.builtinClasses.Boolean);
}

Cell(wrappedType: Type): Type {
Cell(wrappedType: Type = this.AnyOrNull): Type {
const cell = this.builtinClasses.Cell;
const wrappedTypeParameter = getTypeParameters(cell)[0];

Expand Down
54 changes: 44 additions & 10 deletions packages/safe-ds-lang/src/language/typing/safe-ds-type-computer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,24 +371,23 @@ export class SafeDsTypeComputer {
return this.computeTypeOfIndexedAccess(node);
} else if (isSdsInfixOperation(node)) {
switch (node.operator) {
// Boolean operators
case 'or':
case 'and':
return this.coreTypes.Boolean;

// Equality operators
case '==':
case '!=':
case '===':
case '!==':
return this.coreTypes.Boolean;
case '==':
case '!=':

// Logical operators
case 'or':
case 'and':

// Comparison operators
case '<':
case '<=':
case '>=':
case '>':
return this.coreTypes.Boolean;
return this.computeTypeOfBooleanOperation(node);

// Arithmetic operators
case '+':
Expand Down Expand Up @@ -429,7 +428,7 @@ export class SafeDsTypeComputer {
} else if (isSdsPrefixOperation(node)) {
switch (node.operator) {
case 'not':
return this.coreTypes.Boolean;
return this.computeTypeOfBooleanPrefixOperation(node);
case '-':
return this.computeTypeOfArithmeticPrefixOperation(node);

Expand Down Expand Up @@ -509,11 +508,32 @@ export class SafeDsTypeComputer {
return UnknownType;
}

private computeTypeOfBooleanOperation(node: SdsInfixOperation): Type {
const leftOperandType = this.computeType(node.leftOperand);
const rightOperandType = this.computeType(node.rightOperand);
const cellType = this.coreTypes.Cell();

if (
this.typeChecker.isSubtypeOf(leftOperandType, cellType) ||
this.typeChecker.isSubtypeOf(rightOperandType, cellType)
) {
return this.coreTypes.Cell(this.coreTypes.Boolean);
} else {
return this.coreTypes.Boolean;
}
}

private computeTypeOfArithmeticInfixOperation(node: SdsInfixOperation): Type {
const leftOperandType = this.computeType(node.leftOperand);
const rightOperandType = this.computeType(node.rightOperand);
const cellType = this.coreTypes.Cell();

if (
this.typeChecker.isSubtypeOf(leftOperandType, cellType) ||
this.typeChecker.isSubtypeOf(rightOperandType, cellType)
) {
return this.coreTypes.Cell(this.coreTypes.Number);
} else if (
this.typeChecker.isSubtypeOf(leftOperandType, this.coreTypes.Int) &&
this.typeChecker.isSubtypeOf(rightOperandType, this.coreTypes.Int)
) {
Expand Down Expand Up @@ -596,10 +616,24 @@ export class SafeDsTypeComputer {
);
}

private computeTypeOfBooleanPrefixOperation(node: SdsPrefixOperation): Type {
const operandType = this.computeType(node.operand);
const cellType = this.coreTypes.Cell();

if (this.typeChecker.isSubtypeOf(operandType, cellType)) {
return this.coreTypes.Cell(this.coreTypes.Boolean);
} else {
return this.coreTypes.Boolean;
}
}

private computeTypeOfArithmeticPrefixOperation(node: SdsPrefixOperation): Type {
const operandType = this.computeType(node.operand);
const cellType = this.coreTypes.Cell();

if (this.typeChecker.isSubtypeOf(operandType, this.coreTypes.Int)) {
if (this.typeChecker.isSubtypeOf(operandType, cellType)) {
return this.coreTypes.Cell(this.coreTypes.Number);
} else if (this.typeChecker.isSubtypeOf(operandType, this.coreTypes.Int)) {
return this.coreTypes.Int;
} else {
return this.coreTypes.Float;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package tests.typing.operations.arithmetic

fun anyInt() -> r: Int
fun anyFloat() -> r: Float
@Pure fun anyInt() -> r: Int
@Pure fun anyFloat() -> r: Float

@Pure fun cell() -> r: Cell<Number>

pipeline constantOperands {
// $TEST$ serialization literal<2>
Expand Down Expand Up @@ -141,6 +143,74 @@ pipeline mixedOperands {
val divisionFloatFloat = »1.5 / anyFloat()«;
}

pipeline cellOperands {
// $TEST$ serialization Cell<Number>
val additionIntCell = »10 + cell()«;
// $TEST$ serialization Cell<Number>
val subtractionIntCell = »10 - cell()«;
// $TEST$ serialization Cell<Number>
val multiplicationIntCell = »10 * cell()«;
// $TEST$ serialization Cell<Number>
val divisionIntCell = »10 / cell()«;

// $TEST$ serialization Cell<Number>
val additionFloatCell = »1.5 + cell()«;
// $TEST$ serialization Cell<Number>
val subtractionFloatCell = »1.5 - cell()«;
// $TEST$ serialization Cell<Number>
val multiplicationFloatCell = »1.5 * cell()«;
// $TEST$ serialization Cell<Number>
val divisionFloatCell = »1.5 / cell()«;

// $TEST$ serialization Cell<Number>
val additionInvalidCell = »true + cell()«;
// $TEST$ serialization Cell<Number>
val subtractionInvalidCell = »true - cell()«;
// $TEST$ serialization Cell<Number>
val multiplicationInvalidCell = »true * cell()«;
// $TEST$ serialization Cell<Number>
val divisionInvalidCell = »true / cell()«;

// $TEST$ serialization Cell<Number>
val additionCellInt = »cell() + 10«;
// $TEST$ serialization Cell<Number>
val subtractionCellInt = »cell() - 10«;
// $TEST$ serialization Cell<Number>
val multiplicationCellInt = »cell() * 10«;
// $TEST$ serialization Cell<Number>
val divisionCellInt = »cell() / 10«;

// $TEST$ serialization Cell<Number>
val additionCellFloat = »cell() + 1.5«;
// $TEST$ serialization Cell<Number>
val subtractionCellFloat = »cell() - 1.5«;
// $TEST$ serialization Cell<Number>
val multiplicationCellFloat = »cell() * 1.5«;
// $TEST$ serialization Cell<Number>
val divisionCellFloat = »cell() / 1.5«;

// $TEST$ serialization Cell<Number>
val additionCellInvalid = »cell() + true«;
// $TEST$ serialization Cell<Number>
val subtractionCellInvalid = »cell() - true«;
// $TEST$ serialization Cell<Number>
val multiplicationCellInvalid = »cell() * true«;
// $TEST$ serialization Cell<Number>
val divisionCellInvalid = »cell() / true«;

// $TEST$ serialization Cell<Number>
val additionCellCell = »cell() + cell()«;
// $TEST$ serialization Cell<Number>
val subtractionCellCell = »cell() - cell()«;
// $TEST$ serialization Cell<Number>
val multiplicationCellCell = »cell() * cell()«;
// $TEST$ serialization Cell<Number>
val divisionCellCell = »cell() / cell()«;

// $TEST$ serialization Cell<Number>
val negationCell = »-cell()«;
}

// Strict checking of type parameter types
class MyClass<T sub Any>(
p1: T,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tests.typing.operations.comparison

pipeline myPipeline {
@Pure fun cell() -> r: Cell<Boolean>

pipeline constantOperands {
// $TEST$ serialization literal<false>
val lessThan = »1 < 1«;
// $TEST$ serialization literal<true>
Expand All @@ -9,7 +11,9 @@ pipeline myPipeline {
val greaterThanOrEquals = »1 >= 1«;
// $TEST$ serialization literal<false>
val greaterThan = »1 > 1«;
}

pipeline invalidOperands {
// $TEST$ serialization Boolean
val lessThanInvalid = »true < true«;
// $TEST$ serialization Boolean
Expand All @@ -19,3 +23,50 @@ pipeline myPipeline {
// $TEST$ serialization Boolean
val greaterThanInvalid = »true > true«;
}

pipeline cellOperands {
// $TEST$ serialization Cell<Boolean>
val lessThanNumberCell = »10 < cell()«;
// $TEST$ serialization Cell<Boolean>
val lessThanOrEqualsNumberCell = »10 <= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanOrEqualsNumberCell = »10 >= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanNumberCell = »10 > cell()«;

// $TEST$ serialization Cell<Boolean>
val lessThanInvalidCell = »true < cell()«;
// $TEST$ serialization Cell<Boolean>
val lessThanOrEqualsInvalidCell = »true <= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanOrEqualsInvalidCell = »true >= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanInvalidCell = »true > cell()«;

// $TEST$ serialization Cell<Boolean>
val lessThanCellNumber = »cell() < 10«;
// $TEST$ serialization Cell<Boolean>
val lessThanOrEqualsCellNumber = »cell() <= 10«;
// $TEST$ serialization Cell<Boolean>
val greaterThanOrEqualsCellNumber = »cell() >= 10«;
// $TEST$ serialization Cell<Boolean>
val greaterThanCellNumber = »cell() > 10«;

// $TEST$ serialization Cell<Boolean>
val lessThanCellInvalid = »cell() < true«;
// $TEST$ serialization Cell<Boolean>
val lessThanOrEqualsCellInvalid = »cell() <= true«;
// $TEST$ serialization Cell<Boolean>
val greaterThanOrEqualsCellInvalid = »cell() >= true«;
// $TEST$ serialization Cell<Boolean>
val greaterThanCellInvalid = »cell() > true«;

// $TEST$ serialization Cell<Boolean>
val lessThanCellCell = »cell() < cell()«;
// $TEST$ serialization Cell<Boolean>
val lessThanOrEqualsCellCell = »cell() <= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanOrEqualsCellCell = »cell() >= cell()«;
// $TEST$ serialization Cell<Boolean>
val greaterThanCellCell = »cell() > cell()«;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tests.typing.operations.equality

pipeline myPipeline {
@Pure fun cell() -> r: Cell<Number>

pipeline basicOperands {
// $TEST$ serialization literal<true>
val equals = (»1 == 1«);
// $TEST$ serialization literal<false>
Expand All @@ -20,3 +22,20 @@ pipeline myPipeline {
// $TEST$ serialization Boolean
val nonConstantNotIdenticalTo = (»1 !== unresolved«);
}

pipeline cellOperands {
// $TEST$ serialization Cell<Boolean>
val equalsAnyCell = (»1 == cell()«);
// $TEST$ serialization Cell<Boolean>
val notEqualsAnyCell = (»1 != cell()«);

// $TEST$ serialization Cell<Boolean>
val equalsCellAny = (»cell() == 1«);
// $TEST$ serialization Cell<Boolean>
val notEqualsCellAny = (»cell() != 1«);

// $TEST$ serialization Cell<Boolean>
val equalsCellCell = (»cell() == cell()«);
// $TEST$ serialization Cell<Boolean>
val notEqualsCellCell = (»cell() != cell()«);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
package tests.typing.operations.logical

pipeline myPipeline {
@Pure fun cell() -> r: Cell<Number>

pipeline constantOperands {
// $TEST$ serialization literal<true>
val conjunction = »true and true«;
// $TEST$ serialization literal<true>
val disjunction = »true or true«;
// $TEST$ serialization literal<false>
val negation = »not true«;
}

pipeline invalidOperands {
// $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"«;
}

pipeline cellOperands {
// $TEST$ serialization Cell<Boolean>
val conjunctionBooleanCell = »true and cell()«;
// $TEST$ serialization Cell<Boolean>
val disjunctionBooleanCell = »true or cell()«;

// $TEST$ serialization Cell<Boolean>
val conjunctionCellBoolean = »cell() and true«;
// $TEST$ serialization Cell<Boolean>
val disjunctionCellBoolean = »cell() or true«;

// $TEST$ serialization Cell<Boolean>
val conjunctionCellCell = »cell() and cell()«;
// $TEST$ serialization Cell<Boolean>
val disjunctionCellCell = »cell() or cell()«;

// $TEST$ serialization Cell<Boolean>
val negationCell = »not cell()«;
}

0 comments on commit b168f4a

Please sign in to comment.