[NI] Add feature for choosing candidate by lambda return type
This commit is contained in:
+23
@@ -1788,6 +1788,29 @@ public class FirOldFrontendDiagnosticsTestWithStdlibGenerated extends AbstractFi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/factoryPattern")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FactoryPattern extends AbstractFirOldFrontendDiagnosticsTestWithStdlib {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFactoryPattern() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/factoryPattern"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_disabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_disabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_disabled.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_enabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_enabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_enabled.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+2
@@ -119,6 +119,8 @@ class FirCallCompleter(
|
|||||||
inferenceSession.addPartiallyResolvedCall(approximatedCall)
|
inferenceSession.addPartiallyResolvedCall(approximatedCall)
|
||||||
CompletionResult(approximatedCall, false)
|
CompletionResult(approximatedCall, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isPrimitiveTypeOrNullablePri
|
|||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnderKotlinPackage
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnderKotlinPackage
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||||
|
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
@@ -196,8 +197,10 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
||||||
(temporaryTrace ?: trace).record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
(temporaryTrace ?: trace).record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||||
|
|
||||||
|
val inferedReturnType = functionTypeInfo.type?.arguments?.last()?.type?.takeIf { functionTypeInfo.type?.isFunctionTypeOrSubtype == true }
|
||||||
|
|
||||||
if (coroutineSession?.hasInapplicableCall() == true) {
|
if (coroutineSession?.hasInapplicableCall() == true) {
|
||||||
return ReturnArgumentsAnalysisResult(ReturnArgumentsInfo.empty, coroutineSession, hasInapplicableCallForBuilderInference = true)
|
return ReturnArgumentsAnalysisResult(ReturnArgumentsInfo.empty, coroutineSession, inferedReturnType, hasInapplicableCallForBuilderInference = true)
|
||||||
} else {
|
} else {
|
||||||
temporaryTrace?.commit()
|
temporaryTrace?.commit()
|
||||||
}
|
}
|
||||||
@@ -244,7 +247,8 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
lastExpressionCoercedToUnit,
|
lastExpressionCoercedToUnit,
|
||||||
returnArgumentFound
|
returnArgumentFound
|
||||||
),
|
),
|
||||||
coroutineSession
|
coroutineSession,
|
||||||
|
inferedReturnType
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,15 +18,14 @@ package org.jetbrains.kotlin.resolve.calls
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceResolver
|
import org.jetbrains.kotlin.resolve.calls.components.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.model.safeSubstitute
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.same
|
||||||
import java.lang.UnsupportedOperationException
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
|
|
||||||
@@ -142,13 +141,19 @@ class KotlinCallResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
var maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
|
||||||
refinedCandidates,
|
refinedCandidates,
|
||||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||||
discriminateGenerics = true // todo
|
discriminateGenerics = true // todo
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (maximallySpecificCandidates.size > 1 && callComponents.languageVersionSettings.supportsFeature(LanguageFeature.FactoryPatternResolution)) {
|
||||||
|
maximallySpecificCandidates = kotlinCallCompleter.chooseCandidateRegardingFactoryPatternResolution(maximallySpecificCandidates, resolutionCallbacks)
|
||||||
|
}
|
||||||
|
|
||||||
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
|
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -59,6 +59,7 @@ data class ReturnArgumentsInfo(
|
|||||||
data class ReturnArgumentsAnalysisResult(
|
data class ReturnArgumentsAnalysisResult(
|
||||||
val returnArgumentsInfo: ReturnArgumentsInfo,
|
val returnArgumentsInfo: ReturnArgumentsInfo,
|
||||||
val inferenceSession: InferenceSession?,
|
val inferenceSession: InferenceSession?,
|
||||||
|
val lambdaReturnType: KotlinType? = null,
|
||||||
val hasInapplicableCallForBuilderInference: Boolean = false
|
val hasInapplicableCallForBuilderInference: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+84
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.components
|
package org.jetbrains.kotlin.resolve.calls.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
||||||
@@ -15,11 +16,15 @@ 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.components.TrivialConstraintTypeInferenceOracle
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage.Empty.hasContradiction
|
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.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.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
|
import org.jetbrains.kotlin.types.model.safeSubstitute
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.same
|
||||||
|
|
||||||
class KotlinCallCompleter(
|
class KotlinCallCompleter(
|
||||||
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
|
||||||
@@ -66,10 +71,89 @@ class KotlinCallCompleter(
|
|||||||
candidate.runCompletion(completionMode, diagnosticHolder, resolutionCallbacks)
|
candidate.runCompletion(completionMode, diagnosticHolder, resolutionCallbacks)
|
||||||
candidate.asCallResolutionResult(completionMode, diagnosticHolder)
|
candidate.asCallResolutionResult(completionMode, diagnosticHolder)
|
||||||
}
|
}
|
||||||
|
ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA -> throw IllegalStateException("Should not be here")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun chooseCandidateRegardingFactoryPatternResolution(
|
||||||
|
candidates: Set<KotlinResolutionCandidate>,
|
||||||
|
resolutionCallbacks: KotlinResolutionCallbacks
|
||||||
|
): Set<KotlinResolutionCandidate> {
|
||||||
|
val lambdas = candidates.flatMap { candidate ->
|
||||||
|
candidate.getSubResolvedAtoms()
|
||||||
|
.filter { it is ResolvedLambdaAtom && !it.analyzed }
|
||||||
|
.map { candidate to it as ResolvedLambdaAtom }
|
||||||
|
}.groupBy { (_, atom) -> atom.atom }
|
||||||
|
.values
|
||||||
|
.singleOrNull()
|
||||||
|
?.toMap() ?: return candidates
|
||||||
|
|
||||||
|
if (!lambdas.values.same { it.parameters.size }) return candidates
|
||||||
|
if (!lambdas.values.all { it.expectedType?.isFunctionTypeOrSubtype == true }) return candidates
|
||||||
|
|
||||||
|
for (candidate in lambdas.keys) {
|
||||||
|
candidate.runCompletion(
|
||||||
|
ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA,
|
||||||
|
candidate,
|
||||||
|
resolutionCallbacks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!lambdas.entries.same { (candidate, atom) -> candidate.getInputTypesOfLambdaAtom(atom) }) {
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
val newAtoms = mutableMapOf<KotlinResolutionCandidate, ResolvedLambdaAtom>()
|
||||||
|
for ((candidate, atom) in lambdas.entries) {
|
||||||
|
newAtoms[candidate] = kotlinConstraintSystemCompleter.prepareLambdaAtomForFactoryPattern(atom, candidate, candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
val diagnosticHolderForLambda = KotlinDiagnosticsHolder.SimpleHolder()
|
||||||
|
val iterator = newAtoms.entries.iterator()
|
||||||
|
val (firstCandidate, firstAtom) = iterator.next()
|
||||||
|
val results = postponedArgumentsAnalyzer.analyzeLambda(
|
||||||
|
firstCandidate.getSystem().asPostponedArgumentsAnalyzerContext(),
|
||||||
|
resolutionCallbacks,
|
||||||
|
firstAtom,
|
||||||
|
diagnosticHolderForLambda
|
||||||
|
)
|
||||||
|
lambdas.getValue(firstCandidate).setAnalyzedResults(results.returnArgumentsInfo, listOf(firstAtom))
|
||||||
|
|
||||||
|
val lambdaReturnType = results.lambdaReturnType ?: return candidates
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val (candidate, atom) = iterator.next()
|
||||||
|
atom.setAnalyzedResults(results.returnArgumentsInfo, firstAtom.subResolvedAtoms!!)
|
||||||
|
lambdas.getValue(candidate).setAnalyzedResults(results.returnArgumentsInfo, listOf(atom))
|
||||||
|
candidate.csBuilder.addSubtypeConstraint(lambdaReturnType, atom.returnType, LambdaArgumentConstraintPosition(atom))
|
||||||
|
}
|
||||||
|
|
||||||
|
val errorCandidates = mutableSetOf<KotlinResolutionCandidate>()
|
||||||
|
val successfulCandidates = mutableSetOf<KotlinResolutionCandidate>()
|
||||||
|
|
||||||
|
for (candidate in candidates) {
|
||||||
|
if (candidate.isSuccessful) {
|
||||||
|
successfulCandidates += candidate
|
||||||
|
} else {
|
||||||
|
errorCandidates += candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
successfulCandidates.isNotEmpty() -> successfulCandidates
|
||||||
|
else -> errorCandidates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinResolutionCandidate.getInputTypesOfLambdaAtom(atom: ResolvedLambdaAtom): List<UnwrappedType> {
|
||||||
|
val result = mutableListOf<UnwrappedType>()
|
||||||
|
val substitutor = csBuilder.buildCurrentSubstitutor()
|
||||||
|
val ctx = getSystem().asConstraintSystemCompleterContext()
|
||||||
|
for (inputType in atom.inputTypes) {
|
||||||
|
result += substitutor.safeSubstitute(ctx, inputType) as UnwrappedType
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun KotlinResolutionCandidate.checkSamWithVararg(diagnosticHolder: KotlinDiagnosticsHolder.SimpleHolder) {
|
private fun KotlinResolutionCandidate.checkSamWithVararg(diagnosticHolder: KotlinDiagnosticsHolder.SimpleHolder) {
|
||||||
val samConversionPerArgumentWithWarningsForVarargAfterSam =
|
val samConversionPerArgumentWithWarningsForVarargAfterSam =
|
||||||
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) &&
|
callComponents.languageVersionSettings.supportsFeature(LanguageFeature.SamConversionPerArgument) &&
|
||||||
|
|||||||
+18
@@ -220,6 +220,24 @@ fun LambdaWithTypeVariableAsExpectedTypeAtom.transformToResolvedLambda(
|
|||||||
return resolvedLambdaAtom
|
return resolvedLambdaAtom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ResolvedLambdaAtom.transformToResolvedLambda(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||||
|
expectedType: UnwrappedType,
|
||||||
|
returnTypeVariable: TypeVariableForLambdaReturnType? = null
|
||||||
|
): ResolvedLambdaAtom {
|
||||||
|
val resolvedLambdaAtom = preprocessLambdaArgument(
|
||||||
|
csBuilder,
|
||||||
|
atom,
|
||||||
|
expectedType,
|
||||||
|
diagnosticsHolder,
|
||||||
|
forceResolution = true,
|
||||||
|
returnTypeVariable = returnTypeVariable
|
||||||
|
) as ResolvedLambdaAtom
|
||||||
|
|
||||||
|
return resolvedLambdaAtom
|
||||||
|
}
|
||||||
|
|
||||||
private fun preprocessCallableReference(
|
private fun preprocessCallableReference(
|
||||||
csBuilder: ConstraintSystemBuilder,
|
csBuilder: ConstraintSystemBuilder,
|
||||||
argument: CallableReferenceKotlinCallArgument,
|
argument: CallableReferenceKotlinCallArgument,
|
||||||
|
|||||||
+18
-14
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.CoroutinePosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.CoroutinePosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.model.*
|
import org.jetbrains.kotlin.types.model.*
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
@@ -65,12 +66,12 @@ class PostponedArgumentsAnalyzer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeLambda(
|
fun analyzeLambda(
|
||||||
c: Context,
|
c: Context,
|
||||||
resolutionCallbacks: KotlinResolutionCallbacks,
|
resolutionCallbacks: KotlinResolutionCallbacks,
|
||||||
lambda: ResolvedLambdaAtom,
|
lambda: ResolvedLambdaAtom,
|
||||||
diagnosticHolder: KotlinDiagnosticsHolder
|
diagnosticHolder: KotlinDiagnosticsHolder
|
||||||
) {
|
): ReturnArgumentsAnalysisResult {
|
||||||
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
|
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
|
||||||
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
|
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
|
||||||
|
|
||||||
@@ -120,20 +121,21 @@ class PostponedArgumentsAnalyzer(
|
|||||||
else FilteredAnnotations(annotations, true) { it != KotlinBuiltIns.FQ_NAMES.extensionFunctionType }
|
else FilteredAnnotations(annotations, true) { it != KotlinBuiltIns.FQ_NAMES.extensionFunctionType }
|
||||||
}
|
}
|
||||||
|
|
||||||
val (returnArgumentsInfo, inferenceSession, hasInapplicableCallForBuilderInference) =
|
val returnArgumentsAnalysisResult = resolutionCallbacks.analyzeAndGetLambdaReturnArguments(
|
||||||
resolutionCallbacks.analyzeAndGetLambdaReturnArguments(
|
lambda.atom,
|
||||||
lambda.atom,
|
lambda.isSuspend,
|
||||||
lambda.isSuspend,
|
receiver,
|
||||||
receiver,
|
parameters,
|
||||||
parameters,
|
expectedTypeForReturnArguments,
|
||||||
expectedTypeForReturnArguments,
|
convertedAnnotations ?: Annotations.EMPTY,
|
||||||
convertedAnnotations ?: Annotations.EMPTY,
|
stubsForPostponedVariables.cast()
|
||||||
stubsForPostponedVariables.cast()
|
)
|
||||||
)
|
val (returnArgumentsInfo, inferenceSession, inferedReturnType, hasInapplicableCallForBuilderInference) =
|
||||||
|
returnArgumentsAnalysisResult
|
||||||
|
|
||||||
if (hasInapplicableCallForBuilderInference) {
|
if (hasInapplicableCallForBuilderInference) {
|
||||||
c.getBuilder().removePostponedVariables()
|
c.getBuilder().removePostponedVariables()
|
||||||
return
|
return returnArgumentsAnalysisResult
|
||||||
}
|
}
|
||||||
|
|
||||||
val returnArguments = returnArgumentsInfo.nonErrorArguments
|
val returnArguments = returnArgumentsInfo.nonErrorArguments
|
||||||
@@ -169,7 +171,7 @@ class PostponedArgumentsAnalyzer(
|
|||||||
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, storageSnapshot, diagnosticHolder)
|
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, storageSnapshot, diagnosticHolder)
|
||||||
if (postponedVariables == null) {
|
if (postponedVariables == null) {
|
||||||
c.getBuilder().removePostponedVariables()
|
c.getBuilder().removePostponedVariables()
|
||||||
return
|
return returnArgumentsAnalysisResult
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((constructor, resultType) in postponedVariables) {
|
for ((constructor, resultType) in postponedVariables) {
|
||||||
@@ -180,6 +182,8 @@ class PostponedArgumentsAnalyzer(
|
|||||||
c.getBuilder().addEqualityConstraint(variable.defaultType(c), resultType, CoroutinePosition())
|
c.getBuilder().addEqualityConstraint(variable.defaultType(c), resultType, CoroutinePosition())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return returnArgumentsAnalysisResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun UnwrappedType?.receiver(): UnwrappedType? {
|
private fun UnwrappedType?.receiver(): UnwrappedType? {
|
||||||
|
|||||||
+36
-1
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference.components
|
package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.transformToResolvedLambda
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
@@ -12,6 +13,8 @@ import org.jetbrains.kotlin.types.*
|
|||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.safeSubstitute
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import kotlin.collections.LinkedHashSet
|
import kotlin.collections.LinkedHashSet
|
||||||
@@ -24,7 +27,8 @@ class KotlinConstraintSystemCompleter(
|
|||||||
|
|
||||||
enum class ConstraintSystemCompletionMode {
|
enum class ConstraintSystemCompletionMode {
|
||||||
FULL,
|
FULL,
|
||||||
PARTIAL
|
PARTIAL,
|
||||||
|
UNTIL_FIRST_LAMBDA
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
|
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
|
||||||
@@ -91,7 +95,9 @@ class KotlinConstraintSystemCompleter(
|
|||||||
analyze: (PostponedResolvedAtom) -> Unit
|
analyze: (PostponedResolvedAtom) -> Unit
|
||||||
) {
|
) {
|
||||||
completion@ while (true) {
|
completion@ while (true) {
|
||||||
|
// TODO
|
||||||
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
val postponedArguments = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
||||||
|
if (completionMode == ConstraintSystemCompletionMode.UNTIL_FIRST_LAMBDA && hasLambdaToAnalyze(postponedArguments)) return
|
||||||
|
|
||||||
// Stage 1: analyze postponed arguments with fixed parameter types
|
// Stage 1: analyze postponed arguments with fixed parameter types
|
||||||
if (analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze))
|
if (analyzeArgumentWithFixedParameterTypes(postponedArguments, analyze))
|
||||||
@@ -210,6 +216,35 @@ class KotlinConstraintSystemCompleter(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun prepareLambdaAtomForFactoryPattern(
|
||||||
|
atom: ResolvedLambdaAtom,
|
||||||
|
candidate: KotlinResolutionCandidate,
|
||||||
|
diagnosticsHolder: KotlinDiagnosticsHolder,
|
||||||
|
): ResolvedLambdaAtom {
|
||||||
|
val returnVariable = TypeVariableForLambdaReturnType(candidate.callComponents.builtIns, "_R")
|
||||||
|
val csBuilder = candidate.csBuilder
|
||||||
|
csBuilder.registerVariable(returnVariable)
|
||||||
|
val functionalType: KotlinType = csBuilder.buildCurrentSubstitutor().safeSubstitute(candidate.getSystem().asConstraintSystemCompleterContext(), atom.expectedType!!) as KotlinType
|
||||||
|
val expectedType = KotlinTypeFactory.simpleType(
|
||||||
|
functionalType.annotations,
|
||||||
|
functionalType.constructor,
|
||||||
|
functionalType.arguments.dropLast(1) + returnVariable.defaultType.asTypeProjection(),
|
||||||
|
functionalType.isMarkedNullable
|
||||||
|
)
|
||||||
|
csBuilder.addSubtypeConstraint(
|
||||||
|
expectedType,
|
||||||
|
functionalType,
|
||||||
|
ArgumentConstraintPosition(atom.atom)
|
||||||
|
)
|
||||||
|
return atom.transformToResolvedLambda(csBuilder, diagnosticsHolder, expectedType, returnVariable)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Context.hasLambdaToAnalyze(
|
||||||
|
postponedArguments: List<PostponedResolvedAtom>
|
||||||
|
): Boolean {
|
||||||
|
return analyzeArgumentWithFixedParameterTypes(postponedArguments) {}
|
||||||
|
}
|
||||||
|
|
||||||
private fun findPostponedArgumentWithRevisableExpectedType(postponedArguments: List<PostponedResolvedAtom>) =
|
private fun findPostponedArgumentWithRevisableExpectedType(postponedArguments: List<PostponedResolvedAtom>) =
|
||||||
postponedArguments.firstOrNull { argument -> argument is PostponedAtomWithRevisableExpectedType }
|
postponedArguments.firstOrNull { argument -> argument is PostponedAtomWithRevisableExpectedType }
|
||||||
|
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// !LANGUAGE: +NewInference -FactoryPatternResolution
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION
|
||||||
|
// ISSUE: KT-11265
|
||||||
|
|
||||||
|
fun create(f: (Int) -> Int): Int = 1
|
||||||
|
fun create(f: (Int) -> String): String = ""
|
||||||
|
|
||||||
|
fun takeString(s: String) {}
|
||||||
|
fun takeInt(s: Int) {}
|
||||||
|
|
||||||
|
fun test_1() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_3() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K> create(x: K, f: (K) -> Int): Int = 1
|
||||||
|
fun <T> create(x: T, f: (T) -> String): String = ""
|
||||||
|
|
||||||
|
fun test_4() {
|
||||||
|
val x = <!AMBIGUITY!>create<!>("") { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_5() {
|
||||||
|
val x = <!AMBIGUITY!>create<!>("") { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
Vendored
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// !LANGUAGE: +NewInference -FactoryPatternResolution
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION
|
||||||
|
// ISSUE: KT-11265
|
||||||
|
|
||||||
|
fun create(f: (Int) -> Int): Int = 1
|
||||||
|
fun create(f: (Int) -> String): String = ""
|
||||||
|
|
||||||
|
fun takeString(s: String) {}
|
||||||
|
fun takeInt(s: Int) {}
|
||||||
|
|
||||||
|
fun test_1() {
|
||||||
|
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY!>create<!> { "" }
|
||||||
|
takeString(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2() {
|
||||||
|
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY!>create<!> { 1 }
|
||||||
|
takeInt(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_3() {
|
||||||
|
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY!>create<!> { 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K> create(x: K, f: (K) -> Int): Int = 1
|
||||||
|
fun <T> create(x: T, f: (T) -> String): String = ""
|
||||||
|
|
||||||
|
fun test_4() {
|
||||||
|
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY!>create<!>("") { "" }
|
||||||
|
takeString(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!>)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_5() {
|
||||||
|
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY!>create<!>("") { 1 }
|
||||||
|
takeInt(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!>)
|
||||||
|
}
|
||||||
compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_disabled.txt
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun create(/*0*/ f: (kotlin.Int) -> kotlin.Int): kotlin.Int
|
||||||
|
public fun create(/*0*/ f: (kotlin.Int) -> kotlin.String): kotlin.String
|
||||||
|
public fun </*0*/ K> create(/*0*/ x: K, /*1*/ f: (K) -> kotlin.Int): kotlin.Int
|
||||||
|
public fun </*0*/ T> create(/*0*/ x: T, /*1*/ f: (T) -> kotlin.String): kotlin.String
|
||||||
|
public fun takeInt(/*0*/ s: kotlin.Int): kotlin.Unit
|
||||||
|
public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
public fun test_1(): kotlin.Unit
|
||||||
|
public fun test_2(): kotlin.Unit
|
||||||
|
public fun test_3(): kotlin.Unit
|
||||||
|
public fun test_4(): kotlin.Unit
|
||||||
|
public fun test_5(): kotlin.Unit
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// !LANGUAGE: +NewInference +FactoryPatternResolution
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION
|
||||||
|
// ISSUE: KT-11265
|
||||||
|
|
||||||
|
fun create(f: (Int) -> Int): Int = 1
|
||||||
|
fun create(f: (Int) -> String): String = ""
|
||||||
|
|
||||||
|
fun takeString(s: String) {}
|
||||||
|
fun takeInt(s: Int) {}
|
||||||
|
|
||||||
|
fun test_1() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_3() {
|
||||||
|
val x = <!AMBIGUITY!>create<!> { 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K> create(x: K, f: (K) -> Int): Int = 1
|
||||||
|
fun <T> create(x: T, f: (T) -> String): String = ""
|
||||||
|
|
||||||
|
fun test_4() {
|
||||||
|
val x = <!AMBIGUITY!>create<!>("") { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_5() {
|
||||||
|
val x = <!AMBIGUITY!>create<!>("") { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
Vendored
+36
@@ -0,0 +1,36 @@
|
|||||||
|
// !LANGUAGE: +NewInference +FactoryPatternResolution
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE -UNUSED_EXPRESSION
|
||||||
|
// ISSUE: KT-11265
|
||||||
|
|
||||||
|
fun create(f: (Int) -> Int): Int = 1
|
||||||
|
fun create(f: (Int) -> String): String = ""
|
||||||
|
|
||||||
|
fun takeString(s: String) {}
|
||||||
|
fun takeInt(s: Int) {}
|
||||||
|
|
||||||
|
fun test_1() {
|
||||||
|
val x = create { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2() {
|
||||||
|
val x = create { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_3() {
|
||||||
|
val x = <!NONE_APPLICABLE!>create<!> { 1.0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <K> create(x: K, f: (K) -> Int): Int = 1
|
||||||
|
fun <T> create(x: T, f: (T) -> String): String = ""
|
||||||
|
|
||||||
|
fun test_4() {
|
||||||
|
val x = create("") { "" }
|
||||||
|
takeString(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_5() {
|
||||||
|
val x = create("") { 1 }
|
||||||
|
takeInt(x)
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun create(/*0*/ f: (kotlin.Int) -> kotlin.Int): kotlin.Int
|
||||||
|
public fun create(/*0*/ f: (kotlin.Int) -> kotlin.String): kotlin.String
|
||||||
|
public fun </*0*/ K> create(/*0*/ x: K, /*1*/ f: (K) -> kotlin.Int): kotlin.Int
|
||||||
|
public fun </*0*/ T> create(/*0*/ x: T, /*1*/ f: (T) -> kotlin.String): kotlin.String
|
||||||
|
public fun takeInt(/*0*/ s: kotlin.Int): kotlin.Unit
|
||||||
|
public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
|
public fun test_1(): kotlin.Unit
|
||||||
|
public fun test_2(): kotlin.Unit
|
||||||
|
public fun test_3(): kotlin.Unit
|
||||||
|
public fun test_4(): kotlin.Unit
|
||||||
|
public fun test_5(): kotlin.Unit
|
||||||
+23
@@ -2803,6 +2803,29 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/factoryPattern")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FactoryPattern extends AbstractDiagnosticsTestWithStdLib {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFactoryPattern() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/factoryPattern"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_disabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_disabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_disabled.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_enabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_enabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_enabled.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+23
@@ -2803,6 +2803,29 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/factoryPattern")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class FactoryPattern extends AbstractDiagnosticsTestWithStdLibUsingJavac {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInFactoryPattern() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/factoryPattern"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_disabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_disabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_disabled.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadByLambdaReturnType_enabled.kt")
|
||||||
|
public void testOverloadByLambdaReturnType_enabled() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/factoryPattern/overloadByLambdaReturnType_enabled.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/forInArrayLoop")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ enum class LanguageFeature(
|
|||||||
FunctionReferenceWithDefaultValueAsOtherType(sinceVersion = KOTLIN_1_4),
|
FunctionReferenceWithDefaultValueAsOtherType(sinceVersion = KOTLIN_1_4),
|
||||||
NonStrictOnlyInputTypesChecks(sinceVersion = KOTLIN_1_4),
|
NonStrictOnlyInputTypesChecks(sinceVersion = KOTLIN_1_4),
|
||||||
SuspendConversion(sinceVersion = KOTLIN_1_4, defaultState = State.DISABLED),
|
SuspendConversion(sinceVersion = KOTLIN_1_4, defaultState = State.DISABLED),
|
||||||
|
FactoryPatternResolution(sinceVersion = KOTLIN_1_4),
|
||||||
|
|
||||||
BooleanElvisBoundSmartCasts(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), // see KT-26357 for details
|
BooleanElvisBoundSmartCasts(sinceVersion = KOTLIN_1_3, defaultState = State.DISABLED), // see KT-26357 for details
|
||||||
NewDataFlowForTryExpressions(sinceVersion = KOTLIN_1_4, defaultState = State.DISABLED),
|
NewDataFlowForTryExpressions(sinceVersion = KOTLIN_1_4, defaultState = State.DISABLED),
|
||||||
|
|||||||
@@ -149,3 +149,16 @@ inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapToNullable(des
|
|||||||
|
|
||||||
fun <E : Enum<E>> min(a: E, b: E): E = if (a < b) a else b
|
fun <E : Enum<E>> min(a: E, b: E): E = if (a < b) a else b
|
||||||
fun <E : Comparable<E>> min(a: E, b: E): E = if (a < b) a else b
|
fun <E : Comparable<E>> min(a: E, b: E): E = if (a < b) a else b
|
||||||
|
|
||||||
|
inline fun <T, R> Iterable<T>.same(extractor: (T) -> R): Boolean {
|
||||||
|
val iterator = iterator()
|
||||||
|
val firstValue = extractor(iterator.next())
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val item = iterator.next()
|
||||||
|
val value = extractor(item)
|
||||||
|
if (value != firstValue) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user