diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 563c3c35c99..c99eb06e260 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -10362,6 +10362,39 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractFirOldFrontendDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); + } + + @TestMetadata("kt33166.kt") + public void testKt33166() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); + } + + @TestMetadata("partialForIlt.kt") + public void testPartialForIlt() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); + } + + @TestMetadata("withExact.kt") + public void testWithExact() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt new file mode 100644 index 00000000000..ba3831f2486 --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CompletionModeCalculator.kt @@ -0,0 +1,176 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.components + +import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode +import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint +import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints +import org.jetbrains.kotlin.resolve.calls.model.KotlinResolutionCandidate +import org.jetbrains.kotlin.types.AbstractTypeChecker +import org.jetbrains.kotlin.types.UnwrappedType +import org.jetbrains.kotlin.types.model.* +import java.util.* + +typealias CsCompleterContext = KotlinConstraintSystemCompleter.Context + +class CompletionModeCalculator { + companion object { + fun computeCompletionMode( + candidate: KotlinResolutionCandidate, + expectedType: UnwrappedType?, + returnType: UnwrappedType? + ): ConstraintSystemCompletionMode = with(candidate) { + val csCompleterContext = getSystem().asConstraintSystemCompleterContext() + + // Presence of expected type means that we are trying to complete outermost call => completion mode should be full + if (expectedType != null) return ConstraintSystemCompletionMode.FULL + + // This is questionable as null return type can be only for error call + if (returnType == null) return ConstraintSystemCompletionMode.PARTIAL + + // Full if return type for call has no type variables + if (csBuilder.isProperType(returnType)) return ConstraintSystemCompletionMode.FULL + + // For nested call with variables in return type check possibility of full completion + return CalculatorForNestedCall(returnType, csCompleterContext).computeCompletionMode() + } + } + + private class CalculatorForNestedCall( + private val returnType: UnwrappedType?, + private val csCompleterContext: CsCompleterContext + ) { + private enum class FixationDirection { + TO_SUBTYPE, TO_SUPERTYPE, EQUALITY + } + + private val fixationDirectionsForVariables = mutableMapOf() + private val variablesWithQueuedConstraints = mutableSetOf() + private val typesToProcess: Queue = ArrayDeque() + + fun computeCompletionMode(): ConstraintSystemCompletionMode = with(csCompleterContext) { + // Add fixation directions for variables based on effective variance in type + typesToProcess.add(returnType) + computeDirections() + + // If all variables have required proper constraint, run full completion + if (directionRequirementsForVariablesHold()) + return ConstraintSystemCompletionMode.FULL + + return ConstraintSystemCompletionMode.PARTIAL + } + + private fun CsCompleterContext.computeDirections() { + while (typesToProcess.isNotEmpty()) { + val type = typesToProcess.poll() ?: break + + fixationRequirementForTopLevel(type)?.let { directionForVariable -> + updateDirection(directionForVariable) + enqueueTypesFromConstraints(directionForVariable.variable) + } + + // find all variables in type and make requirements for them + type.contains { fromReturnType -> + for (directionForVariable in directionsForVariablesInTypeArguments(fromReturnType)) { + updateDirection(directionForVariable) + enqueueTypesFromConstraints(directionForVariable.variable) + } + false + } + } + } + + private fun enqueueTypesFromConstraints(variableWithConstraints: VariableWithConstraints) { + val variable = variableWithConstraints.typeVariable + if (variable !in variablesWithQueuedConstraints) { + for (constraint in variableWithConstraints.constraints) { + typesToProcess.add(constraint.type) + } + + variablesWithQueuedConstraints.add(variable) + } + } + + private fun CsCompleterContext.directionRequirementsForVariablesHold(): Boolean { + for ((variable, fixationDirection) in fixationDirectionsForVariables) { + if (!hasProperConstraint(variable, fixationDirection)) + return false + } + return true + } + + private fun updateDirection(directionForVariable: FixationDirectionForVariable) { + val (variable, newDirection) = directionForVariable + fixationDirectionsForVariables[variable]?.let { oldDirection -> + // To sub and to super are merged into equality, old equality stays + if (oldDirection != FixationDirection.EQUALITY && oldDirection != newDirection) + fixationDirectionsForVariables[variable] = FixationDirection.EQUALITY + } + fixationDirectionsForVariables[variable] = newDirection + } + + private data class FixationDirectionForVariable(val variable: VariableWithConstraints, val direction: FixationDirection) + + private fun CsCompleterContext.fixationRequirementForTopLevel(type: KotlinTypeMarker): FixationDirectionForVariable? { + return notFixedTypeVariables[type.typeConstructor()]?.let { + FixationDirectionForVariable(it, FixationDirection.TO_SUBTYPE) + } + } + + private fun CsCompleterContext.directionsForVariablesInTypeArguments(type: KotlinTypeMarker): List { + assert(type.argumentsCount() == type.typeConstructor().parametersCount()) { + "Arguments and parameters count don't match for type $type. " + + "Arguments: ${type.argumentsCount()}, parameters: ${type.typeConstructor().parametersCount()}" + } + + val directionsForVariables = mutableListOf() + + for (position in 0 until type.argumentsCount()) { + val argument = type.getArgument(position) + if (!argument.getType().mayBeTypeVariable()) + continue + + val variableWithConstraints = notFixedTypeVariables[argument.getType().typeConstructor()] ?: continue + + val parameter = type.typeConstructor().getParameter(position) + val effectiveVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance()) + ?: TypeVariance.OUT // Discuss + + val direction = when (effectiveVariance) { + TypeVariance.IN -> FixationDirection.TO_SUPERTYPE + TypeVariance.OUT -> FixationDirection.TO_SUBTYPE + TypeVariance.INV -> FixationDirection.EQUALITY + } + + val requirement = FixationDirectionForVariable(variableWithConstraints, direction) + directionsForVariables.add(requirement) + } + + return directionsForVariables + } + + private fun CsCompleterContext.hasProperConstraint( + variableWithConstraints: VariableWithConstraints, + direction: FixationDirection + ): Boolean { + val constraints = variableWithConstraints.constraints + + // todo check correctness for @Exact + return constraints.isNotEmpty() && constraints.any { constraint -> + constraint.hasRequiredKind(direction) + && !constraint.type.typeConstructor().isIntegerLiteralTypeConstructor() + && isProperType(constraint.type) + } + } + + private fun Constraint.hasRequiredKind(direction: FixationDirection) = when (direction) { + FixationDirection.TO_SUBTYPE -> kind.isLower() || kind.isEqual() + FixationDirection.TO_SUPERTYPE -> kind.isUpper() || kind.isEqual() + FixationDirection.EQUALITY -> kind.isEqual() + } + } +} \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt index 31f774d6712..5fb2bbf093e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/KotlinCallCompleter.kt @@ -53,7 +53,7 @@ class KotlinCallCompleter( return if (resolutionCallbacks.inferenceSession.shouldRunCompletion(candidate)) candidate.runCompletion( - candidate.computeCompletionMode(expectedType, returnType), + CompletionModeCalculator.computeCompletionMode(candidate, expectedType, returnType), diagnosticHolder, resolutionCallbacks ) @@ -208,69 +208,6 @@ class KotlinCallCompleter( csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom)) } - private fun KotlinResolutionCandidate.computeCompletionMode( - expectedType: UnwrappedType?, - currentReturnType: UnwrappedType? - ): ConstraintSystemCompletionMode { - // Presence of expected type means that we trying to complete outermost call => completion mode should be full - if (expectedType != null) return ConstraintSystemCompletionMode.FULL - - // This is questionable as null return type can be only for error call - if (currentReturnType == null) return ConstraintSystemCompletionMode.PARTIAL - - return when { - // Consider call foo(bar(x)), if return type of bar is a proper one, then we can complete resolve for bar => full completion mode - // Otherwise, we shouldn't complete bar until we process call foo - csBuilder.isProperType(currentReturnType) -> ConstraintSystemCompletionMode.FULL - - // Nested call is connected with the outer one through the UPPER constraint (returnType <: expectedOuterType) - // This means that there will be no new LOWER constraints => - // it's possible to complete call now if there are proper LOWER constraints - csBuilder.isTypeVariable(currentReturnType) -> - if (hasProperNonTrivialLowerConstraints(currentReturnType)) - ConstraintSystemCompletionMode.FULL - else - ConstraintSystemCompletionMode.PARTIAL - - // Return type has proper equal constraints => there is no need in the outer call - containsTypeVariablesWithProperEqualConstraints(currentReturnType) -> ConstraintSystemCompletionMode.FULL - - else -> ConstraintSystemCompletionMode.PARTIAL - } - } - - private fun KotlinResolutionCandidate.containsTypeVariablesWithProperEqualConstraints(type: UnwrappedType): Boolean { - for ((variableConstructor, variableWithConstraints) in csBuilder.currentStorage().notFixedTypeVariables) { - if (!type.contains { it.constructor == variableConstructor }) continue - - val constraints = variableWithConstraints.constraints - val onlyProperEqualConstraints = - constraints.isNotEmpty() && constraints.any { it.kind.isEqual() && csBuilder.isProperType(it.type) } - - if (!onlyProperEqualConstraints) return false - } - - return true - } - - private fun KotlinResolutionCandidate.hasProperNonTrivialLowerConstraints(typeVariable: UnwrappedType): Boolean { - assert(csBuilder.isTypeVariable(typeVariable)) { "$typeVariable is not a type variable" } - - val context = getSystem() as TypeSystemInferenceExtensionContext - val constructor = typeVariable.constructor - val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false - val constraints = variableWithConstraints.constraints - return constraints.isNotEmpty() && constraints.anyOrAll(requireAll = typeVariable.hasExactAnnotation()) { - !it.type.typeConstructor(context).isIntegerLiteralTypeConstructor(context) && - (it.kind.isLower() || it.kind.isEqual()) && - csBuilder.isProperType(it.type) && - !trivialConstraintTypeInferenceOracle.isNotInterestingConstraint(it) - } - } - - private inline fun Iterable.anyOrAll(requireAll: Boolean, p: (T) -> Boolean): Boolean = - if (requireAll) all(p) else any(p) - fun KotlinResolutionCandidate.asCallResolutionResult( type: ConstraintSystemCompletionMode, diagnosticsHolder: KotlinDiagnosticsHolder.SimpleHolder diff --git a/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt new file mode 100644 index 00000000000..84291207f65 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/basic.fir.kt @@ -0,0 +1,70 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +interface Bound +class Cls : Bound + +class Inv(val prop: T) +class In(param: I) +class InB(param: I) +class Out(val prop: O) + +fun id(arg: K): K = arg +fun makeInv(arg: W): Inv = TODO() +fun wrapOut(arg: O): Inv = TODO() +fun wrapIn(arg: I): Inv = TODO() + +fun test1(cls: Cls) { + id( + Inv(cls) + ) +} + +fun test2(cls: Cls) { + id>( + Inv(cls) + ) +} + +fun test3(cls: Cls) { + id>( + Out(cls) + ) +} + +fun test4(cls: Cls) { + id( + Out(cls) + ) +} + +fun test5(cls: Cls) { + id( + In(cls) + ) +} + +fun test6(cls: Cls) { + id>( + In(cls) + ) +} + +fun test7(cls: Cls) { + id( + wrapOut(cls) + ) +} + +fun test8(cls: Cls) { + // TODO + id( + wrapIn(cls) + ) +} + +fun test9(cls: Cls) { + id( + InB(cls) + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/basic.kt b/compiler/testData/diagnostics/tests/inference/completion/basic.kt new file mode 100644 index 00000000000..a0ee120c7c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/basic.kt @@ -0,0 +1,70 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +interface Bound +class Cls : Bound + +class Inv(val prop: T) +class In(param: I) +class InB(param: I) +class Out(val prop: O) + +fun id(arg: K): K = arg +fun makeInv(arg: W): Inv = TODO() +fun wrapOut(arg: O): Inv = TODO() +fun wrapIn(arg: I): Inv = TODO() + +fun test1(cls: Cls) { + id( + ")!>Inv(cls) + ) +} + +fun test2(cls: Cls) { + id>( + ")!>Inv(cls) + ) +} + +fun test3(cls: Cls) { + id>( + ")!>Out(cls) + ) +} + +fun test4(cls: Cls) { + id( + ")!>Out(cls) + ) +} + +fun test5(cls: Cls) { + id( + ")!>In(cls) + ) +} + +fun test6(cls: Cls) { + id>( + ")!>In(cls) + ) +} + +fun test7(cls: Cls) { + id( + ")!>wrapOut(cls) + ) +} + +fun test8(cls: Cls) { + // TODO + id( + ")!>wrapIn(cls) + ) +} + +fun test9(cls: Cls) { + id( + ")!>InB(cls) + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/basic.txt b/compiler/testData/diagnostics/tests/inference/completion/basic.txt new file mode 100644 index 00000000000..a6ff4be5dc9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/basic.txt @@ -0,0 +1,58 @@ +package + +public fun id(/*0*/ arg: K): K +public fun makeInv(/*0*/ arg: W): Inv +public fun test1(/*0*/ cls: Cls): kotlin.Unit +public fun test2(/*0*/ cls: Cls): kotlin.Unit +public fun test3(/*0*/ cls: Cls): kotlin.Unit +public fun test4(/*0*/ cls: Cls): kotlin.Unit +public fun test5(/*0*/ cls: Cls): kotlin.Unit +public fun test6(/*0*/ cls: Cls): kotlin.Unit +public fun test7(/*0*/ cls: Cls): kotlin.Unit +public fun test8(/*0*/ cls: Cls): kotlin.Unit +public fun test9(/*0*/ cls: Cls): kotlin.Unit +public fun wrapIn(/*0*/ arg: I): Inv +public fun wrapOut(/*0*/ arg: O): Inv + +public interface Bound { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Cls : Bound { + public constructor Cls() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class In { + public constructor In(/*0*/ param: I) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class InB { + public constructor InB(/*0*/ param: I) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ prop: T) + public final val prop: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Out { + public constructor Out(/*0*/ prop: O) + public final val prop: O + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/kt33166.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/kt33166.fir.kt new file mode 100644 index 00000000000..257cfd0b79c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/kt33166.fir.kt @@ -0,0 +1,45 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +// FILE: GenericRunnable.java + +public interface GenericRunnable { + T invoke(); +} + +// FILE: OurFuture.java + +public class OurFuture { + static OurFuture createOurFuture(T result) { + return null; + } + + public OurFuture compose(GenericRunnable> mapper) { + return null; + } +} + +// FILE: test.kt + +open class Either { + class Left(val a: L) : Either() +} + +fun f1(future: OurFuture, e: Either.Left) { + future.compose> { + val x = when { + true -> OurFuture.createOurFuture(e) + else -> throw Exception() + } + x + } +} + +fun f2(future: OurFuture, e: Either.Left) { + future.compose> { + when { + true -> OurFuture.createOurFuture(e) + else -> throw Exception() + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/kt33166.kt b/compiler/testData/diagnostics/tests/inference/completion/kt33166.kt new file mode 100644 index 00000000000..f2e008933fe --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/kt33166.kt @@ -0,0 +1,45 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +// FILE: GenericRunnable.java + +public interface GenericRunnable { + T invoke(); +} + +// FILE: OurFuture.java + +public class OurFuture { + static OurFuture createOurFuture(T result) { + return null; + } + + public OurFuture compose(GenericRunnable> mapper) { + return null; + } +} + +// FILE: test.kt + +open class Either { + class Left(val a: L) : Either() +} + +fun f1(future: OurFuture, e: Either.Left) { + future.compose> { + val x = when { + true -> OurFuture.createOurFuture(e) + else -> throw Exception() + } + x + } +} + +fun f2(future: OurFuture, e: Either.Left) { + future.compose> { + when { + true -> OurFuture.createOurFuture(e) + else -> throw Exception() + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/kt33166.txt b/compiler/testData/diagnostics/tests/inference/completion/kt33166.txt new file mode 100644 index 00000000000..f0a742ae4bd --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/kt33166.txt @@ -0,0 +1,37 @@ +package + +public fun f1(/*0*/ future: OurFuture, /*1*/ e: Either.Left): kotlin.Unit +public fun f2(/*0*/ future: OurFuture, /*1*/ e: Either.Left): kotlin.Unit + +public open class Either { + public constructor Either() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class Left : Either { + public constructor Left(/*0*/ a: L) + public final val a: L + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public interface GenericRunnable { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract operator fun invoke(): T! + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class OurFuture { + public constructor OurFuture() + public open fun compose(/*0*/ mapper: GenericRunnable!>!): OurFuture! + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ open fun createOurFuture(/*0*/ result: T!): OurFuture! +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.fir.kt new file mode 100644 index 00000000000..0308772d09d --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.fir.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun takeByte(ilt: Byte) {} +fun takeShort(ilt: Short) {} +fun takeInt(ilt: Int) {} +fun takeLong(ilt: Long) {} + +fun id(arg: T): T = arg + +fun test() { + takeByte(id(42)) + takeShort(id(42)) + takeInt(id(42)) + takeLong(id(42)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt new file mode 100644 index 00000000000..d6d238bf7e8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun takeByte(ilt: Byte) {} +fun takeShort(ilt: Short) {} +fun takeInt(ilt: Int) {} +fun takeLong(ilt: Long) {} + +fun id(arg: T): T = arg + +fun test() { + takeByte(id(42)) + takeShort(id(42)) + takeInt(id(42)) + takeLong(id(42)) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.txt b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.txt new file mode 100644 index 00000000000..aae3c8f5b0c --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/partialForIlt.txt @@ -0,0 +1,8 @@ +package + +public fun id(/*0*/ arg: T): T +public fun takeByte(/*0*/ ilt: kotlin.Byte): kotlin.Unit +public fun takeInt(/*0*/ ilt: kotlin.Int): kotlin.Unit +public fun takeLong(/*0*/ ilt: kotlin.Long): kotlin.Unit +public fun takeShort(/*0*/ ilt: kotlin.Short): kotlin.Unit +public fun test(): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/inference/completion/withExact.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/withExact.fir.kt new file mode 100644 index 00000000000..8a9c36b2f74 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/withExact.fir.kt @@ -0,0 +1,26 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +import kotlin.internal.Exact + +class Inv(val arg: I) +class InvExact(val arg: @kotlin.internal.Exact E) + +interface Base +class Derived : Base +class Other : Base + +fun id(arg: K): K = arg + +fun test1(arg: Derived) { + id>(Inv(arg)) + id>(InvExact(arg)) +} + +fun Inv<@Exact R>.select(first: R, second: R): R = TODO() + +fun test2(derived: Derived, other: Other) { + Inv(derived).select(derived, other) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/withExact.kt b/compiler/testData/diagnostics/tests/inference/completion/withExact.kt new file mode 100644 index 00000000000..34e66140ba0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/withExact.kt @@ -0,0 +1,26 @@ +// !LANGUAGE: +NewInference +// !DIAGNOSTICS: -UNUSED_PARAMETER + +@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + +import kotlin.internal.Exact + +class Inv(val arg: I) +class InvExact(val arg: @kotlin.internal.Exact E) + +interface Base +class Derived : Base +class Other : Base + +fun id(arg: K): K = arg + +fun test1(arg: Derived) { + id>(Inv(arg)) + id>(InvExact(arg)) +} + +fun Inv<@Exact R>.select(first: R, second: R): R = TODO() + +fun test2(derived: Derived, other: Other) { + Inv(derived).select(derived, other) +} diff --git a/compiler/testData/diagnostics/tests/inference/completion/withExact.txt b/compiler/testData/diagnostics/tests/inference/completion/withExact.txt new file mode 100644 index 00000000000..4c0efdc7abc --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/completion/withExact.txt @@ -0,0 +1,42 @@ +package + +public fun id(/*0*/ arg: K): K +public fun test1(/*0*/ arg: Derived): kotlin.Unit +public fun test2(/*0*/ derived: Derived, /*1*/ other: Other): kotlin.Unit +public fun Inv.select(/*0*/ first: R, /*1*/ second: R): R + +public interface Base { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Derived : Base { + public constructor Derived() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ arg: I) + public final val arg: I + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class InvExact { + public constructor InvExact(/*0*/ arg: E) + public final val arg: E + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Other : Base { + public constructor Other() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 8b64711d43d..005d0d545cc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -10369,6 +10369,39 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractDiagnosticsTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); + } + + @TestMetadata("kt33166.kt") + public void testKt33166() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); + } + + @TestMetadata("partialForIlt.kt") + public void testPartialForIlt() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); + } + + @TestMetadata("withExact.kt") + public void testWithExact() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") @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 e831d6de918..ecabe26b1f5 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -10364,6 +10364,39 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing } } + @TestMetadata("compiler/testData/diagnostics/tests/inference/completion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Completion extends AbstractDiagnosticsUsingJavacTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCompletion() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/inference/completion"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/basic.kt"); + } + + @TestMetadata("kt33166.kt") + public void testKt33166() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/kt33166.kt"); + } + + @TestMetadata("partialForIlt.kt") + public void testPartialForIlt() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/partialForIlt.kt"); + } + + @TestMetadata("withExact.kt") + public void testWithExact() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/completion/withExact.kt"); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/inference/constraints") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)