Inconsistent Casting in Unions
I've discovered inconsistent translation behavior in CQL-to-ELM when a function that returns a list of Any is involved in a union. In short:
If you have CQL that only does ListOfIntegers union ToList('MyString'), then the translator will cast each item in ToList('MyString') to an Integer (resulting in nulls).
If, however, you put a definition that does the reverse order first (e.g., ToList('MyString') union ListOfIntegers) -- and then you do ListOfIntegers union ToList('MyString') -- this time the translator will not attempt the cast at all (in either case).
I think the latter behavior (no cast) is preferred, as ListOfIntegers union ToList('MyString') does not setup any expectation that it should be a singly-typed list -- so a I expect a list of mixed types back.
Specific Details (for Reproducing)
Consider the following CQL:
define function "ToList"(Object "Any"):
if Object is null then List{} else List{Object}
define Foo:
Tuple{ Bar: 'Baz', Boo: null as Integer }
define NumsUnionFoo:
List{1, 2, 3} union ToList(Foo)
When run through CQL-to-ELM, the translator attempts to cast ToList(Foo) to an Integer in NumsUnionFoo:
{
"name": "NumsUnionFoo",
"context": "Patient",
"accessLevel": "Public",
"expression": {
"type": "Union",
"operand": [
{
"type": "List",
"element": [
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "1",
"type": "Literal"
},
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "2",
"type": "Literal"
},
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "3",
"type": "Literal"
}
]
},
{
"type": "Query",
"source": [
{
"alias": "X",
"expression": {
"name": "ToList",
"type": "FunctionRef",
"operand": [
{
"name": "Foo",
"type": "ExpressionRef"
}
]
}
}
],
"return": {
"distinct": false,
"expression": {
"asType": "{urn:hl7-org:elm-types:r1}Integer",
"type": "As",
"operand": {
"name": "X",
"type": "AliasRef"
}
}
}
}
]
}
}
Now simply add an expression with the union in reverse order before NumsUnionFoo:
define function "ToList"(Object "Any"):
if Object is null then List{} else List{Object}
define Foo:
Tuple{ Bar: 'Baz', Boo: null as Integer }
define FooUnionNums:
ToList(Foo) union List{1, 2, 3}
define NumsUnionFoo:
List{1, 2, 3} union ToList(Foo)
NOW when running it through CQL-to-ELM, the translator does not cast ToList(Foo) to an Integer in NumsUnionFoo:
{
"name": "NumsUnionFoo",
"context": "Patient",
"accessLevel": "Public",
"expression": {
"type": "Union",
"operand": [
{
"type": "List",
"element": [
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "1",
"type": "Literal"
},
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "2",
"type": "Literal"
},
{
"valueType": "{urn:hl7-org:elm-types:r1}Integer",
"value": "3",
"type": "Literal"
}
]
},
{
"name": "ToList",
"type": "FunctionRef",
"operand": [
{
"name": "Foo",
"type": "ExpressionRef"
}
]
}
]
}
}
Potentially resolved by #1243. Will retest.
Not fixed by #1243. :)
Using the first CQL expression with the latest version of the translator gives me this XML for numsUnionFoo
<def name="NumsUnionFoo" context="Patient" accessLevel="Public">
<expression xsi:type="Union">
<operand xsi:type="List">
<element valueType="t:Integer" value="1" xsi:type="Literal"/>
<element valueType="t:Integer" value="2" xsi:type="Literal"/>
<element valueType="t:Integer" value="3" xsi:type="Literal"/>
</operand>
<operand xsi:type="Query">
<source alias="X">
<expression name="ToList" xsi:type="FunctionRef">
<operand name="Foo" xsi:type="ExpressionRef"/>
</expression>
</source>
<return distinct="false">
<expression asType="t:Integer" xsi:type="As">
<operand name="X" xsi:type="AliasRef"/>
</expression>
</return>
</operand>
</expression>
</def>```
Using the second CQL expression I get
<def name="NumsUnionFoo" context="Patient" accessLevel="Public">
<expression xsi:type="Union">
<operand xsi:type="List">
<element valueType="t:Integer" value="1" xsi:type="Literal"/>
<element valueType="t:Integer" value="2" xsi:type="Literal"/>
<element valueType="t:Integer" value="3" xsi:type="Literal"/>
</operand>
<operand name="ToList" xsi:type="FunctionRef">
<operand name="Foo" xsi:type="ExpressionRef"/>
</operand>
</expression>
</def>```
I can reproduce this issue and confirm that indeed the translator does not cast ToList(Foo) to an Integer in NumsUnionFoo