From ad33708bc7087fa5f40abd9f666a7e9ae15dd3f1 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Mon, 28 Oct 2024 22:25:02 -0600 Subject: [PATCH 1/7] Improved generic instantiation behavior and added type precedence to ambiguous resolution logic --- .../cql/cql2elm/Cql2ElmVisitor.java | 14 ++- .../cql/cql2elm/model/ConversionMap.java | 39 ++++++++ .../cql/cql2elm/model/GenericOperator.java | 4 +- .../cql2elm/model/InstantiationResult.java | 17 +++- .../cql/cql2elm/model/OperatorEntry.java | 91 +++++++++++-------- .../cql/cql2elm/model/OperatorMap.java | 22 +++++ .../cql/cql2elm/SemanticTests.java | 11 ++- .../cql/cql2elm/TranslationTests.java | 2 +- .../operators/CqlListOperatorsTest.java | 2 +- ...6v2_Expected_SignatureLevel_Overloads.json | 13 +++ ...46v2_Expected_SignatureLevel_Overloads.xml | 10 +- .../org/cqframework/cql/cql2elm/Issue435.cql | 10 ++ .../fhir/OpioidCDSSTU3/cql/OMTKData2019.cql | 8 +- .../engine/execution/ListOperatorsTest.java | 5 +- .../java/org/hl7/cql/model/IntervalType.java | 4 + .../main/java/org/hl7/cql/model/ListType.java | 4 + .../java/org/hl7/cql/model/TupleType.java | 4 + 17 files changed, 203 insertions(+), 57 deletions(-) create mode 100644 Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/Issue435.cql diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java index 5954ca107..c4c1de08e 100755 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java @@ -728,6 +728,7 @@ public Object visitListSelector(cqlParser.ListSelectorContext ctx) { DataType elementType = elementTypeSpecifier != null ? elementTypeSpecifier.getResultType() : null; DataType inferredElementType = null; + DataType initialInferredElementType = null; List elements = new ArrayList<>(); for (cqlParser.ExpressionContext elementContext : ctx.expression()) { @@ -736,12 +737,19 @@ public Object visitListSelector(cqlParser.ListSelectorContext ctx) { if (elementType != null) { libraryBuilder.verifyType(element.getResultType(), elementType); } else { - if (inferredElementType == null) { - inferredElementType = element.getResultType(); + if (initialInferredElementType == null) { + initialInferredElementType = element.getResultType(); + inferredElementType = initialInferredElementType; } else { + // Once a list type is inferred as Any, keep it that way + // The only potential exception to this is if the element responsible for the inferred type of Any + // is a null DataType compatibleType = libraryBuilder.findCompatibleType(inferredElementType, element.getResultType()); - if (compatibleType != null) { + if (compatibleType != null + && (!inferredElementType.equals(libraryBuilder.resolveTypeName("System", "Any")) + || initialInferredElementType.equals( + libraryBuilder.resolveTypeName("System", "Any")))) { inferredElementType = compatibleType; } else { inferredElementType = libraryBuilder.resolveTypeName("System", "Any"); diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ConversionMap.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ConversionMap.java index fafbbca16..8ffbdaa79 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ConversionMap.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/ConversionMap.java @@ -7,6 +7,26 @@ import org.hl7.cql.model.*; public class ConversionMap { + public enum TypePrecedenceScore { + Simple(1), + Tuple(2), + Class(3), + Interval(4), + List(5), + Choice(6), + Other(7); + + private final int score; + + public int score() { + return score; + } + + TypePrecedenceScore(int score) { + this.score = score; + } + } + public enum ConversionScore { ExactMatch(0), SubType(1), @@ -30,6 +50,25 @@ public int score() { } } + public static int getTypePrecedenceScore(DataType operand) { + switch (operand.getClass().getSimpleName()) { + case "SimpleType": + return ConversionMap.TypePrecedenceScore.Simple.score(); + case "TupleType": + return ConversionMap.TypePrecedenceScore.Tuple.score(); + case "ClassType": + return ConversionMap.TypePrecedenceScore.Class.score(); + case "IntervalType": + return ConversionMap.TypePrecedenceScore.Interval.score(); + case "ListType": + return ConversionMap.TypePrecedenceScore.List.score(); + case "ChoiceType": + return ConversionMap.TypePrecedenceScore.Choice.score(); + default: + return ConversionMap.TypePrecedenceScore.Other.score(); + } + } + public static int getConversionScore(DataType callOperand, DataType operand, Conversion conversion) { if (operand.equals(callOperand)) { return ConversionMap.ConversionScore.ExactMatch.score(); diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java index 0b0588226..92ba632dd 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java @@ -62,9 +62,9 @@ public InstantiationResult instantiate( getResultType().instantiate(context)); result.setAccessLevel(getAccessLevel()); result.setLibraryName(getLibraryName()); - return new InstantiationResult(this, result, context.getConversionScore()); + return new InstantiationResult(this, result, typeMap, context.getConversionScore()); } - return new InstantiationResult(this, null, context.getConversionScore()); + return new InstantiationResult(this, null, null, context.getConversionScore()); } } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java index d44787a0e..ae508379d 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java @@ -1,16 +1,25 @@ package org.cqframework.cql.cql2elm.model; +import java.util.Map; +import org.hl7.cql.model.DataType; +import org.hl7.cql.model.TypeParameter; + /** * Created by Bryn on 12/22/2016. */ public class InstantiationResult { - public InstantiationResult(GenericOperator genericOperator, Operator operator, int conversionScore) { + public InstantiationResult( + GenericOperator genericOperator, + Operator operator, + Map typeMap, + int conversionScore) { if (genericOperator == null) { throw new IllegalArgumentException("genericOperator is required"); } this.genericOperator = genericOperator; this.operator = operator; + this.typeMap = typeMap; this.conversionScore = conversionScore; } @@ -26,6 +35,12 @@ public Operator getOperator() { return operator; } + private Map typeMap; + + public Map getTypeMap() { + return typeMap; + } + private int conversionScore; public int getConversionScore() { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java index 6aa93db5f..e0a3bb186 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java @@ -41,17 +41,50 @@ public Signature getSignature() { return operator.getSignature(); } + /* + The invocation signature is the call signature with arguments of type Any set to the operand types + */ + private Signature getInvocationSignature(Signature callSignature, Signature operatorSignature) { + if (callSignature.getSize() == operatorSignature.getSize()) { + DataType[] invocationTypes = new DataType[callSignature.getSize()]; + Iterator callTypes = callSignature.getOperandTypes().iterator(); + Iterator operatorTypes = + operatorSignature.getOperandTypes().iterator(); + boolean isResolved = false; + for (int i = 0; i < invocationTypes.length; i++) { + DataType callType = callTypes.next(); + DataType operatorType = operatorTypes.next(); + if (callType.equals(DataType.ANY) && !operatorType.equals(DataType.ANY)) { + isResolved = true; + invocationTypes[i] = operatorType; + } else { + invocationTypes[i] = callType; + } + } + if (isResolved) { + return new Signature(invocationTypes); + } + } + return callSignature; + } + public List resolve( CallContext callContext, ConversionMap conversionMap, OperatorMap operatorMap) { List results = null; - if (operator.getSignature().equals(callContext.getSignature())) { + Signature invocationSignature = getInvocationSignature(callContext.getSignature(), operator.getSignature()); + + // Attempt exact match against this signature + if (operator.getSignature().equals(invocationSignature)) { results = new ArrayList<>(); results.add(new OperatorResolution(operator)); return results; } + // Attempt to resolve against sub signatures results = subSignatures.resolve(callContext, conversionMap, operatorMap); - if (results == null && operator.getSignature().isSuperTypeOf(callContext.getSignature())) { + + // If no subsignatures match, attempt subType match against this signature + if (results == null && operator.getSignature().isSuperTypeOf(invocationSignature)) { results = new ArrayList<>(); results.add(new OperatorResolution(operator)); } @@ -277,60 +310,42 @@ public List resolve( throw new IllegalArgumentException("callContext is null"); } - List results = signatures.resolve(callContext, conversionMap, operatorMap); - - // If there is no resolution, or all resolutions require conversion, attempt to instantiate a generic signature - if (results == null || allResultsUseConversion(results)) { - // If the callContext signature contains choices, attempt instantiation with all possible combinations of - // the call signature (ouch, this could really hurt...) - boolean signaturesInstantiated = false; - List callSignatures = expandChoices(callContext.getSignature()); - for (Signature callSignature : callSignatures) { - Operator result = instantiate( - callSignature, operatorMap, conversionMap, callContext.getAllowPromotionAndDemotion()); - if (result != null && !signatures.contains(result)) { - // If the generic signature was instantiated, store it as an actual signature. - signatures.add(new SignatureNode(result)); - signaturesInstantiated = true; + // Attempt to instantiate any generic signatures + // If the callContext signature contains choices, attempt instantiation with all possible combinations of + // the call signature (ouch, this could really hurt...) + boolean signaturesInstantiated = false; + List callSignatures = expandChoices(callContext.getSignature()); + for (Signature callSignature : callSignatures) { + List instantiations = + instantiate(callSignature, operatorMap, conversionMap, callContext.getAllowPromotionAndDemotion()); + for (Operator instantiation : instantiations) { + // If the generic signature was instantiated, store it as an actual signature. + if (!signatures.contains(instantiation)) { + signatures.add(new SignatureNode(instantiation)); } } - - // re-attempt the resolution with the instantiated signature registered - if (signaturesInstantiated) { - results = signatures.resolve(callContext, conversionMap, operatorMap); - } } + List results = signatures.resolve(callContext, conversionMap, operatorMap); + return results; } - private Operator instantiate( + private List instantiate( Signature signature, OperatorMap operatorMap, ConversionMap conversionMap, boolean allowPromotionAndDemotion) { List instantiations = new ArrayList(); - int lowestConversionScore = Integer.MAX_VALUE; - Operator instantiation = null; + for (GenericOperator genericOperator : genericOperators.values()) { InstantiationResult instantiationResult = genericOperator.instantiate(signature, operatorMap, conversionMap, allowPromotionAndDemotion); if (instantiationResult.getOperator() != null) { - if (instantiationResult.getConversionScore() <= lowestConversionScore) { - if (instantiation == null || instantiationResult.getConversionScore() < lowestConversionScore) { - instantiation = instantiationResult.getOperator(); - lowestConversionScore = instantiationResult.getConversionScore(); - } else { - throw new IllegalArgumentException(String.format( - "Ambiguous generic instantiation of operator %s between signature %s and %s.", - this.name, - instantiation.getSignature().toString(), - instantiationResult.getOperator().getSignature().toString())); - } - } + instantiations.add(instantiationResult.getOperator()); } } - return instantiation; + return instantiations; } } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorMap.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorMap.java index 769c3598a..246c250be 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorMap.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorMap.java @@ -90,6 +90,28 @@ public OperatorResolution resolveOperator(CallContext callContext, ConversionMap } } + if (lowestScoringResults.size() > 1) { + int lowestTypeScore = Integer.MAX_VALUE; + List lowestTypeScoringResults = new ArrayList<>(); + for (OperatorResolution resolution : lowestScoringResults) { + int typeScore = ConversionMap.ConversionScore.ExactMatch.score(); + for (DataType operand : + resolution.getOperator().getSignature().getOperandTypes()) { + typeScore += ConversionMap.getTypePrecedenceScore(operand); + } + + if (typeScore < lowestTypeScore) { + lowestTypeScore = typeScore; + lowestTypeScoringResults.clear(); + lowestTypeScoringResults.add(resolution); + } else if (typeScore == lowestTypeScore) { + lowestTypeScoringResults.add(resolution); + } + } + + lowestScoringResults = lowestTypeScoringResults; + } + if (lowestScoringResults.size() > 1) { if (callContext.getMustResolve()) { // ERROR: diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java index 5d9ddf396..6a264b97e 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/SemanticTests.java @@ -373,13 +373,20 @@ void issue395() throws IOException { assertThat(expressionDef.getExpression().getLocalId(), notNullValue()); } + @Test + void issue435() throws IOException { + CqlTranslator translator = TestUtils.runSemanticTest("Issue435.cql", 2); + // [#435](https://github.com/cqframework/clinical_quality_language/issues/435) + assertThat(translator.getErrors().size(), equalTo(2)); + } + @Test void issue587() throws IOException { - CqlTranslator translator = TestUtils.runSemanticTest("Issue587.cql", 2); + CqlTranslator translator = TestUtils.runSemanticTest("Issue587.cql", 1); // This doesn't resolve correctly, collapse null should work, but it's related to this issue: // [#435](https://github.com/cqframework/clinical_quality_language/issues/435) // So keeping as a verification of current behavior here, will address as part of vNext - assertThat(translator.getErrors().size(), equalTo(2)); + assertThat(translator.getErrors().size(), equalTo(1)); } @Test diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java index afcfa35f5..85cb2a424 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java @@ -387,7 +387,7 @@ void abstractClassNotRetrievable() throws IOException { final CqlTranslator translator = TestUtils.runSemanticTest("abstractClassNotRetrievable.cql", 1); final List errors = translator.getErrors(); final List errorMessages = - errors.stream().map(Throwable::getMessage).toList(); + errors.stream().map(Throwable::getMessage).collect(Collectors.toList()); assertThat(errorMessages, contains("Specified data type DomainResource does not support retrieval.")); } } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/CqlListOperatorsTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/CqlListOperatorsTest.java index 5d5ee1507..c8e413dcd 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/CqlListOperatorsTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/operators/CqlListOperatorsTest.java @@ -42,6 +42,6 @@ static void setup() throws IOException { @Test void union() { ExpressionDef def = defs.get("Union123AndEmpty"); - assertThat(def, hasTypeAndResult(Union.class, "list")); + assertThat(def, hasTypeAndResult(Union.class, "list")); } } diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json index 0d7a10925..d92cc0903 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.json @@ -412,6 +412,19 @@ } ], "where" : { "type" : "IncludedIn", + "signature" : [ { + "type" : "IntervalTypeSpecifier", + "pointType" : { + "type" : "NamedTypeSpecifier", + "name" : "{urn:hl7-org:elm-types:r1}DateTime" + } + }, { + "type" : "IntervalTypeSpecifier", + "pointType" : { + "type" : "NamedTypeSpecifier", + "name" : "{urn:hl7-org:elm-types:r1}DateTime" + } + } ], "operand" : [ { "type" : "Property", "path" : "period", diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml index 4d7d0c31e..2721f5a87 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/CMS146v2_Expected_SignatureLevel_Overloads.xml @@ -184,6 +184,14 @@ + + + + + + + + @@ -333,4 +341,4 @@ - + \ No newline at end of file diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/Issue435.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/Issue435.cql new file mode 100644 index 000000000..73f282bfb --- /dev/null +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/Issue435.cql @@ -0,0 +1,10 @@ +/* +@issue: [#435](https://github.com/cqframework/clinical_quality_language/issues/435) + */ +library Issue435 + +/* +These both now correctly result in ambiguous resolution among the various overloads of Equal for the system types +*/ +define Test1: null ~ null +define Test2: null = null \ No newline at end of file diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/OpioidCDSSTU3/cql/OMTKData2019.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/OpioidCDSSTU3/cql/OMTKData2019.cql index 21084ac05..e95d91690 100644 --- a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/OpioidCDSSTU3/cql/OMTKData2019.cql +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/OpioidCDSSTU3/cql/OMTKData2019.cql @@ -113,7 +113,7 @@ define DrugIngredients: { drugCode: 247626, drugName: 'Oxycodone 10 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Rectal Suppository', ingredientCode: 7804, ingredientName: 'Oxycodone', strength: ' 10 MG', strengthValue: 10.0 , strengthUnit: 'mg' }, { drugCode: 247627, drugName: 'Oxycodone 20 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Rectal Suppository', ingredientCode: 7804, ingredientName: 'Oxycodone', strength: '20 mg', strengthValue: 20.0, strengthUnit: 'MG' }, { drugCode: 248307, drugName: 'Oxycodone 30 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Rectal Suppository', ingredientCode: 7804, ingredientName: 'Oxycodone', strength: '30 mg', strengthValue: 30.0, strengthUnit: 'MG' }, - { drugCode: 248477, drugName: 'Belladonna Alkaloids 15 MG / Opium 65 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676 , ingredientName: 'Opium', strength: '65 MG', strengthValue: 65, strengthUnit: 'MG' }, + { drugCode: 248477, drugName: 'Belladonna Alkaloids 15 MG / Opium 65 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676 , ingredientName: 'Opium', strength: '65 MG', strengthValue: 65.0, strengthUnit: 'MG' }, { drugCode: 250426, drugName: 'Buprenorphine 0.4 MG Sublingual Tablet', doseFormCode: 317007, doseFormName: 'Sublingual Tablet', ingredientCode: 1819, ingredientName: 'Buprenorphine', strength: '0.4 MG', strengthValue: 0.4, strengthUnit: 'MG' }, { drugCode: 250485, drugName: 'Pentazocine 25 MG Oral Tablet', doseFormCode: 317541, doseFormName: 'Oral Tablet', ingredientCode: 8001, ingredientName: 'Pentazocine', strength: '25 MG', strengthValue: 25.0, strengthUnit: 'MG' }, { drugCode: 250486, drugName: 'Pentazocine 50 MG Oral Capsule', doseFormCode: 316965, doseFormName: 'Oral Capsule', ingredientCode: 8001, ingredientName: 'Pentazocine', strength: '50 MG', strengthValue: 50.0, strengthUnit: 'MG' }, @@ -136,8 +136,8 @@ define DrugIngredients: { drugCode: 310297, drugName: 'Fentanyl 0.4 MG Oral Lozenge', doseFormCode: 316992, doseFormName: 'Oral Lozenge', ingredientCode: 4337, ingredientName: 'Fentanyl', strength: '0.4 MG', strengthValue: 0.4, strengthUnit: 'MG' }, { drugCode: 311297, drugName: 'Levomethadyl 10 MG/ML Oral Solution', doseFormCode: 316968, doseFormName: 'Oral Solution', ingredientCode: 237005, ingredientName: 'Levomethadyl', strength: '10 MG/ML', strengthValue: 10.0, strengthUnit: 'MG/ML' }, { drugCode: 311300, drugName: 'Levorphanol 2 MG/ML Injectable Solution', doseFormCode: 316949, doseFormName: 'Injectable Solution', ingredientCode: 6378, ingredientName: 'Levorphanol', strength: '2 MG/ML', strengthValue: 2.0, strengthUnit: 'MG/ML' }, - { drugCode: 312104, drugName: 'Belladonna Alkaloids 16.2 MG / Opium 30 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676, ingredientName: 'Opium', strength: '30 MG ', strengthValue: 30, strengthUnit: 'MG' }, - { drugCode: 312107, drugName: 'Belladonna Alkaloids 16.2 MG / Opium 60 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676, ingredientName: 'Opium', strength: '60 MG', strengthValue: 60, strengthUnit: 'MG' }, + { drugCode: 312104, drugName: 'Belladonna Alkaloids 16.2 MG / Opium 30 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676, ingredientName: 'Opium', strength: '30 MG ', strengthValue: 30.0, strengthUnit: 'MG' }, + { drugCode: 312107, drugName: 'Belladonna Alkaloids 16.2 MG / Opium 60 MG Rectal Suppository', doseFormCode: 316978, doseFormName: 'Suppository', ingredientCode: 7676, ingredientName: 'Opium', strength: '60 MG', strengthValue: 60.0, strengthUnit: 'MG' }, { drugCode: 312288, drugName: 'Acetaminophen 650 MG / Pentazocine 25 MG Oral Tablet', doseFormCode: 317541, doseFormName: 'Oral Tablet', ingredientCode: 8001, ingredientName: 'Pentazocine', strength: '25 MG', strengthValue: 25.0, strengthUnit: 'MG' }, { drugCode: 312289, drugName: 'Naloxone 0.5 MG / Pentazocine 50 MG Oral Tablet', doseFormCode: 317541, doseFormName: 'Oral Tablet', ingredientCode: 8001, ingredientName: 'Pentazocine', strength: '50 MG', strengthValue: 50.0, strengthUnit: 'MG' }, { drugCode: 313992, drugName: 'Fentanyl 0.6 MG Oral Lozenge', doseFormCode: 316992, doseFormName: 'Oral Lozenge', ingredientCode: 4337, ingredientName: 'Fentanyl', strength: '0.6 MG', strengthValue: 0.6, strengthUnit: 'MG' }, @@ -178,7 +178,7 @@ define DrugIngredients: { drugCode: 828581, drugName: 'Acetaminophen 650 MG / Propoxyphene Hydrochloride 65 MG Oral Tablet', doseFormCode: 317541, doseFormName: 'Oral Tablet', ingredientCode: 8785, ingredientName: 'Propoxyphene', strength: '65 MG', strengthValue: 65.0, strengthUnit: 'MG' }, { drugCode: 828585, drugName: 'Aspirin 389 MG / Caffeine 32.4 MG / Propoxyphene Hydrochloride 32 MG Oral Capsule', doseFormCode: 316965, doseFormName: 'Oral Capsule', ingredientCode: 8785, ingredientName: 'Propoxyphene', strength: '32 MG', strengthValue: 32.0, strengthUnit: 'MG' }, { drugCode: 828594, drugName: 'Aspirin 389 MG / Caffeine 32.4 MG / Propoxyphene Hydrochloride 65 MG Oral Capsule', doseFormCode: 316965, doseFormName: 'Oral Capsule', ingredientCode: 8785, ingredientName: 'Propoxyphene', strength: '65 MG', strengthValue: 65.0, strengthUnit: 'MG' }, - { drugCode: 830196, drugName: 'Opium tincture 100 MG/ML Oral Solution', doseFormCode: 316968, doseFormName: 'Oral', ingredientCode: 7676, ingredientName: 'opium tincture ', strength: ' 100 MG/ML', strengthValue: 100, strengthUnit: 'MG/ML' }, + { drugCode: 830196, drugName: 'Opium tincture 100 MG/ML Oral Solution', doseFormCode: 316968, doseFormName: 'Oral', ingredientCode: 7676, ingredientName: 'opium tincture ', strength: ' 100 MG/ML', strengthValue: 100.0, strengthUnit: 'MG/ML' }, { drugCode: 833036, drugName: 'Acetaminophen 750 MG / Hydrocodone Bitartrate 7.5 MG Oral Tablet', doseFormCode: 317541, doseFormName: 'Oral Tablet', ingredientCode: 5489, ingredientName: 'Hydrocodone', strength: '7.5 MG', strengthValue: 7.5, strengthUnit: 'MG' }, { drugCode: 833709, drugName: '24 HR tramadol hydrochloride 100 MG Extended Release Oral Tablet', doseFormCode: 316945, doseFormName: 'Extended Release Oral Tablet', ingredientCode: 10689, ingredientName: 'Tramadol', strength: '100 MG', strengthValue: 100.0, strengthUnit: 'MG' }, { drugCode: 833710, drugName: 'Matrix Delivery 24 HR tramadol hydrochloride 100 MG Extended Release Oral Tablet [Ryzolt]', doseFormCode: 316945, doseFormName: 'Extended Release Oral Tablet', ingredientCode: 10689, ingredientName: 'Tramadol', strength: '100 MG', strengthValue: 100.0, strengthUnit: 'MG' }, diff --git a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java index 46ebd22be..cc5319bed 100644 --- a/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java +++ b/Src/java/engine/src/test/java/org/opencds/cqf/cql/engine/execution/ListOperatorsTest.java @@ -7,10 +7,7 @@ import static org.opencds.cqf.cql.engine.elm.executing.EquivalentEvaluator.equivalent; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import org.cqframework.cql.cql2elm.CqlCompilerException; import org.cqframework.cql.cql2elm.CqlCompilerOptions; import org.junit.jupiter.api.Test; diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.java b/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.java index 47a6976da..273859720 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.java +++ b/Src/java/model/src/main/java/org/hl7/cql/model/IntervalType.java @@ -69,6 +69,10 @@ public boolean isGeneric() { @Override public boolean isInstantiable(DataType callType, InstantiationContext context) { + if (callType.equals(DataType.ANY)) { + return pointType.isInstantiable(callType, context); + } + if (callType instanceof IntervalType) { IntervalType intervalType = (IntervalType) callType; return pointType.isInstantiable(intervalType.pointType, context); diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ListType.java b/Src/java/model/src/main/java/org/hl7/cql/model/ListType.java index e9c34cde5..13dd6b7e3 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ListType.java +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ListType.java @@ -69,6 +69,10 @@ public boolean isGeneric() { @Override public boolean isInstantiable(DataType callType, InstantiationContext context) { + if (callType.equals(DataType.ANY)) { + return elementType.isInstantiable(callType, context); + } + if (callType instanceof ListType) { ListType listType = (ListType) callType; return elementType.isInstantiable(listType.elementType, context); diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java index 587619a05..79474bc31 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java +++ b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java @@ -164,6 +164,10 @@ public boolean isGeneric() { @Override public boolean isInstantiable(DataType callType, InstantiationContext context) { + if (callType.equals(DataType.ANY)) { + return true; + } + if (callType instanceof TupleType) { TupleType tupleType = (TupleType) callType; if (elements.size() == tupleType.elements.size()) { From 49ff33b4507924625f8f88ed5be9e412c3d0c196 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Tue, 29 Oct 2024 22:17:07 -0600 Subject: [PATCH 2/7] Fixes from regression testing --- .../cql/cql2elm/LibraryBuilder.java | 36 +++++++ .../cql/cql2elm/model/OperatorEntry.java | 100 ++++++++++++++---- .../cql/cql2elm/model/OperatorResolution.java | 5 +- .../cql/cql2elm/TranslationTests.java | 77 ++++++++++++++ .../cql/cql2elm/fhir/r4/BaseTest.java | 20 ++-- .../cql/cql2elm/fhir/r401/BaseTest.java | 20 ++-- .../cql/cql2elm/fhir/stu3/BaseTest.java | 18 ++-- .../cql/cql2elm/fhir/stu301/BaseTest.java | 12 +-- .../cql/cql2elm/quick/v330/BaseTest.java | 18 ++-- .../ResolutionTests/ProperlyIncludesTests.cql | 9 ++ .../cql/cql2elm/fhir/r4/TestFHIRTiming.cql | 1 + 11 files changed, 249 insertions(+), 67 deletions(-) create mode 100644 Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/ResolutionTests/ProperlyIncludesTests.cql diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java index 4ece6bfc9..9e66f360d 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java @@ -1098,12 +1098,48 @@ public Invocation resolveProperContainsInvocation( return resolveBinaryInvocation("System", "ProperContains", properContains); } + private int getTypeScore(OperatorResolution resolution) { + int typeScore = ConversionMap.ConversionScore.ExactMatch.score(); + for (DataType operand : + resolution.getOperator().getSignature().getOperandTypes()) { + typeScore += ConversionMap.getTypePrecedenceScore(operand); + } + + return typeScore; + } + private Expression lowestScoringInvocation(Invocation primary, Invocation secondary) { if (primary != null) { if (secondary != null) { if (secondary.getResolution().getScore() < primary.getResolution().getScore()) { return secondary.getExpression(); + } else if (primary.getResolution().getScore() < secondary.getResolution().getScore()) { + return primary.getExpression(); + } + if (primary.getResolution().getScore() == secondary.getResolution().getScore()) { + int primaryTypeScore = getTypeScore(primary.getResolution()); + int secondaryTypeScore = getTypeScore(secondary.getResolution()); + + if (secondaryTypeScore < primaryTypeScore) { + return secondary.getExpression(); + } else if (primaryTypeScore < secondaryTypeScore) { + return primary.getExpression(); + } else { + // ERROR: + StringBuilder message = new StringBuilder("Call to operator ") + .append(primary.getResolution().getOperator().getName()) + .append("/") + .append(secondary.getResolution().getOperator().getName()) + .append(" is ambiguous with: ") + .append("\n - ") + .append(primary.getResolution().getOperator().getName()) + .append(primary.getResolution().getOperator().getSignature()) + .append("\n - ") + .append(secondary.getResolution().getOperator().getName()) + .append(secondary.getResolution().getOperator().getSignature()); + throw new IllegalArgumentException(message.toString()); + } } } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java index e0a3bb186..9c8f87d04 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java @@ -68,6 +68,24 @@ private Signature getInvocationSignature(Signature callSignature, Signature oper return callSignature; } + private OperatorResolution getOperatorResolution( + Operator operator, + Signature callSignature, + Signature invocationSignature, + ConversionMap conversionMap, + OperatorMap operatorMap, + boolean allowPromotionAndDemotion, + boolean requireConversions) { + Conversion[] conversions = getConversions( + callSignature, operator.getSignature(), conversionMap, operatorMap, allowPromotionAndDemotion); + OperatorResolution result = new OperatorResolution( + operator, conversions); + if (requireConversions && conversions == null) { + return null; + } + return result; + } + public List resolve( CallContext callContext, ConversionMap conversionMap, OperatorMap operatorMap) { List results = null; @@ -75,9 +93,19 @@ public List resolve( // Attempt exact match against this signature if (operator.getSignature().equals(invocationSignature)) { - results = new ArrayList<>(); - results.add(new OperatorResolution(operator)); - return results; + OperatorResolution result = getOperatorResolution( + operator, + callContext.getSignature(), + invocationSignature, + conversionMap, + operatorMap, + callContext.getAllowPromotionAndDemotion(), + false); + if (result != null) { + results = new ArrayList<>(); + results.add(result); + return results; + } } // Attempt to resolve against sub signatures @@ -85,33 +113,65 @@ public List resolve( // If no subsignatures match, attempt subType match against this signature if (results == null && operator.getSignature().isSuperTypeOf(invocationSignature)) { - results = new ArrayList<>(); - results.add(new OperatorResolution(operator)); + OperatorResolution result = getOperatorResolution( + operator, + callContext.getSignature(), + invocationSignature, + conversionMap, + operatorMap, + callContext.getAllowPromotionAndDemotion(), + false); + if (result != null) { + results = new ArrayList<>(); + results.add(result); + return results; + } } if (results == null && conversionMap != null) { // Attempt to find a conversion path from the call signature to the target signature - Conversion[] conversions = - new Conversion[operator.getSignature().getSize()]; - boolean isConvertible = callContext - .getSignature() - .isConvertibleTo( - operator.getSignature(), - conversionMap, - operatorMap, - callContext.getAllowPromotionAndDemotion(), - conversions); - if (isConvertible) { - OperatorResolution resolution = new OperatorResolution(operator); - resolution.setConversions(conversions); - results = new ArrayList<>(); - results.add(resolution); + OperatorResolution result = getOperatorResolution( + operator, + callContext.getSignature(), + invocationSignature, + conversionMap, + operatorMap, + callContext.getAllowPromotionAndDemotion(), + true); + if (result != null) { + if (results == null) { + results = new ArrayList<>(); + } + results.add(result); } } return results; } + private Conversion[] getConversions( + Signature callSignature, + Signature operatorSignature, + ConversionMap conversionMap, + OperatorMap operatorMap, + boolean allowPromotionAndDemotion) { + if (callSignature == null + || operatorSignature == null + || callSignature.getSize() != operatorSignature.getSize()) { + return null; + } + + Conversion[] conversions = new Conversion[callSignature.getSize()]; + boolean isConvertible = callSignature.isConvertibleTo( + operatorSignature, conversionMap, operatorMap, allowPromotionAndDemotion, conversions); + + if (isConvertible) { + return conversions; + } + + return null; + } + private SignatureNodes subSignatures = new SignatureNodes(); public boolean hasSubSignatures() { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorResolution.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorResolution.java index 7ca38d7d6..507429091 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorResolution.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorResolution.java @@ -7,8 +7,11 @@ public class OperatorResolution { public OperatorResolution() {} - public OperatorResolution(Operator operator) { + public OperatorResolution(Operator operator, Conversion[] conversions) { this.operator = operator; + if (conversions != null) { + setConversions(conversions); + } } private Operator operator; diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java index 85cb2a424..808511f6d 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java @@ -17,6 +17,8 @@ import java.util.stream.Collectors; import org.cqframework.cql.elm.tracking.TrackBack; import org.hamcrest.Matchers; +import org.hl7.cql.model.IntervalType; +import org.hl7.cql.model.SimpleType; import org.hl7.cql_annotations.r1.CqlToElmInfo; import org.hl7.elm.r1.*; import org.junit.jupiter.api.Disabled; @@ -329,6 +331,81 @@ void multiThreadedTranslation() throws IOException { CompletableFuture.allOf(cfs).join(); } + @Test + void resolutionProperlyIncludesTests() throws IOException { + final CqlTranslator translator = TestUtils.runSemanticTest("ResolutionTests/ProperlyIncludesTests.cql", 0); + Library compiledLibrary = translator.getTranslatedLibrary().getLibrary(); + List statements = compiledLibrary.getStatements().getDef(); + + assertThat(statements.size(), equalTo(5)); + + ExpressionDef test = statements.get(0); + assertThat(test.getExpression(), instanceOf(ProperContains.class)); + ProperContains properContains = (ProperContains)test.getExpression(); + assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); + Interval interval = (Interval)properContains.getOperand().get(0); + assertThat(interval.getResultType(), instanceOf(IntervalType.class)); + IntervalType intervalType = (IntervalType)interval.getResultType(); + assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); + SimpleType pointType = (SimpleType)intervalType.getPointType(); + assertThat(pointType.getName(), equalTo("System.Integer")); + assertThat(properContains.getOperand().get(1), instanceOf(As.class)); + As _as = (As)properContains.getOperand().get(1); + assertThat(_as.getAsType().toString(), equalTo("{urn:hl7-org:elm-types:r1}Integer")); + assertThat(_as.getOperand(), instanceOf(Null.class)); + + test = statements.get(1); + assertThat(test.getExpression(), instanceOf(ProperContains.class)); + properContains = (ProperContains)test.getExpression(); + assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); + interval = (Interval)properContains.getOperand().get(0); + assertThat(interval.getResultType(), instanceOf(IntervalType.class)); + intervalType = (IntervalType)interval.getResultType(); + assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); + pointType = (SimpleType)intervalType.getPointType(); + assertThat(pointType.getName(), equalTo("System.Integer")); + assertThat(properContains.getOperand().get(1), instanceOf(As.class)); + _as = (As)properContains.getOperand().get(1); + assertThat(_as.getAsType().toString(), equalTo("{urn:hl7-org:elm-types:r1}Integer")); + assertThat(_as.getOperand(), instanceOf(Null.class)); + + test = statements.get(2); + assertThat(test.getExpression(), instanceOf(ProperContains.class)); + properContains = (ProperContains)test.getExpression(); + assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); + interval = (Interval)properContains.getOperand().get(0); + assertThat(interval.getResultType(), instanceOf(IntervalType.class)); + intervalType = (IntervalType)interval.getResultType(); + assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); + pointType = (SimpleType)intervalType.getPointType(); + assertThat(pointType.getName(), equalTo("System.Any")); + assertThat(properContains.getOperand().get(1), instanceOf(Null.class)); + + test = statements.get(3); + assertThat(test.getExpression(), instanceOf(ProperContains.class)); + properContains = (ProperContains)test.getExpression(); + assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); + interval = (Interval)properContains.getOperand().get(0); + assertThat(interval.getResultType(), instanceOf(IntervalType.class)); + intervalType = (IntervalType)interval.getResultType(); + assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); + pointType = (SimpleType)intervalType.getPointType(); + assertThat(pointType.getName(), equalTo("System.Any")); + assertThat(properContains.getOperand().get(1), instanceOf(Null.class)); + + test = statements.get(4); + assertThat(test.getExpression(), instanceOf(ProperContains.class)); + properContains = (ProperContains)test.getExpression(); + assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); + interval = (Interval)properContains.getOperand().get(0); + assertThat(interval.getResultType(), instanceOf(IntervalType.class)); + intervalType = (IntervalType)interval.getResultType(); + assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); + pointType = (SimpleType)intervalType.getPointType(); + assertThat(pointType.getName(), equalTo("System.Integer")); + assertThat(properContains.getOperand().get(1), instanceOf(As.class)); + } + @Test void hidingVariousUseCases() throws IOException { final CqlTranslator translator = TestUtils.runSemanticTest("HidingTests/TestHidingVariousUseCases.cql", 0); diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r4/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r4/BaseTest.java index 27abd12d5..c6227e015 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r4/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r4/BaseTest.java @@ -55,10 +55,10 @@ void fhirTiming() throws IOException { ExpressionDef def = (ExpressionDef) visitFile("fhir/r4/TestFHIRTiming.cql"); // Query-> // where-> - // IncludedIn-> + // In-> // left-> - // ToInterval() - // As(fhir:Period) -> + // ToDateTime() + // As(fhir:dateTime) -> // Property(P.performed) // right-> MeasurementPeriod Query query = (Query) def.getExpression(); @@ -69,16 +69,16 @@ void fhirTiming() throws IOException { Retrieve request = (Retrieve) source.getExpression(); assertThat(request.getDataType(), quickDataType("Procedure")); - // Then check that the where an IncludedIn with a ToInterval as the left operand + // Then check that the where is an In with a ToDateTime as the left operand Expression where = query.getWhere(); - assertThat(where, instanceOf(IncludedIn.class)); - IncludedIn includedIn = (IncludedIn) where; - assertThat(includedIn.getOperand().get(0), instanceOf(FunctionRef.class)); - FunctionRef functionRef = (FunctionRef) includedIn.getOperand().get(0); - assertThat(functionRef.getName(), is("ToInterval")); + assertThat(where, instanceOf(In.class)); + In in = (In) where; + assertThat(in.getOperand().get(0), instanceOf(FunctionRef.class)); + FunctionRef functionRef = (FunctionRef) in.getOperand().get(0); + assertThat(functionRef.getName(), is("ToDateTime")); assertThat(functionRef.getOperand().get(0), instanceOf(As.class)); As asExpression = (As) functionRef.getOperand().get(0); - assertThat(asExpression.getAsType().getLocalPart(), is("Period")); + assertThat(asExpression.getAsType().getLocalPart(), is("dateTime")); assertThat(asExpression.getOperand(), instanceOf(Property.class)); Property property = (Property) asExpression.getOperand(); assertThat(property.getScope(), is("P")); diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java index 37aea3a22..84b66898d 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/r401/BaseTest.java @@ -59,10 +59,10 @@ void fhirTiming() throws IOException { ExpressionDef def = (ExpressionDef) visitFile("fhir/r401/TestFHIRTiming.cql"); // Query-> // where-> - // IncludedIn-> + // In-> // left-> - // ToInterval() - // As(fhir:Period) -> + // ToDateTime() + // As(fhir:dateTime) -> // Property(P.performed) // right-> MeasurementPeriod Query query = (Query) def.getExpression(); @@ -73,16 +73,16 @@ void fhirTiming() throws IOException { Retrieve request = (Retrieve) source.getExpression(); assertThat(request.getDataType(), quickDataType("Procedure")); - // Then check that the where an IncludedIn with a ToInterval as the left operand + // Then check that the where is an In with a ToDateTime as the left operand Expression where = query.getWhere(); - assertThat(where, instanceOf(IncludedIn.class)); - IncludedIn includedIn = (IncludedIn) where; - assertThat(includedIn.getOperand().get(0), instanceOf(FunctionRef.class)); - FunctionRef functionRef = (FunctionRef) includedIn.getOperand().get(0); - assertThat(functionRef.getName(), is("ToInterval")); + assertThat(where, instanceOf(In.class)); + In in = (In) where; + assertThat(in.getOperand().get(0), instanceOf(FunctionRef.class)); + FunctionRef functionRef = (FunctionRef) in.getOperand().get(0); + assertThat(functionRef.getName(), is("ToDateTime")); assertThat(functionRef.getOperand().get(0), instanceOf(As.class)); As asExpression = (As) functionRef.getOperand().get(0); - assertThat(asExpression.getAsType().getLocalPart(), is("Period")); + assertThat(asExpression.getAsType().getLocalPart(), is("dateTime")); assertThat(asExpression.getOperand(), instanceOf(Property.class)); Property property = (Property) asExpression.getOperand(); assertThat(property.getScope(), is("P")); diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu3/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu3/BaseTest.java index bfdaf1916..8ea70b1b0 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu3/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu3/BaseTest.java @@ -51,10 +51,10 @@ void fhirTiming() throws IOException { ExpressionDef def = (ExpressionDef) visitFile("fhir/stu3/TestFHIRTiming.cql"); // Query-> // where-> - // IncludedIn-> + // In-> // left-> - // ToInterval() - // As(fhir:Period) -> + // ToDateTime() + // As(fhir:dateTime) -> // Property(P.performed) // right-> MeasurementPeriod Query query = (Query) def.getExpression(); @@ -67,14 +67,14 @@ void fhirTiming() throws IOException { // Then check that the where an IncludedIn with a Case as the left operand Expression where = query.getWhere(); - assertThat(where, instanceOf(IncludedIn.class)); - IncludedIn includedIn = (IncludedIn) where; - assertThat(includedIn.getOperand().get(0), instanceOf(FunctionRef.class)); - FunctionRef functionRef = (FunctionRef) includedIn.getOperand().get(0); - assertThat(functionRef.getName(), is("ToInterval")); + assertThat(where, instanceOf(In.class)); + In in = (In) where; + assertThat(in.getOperand().get(0), instanceOf(FunctionRef.class)); + FunctionRef functionRef = (FunctionRef) in.getOperand().get(0); + assertThat(functionRef.getName(), is("ToDateTime")); assertThat(functionRef.getOperand().get(0), instanceOf(As.class)); As asExpression = (As) functionRef.getOperand().get(0); - assertThat(asExpression.getAsType().getLocalPart(), is("Period")); + assertThat(asExpression.getAsType().getLocalPart(), is("dateTime")); assertThat(asExpression.getOperand(), instanceOf(Property.class)); Property property = (Property) asExpression.getOperand(); assertThat(property.getScope(), is("P")); diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu301/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu301/BaseTest.java index ee06cb82f..a9cf737d1 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu301/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/fhir/stu301/BaseTest.java @@ -69,14 +69,14 @@ void fhirTiming() throws IOException { // Then check that the where an IncludedIn with a ToInterval as the left operand Expression where = query.getWhere(); - assertThat(where, instanceOf(IncludedIn.class)); - IncludedIn includedIn = (IncludedIn) where; - assertThat(includedIn.getOperand().get(0), instanceOf(FunctionRef.class)); - FunctionRef functionRef = (FunctionRef) includedIn.getOperand().get(0); - assertThat(functionRef.getName(), is("ToInterval")); + assertThat(where, instanceOf(In.class)); + In in = (In) where; + assertThat(in.getOperand().get(0), instanceOf(FunctionRef.class)); + FunctionRef functionRef = (FunctionRef) in.getOperand().get(0); + assertThat(functionRef.getName(), is("ToDateTime")); assertThat(functionRef.getOperand().get(0), instanceOf(As.class)); As asExpression = (As) functionRef.getOperand().get(0); - assertThat(asExpression.getAsType().getLocalPart(), is("Period")); + assertThat(asExpression.getAsType().getLocalPart(), is("dateTime")); assertThat(asExpression.getOperand(), instanceOf(Property.class)); Property property = (Property) asExpression.getOperand(); assertThat(property.getScope(), is("P")); diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/quick/v330/BaseTest.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/quick/v330/BaseTest.java index 67133edf9..0fddd1fd8 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/quick/v330/BaseTest.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/quick/v330/BaseTest.java @@ -55,9 +55,9 @@ void fhirTiming() throws IOException { ExpressionDef def = (ExpressionDef) visitFile("quick/v330/TestFHIRTiming.cql"); // Query-> // where-> - // IncludedIn-> + // In-> // left-> - // As(Interval) -> + // As(DateTime) -> // Property(P.performed) // right-> MeasurementPeriod Query query = (Query) def.getExpression(); @@ -70,15 +70,11 @@ void fhirTiming() throws IOException { // Then check that the where an IncludedIn with a Case as the left operand Expression where = query.getWhere(); - assertThat(where, instanceOf(IncludedIn.class)); - IncludedIn includedIn = (IncludedIn) where; - assertThat(includedIn.getOperand().get(0), instanceOf(As.class)); - As asExpression = (As) includedIn.getOperand().get(0); - assertThat(asExpression.getAsTypeSpecifier(), instanceOf(IntervalTypeSpecifier.class)); - IntervalTypeSpecifier intervalTypeSpecifier = (IntervalTypeSpecifier) asExpression.getAsTypeSpecifier(); - assertThat(intervalTypeSpecifier.getPointType(), instanceOf(NamedTypeSpecifier.class)); - NamedTypeSpecifier namedTypeSpecifier = (NamedTypeSpecifier) intervalTypeSpecifier.getPointType(); - assertThat(namedTypeSpecifier.getName().getLocalPart(), is("DateTime")); + assertThat(where, instanceOf(In.class)); + In in = (In) where; + assertThat(in.getOperand().get(0), instanceOf(As.class)); + As asExpression = (As) in.getOperand().get(0); + assertThat(asExpression.getAsType().getLocalPart(), equalTo("DateTime")); assertThat(asExpression.getOperand(), instanceOf(Property.class)); Property property = (Property) asExpression.getOperand(); assertThat(property.getScope(), is("P")); diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/ResolutionTests/ProperlyIncludesTests.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/ResolutionTests/ProperlyIncludesTests.cql new file mode 100644 index 000000000..57b834ec7 --- /dev/null +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/ResolutionTests/ProperlyIncludesTests.cql @@ -0,0 +1,9 @@ +library ProperlyIncludesTests + +// These should all resolve to ProperContains(Interval, Integer) +// ProperContains(Interval, Integer) +define TestA: Interval[1, null] properly includes null +define TestB: Interval[1, null) properly includes null +define TestC: Interval[null, null] properly includes null +define TestD: Interval(null, null) properly includes null +define TestE: Interval[1, null] properly includes null as Choice> diff --git a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r4/TestFHIRTiming.cql b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r4/TestFHIRTiming.cql index 2428f8486..c2e262560 100644 --- a/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r4/TestFHIRTiming.cql +++ b/Src/java/cql-to-elm/src/test/resources/org/cqframework/cql/cql2elm/fhir/r4/TestFHIRTiming.cql @@ -15,4 +15,5 @@ define Procedures: // Because performed is a "choice", it could be interval-valued, or it could be datetime-valued // In that case, it should continue to treat it as an interval timing phrase, not a left-point-valued timing phrase // Fixed much more generally with a combination of interval promotion/demotion and better instantiation in the presence of choice types + // NOTE: As of 1.5.3 with the clarification of type precedence (Simple, Class, Tuple, Interval, List) this resolves as an In, not an IncludedIn where P.performed included in "Measurement Period" From 4866823f5f474bd738e5d49b5273bd44786bd2ad Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Tue, 29 Oct 2024 22:51:22 -0600 Subject: [PATCH 3/7] Spotless and quality gate fixes --- .../cql/cql2elm/Cql2ElmVisitor.java | 4 ++ .../cql/cql2elm/LibraryBuilder.java | 9 ++-- .../cql/cql2elm/model/OperatorEntry.java | 3 +- .../cql/cql2elm/TranslationTests.java | 44 +++++++++---------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java index c4c1de08e..d5041a294 100755 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/Cql2ElmVisitor.java @@ -734,6 +734,10 @@ public Object visitListSelector(cqlParser.ListSelectorContext ctx) { for (cqlParser.ExpressionContext elementContext : ctx.expression()) { Expression element = parseExpression(elementContext); + if (element == null) { + throw new RuntimeException("Element failed to parse"); + } + if (elementType != null) { libraryBuilder.verifyType(element.getResultType(), elementType); } else { diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java index 9e66f360d..a4fc5efcf 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/LibraryBuilder.java @@ -1100,8 +1100,7 @@ public Invocation resolveProperContainsInvocation( private int getTypeScore(OperatorResolution resolution) { int typeScore = ConversionMap.ConversionScore.ExactMatch.score(); - for (DataType operand : - resolution.getOperator().getSignature().getOperandTypes()) { + for (DataType operand : resolution.getOperator().getSignature().getOperandTypes()) { typeScore += ConversionMap.getTypePrecedenceScore(operand); } @@ -1114,10 +1113,12 @@ private Expression lowestScoringInvocation(Invocation primary, Invocation second if (secondary.getResolution().getScore() < primary.getResolution().getScore()) { return secondary.getExpression(); - } else if (primary.getResolution().getScore() < secondary.getResolution().getScore()) { + } else if (primary.getResolution().getScore() + < secondary.getResolution().getScore()) { return primary.getExpression(); } - if (primary.getResolution().getScore() == secondary.getResolution().getScore()) { + if (primary.getResolution().getScore() + == secondary.getResolution().getScore()) { int primaryTypeScore = getTypeScore(primary.getResolution()); int secondaryTypeScore = getTypeScore(secondary.getResolution()); diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java index 9c8f87d04..ed1a17a34 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/OperatorEntry.java @@ -78,8 +78,7 @@ private OperatorResolution getOperatorResolution( boolean requireConversions) { Conversion[] conversions = getConversions( callSignature, operator.getSignature(), conversionMap, operatorMap, allowPromotionAndDemotion); - OperatorResolution result = new OperatorResolution( - operator, conversions); + OperatorResolution result = new OperatorResolution(operator, conversions); if (requireConversions && conversions == null) { return null; } diff --git a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java index 808511f6d..876205432 100644 --- a/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java +++ b/Src/java/cql-to-elm/src/test/java/org/cqframework/cql/cql2elm/TranslationTests.java @@ -341,67 +341,67 @@ void resolutionProperlyIncludesTests() throws IOException { ExpressionDef test = statements.get(0); assertThat(test.getExpression(), instanceOf(ProperContains.class)); - ProperContains properContains = (ProperContains)test.getExpression(); + ProperContains properContains = (ProperContains) test.getExpression(); assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); - Interval interval = (Interval)properContains.getOperand().get(0); + Interval interval = (Interval) properContains.getOperand().get(0); assertThat(interval.getResultType(), instanceOf(IntervalType.class)); - IntervalType intervalType = (IntervalType)interval.getResultType(); + IntervalType intervalType = (IntervalType) interval.getResultType(); assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); - SimpleType pointType = (SimpleType)intervalType.getPointType(); + SimpleType pointType = (SimpleType) intervalType.getPointType(); assertThat(pointType.getName(), equalTo("System.Integer")); assertThat(properContains.getOperand().get(1), instanceOf(As.class)); - As _as = (As)properContains.getOperand().get(1); + As _as = (As) properContains.getOperand().get(1); assertThat(_as.getAsType().toString(), equalTo("{urn:hl7-org:elm-types:r1}Integer")); assertThat(_as.getOperand(), instanceOf(Null.class)); test = statements.get(1); assertThat(test.getExpression(), instanceOf(ProperContains.class)); - properContains = (ProperContains)test.getExpression(); + properContains = (ProperContains) test.getExpression(); assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); - interval = (Interval)properContains.getOperand().get(0); + interval = (Interval) properContains.getOperand().get(0); assertThat(interval.getResultType(), instanceOf(IntervalType.class)); - intervalType = (IntervalType)interval.getResultType(); + intervalType = (IntervalType) interval.getResultType(); assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); - pointType = (SimpleType)intervalType.getPointType(); + pointType = (SimpleType) intervalType.getPointType(); assertThat(pointType.getName(), equalTo("System.Integer")); assertThat(properContains.getOperand().get(1), instanceOf(As.class)); - _as = (As)properContains.getOperand().get(1); + _as = (As) properContains.getOperand().get(1); assertThat(_as.getAsType().toString(), equalTo("{urn:hl7-org:elm-types:r1}Integer")); assertThat(_as.getOperand(), instanceOf(Null.class)); test = statements.get(2); assertThat(test.getExpression(), instanceOf(ProperContains.class)); - properContains = (ProperContains)test.getExpression(); + properContains = (ProperContains) test.getExpression(); assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); - interval = (Interval)properContains.getOperand().get(0); + interval = (Interval) properContains.getOperand().get(0); assertThat(interval.getResultType(), instanceOf(IntervalType.class)); - intervalType = (IntervalType)interval.getResultType(); + intervalType = (IntervalType) interval.getResultType(); assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); - pointType = (SimpleType)intervalType.getPointType(); + pointType = (SimpleType) intervalType.getPointType(); assertThat(pointType.getName(), equalTo("System.Any")); assertThat(properContains.getOperand().get(1), instanceOf(Null.class)); test = statements.get(3); assertThat(test.getExpression(), instanceOf(ProperContains.class)); - properContains = (ProperContains)test.getExpression(); + properContains = (ProperContains) test.getExpression(); assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); - interval = (Interval)properContains.getOperand().get(0); + interval = (Interval) properContains.getOperand().get(0); assertThat(interval.getResultType(), instanceOf(IntervalType.class)); - intervalType = (IntervalType)interval.getResultType(); + intervalType = (IntervalType) interval.getResultType(); assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); - pointType = (SimpleType)intervalType.getPointType(); + pointType = (SimpleType) intervalType.getPointType(); assertThat(pointType.getName(), equalTo("System.Any")); assertThat(properContains.getOperand().get(1), instanceOf(Null.class)); test = statements.get(4); assertThat(test.getExpression(), instanceOf(ProperContains.class)); - properContains = (ProperContains)test.getExpression(); + properContains = (ProperContains) test.getExpression(); assertThat(properContains.getOperand().get(0), instanceOf(Interval.class)); - interval = (Interval)properContains.getOperand().get(0); + interval = (Interval) properContains.getOperand().get(0); assertThat(interval.getResultType(), instanceOf(IntervalType.class)); - intervalType = (IntervalType)interval.getResultType(); + intervalType = (IntervalType) interval.getResultType(); assertThat(intervalType.getPointType(), instanceOf(SimpleType.class)); - pointType = (SimpleType)intervalType.getPointType(); + pointType = (SimpleType) intervalType.getPointType(); assertThat(pointType.getName(), equalTo("System.Integer")); assertThat(properContains.getOperand().get(1), instanceOf(As.class)); } From 10fc56c227c0675e7401df83902ec06d58ba11ea Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 31 Oct 2024 11:27:32 -0600 Subject: [PATCH 4/7] Fixed precedence of infix set operators to match FHIRPath --- Src/grammar/cql.g4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/grammar/cql.g4 b/Src/grammar/cql.g4 index 894c626e8..0ed90486c 100644 --- a/Src/grammar/cql.g4 +++ b/Src/grammar/cql.g4 @@ -320,6 +320,7 @@ expression | expression 'properly'? 'between' expressionTerm 'and' expressionTerm #betweenExpression | ('duration' 'in')? pluralDateTimePrecision 'between' expressionTerm 'and' expressionTerm #durationBetweenExpression | 'difference' 'in' pluralDateTimePrecision 'between' expressionTerm 'and' expressionTerm #differenceBetweenExpression + | expression ('|' | 'union' | 'intersect' | 'except') expression #inFixSetExpression | expression ('<=' | '<' | '>' | '>=') expression #inequalityExpression | expression intervalOperatorPhrase expression #timingExpression | expression ('=' | '!=' | '~' | '!~') expression #equalityExpression @@ -327,7 +328,6 @@ expression | expression 'and' expression #andExpression | expression ('or' | 'xor') expression #orExpression | expression 'implies' expression #impliesExpression - | expression ('|' | 'union' | 'intersect' | 'except') expression #inFixSetExpression ; dateTimePrecision From 482459d54eeff288d7d1b36320eedaf8aada5e7f Mon Sep 17 00:00:00 2001 From: Anton Vasetenkov Date: Fri, 1 Nov 2024 06:32:49 +1300 Subject: [PATCH 5/7] Call isInstantiable recursively to make sure that type parameters (if present) are bound (#1431) --- .../src/main/java/org/hl7/cql/model/ChoiceType.java | 10 ++++++++++ .../src/main/java/org/hl7/cql/model/TupleType.java | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.java b/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.java index 017a69b9e..5b43a3f0b 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.java +++ b/Src/java/model/src/main/java/org/hl7/cql/model/ChoiceType.java @@ -148,6 +148,16 @@ public boolean isGeneric() { @Override public boolean isInstantiable(DataType callType, InstantiationContext context) { + // Call isInstantiable recursively to make sure that type parameters (if present) are bound + if (callType.equals(DataType.ANY)) { + for (var type : types) { + if (!type.isInstantiable(callType, context)) { + return false; + } + } + return true; + } + return isSuperTypeOf(callType); } diff --git a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java index 79474bc31..473d6c9d2 100644 --- a/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java +++ b/Src/java/model/src/main/java/org/hl7/cql/model/TupleType.java @@ -164,7 +164,13 @@ public boolean isGeneric() { @Override public boolean isInstantiable(DataType callType, InstantiationContext context) { + // Call isInstantiable recursively to make sure that type parameters (if present) are bound if (callType.equals(DataType.ANY)) { + for (var element : elements) { + if (!element.getType().isInstantiable(callType, context)) { + return false; + } + } return true; } From 2f7f9731b71363953342a39fe1fc9863aa597078 Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 31 Oct 2024 11:33:54 -0600 Subject: [PATCH 6/7] Removed unused typeMap field in InstantiationResult class --- .../cqframework/cql/cql2elm/model/GenericOperator.java | 4 ++-- .../cql/cql2elm/model/InstantiationResult.java | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java index 92ba632dd..0b0588226 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/GenericOperator.java @@ -62,9 +62,9 @@ public InstantiationResult instantiate( getResultType().instantiate(context)); result.setAccessLevel(getAccessLevel()); result.setLibraryName(getLibraryName()); - return new InstantiationResult(this, result, typeMap, context.getConversionScore()); + return new InstantiationResult(this, result, context.getConversionScore()); } - return new InstantiationResult(this, null, null, context.getConversionScore()); + return new InstantiationResult(this, null, context.getConversionScore()); } } diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java index ae508379d..deba61dec 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java @@ -11,7 +11,6 @@ public class InstantiationResult { public InstantiationResult( GenericOperator genericOperator, Operator operator, - Map typeMap, int conversionScore) { if (genericOperator == null) { throw new IllegalArgumentException("genericOperator is required"); @@ -19,7 +18,6 @@ public InstantiationResult( this.genericOperator = genericOperator; this.operator = operator; - this.typeMap = typeMap; this.conversionScore = conversionScore; } @@ -35,12 +33,6 @@ public Operator getOperator() { return operator; } - private Map typeMap; - - public Map getTypeMap() { - return typeMap; - } - private int conversionScore; public int getConversionScore() { From e9cf8f092744fb63f188748e48d4f44b4291f95b Mon Sep 17 00:00:00 2001 From: Bryn Rhodes Date: Thu, 31 Oct 2024 11:39:36 -0600 Subject: [PATCH 7/7] Spotless --- .../cql/cql2elm/model/InstantiationResult.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java index deba61dec..d44787a0e 100644 --- a/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java +++ b/Src/java/cql-to-elm/src/main/java/org/cqframework/cql/cql2elm/model/InstantiationResult.java @@ -1,17 +1,10 @@ package org.cqframework.cql.cql2elm.model; -import java.util.Map; -import org.hl7.cql.model.DataType; -import org.hl7.cql.model.TypeParameter; - /** * Created by Bryn on 12/22/2016. */ public class InstantiationResult { - public InstantiationResult( - GenericOperator genericOperator, - Operator operator, - int conversionScore) { + public InstantiationResult(GenericOperator genericOperator, Operator operator, int conversionScore) { if (genericOperator == null) { throw new IllegalArgumentException("genericOperator is required"); }