Skip to content

Commit 17449e5

Browse files
improved test cases to explicitly check the resulting path
1 parent 03dc6b6 commit 17449e5

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

packages/typir/test/kinds/function/operator-overloaded.test.ts

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
/* eslint-disable @typescript-eslint/parameter-properties */
88

99
import { beforeAll, describe, expect, test } from 'vitest';
10-
import { AssignmentStatement, BinaryExpression, BooleanLiteral, DoubleLiteral, InferenceRuleBinaryExpression, IntegerLiteral, StringLiteral, TestExpressionNode, Variable } from '../../../src/test/predefined-language-nodes.js';
11-
import { createTypirServicesForTesting, expectToBeType } from '../../../src/utils/test-utils.js';
12-
import { InferenceRuleNotApplicable} from '../../../src/services/inference.js';
10+
import { assertTrue, ConversionEdge, isAssignabilitySuccess, isPrimitiveType, isType, SubTypeEdge } from '../../../src/index.js';
11+
import { InferenceRuleNotApplicable } from '../../../src/services/inference.js';
1312
import { ValidationMessageDetails } from '../../../src/services/validation.js';
13+
import { AssignmentStatement, BinaryExpression, BooleanLiteral, DoubleLiteral, InferenceRuleBinaryExpression, IntegerLiteral, StringLiteral, TestExpressionNode, Variable } from '../../../src/test/predefined-language-nodes.js';
1414
import { TypirServices } from '../../../src/typir.js';
15-
import { isPrimitiveType } from '../../../src/index.js';
15+
import { createTypirServicesForTesting, expectToBeType } from '../../../src/utils/test-utils.js';
1616

1717
describe('Multiple best matches for overloaded operators', () => {
1818
let typir: TypirServices;
@@ -35,9 +35,9 @@ describe('Multiple best matches for overloaded operators', () => {
3535
], inferenceRule: InferenceRuleBinaryExpression });
3636

3737
// define relationships between types
38-
typir.Conversion.markAsConvertible(doubleType, stringType, 'IMPLICIT_EXPLICIT'); // stringVariable := doubleValue;
3938
typir.Conversion.markAsConvertible(booleanType, integerType, 'IMPLICIT_EXPLICIT'); // integerVariable := booleanValue;
4039
typir.Subtype.markAsSubType(integerType, doubleType); // double <|--- integer
40+
typir.Conversion.markAsConvertible(doubleType, stringType, 'IMPLICIT_EXPLICIT'); // stringVariable := doubleValue;
4141

4242
// specify, how Typir can detect the type of a variable
4343
typir.Inference.addInferenceRule(node => {
@@ -58,7 +58,7 @@ describe('Multiple best matches for overloaded operators', () => {
5858
});
5959

6060

61-
describe('tests all cases for assignability', () => {
61+
describe('tests all cases for assignability and the checks the found assignability paths', () => {
6262
test('integer to integer', () => {
6363
expectAssignmentValid(new IntegerLiteral(123), new IntegerLiteral(456));
6464
});
@@ -69,11 +69,11 @@ describe('Multiple best matches for overloaded operators', () => {
6969
expectAssignmentError(new StringLiteral('123'), new IntegerLiteral(456));
7070
});
7171
test('boolean to integer', () => {
72-
expectAssignmentValid(new BooleanLiteral(true), new IntegerLiteral(456));
72+
expectAssignmentValid(new BooleanLiteral(true), new IntegerLiteral(456), 'ConversionEdge');
7373
});
7474

7575
test('integer to double', () => {
76-
expectAssignmentValid(new IntegerLiteral(123), new DoubleLiteral(456.0));
76+
expectAssignmentValid(new IntegerLiteral(123), new DoubleLiteral(456.0), 'SubTypeEdge');
7777
});
7878
test('double to double', () => {
7979
expectAssignmentValid(new DoubleLiteral(123.0), new DoubleLiteral(456.0));
@@ -82,20 +82,20 @@ describe('Multiple best matches for overloaded operators', () => {
8282
expectAssignmentError(new StringLiteral('123'), new DoubleLiteral(456.0));
8383
});
8484
test('boolean to double', () => {
85-
expectAssignmentValid(new BooleanLiteral(true), new DoubleLiteral(456.0));
85+
expectAssignmentValid(new BooleanLiteral(true), new DoubleLiteral(456.0), 'ConversionEdge', 'SubTypeEdge');
8686
});
8787

8888
test('integer to string', () => {
89-
expectAssignmentValid(new IntegerLiteral(123), new StringLiteral('456'));
89+
expectAssignmentValid(new IntegerLiteral(123), new StringLiteral('456'), 'SubTypeEdge', 'ConversionEdge');
9090
});
9191
test('double to string', () => {
92-
expectAssignmentValid(new DoubleLiteral(123.0), new StringLiteral('456'));
92+
expectAssignmentValid(new DoubleLiteral(123.0), new StringLiteral('456'), 'ConversionEdge');
9393
});
9494
test('string to string', () => {
9595
expectAssignmentValid(new StringLiteral('123'), new StringLiteral('456'));
9696
});
9797
test('boolean to string', () => {
98-
expectAssignmentValid(new BooleanLiteral(true), new StringLiteral('456'));
98+
expectAssignmentValid(new BooleanLiteral(true), new StringLiteral('456'), 'ConversionEdge', 'SubTypeEdge', 'ConversionEdge');
9999
});
100100

101101
test('integer to boolean', () => {
@@ -112,10 +112,34 @@ describe('Multiple best matches for overloaded operators', () => {
112112
});
113113

114114

115-
function expectAssignmentValid(value: TestExpressionNode, variableInitType: TestExpressionNode): void {
115+
function expectAssignmentValid(value: TestExpressionNode, variableInitType: TestExpressionNode, ...expectedPath: Array<SubTypeEdge['$relation']|ConversionEdge['$relation']>): void {
116116
const variable = new Variable('v1', variableInitType);
117117
const assignment = new AssignmentStatement(variable, value);
118118
expect(typir.validation.Collector.validate(assignment)).toHaveLength(0);
119+
120+
// do type inference
121+
const valueType = typir.Inference.inferType(value);
122+
assertTrue(isType(valueType));
123+
const variableType = typir.Inference.inferType(variable);
124+
assertTrue(isType(variableType));
125+
// check the resulting assignability path
126+
const assignabilityResult = typir.Assignability.getAssignabilityResult(valueType, variableType);
127+
assertTrue(isAssignabilitySuccess(assignabilityResult));
128+
const actualPath = assignabilityResult.path;
129+
const msg = `Actual assignability path is ${actualPath.map(e => e.$relation).join(' --> ')}.`;
130+
expect(actualPath.length, msg).toBe(expectedPath.length);
131+
for (let i = 0; i < actualPath.length; i++) {
132+
expect(actualPath[i].$relation, msg).toBe(expectedPath[i]);
133+
if (i >= 1) {
134+
// the edges are connected with each other
135+
expect(actualPath[i - 1].to).toBe(actualPath[i].from);
136+
}
137+
}
138+
// check beginning and end of the path
139+
if (actualPath.length >= 1) {
140+
expect(actualPath[0].from).toBe(valueType);
141+
expect(actualPath[actualPath.length - 1].to).toBe(variableType);
142+
}
119143
}
120144

121145
function expectAssignmentError(value: TestExpressionNode, variableInitType: TestExpressionNode): void {
@@ -128,7 +152,7 @@ describe('Multiple best matches for overloaded operators', () => {
128152
});
129153

130154

131-
describe('Test multiple matches for overloaded operators', () => {
155+
describe('Test multiple matches for overloaded operators and ensures that the best match is chosen', () => {
132156
test('2 + 3 => both are integers', () => {
133157
expectOverload(new IntegerLiteral(2), new IntegerLiteral(3), 'integer');
134158
});

0 commit comments

Comments
 (0)