Skip to content

Commit

Permalink
Merge pull request #38029 from SasinduDilshara/issue-37750
Browse files Browse the repository at this point in the history
[Master] Fix Invalid type inferring for literal expression
  • Loading branch information
pcnfernando authored Aug 18, 2023
2 parents ce5a035 + e57a4ab commit c86770c
Show file tree
Hide file tree
Showing 14 changed files with 1,164 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -501,12 +501,13 @@ private void checkXMLNamespacePrefixes(List<BLangXMLElementFilter> filters, Anal
}

private int getPreferredMemberTypeTag(BFiniteType finiteType) {
for (BLangExpression valueExpr : finiteType.getValueSpace()) {
int typeTag = Types.getImpliedType(valueExpr.getBType()).tag;
if (typeTag > TypeTags.DECIMAL) {
continue;
}
for (int i = TypeTags.INT; i <= TypeTags.DECIMAL; i++) {
for (int i = TypeTags.INT; i <= TypeTags.DECIMAL; i++) {
for (BLangExpression valueExpr : finiteType.getValueSpace()) {
int typeTag = Types.getImpliedType(valueExpr.getBType()).tag;
if (typeTag > TypeTags.DECIMAL) {
continue;
}

if (typeTag == i) {
return i;
}
Expand Down Expand Up @@ -535,29 +536,35 @@ private BType getFiniteTypeMatchWithIntType(BLangLiteral literalExpr, BFiniteTyp
}

private BType getFiniteTypeMatchWithIntLiteral(BLangLiteral literalExpr, BFiniteType finiteType,
Object literalValue, AnalyzerData data) {
Object literalValue, BType compatibleType, AnalyzerData data) {
BType intLiteralType = getFiniteTypeMatchWithIntType(literalExpr, finiteType, data);
if (intLiteralType != symTable.noType) {
return intLiteralType;
}

int typeTag = getPreferredMemberTypeTag(finiteType);
if (typeTag == TypeTags.NONE) {
return symTable.intType;
}

if (literalAssignableToFiniteType(literalExpr, finiteType, typeTag)) {
BType type = symTable.getTypeFromTag(typeTag);
setLiteralValueForFiniteType(literalExpr, type, data);
literalExpr.value = String.valueOf(literalValue);
return type;
}

// Handle out of range ints
if (literalValue instanceof Double) {
return symTable.floatType;
}
if (literalValue instanceof String) {
return symTable.decimalType;
}
return symTable.intType;
if (compatibleType.tag == TypeTags.BYTE) {
return symTable.intType;
}
return compatibleType;
}

private BType silentIntTypeCheck(BLangLiteral literalExpr, Object literalValue, BType expType,
Expand All @@ -580,15 +587,23 @@ private BType silentIntTypeCheck(BLangLiteral literalExpr, Object literalValue,
}

private BType silentCompatibleLiteralTypeCheck(BFiniteType finiteType, BLangLiteral literalExpr,
Object literalValue, AnalyzerData data) {
BType resIntType = symTable.semanticError;
Object literalValue, AnalyzerData data) {
BType resIntegerLiteralType = symTable.semanticError;
List<BType> compatibleTypes = new ArrayList<>();
for (BLangExpression valueExpr : finiteType.getValueSpace()) {
resIntType = silentIntTypeCheck(literalExpr, literalValue, valueExpr.getBType(), data);
if (resIntType != symTable.semanticError) {
return resIntType;
resIntegerLiteralType = silentIntTypeCheck(literalExpr, literalValue, valueExpr.getBType(), data);
if (resIntegerLiteralType != symTable.semanticError) {
compatibleTypes.add(resIntegerLiteralType);
}
}
return resIntType;
for (int i = TypeTags.INT; i <= TypeTags.DECIMAL; i++) {
for (BType type: compatibleTypes) {
if (Types.getReferredType(type).tag == i) {
return type;
}
}
}
return resIntegerLiteralType;
}

private BType checkIfOutOfRangeAndReturnType(BFiniteType finiteType, BLangLiteral literalExpr, Object literalValue,
Expand Down Expand Up @@ -633,7 +648,7 @@ public BType getIntegerLiteralType(BLangLiteral literalExpr, Object literalValue
if (compatibleType == symTable.semanticError) {
return compatibleType;
} else {
return getFiniteTypeMatchWithIntLiteral(literalExpr, finiteType, literalValue, data);
return getFiniteTypeMatchWithIntLiteral(literalExpr, finiteType, literalValue, compatibleType, data);
}
} else if (expectedType.tag == TypeTags.UNION) {
BUnionType expectedUnionType = (BUnionType) expectedType;
Expand Down Expand Up @@ -749,12 +764,29 @@ public BType getTypeOfDecimalFloatingPointLiteral(BLangLiteral literalExpr, Obje
} else if (expectedType.tag == TypeTags.FINITE) {
BFiniteType finiteType = (BFiniteType) expectedType;
for (int tag = TypeTags.FLOAT; tag <= TypeTags.DECIMAL; tag++) {
if (literalAssignableToFiniteType(literalExpr, finiteType, tag)) {
BType valueType = setLiteralValueAndGetType(literalExpr, symTable.getTypeFromTag(tag), data);
setLiteralValueForFiniteType(literalExpr, valueType, data);
return valueType;
BType literalValueType = null;
for (BLangExpression valueExpr : finiteType.getValueSpace()) {
if (valueExpr.getBType().tag == tag) {
if (types.checkLiteralAssignabilityBasedOnType((BLangLiteral) valueExpr, literalExpr)) {
BType valueType = setLiteralValueAndGetType(literalExpr,
symTable.getTypeFromTag(tag), data);
setLiteralValueForFiniteType(literalExpr, valueType, data);
return valueType;
}
literalValueType = valueExpr.getBType();
}
}
if (literalValueType != null) {
return literalValueType;
}
}
return literalExpr.getBType();
} else if (expectedType.tag == TypeTags.FLOAT) {
if (!types.validateFloatLiteral(literalExpr.pos, numericLiteral)) {
data.resultType = symTable.semanticError;
return symTable.semanticError;
}
return symTable.floatType;
} else if (expectedType.tag == TypeTags.UNION) {
BUnionType unionType = (BUnionType) expectedType;
for (int tag = TypeTags.FLOAT; tag <= TypeTags.DECIMAL; tag++) {
Expand Down Expand Up @@ -913,6 +945,9 @@ private BType getTypeMatchingFloatOrDecimal(BType finiteType, List<BType> member
}
}
}
if (finiteType.tag == TypeTags.FINITE) {
return checkIfOutOfRangeAndReturnType((BFiniteType) finiteType, literalExpr, literalExpr.value, data);
}
return symTable.intType;
}

Expand All @@ -934,7 +969,7 @@ private BType getAndSetAssignableUnionMember(BLangLiteral literalExpr, BUnionTyp
BType finiteType = getFiniteTypeWithValuesOfSingleType(expType, desiredType);
if (finiteType != symTable.semanticError) {
BType setType = setLiteralValueAndGetType(literalExpr, finiteType, data);
if (literalExpr.isFiniteContext) {
if (setType != symTable.semanticError) {
// i.e., a match was found for a finite type
return setType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void testNegative() {
BAssertUtil.validateError(compileResult, i++, "incompatible types: expected 'FloatTypeWithoutType'," +
" found 'float'", offset += 7, 30);
BAssertUtil.validateError(compileResult, i++, "incompatible types: expected 'DecimalTypeWithType'," +
" found 'float'", offset += 9, 29);
" found 'decimal'", offset += 9, 29);
BAssertUtil.validateError(compileResult, i++, "incompatible types: expected 'StringTypeWithType'," +
" found 'string'", offset += 9, 28);
BAssertUtil.validateError(compileResult, i++, "incompatible types: expected 'StringTypeWithoutType'," +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.ballerinalang.test.bala.literals;

import org.ballerinalang.test.BAssertUtil;
import org.ballerinalang.test.BCompileUtil;
import org.ballerinalang.test.CompileResult;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/**
* Negative test cases for numeric literals in ballerina.
*/
public class NumericLiteralNegativeTest {
private CompileResult negativeResult;

@BeforeClass
public void setup() {
BCompileUtil.compileAndCacheBala("test-src/bala/test_projects/test_numeric_literals");
negativeResult = BCompileUtil
.compile("test-src/bala/test_bala/literals/test_numeric_literal_negative_test.bal");
}

@Test(description = "Test numeric literal assignment statement with errors")
public void testNumericLiteralAssignmentNegativeCases() {
int index = 0;
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo', found 'float'", 20, 21);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo', found 'float'", 23, 21);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo', found 'float'", 24, 21);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo', found 'float'", 26, 21);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'int'", 30, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'int'", 31, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'int'", 32, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'int'", 33, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'int'", 35, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo2', found 'float'", 36, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo3', found 'float'", 39, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo3', found 'float'", 40, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo3', found 'float'", 41, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo3', found 'float'", 42, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'int'", 50, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 51, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 52, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 53, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 54, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 56, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'int'", 59, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 60, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 61, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 64, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'int'", 67, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 68, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 69, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 72, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'int'", 75, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 76, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 77, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 78, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 80, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 85, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 86, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 88, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 89, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 90, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'float'", 92, 22);
BAssertUtil.validateError(negativeResult, index++, "incompatible types: expected " +
"'numericliteral/testproject:0.1.0:Foo5', found 'int'", 93, 22);
Assert.assertEquals(negativeResult.getErrorCount(), index);
}
}
Loading

0 comments on commit c86770c

Please sign in to comment.