diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 8f12187f6f6..d1b98a52684 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -1999,6 +1999,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.kt"); } + @TestMetadata("withQuestionMarks.kt") + public void testWithQuestionMarks() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); + } + @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 43f8a13f3a5..166917e6ee2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -325,7 +325,7 @@ class DoubleColonExpressionResolver( } private fun resolveReservedExpressionSyntaxOnDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): - Pair { + ReservedDoubleColonLHSResolutionResult { val resultForReservedExpr = tryResolveLHS( doubleColonExpression, c, this::shouldTryResolveLHSAsReservedExpression, @@ -335,7 +335,7 @@ class DoubleColonExpressionResolver( val lhs = resultForReservedExpr.lhs if (lhs != null) { c.trace.report(RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS.on(resultForReservedExpr.expression)) - return Pair(true, resultForReservedExpr.commit()) + return ReservedDoubleColonLHSResolutionResult(true, resultForReservedExpr.commit(), resultForReservedExpr.traceAndCache) } } @@ -349,11 +349,13 @@ class DoubleColonExpressionResolver( if (lhs != null) { c.trace.report(RESERVED_SYNTAX_IN_CALLABLE_REFERENCE_LHS.on(resultForReservedCallChain.expression)) // DO NOT commit trace from resultForReservedCallChain here - return Pair(true, null) + return ReservedDoubleColonLHSResolutionResult(true, null, resultForReservedExpr?.traceAndCache) } } - return Pair(false, null) + return ReservedDoubleColonLHSResolutionResult( + false, null, resultForReservedExpr?.traceAndCache ?: resultForReservedCallChain?.traceAndCache + ) } internal fun resolveDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): DoubleColonLHS? { @@ -367,7 +369,9 @@ class DoubleColonExpressionResolver( } } - val (isReservedExpressionSyntax, doubleColonLHS) = resolveReservedExpressionSyntaxOnDoubleColonLHS(doubleColonExpression, c) + val (isReservedExpressionSyntax, doubleColonLHS, traceAndCacheFromReservedDoubleColonLHS) = + resolveReservedExpressionSyntaxOnDoubleColonLHS(doubleColonExpression, c) + if (isReservedExpressionSyntax) return doubleColonLHS val resultForType = tryResolveLHS(doubleColonExpression, c, this::shouldTryResolveLHSAsType) { expression, context -> @@ -390,14 +394,25 @@ class DoubleColonExpressionResolver( } } - // If the LHS could be resolved neither as an expression nor as a type, we should still type-check it to allow all diagnostics - // to be reported and references to be resolved. For that, we commit one of the applicable traces here, preferring the expression if (resultForExpr != null) return resultForExpr.commit() if (resultForType != null) return resultForType.commit() + /* + * If the LHS could be resolved neither as an expression nor as a type, + * but it was resolved as expression with reserved syntax like `foo?::bar?::bar`, + * then we commit the trace of that resolution result. + */ + traceAndCacheFromReservedDoubleColonLHS?.commit() + return null } + private data class ReservedDoubleColonLHSResolutionResult( + val isReservedExpressionSyntax: Boolean, + val lhs: DoubleColonLHS?, + val traceAndCache: TemporaryTraceAndCache? + ) + private class LHSResolutionResult( val lhs: T?, val expression: KtExpression, diff --git a/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.fir.kt b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.fir.kt new file mode 100644 index 00000000000..f4318eb68f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.fir.kt @@ -0,0 +1,31 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// Issue: KT-35075 + +fun foo() {} + +fun main() { + val x1 = logger::info?::print + val x2 = logger?::info?::print + val x3 = logger?::info::print + val x4 = logger?::info?::print?::print?::print?::print?::print?::print?::print?::print?::print?::print + val x5 = logger::info?::print?::print?::print?::print?::print?::print?::print?::print?::print?::print + val x6 = logger!!::info?::print?::print + val x7 = logger::info!!::print?::print + val x8 = logger?::info!!::print?::print + val x9 = logger!!::info?::print?::print + val x10 = logger::info?::print!!::print + val x11 = logger!!::info!!::print!!::print + val x12 = logger?::info!!::print!!::print + val x13 = 42?::unresolved?::print + + val x14 = logger?!!::info?::print?::print + val x15 = logger::info?!!::print?::print + val x16 = logger!!?::info?::print?::print + val x17 = logger::info!!?::print?::print + + // It must be OK + val x18 = String?::hashCode ?: ::foo + val x19 = String::hashCode ?: ::foo + val x20 = String?::hashCode::hashCode + val x21 = kotlin.String?::hashCode::hashCode +} diff --git a/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt new file mode 100644 index 00000000000..f02e92b22f5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt @@ -0,0 +1,31 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE +// Issue: KT-35075 + +fun foo() {} + +fun main() { + val x1 = logger::info?::print + val x2 = logger?::info?::print + val x3 = logger?::info::print + val x4 = logger?::info?::print?::print?::print?::print?::print?::print?::print?::print?::print?::print + val x5 = logger::info?::print?::print?::print?::print?::print?::print?::print?::print?::print?::print + val x6 = logger!!::info?::print?::print + val x7 = logger::info!!::print?::print + val x8 = logger?::info!!::print?::print + val x9 = logger!!::info?::print?::print + val x10 = logger::info?::print!!::print + val x11 = logger!!::info!!::print!!::print + val x12 = logger?::info!!::print!!::print + val x13 = 42?::unresolved?::print + + val x14 = logger?!!::info?::print?::print + val x15 = logger::info?!!::print?::print + val x16 = logger!!?::info?::print?::print + val x17 = logger::info!!?::print?::print + + // It must be OK + val x18 = String?::hashCode ?: ::foo + val x19 = String::hashCode ?: ::foo + val x20 = String?::hashCode::hashCode + val x21 = kotlin.String?::hashCode::hashCode +} diff --git a/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.txt b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.txt new file mode 100644 index 00000000000..465b4f7a5a3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.txt @@ -0,0 +1,4 @@ +package + +public fun foo(): kotlin.Unit +public fun main(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 93e1de72a1a..9c0d91ced16 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2006,6 +2006,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.kt"); } + @TestMetadata("withQuestionMarks.kt") + public void testWithQuestionMarks() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); + } + @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index cf78fd6d00b..76e3d008ee0 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -2001,6 +2001,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.kt"); } + @TestMetadata("withQuestionMarks.kt") + public void testWithQuestionMarks() throws Exception { + runTest("compiler/testData/diagnostics/tests/callableReference/withQuestionMarks.kt"); + } + @TestMetadata("compiler/testData/diagnostics/tests/callableReference/bound") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)