7
7
/* eslint-disable @typescript-eslint/parameter-properties */
8
8
9
9
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' ;
13
12
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' ;
14
14
import { TypirServices } from '../../../src/typir.js' ;
15
- import { isPrimitiveType } from '../../../src/index .js' ;
15
+ import { createTypirServicesForTesting , expectToBeType } from '../../../src/utils/test-utils .js' ;
16
16
17
17
describe ( 'Multiple best matches for overloaded operators' , ( ) => {
18
18
let typir : TypirServices ;
@@ -35,9 +35,9 @@ describe('Multiple best matches for overloaded operators', () => {
35
35
] , inferenceRule : InferenceRuleBinaryExpression } ) ;
36
36
37
37
// define relationships between types
38
- typir . Conversion . markAsConvertible ( doubleType , stringType , 'IMPLICIT_EXPLICIT' ) ; // stringVariable := doubleValue;
39
38
typir . Conversion . markAsConvertible ( booleanType , integerType , 'IMPLICIT_EXPLICIT' ) ; // integerVariable := booleanValue;
40
39
typir . Subtype . markAsSubType ( integerType , doubleType ) ; // double <|--- integer
40
+ typir . Conversion . markAsConvertible ( doubleType , stringType , 'IMPLICIT_EXPLICIT' ) ; // stringVariable := doubleValue;
41
41
42
42
// specify, how Typir can detect the type of a variable
43
43
typir . Inference . addInferenceRule ( node => {
@@ -58,7 +58,7 @@ describe('Multiple best matches for overloaded operators', () => {
58
58
} ) ;
59
59
60
60
61
- describe ( 'tests all cases for assignability' , ( ) => {
61
+ describe ( 'tests all cases for assignability and the checks the found assignability paths ' , ( ) => {
62
62
test ( 'integer to integer' , ( ) => {
63
63
expectAssignmentValid ( new IntegerLiteral ( 123 ) , new IntegerLiteral ( 456 ) ) ;
64
64
} ) ;
@@ -69,11 +69,11 @@ describe('Multiple best matches for overloaded operators', () => {
69
69
expectAssignmentError ( new StringLiteral ( '123' ) , new IntegerLiteral ( 456 ) ) ;
70
70
} ) ;
71
71
test ( 'boolean to integer' , ( ) => {
72
- expectAssignmentValid ( new BooleanLiteral ( true ) , new IntegerLiteral ( 456 ) ) ;
72
+ expectAssignmentValid ( new BooleanLiteral ( true ) , new IntegerLiteral ( 456 ) , 'ConversionEdge' ) ;
73
73
} ) ;
74
74
75
75
test ( 'integer to double' , ( ) => {
76
- expectAssignmentValid ( new IntegerLiteral ( 123 ) , new DoubleLiteral ( 456.0 ) ) ;
76
+ expectAssignmentValid ( new IntegerLiteral ( 123 ) , new DoubleLiteral ( 456.0 ) , 'SubTypeEdge' ) ;
77
77
} ) ;
78
78
test ( 'double to double' , ( ) => {
79
79
expectAssignmentValid ( new DoubleLiteral ( 123.0 ) , new DoubleLiteral ( 456.0 ) ) ;
@@ -82,20 +82,20 @@ describe('Multiple best matches for overloaded operators', () => {
82
82
expectAssignmentError ( new StringLiteral ( '123' ) , new DoubleLiteral ( 456.0 ) ) ;
83
83
} ) ;
84
84
test ( 'boolean to double' , ( ) => {
85
- expectAssignmentValid ( new BooleanLiteral ( true ) , new DoubleLiteral ( 456.0 ) ) ;
85
+ expectAssignmentValid ( new BooleanLiteral ( true ) , new DoubleLiteral ( 456.0 ) , 'ConversionEdge' , 'SubTypeEdge' ) ;
86
86
} ) ;
87
87
88
88
test ( 'integer to string' , ( ) => {
89
- expectAssignmentValid ( new IntegerLiteral ( 123 ) , new StringLiteral ( '456' ) ) ;
89
+ expectAssignmentValid ( new IntegerLiteral ( 123 ) , new StringLiteral ( '456' ) , 'SubTypeEdge' , 'ConversionEdge' ) ;
90
90
} ) ;
91
91
test ( 'double to string' , ( ) => {
92
- expectAssignmentValid ( new DoubleLiteral ( 123.0 ) , new StringLiteral ( '456' ) ) ;
92
+ expectAssignmentValid ( new DoubleLiteral ( 123.0 ) , new StringLiteral ( '456' ) , 'ConversionEdge' ) ;
93
93
} ) ;
94
94
test ( 'string to string' , ( ) => {
95
95
expectAssignmentValid ( new StringLiteral ( '123' ) , new StringLiteral ( '456' ) ) ;
96
96
} ) ;
97
97
test ( 'boolean to string' , ( ) => {
98
- expectAssignmentValid ( new BooleanLiteral ( true ) , new StringLiteral ( '456' ) ) ;
98
+ expectAssignmentValid ( new BooleanLiteral ( true ) , new StringLiteral ( '456' ) , 'ConversionEdge' , 'SubTypeEdge' , 'ConversionEdge' ) ;
99
99
} ) ;
100
100
101
101
test ( 'integer to boolean' , ( ) => {
@@ -112,10 +112,34 @@ describe('Multiple best matches for overloaded operators', () => {
112
112
} ) ;
113
113
114
114
115
- function expectAssignmentValid ( value : TestExpressionNode , variableInitType : TestExpressionNode ) : void {
115
+ function expectAssignmentValid ( value : TestExpressionNode , variableInitType : TestExpressionNode , ... expectedPath : Array < SubTypeEdge [ '$relation' ] | ConversionEdge [ '$relation' ] > ) : void {
116
116
const variable = new Variable ( 'v1' , variableInitType ) ;
117
117
const assignment = new AssignmentStatement ( variable , value ) ;
118
118
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
+ }
119
143
}
120
144
121
145
function expectAssignmentError ( value : TestExpressionNode , variableInitType : TestExpressionNode ) : void {
@@ -128,7 +152,7 @@ describe('Multiple best matches for overloaded operators', () => {
128
152
} ) ;
129
153
130
154
131
- describe ( 'Test multiple matches for overloaded operators' , ( ) => {
155
+ describe ( 'Test multiple matches for overloaded operators and ensures that the best match is chosen ' , ( ) => {
132
156
test ( '2 + 3 => both are integers' , ( ) => {
133
157
expectOverload ( new IntegerLiteral ( 2 ) , new IntegerLiteral ( 3 ) , 'integer' ) ;
134
158
} ) ;
0 commit comments