[FE 1.0] Don't lose diagnostics during lambda analysis at the overload resolution by return type stage
^KT-49658 Fixed
This commit is contained in:
committed by
teamcity
parent
7820b268fb
commit
37d163d417
+12
@@ -13647,6 +13647,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt47316.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658.kt")
|
||||
public void testKt49658() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658Strict.kt")
|
||||
public void testKt49658Strict() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658Strict.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
|
||||
+12
@@ -13647,6 +13647,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt47316.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658.kt")
|
||||
public void testKt49658() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658Strict.kt")
|
||||
public void testKt49658Strict() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658Strict.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
|
||||
+12
@@ -13647,6 +13647,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt47316.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658.kt")
|
||||
public void testKt49658() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658Strict.kt")
|
||||
public void testKt49658Strict() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658Strict.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
|
||||
@@ -1103,6 +1103,7 @@ public interface Errors {
|
||||
DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtElement, KtElement> ILLEGAL_ESCAPE = DiagnosticFactory1.create(ERROR, CUT_CHAR_QUOTES);
|
||||
DiagnosticFactory1<KtConstantExpression, KotlinType> NULL_FOR_NONNULL_TYPE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtConstantExpression, KotlinType> NULL_FOR_NONNULL_TYPE_WARNING = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<KtEscapeStringTemplateEntry> ILLEGAL_ESCAPE_SEQUENCE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtConstantExpression> UNSIGNED_LITERAL_WITHOUT_DECLARATIONS_ON_CLASSPATH = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtExpression> SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+1
@@ -632,6 +632,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL, "Too many characters in a character literal ''{0}''", ELEMENT_TEXT);
|
||||
MAP.put(ILLEGAL_ESCAPE, "Illegal escape: ''{0}''", ELEMENT_TEXT);
|
||||
MAP.put(NULL_FOR_NONNULL_TYPE, "Null can not be a value of a non-null type {0}", RENDER_TYPE);
|
||||
MAP.put(NULL_FOR_NONNULL_TYPE_WARNING, "Null can not be a value of a non-null type {0}", RENDER_TYPE);
|
||||
|
||||
MAP.put(ELSE_MISPLACED_IN_WHEN, "'else' entry must be the last one in a when-expression");
|
||||
MAP.put(REDUNDANT_ELSE_IN_WHEN, "'when' is exhaustive so 'else' is redundant here");
|
||||
|
||||
+29
-13
@@ -215,18 +215,14 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentNullabilityMismatchDiagnostic::class.java -> {
|
||||
require(diagnostic is ArgumentNullabilityMismatchDiagnostic)
|
||||
val expression = callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()?.let {
|
||||
KtPsiUtil.deparenthesize(it) ?: it
|
||||
}
|
||||
if (expression != null) {
|
||||
if (expression.isNull() && expression is KtConstantExpression) {
|
||||
trace.reportDiagnosticOnce(NULL_FOR_NONNULL_TYPE.on(expression, diagnostic.expectedType))
|
||||
} else {
|
||||
trace.report(TYPE_MISMATCH.on(expression, diagnostic.expectedType, diagnostic.actualType))
|
||||
}
|
||||
}
|
||||
ArgumentNullabilityErrorDiagnostic::class.java -> {
|
||||
require(diagnostic is ArgumentNullabilityErrorDiagnostic)
|
||||
reportNullabilityMismatchDiagnostic(callArgument, diagnostic)
|
||||
}
|
||||
|
||||
ArgumentNullabilityWarningDiagnostic::class.java -> {
|
||||
require(diagnostic is ArgumentNullabilityWarningDiagnostic)
|
||||
reportNullabilityMismatchDiagnostic(callArgument, diagnostic)
|
||||
}
|
||||
|
||||
CallableReferencesDefaultArgumentUsed::class.java -> {
|
||||
@@ -582,6 +578,27 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportNullabilityMismatchDiagnostic(callArgument: KotlinCallArgument, diagnostic: ArgumentNullabilityMismatchDiagnostic) {
|
||||
val expression = callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()?.let {
|
||||
KtPsiUtil.deparenthesize(it) ?: it
|
||||
}
|
||||
if (expression != null) {
|
||||
if (expression.isNull() && expression is KtConstantExpression) {
|
||||
val factory = when (diagnostic) {
|
||||
is ArgumentNullabilityErrorDiagnostic -> NULL_FOR_NONNULL_TYPE
|
||||
is ArgumentNullabilityWarningDiagnostic -> NULL_FOR_NONNULL_TYPE_WARNING
|
||||
}
|
||||
trace.reportDiagnosticOnce(factory.on(expression, diagnostic.expectedType))
|
||||
} else {
|
||||
val factory = when (diagnostic) {
|
||||
is ArgumentNullabilityErrorDiagnostic -> TYPE_MISMATCH
|
||||
is ArgumentNullabilityWarningDiagnostic -> TYPE_MISMATCH_WARNING
|
||||
}
|
||||
trace.report(factory.on(expression, diagnostic.expectedType, diagnostic.actualType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportNotEnoughInformationForTypeParameterForSpecialCall(
|
||||
resolvedAtom: ResolvedCallAtom,
|
||||
error: NotEnoughInformationForTypeParameterImpl
|
||||
@@ -622,7 +639,6 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
|| it.constructor == uninferredTypeVariable.freshTypeConstructor(typeSystemContext)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun getSubResolvedAtomsOfSpecialCallToReportUninferredTypeParameter(
|
||||
resolvedAtom: ResolvedAtom,
|
||||
uninferredTypeVariable: TypeVariableMarker
|
||||
|
||||
+23
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.resolve.calls.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
@@ -31,7 +32,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.same
|
||||
class KotlinCallCompleter(
|
||||
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
||||
private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter,
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle
|
||||
private val trivialConstraintTypeInferenceOracle: TrivialConstraintTypeInferenceOracle,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
fun runCompletion(
|
||||
@@ -127,6 +129,7 @@ class KotlinCallCompleter(
|
||||
ConstraintSystemCompletionMode.FULL,
|
||||
diagnosticHolderForLambda,
|
||||
)
|
||||
propagateLambdaAnalysisDiagnostics(diagnosticHolderForLambda, firstCandidate)
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
val (candidate, atom) = iterator.next()
|
||||
@@ -137,6 +140,7 @@ class KotlinCallCompleter(
|
||||
ConstraintSystemCompletionMode.FULL,
|
||||
diagnosticHolderForLambda
|
||||
)
|
||||
propagateLambdaAnalysisDiagnostics(diagnosticHolderForLambda, candidate)
|
||||
}
|
||||
|
||||
val errorCandidates = mutableSetOf<SimpleResolutionCandidate>()
|
||||
@@ -155,6 +159,24 @@ class KotlinCallCompleter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun propagateLambdaAnalysisDiagnostics(
|
||||
diagnosticHolder: KotlinDiagnosticsHolder.SimpleHolder,
|
||||
candidate: SimpleResolutionCandidate
|
||||
) {
|
||||
val dontLoseDiagnosticsDuringOverloadResolutionByReturnType =
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.DontLoseDiagnosticsDuringOverloadResolutionByReturnType)
|
||||
|
||||
for (diagnostic in diagnosticHolder.getDiagnostics()) {
|
||||
if (diagnostic is TransformableToWarning<*>) {
|
||||
val transformedDiagnostic =
|
||||
if (dontLoseDiagnosticsDuringOverloadResolutionByReturnType) diagnostic else diagnostic.transformToWarning()
|
||||
if (transformedDiagnostic != null) {
|
||||
candidate.addDiagnostic(transformedDiagnostic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleResolutionCandidate.getInputTypesOfLambdaAtom(atom: ResolvedLambdaAtom): List<UnwrappedType> {
|
||||
val result = mutableListOf<UnwrappedType>()
|
||||
val substitutor = getSystem().getBuilder().buildCurrentSubstitutor()
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ private fun checkExpressionArgument(
|
||||
if (argumentType.isMarkedNullable) {
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, actualExpectedType, position)) return null
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType.makeNotNullable(), actualExpectedType, position)) {
|
||||
return ArgumentNullabilityMismatchDiagnostic(actualExpectedType, argumentType, expressionArgument)
|
||||
return ArgumentNullabilityErrorDiagnostic(actualExpectedType, argumentType, expressionArgument)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ private fun checkExpressionArgument(
|
||||
|
||||
// Used only for arguments with @NotNull annotation
|
||||
if (expectedType is NotNullTypeParameter && argumentType.isMarkedNullable) {
|
||||
diagnosticsHolder.addDiagnostic(ArgumentNullabilityMismatchDiagnostic(expectedType, argumentType, expressionArgument))
|
||||
diagnosticsHolder.addDiagnostic(ArgumentNullabilityErrorDiagnostic(expectedType, argumentType, expressionArgument))
|
||||
}
|
||||
|
||||
if (expressionArgument.isSafeCall) {
|
||||
|
||||
+32
-5
@@ -23,12 +23,18 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.components.candidate.CallableReferenceResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintSystemError
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintError
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintWarning
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.transformToWarning
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability.*
|
||||
import org.jetbrains.kotlin.types.TypeConstructor
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
interface TransformableToWarning<T : KotlinCallDiagnostic> {
|
||||
fun transformToWarning(): T?
|
||||
}
|
||||
|
||||
abstract class InapplicableArgumentDiagnostic : KotlinCallDiagnostic(INAPPLICABLE) {
|
||||
abstract val argument: KotlinCallArgument
|
||||
|
||||
@@ -227,11 +233,29 @@ class NonApplicableCallForBuilderInferenceDiagnostic(val kotlinCall: KotlinCall)
|
||||
}
|
||||
}
|
||||
|
||||
class ArgumentNullabilityMismatchDiagnostic(
|
||||
val expectedType: UnwrappedType,
|
||||
val actualType: UnwrappedType,
|
||||
sealed interface ArgumentNullabilityMismatchDiagnostic {
|
||||
val expectedType: UnwrappedType
|
||||
val actualType: UnwrappedType
|
||||
val expressionArgument: ExpressionKotlinCallArgument
|
||||
) : KotlinCallDiagnostic(UNSAFE_CALL) {
|
||||
}
|
||||
|
||||
class ArgumentNullabilityErrorDiagnostic(
|
||||
override val expectedType: UnwrappedType,
|
||||
override val actualType: UnwrappedType,
|
||||
override val expressionArgument: ExpressionKotlinCallArgument
|
||||
) : KotlinCallDiagnostic(UNSAFE_CALL), TransformableToWarning<ArgumentNullabilityWarningDiagnostic>, ArgumentNullabilityMismatchDiagnostic {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCallArgument(expressionArgument, this)
|
||||
}
|
||||
|
||||
override fun transformToWarning() = ArgumentNullabilityWarningDiagnostic(expectedType, actualType, expressionArgument)
|
||||
}
|
||||
|
||||
class ArgumentNullabilityWarningDiagnostic(
|
||||
override val expectedType: UnwrappedType,
|
||||
override val actualType: UnwrappedType,
|
||||
override val expressionArgument: ExpressionKotlinCallArgument
|
||||
) : KotlinCallDiagnostic(RESOLVED), ArgumentNullabilityMismatchDiagnostic {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCallArgument(expressionArgument, this)
|
||||
}
|
||||
@@ -287,8 +311,11 @@ class MultipleArgumentsApplicableForContextReceiver(val receiverDescriptor: Rece
|
||||
|
||||
class KotlinConstraintSystemDiagnostic(
|
||||
val error: ConstraintSystemError
|
||||
) : KotlinCallDiagnostic(error.applicability) {
|
||||
) : KotlinCallDiagnostic(error.applicability), TransformableToWarning<KotlinConstraintSystemDiagnostic> {
|
||||
override fun report(reporter: DiagnosticReporter) = reporter.constraintError(error)
|
||||
|
||||
override fun transformToWarning(): KotlinConstraintSystemDiagnostic? =
|
||||
if (error is NewConstraintError) KotlinConstraintSystemDiagnostic(error.transformToWarning()) else null
|
||||
}
|
||||
|
||||
val KotlinCallDiagnostic.constraintSystemError: ConstraintSystemError?
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
fun doTheMapThing1(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!ARGUMENT_TYPE_MISMATCH!>when (it) { // NullPointerException
|
||||
is String -> listOf("Yeah")
|
||||
else -> null
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun doTheMapThing2(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!ARGUMENT_TYPE_MISMATCH!>if (it is String) listOf("Yeah") else null<!> // it's OK with `if`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
fun doTheMapThing1(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!TYPE_MISMATCH_WARNING!>when (it) { // NullPointerException
|
||||
is String -> listOf("Yeah")
|
||||
else -> null
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun doTheMapThing2(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH_WARNING!>if (it is String) listOf("Yeah") else null<!> // it's OK with `if`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package
|
||||
|
||||
public fun doTheMapThing1(/*0*/ elements: kotlin.collections.List<kotlin.CharSequence>): kotlin.collections.List<kotlin.String>
|
||||
public fun doTheMapThing2(/*0*/ elements: kotlin.collections.List<kotlin.CharSequence>): kotlin.collections.List<kotlin.String>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +DontLoseDiagnosticsDuringOverloadResolutionByReturnType
|
||||
// WITH_STDLIB
|
||||
|
||||
fun doTheMapThing1(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!ARGUMENT_TYPE_MISMATCH!>when (it) { // NullPointerException
|
||||
is String -> listOf("Yeah")
|
||||
else -> null
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun doTheMapThing2(elements: List<CharSequence>): List<String> {
|
||||
return elements.flatMap {
|
||||
<!ARGUMENT_TYPE_MISMATCH!>if (it is String) listOf("Yeah") else null<!> // it's OK with `if`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +DontLoseDiagnosticsDuringOverloadResolutionByReturnType
|
||||
// WITH_STDLIB
|
||||
|
||||
fun doTheMapThing1(elements: List<CharSequence>): List<String> {
|
||||
return elements.<!CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION!>flatMap {
|
||||
<!TYPE_MISMATCH!>when (it) { // NullPointerException
|
||||
is String -> listOf("Yeah")
|
||||
else -> null
|
||||
}<!>
|
||||
}<!>
|
||||
}
|
||||
|
||||
fun doTheMapThing2(elements: List<CharSequence>): List<String> {
|
||||
return elements.<!CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION!>flatMap {
|
||||
<!TYPE_MISMATCH, TYPE_MISMATCH, TYPE_MISMATCH!>if (it is String) listOf("Yeah") else null<!> // it's OK with `if`
|
||||
}<!>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package
|
||||
|
||||
public fun doTheMapThing1(/*0*/ elements: kotlin.collections.List<kotlin.CharSequence>): kotlin.collections.List<kotlin.String>
|
||||
public fun doTheMapThing2(/*0*/ elements: kotlin.collections.List<kotlin.CharSequence>): kotlin.collections.List<kotlin.String>
|
||||
Generated
+12
@@ -13653,6 +13653,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt47316.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658.kt")
|
||||
public void testKt49658() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt49658Strict.kt")
|
||||
public void testKt49658Strict() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/kt49658Strict.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6175.kt")
|
||||
public void testKt6175() throws Exception {
|
||||
|
||||
@@ -249,6 +249,7 @@ enum class LanguageFeature(
|
||||
|
||||
// 1.8
|
||||
|
||||
DontLoseDiagnosticsDuringOverloadResolutionByReturnType(KOTLIN_1_8),
|
||||
ProhibitConfusingSyntaxInWhenBranches(KOTLIN_1_8, kind = BUG_FIX), // KT-48385
|
||||
UseConsistentRulesForPrivateConstructorsOfSealedClasses(sinceVersion = KOTLIN_1_8, kind = BUG_FIX), // KT-44866
|
||||
ProgressionsChangingResolve(KOTLIN_1_8), // KT-49276
|
||||
|
||||
Reference in New Issue
Block a user