diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SymbolEnter.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SymbolEnter.java index f09f95cc6040..c8f899bcb53c 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SymbolEnter.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SymbolEnter.java @@ -488,7 +488,7 @@ private void defineConstructs(BLangPackage pkgNode, SymbolEnv pkgEnv) { } } } - typeResolver.clearUnknowTypeRefs(); + typeResolver.clearUnknownTypeRefs(); } private void defineDependentFields(List typeDefNodes, SymbolEnv pkgEnv) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index cef5cdbdf1a3..95fcfa20f7e7 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -254,6 +254,7 @@ public class TypeChecker extends SimpleBLangNodeAnalyzer key) { @@ -343,6 +345,7 @@ public TypeChecker(CompilerContext context, CompilerContext.Key key this.missingNodesHelper = BLangMissingNodesHelper.getInstance(context); this.unifier = new Unifier(); this.queryTypeChecker = null; + this.typeResolver = TypeResolver.getInstance(context); } private BType checkExpr(BLangExpression expr, SymbolEnv env, AnalyzerData data) { @@ -600,14 +603,13 @@ private BType silentIntTypeCheck(BLangLiteral literalExpr, Object literalValue, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); BType exprCompatibleType = getIntegerLiteralType(nodeCloner.cloneNode(literalExpr), literalValue, expType, data); data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); @@ -1224,7 +1226,7 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int errorCount = this.dlog.errorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); List matchingTypes = new ArrayList<>(); @@ -1246,7 +1248,7 @@ public void visit(BLangTableConstructorExpr tableConstructorExpr, AnalyzerData d } data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - this.dlog.setErrorCount(errorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -1803,7 +1805,7 @@ private BType checkListConstructorCompatibility(BType referredType, BType origin int tag = referredType.tag; if (tag == TypeTags.UNION) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; - int errorCount = this.dlog.errorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); data.commonAnalyzerData.nonErrorLoggingCheck = true; this.dlog.mute(); @@ -1832,7 +1834,7 @@ private BType checkListConstructorCompatibility(BType referredType, BType origin } data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - this.dlog.setErrorCount(errorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -2545,7 +2547,7 @@ public BType checkMappingConstructorCompatibility(BType bType, BLangRecordLitera if (tag == TypeTags.UNION) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int errorCount = this.dlog.errorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); List compatibleTypes = new ArrayList<>(); @@ -2574,7 +2576,7 @@ public BType checkMappingConstructorCompatibility(BType bType, BLangRecordLitera } data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - dlog.setErrorCount(errorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -3928,13 +3930,13 @@ private void validateErrorConstructorPositionalArgs(BLangErrorConstructorExpr er protected BType checkExprSilent(BLangExpression expr, BType expType, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int errorCount = this.dlog.errorCount(); this.dlog.mute(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); BType type = checkExpr(expr, expType, data); data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - dlog.setErrorCount(errorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -5469,15 +5471,14 @@ public boolean isOptionalFloatOrDecimal(BType expectedType) { private BType checkAndGetType(BLangExpression expr, SymbolEnv env, BLangBinaryExpr binaryExpr, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); expr.cloneAttempt++; BType exprCompatibleType = checkExpr(nodeCloner.cloneNode(expr), env, binaryExpr.expectedType, data); data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; int errorCount = this.dlog.errorCount(); - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -5731,8 +5732,7 @@ public boolean silentCompatibleFiniteMembersInUnionTypeCheck(BLangUnaryExpr unar AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); BType compatibleTypeOfUnaryExpression; @@ -5740,17 +5740,17 @@ public boolean silentCompatibleFiniteMembersInUnionTypeCheck(BLangUnaryExpr unar compatibleTypeOfUnaryExpression = checkExpr(nodeCloner.cloneNode(unaryExpr), Types.getImpliedType(type), data); if (Types.getImpliedType(compatibleTypeOfUnaryExpression).tag == TypeTags.FINITE) { - unmuteDlog(data, prevNonErrorLoggingCheck, prevErrorCount); + unmuteDlog(data, prevNonErrorLoggingCheck, previousGlobalState); return true; } } - unmuteDlog(data, prevNonErrorLoggingCheck, prevErrorCount); + unmuteDlog(data, prevNonErrorLoggingCheck, previousGlobalState); return false; } - private void unmuteDlog(AnalyzerData data, boolean prevNonErrorLoggingCheck, int prevErrorCount) { + private void unmuteDlog(AnalyzerData data, boolean prevNonErrorLoggingCheck, GlobalStateData previousGlobalState) { data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -5759,13 +5759,12 @@ private void unmuteDlog(AnalyzerData data, boolean prevNonErrorLoggingCheck, int public BType silentTypeCheckExpr(BLangExpression expr, BType referredType, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); BType exprCompatibleType = checkExpr(nodeCloner.cloneNode(expr), referredType, data); - unmuteDlog(data, prevNonErrorLoggingCheck, prevErrorCount); + unmuteDlog(data, prevNonErrorLoggingCheck, previousGlobalState); return exprCompatibleType; } @@ -5823,14 +5822,13 @@ public void visit(BLangTypeConversionExpr conversionExpr, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); BType exprCompatibleType = checkExpr(nodeCloner.cloneNode(expr), targetType, data); data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; int errorCount = this.dlog.errorCount(); - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); @@ -6609,9 +6607,8 @@ private BType getCandidateLaxType(BLangNode expr, BType rhsType) { private BType getCandidateType(BLangCheckedExpr checkedExpr, BType checkExprCandidateType, AnalyzerData data) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); this.dlog.mute(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); checkedExpr.expr.cloneAttempt++; BLangExpression clone = nodeCloner.cloneNode(checkedExpr.expr); @@ -6622,7 +6619,7 @@ private BType getCandidateType(BLangCheckedExpr checkedExpr, BType checkExprCand rhsType = checkExpr(clone, checkExprCandidateType, data); } data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); } @@ -8243,15 +8240,14 @@ private List concatSimilarKindXMLNodes(List ex for (BLangExpression expr : exprs) { boolean prevNonErrorLoggingCheck = data.commonAnalyzerData.nonErrorLoggingCheck; data.commonAnalyzerData.nonErrorLoggingCheck = true; - int prevErrorCount = this.dlog.errorCount(); - this.dlog.resetErrorCount(); + GlobalStateData previousGlobalState = getGlobalStateSnapshotAndResetGlobalState(); this.dlog.mute(); BType exprType = checkExpr(nodeCloner.cloneNode(expr), xmlElementEnv, symTable.xmlType, data); data.commonAnalyzerData.nonErrorLoggingCheck = prevNonErrorLoggingCheck; int errorCount = this.dlog.errorCount(); - this.dlog.setErrorCount(prevErrorCount); + restoreGlobalState(previousGlobalState); if (!prevNonErrorLoggingCheck) { this.dlog.unmute(); @@ -9918,6 +9914,24 @@ String recordsToString(Set recordTypeSet) { } } + public GlobalStateData getGlobalStateSnapshotAndResetGlobalState() { + // Preserve global state + GlobalStateData globalStateData = new GlobalStateData(); + globalStateData.unknownTypeRefs = typeResolver.unknownTypeRefs; + globalStateData.errorCount = this.dlog.errorCount(); + + // Reset global state + typeResolver.unknownTypeRefs = new HashSet<>(); + this.dlog.resetErrorCount(); + + return globalStateData; + } + + public void restoreGlobalState(GlobalStateData globalStateData) { + typeResolver.unknownTypeRefs = globalStateData.unknownTypeRefs; + this.dlog.setErrorCount(globalStateData.errorCount); + } + /** * @since 2.0.0 */ @@ -9933,4 +9947,12 @@ public static class AnalyzerData { QueryTypeChecker.AnalyzerData queryData = new QueryTypeChecker.AnalyzerData(); Set queryVariables; } + + /** + * @since 2201.12.0 + */ + public static class GlobalStateData { + HashSet unknownTypeRefs; + int errorCount; + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeResolver.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeResolver.java index 189a1504468d..08df6895c5c4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeResolver.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeResolver.java @@ -164,7 +164,7 @@ public class TypeResolver { private final HashSet resolvedClassDef = new HashSet<>(); private final Map modTable = new LinkedHashMap<>(); private final Map constantMap = new HashMap<>(); - private final HashSet unknownTypeRefs; + public HashSet unknownTypeRefs; private SymbolEnv pkgEnv; private int currentDepth; private Deque resolvingTypes; @@ -188,7 +188,7 @@ public TypeResolver(CompilerContext context) { this.unknownTypeRefs = new HashSet<>(); } - public void clearUnknowTypeRefs() { + public void clearUnknownTypeRefs() { unknownTypeRefs.clear(); } @@ -2133,7 +2133,7 @@ private static class ResolverData { * * @since 2201.7.0 */ - private static class LocationData { + protected static class LocationData { private final String name; private final int row; private final int column; diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/typedefs/TypeDefinitionsNegativeTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/typedefs/TypeDefinitionsNegativeTest.java index 9737f366969e..7e684d9b2422 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/typedefs/TypeDefinitionsNegativeTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/typedefs/TypeDefinitionsNegativeTest.java @@ -74,6 +74,12 @@ public void testSemanticsNegative() { "'function () returns (int)', found 'function () returns (MyTuple)'", 37, 33); BAssertUtil.validateError(compileResult, index++, "incompatible types: expected 'Foo', found 'string'", 43, 13); + BAssertUtil.validateError(compileResult, index++, "unknown type 'I'", 48, 19); + BAssertUtil.validateError(compileResult, index++, "unknown type 'I'", 52, 35); + BAssertUtil.validateError(compileResult, index++, "unknown type 'J'", 54, 17); + BAssertUtil.validateError(compileResult, index++, "unknown type 'J'", 56, 22); + BAssertUtil.validateError(compileResult, index++, "unknown type 'J'", 58, 23); + Assert.assertEquals(compileResult.getErrorCount(), index); } } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/type-definitions-semantics-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/type-definitions-semantics-negative.bal index 19c3ed59e243..ee0248f1c7ce 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/type-definitions-semantics-negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/typedefs/type-definitions-semantics-negative.bal @@ -42,3 +42,17 @@ type Foo boolean|null; function testNullFiniteType() { Foo _ = "null"; // error } + +class H {}; + +H res = check new I(); + +int[] a = [1, 2, 3, 4, 5]; + +int[] b = from var i in a select i; + +float result = 1 + 2.0; + +int result2 = true? 1 : 2; + +var result3 = new J();