[NI] Fix checking for inline lambdas without candidate

#KT-34506
This commit is contained in:
Dmitriy Novozhilov
2020-06-01 13:55:26 +03:00
parent 30037682f8
commit 069adebf01
11 changed files with 160 additions and 13 deletions
@@ -1839,6 +1839,11 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
public void testResolutionInOldInference() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/resolutionInOldInference.kt");
}
@TestMetadata("returnFromInlineLambda.kt")
public void testReturnFromInlineLambda() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/returnFromInlineLambda.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
@@ -274,6 +274,7 @@ public interface BindingContext {
WritableSlice<KtExpression, PrimitiveNumericComparisonInfo> PRIMITIVE_NUMERIC_COMPARISON_INFO = Slices.createSimpleSlice();
WritableSlice<KtExpression, Ref<VariableDescriptor>> NEW_INFERENCE_CATCH_EXCEPTION_PARAMETER = Slices.createSimpleSlice();
WritableSlice<PsiElement, Boolean> NEW_INFERENCE_IS_LAMBDA_FOR_OVERLOAD_RESOLUTION_INLINE = Slices.createSimpleSlice();
@SuppressWarnings("UnusedDeclaration")
@Deprecated // This field is needed only for the side effects of its initializer
@@ -8,19 +8,14 @@ package org.jetbrains.kotlin.resolve.calls.tower
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnderKotlinPackage
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.*
@@ -40,6 +35,7 @@ import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
@@ -48,7 +44,6 @@ import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.types.refinement.TypeRefinement
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
data class LambdaContextInfo(
@@ -317,6 +312,17 @@ class KotlinResolutionCallbacksImpl(
return convertSignedConstantToUnsigned(argumentExpression)
}
override fun recordInlinabilityOfLambda(lambdas: Set<Map.Entry<KotlinResolutionCandidate, ResolvedLambdaAtom>>) {
val call = lambdas.first().value.atom.psiCallArgument.valueArgument as? KtLambdaArgument ?: return
val literal = call.getLambdaExpression()?.functionLiteral ?: return
val isLambdaInline = lambdas.all { (candidate, atom) ->
if (!InlineUtil.isInline(candidate.resolvedCall.candidateDescriptor)) return
val valueParameterDescriptor = candidate.resolvedCall.argumentToCandidateParameter[atom.atom] ?: return
InlineUtil.isInlineParameter(valueParameterDescriptor)
}.takeIf { it }
trace.record(BindingContext.NEW_INFERENCE_IS_LAMBDA_FOR_OVERLOAD_RESOLUTION_INLINE, literal, isLambdaInline)
}
private fun convertSignedConstantToUnsigned(expression: KtExpression): IntegerValueTypeConstant? {
val constant = trace[BindingContext.COMPILE_TIME_VALUE, expression]
if (constant !is IntegerValueTypeConstant || !constantCanBeConvertedToUnsigned(constant)) return null
@@ -99,6 +99,11 @@ public class InlineUtil {
if (containingFunctionDescriptor == null) return false;
while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) {
Boolean isLambdaDefinitelyInline = bindingContext.get(BindingContext.NEW_INFERENCE_IS_LAMBDA_FOR_OVERLOAD_RESOLUTION_INLINE, containingFunction);
if (isLambdaDefinitelyInline != null) {
return isLambdaDefinitelyInline;
}
if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) {
return false;
}
@@ -6,11 +6,8 @@
package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.DefaultImplementation
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -20,7 +17,6 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.SimpleConstraintSystem
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.UnwrappedType
@@ -85,4 +81,6 @@ interface KotlinResolutionCallbacks {
fun disableContractsIfNecessary(resolvedAtom: ResolvedCallAtom)
fun convertSignedConstantToUnsigned(argument: KotlinCallArgument): IntegerValueTypeConstant?
fun recordInlinabilityOfLambda(atom: Set<Map.Entry<KotlinResolutionCandidate, ResolvedLambdaAtom>>)
}
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintS
import org.jetbrains.kotlin.resolve.calls.inference.components.TrivialConstraintTypeInferenceOracle
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empty.hasContradiction
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
import org.jetbrains.kotlin.types.ErrorUtils
@@ -113,6 +111,9 @@ class KotlinCallCompleter(
val diagnosticHolderForLambda = KotlinDiagnosticsHolder.SimpleHolder()
val iterator = newAtoms.entries.iterator()
val (firstCandidate, firstAtom) = iterator.next()
resolutionCallbacks.recordInlinabilityOfLambda(lambdas.entries)
val results = postponedArgumentsAnalyzer.analyzeLambda(
firstCandidate.getSystem().asPostponedArgumentsAnalyzerContext(),
resolutionCallbacks,
@@ -0,0 +1,51 @@
// !LANGUAGE: +NewInference +OverloadResolutionByLambdaReturnType
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION -EXPERIMENTAL_API_USAGE -EXPERIMENTAL_UNSIGNED_LITERALS
// ISSUE: KT-11265
// FILE: OverloadResolutionByLambdaReturnType.kt
package kotlin
annotation class OverloadResolutionByLambdaReturnType
// FILE: main.kt
import kotlin.OverloadResolutionByLambdaReturnType
inline fun <T, R> Array<out T>.myFlatMap(transform: (T) -> Iterable<R>): List<R> {
TODO()
}
@OverloadResolutionByLambdaReturnType
@JvmName("seqFlatMap")
inline fun <T, R> Array<out T>.myFlatMap(transform: (T) -> Sequence<R>): List<R> {
TODO()
}
fun String.toList(): List<String> = null!!
fun test_1(a: Array<String>, b: Boolean) {
a.<!AMBIGUITY!>myFlatMap<!> { <!UNRESOLVED_REFERENCE!>it<!>.toList().ifEmpty { return } }
a.<!AMBIGUITY!>myFlatMap<!> {
if (b) return
<!UNRESOLVED_REFERENCE!>it<!>.toList()
}
}
fun <T, R> Array<out T>.noInlineFlatMap(transform: (T) -> Iterable<R>): List<R> {
TODO()
}
@OverloadResolutionByLambdaReturnType
@JvmName("noInlineSeqFlatMap")
fun <T, R> Array<out T>.noInlineFlatMap(transform: (T) -> Sequence<R>): List<R> {
TODO()
}
fun test_2(a: Array<String>, b: Boolean) {
a.<!AMBIGUITY!>noInlineFlatMap<!> { <!UNRESOLVED_REFERENCE!>it<!>.toList().ifEmpty { return } }
a.<!AMBIGUITY!>noInlineFlatMap<!> {
if (b) return
<!UNRESOLVED_REFERENCE!>it<!>.toList()
}
}
@@ -0,0 +1,51 @@
// !LANGUAGE: +NewInference +OverloadResolutionByLambdaReturnType
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION -EXPERIMENTAL_API_USAGE -EXPERIMENTAL_UNSIGNED_LITERALS
// ISSUE: KT-11265
// FILE: OverloadResolutionByLambdaReturnType.kt
package kotlin
annotation class OverloadResolutionByLambdaReturnType
// FILE: main.kt
import kotlin.OverloadResolutionByLambdaReturnType
inline fun <T, R> Array<out T>.myFlatMap(transform: (T) -> Iterable<R>): List<R> {
TODO()
}
@OverloadResolutionByLambdaReturnType
@JvmName("seqFlatMap")
inline fun <T, R> Array<out T>.myFlatMap(transform: (T) -> Sequence<R>): List<R> {
TODO()
}
fun String.toList(): List<String> = null!!
fun test_1(a: Array<String>, b: Boolean) {
a.myFlatMap { it.toList().ifEmpty { return } }
a.myFlatMap {
if (b) return
it.toList()
}
}
fun <T, R> Array<out T>.noInlineFlatMap(transform: (T) -> Iterable<R>): List<R> {
TODO()
}
@OverloadResolutionByLambdaReturnType
@JvmName("noInlineSeqFlatMap")
fun <T, R> Array<out T>.noInlineFlatMap(transform: (T) -> Sequence<R>): List<R> {
TODO()
}
fun test_2(a: Array<String>, b: Boolean) {
a.noInlineFlatMap { it.toList().ifEmpty { <!RETURN_NOT_ALLOWED!>return<!> } }
a.noInlineFlatMap {
if (b) <!RETURN_NOT_ALLOWED!>return<!>
it.toList()
}
}
@@ -0,0 +1,19 @@
package
public fun test_1(/*0*/ a: kotlin.Array<kotlin.String>, /*1*/ b: kotlin.Boolean): kotlin.Unit
public fun test_2(/*0*/ a: kotlin.Array<kotlin.String>, /*1*/ b: kotlin.Boolean): kotlin.Unit
public inline fun </*0*/ T, /*1*/ R> kotlin.Array<out T>.myFlatMap(/*0*/ transform: (T) -> kotlin.collections.Iterable<R>): kotlin.collections.List<R>
@kotlin.OverloadResolutionByLambdaReturnType @kotlin.jvm.JvmName(name = "seqFlatMap") public inline fun </*0*/ T, /*1*/ R> kotlin.Array<out T>.myFlatMap(/*0*/ transform: (T) -> kotlin.sequences.Sequence<R>): kotlin.collections.List<R>
public fun </*0*/ T, /*1*/ R> kotlin.Array<out T>.noInlineFlatMap(/*0*/ transform: (T) -> kotlin.collections.Iterable<R>): kotlin.collections.List<R>
@kotlin.OverloadResolutionByLambdaReturnType @kotlin.jvm.JvmName(name = "noInlineSeqFlatMap") public fun </*0*/ T, /*1*/ R> kotlin.Array<out T>.noInlineFlatMap(/*0*/ transform: (T) -> kotlin.sequences.Sequence<R>): kotlin.collections.List<R>
public fun kotlin.String.toList(): kotlin.collections.List<kotlin.String>
package kotlin {
public final annotation class OverloadResolutionByLambdaReturnType : kotlin.Annotation {
public constructor OverloadResolutionByLambdaReturnType()
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
}
}
@@ -2854,6 +2854,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
public void testResolutionInOldInference() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/resolutionInOldInference.kt");
}
@TestMetadata("returnFromInlineLambda.kt")
public void testReturnFromInlineLambda() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/returnFromInlineLambda.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
@@ -2854,6 +2854,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
public void testResolutionInOldInference() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/resolutionInOldInference.kt");
}
@TestMetadata("returnFromInlineLambda.kt")
public void testReturnFromInlineLambda() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/returnFromInlineLambda.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")