[FIR] Implement new completion mode calculator
Note that `testDelegates` now fails due to KT-37638 and
`testSimpleIn` fails due to problems with type parameters
of inner classes
This commit is contained in:
Vendored
+1
-1
@@ -2,7 +2,7 @@ interface Out<out E>
|
|||||||
|
|
||||||
fun <X> id(x: Out<X>): Out<X> = TODO()
|
fun <X> id(x: Out<X>): Out<X> = TODO()
|
||||||
|
|
||||||
fun <F : Any> foo(computable: Out<F?>)
|
fun <F : Any> foo(computable: Out<F?>) {}
|
||||||
|
|
||||||
fun <T : Any> bar(computable: Out<T?>) {
|
fun <T : Any> bar(computable: Out<T?>) {
|
||||||
foo(id(computable))
|
foo(id(computable))
|
||||||
|
|||||||
Vendored
+4
-3
@@ -4,7 +4,8 @@ FILE: definetelyNotNullForTypeParameter.kt
|
|||||||
public final fun <X> id(x: R|Out<X>|): R|Out<X>| {
|
public final fun <X> id(x: R|Out<X>|): R|Out<X>| {
|
||||||
^id R|kotlin/TODO|()
|
^id R|kotlin/TODO|()
|
||||||
}
|
}
|
||||||
public final fun <F : R|kotlin/Any|> foo(computable: R|Out<F?>|): R|kotlin/Unit|
|
public final fun <F : R|kotlin/Any|> foo(computable: R|Out<F?>|): R|kotlin/Unit| {
|
||||||
public final fun <T : R|kotlin/Any|> bar(computable: R|Out<T?>|): R|kotlin/Unit| {
|
}
|
||||||
R|/foo|<R|T|>(R|/id|<R|T?|>(R|<local>/computable|))
|
public final fun <T : R|kotlin/Any|> bar(computable: R|Out<T?>|): R|kotlin/Unit| {
|
||||||
|
R|/foo|<R|T?!!|>(R|/id|<R|T?|>(R|<local>/computable|))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
|
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
|
||||||
@@ -17,6 +16,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
|||||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||||
import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack
|
import org.jetbrains.kotlin.fir.resolve.ImplicitReceiverStack
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.PostponedResolvedAtom
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
|
|
||||||
data class CallInfo(
|
data class CallInfo(
|
||||||
@@ -114,7 +113,7 @@ class Candidate(
|
|||||||
|
|
||||||
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
var argumentMapping: Map<FirExpression, FirValueParameter>? = null
|
||||||
lateinit var typeArgumentMapping: TypeArgumentMapping
|
lateinit var typeArgumentMapping: TypeArgumentMapping
|
||||||
val postponedAtoms = mutableListOf<PostponedResolvedAtomMarker>()
|
val postponedAtoms = mutableListOf<PostponedResolvedAtom>()
|
||||||
|
|
||||||
val diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf()
|
val diagnostics: MutableList<ResolutionDiagnostic> = mutableListOf()
|
||||||
|
|
||||||
|
|||||||
+231
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.fir.resolve.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeIntegerLiteralType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.Context
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.TrivialConstraintTypeInferenceOracle
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
fun Candidate.computeCompletionMode(
|
||||||
|
components: InferenceComponents,
|
||||||
|
expectedType: FirTypeRef?,
|
||||||
|
currentReturnType: ConeKotlinType?
|
||||||
|
): ConstraintSystemCompletionMode {
|
||||||
|
return when {
|
||||||
|
// Presence of expected type means that we are trying to complete outermost call => completion mode should be full
|
||||||
|
expectedType != null -> ConstraintSystemCompletionMode.FULL
|
||||||
|
|
||||||
|
// This is questionable as null return type can be only for error call
|
||||||
|
currentReturnType == null || currentReturnType is ConeIntegerLiteralType -> ConstraintSystemCompletionMode.PARTIAL
|
||||||
|
|
||||||
|
// Full if return type for call has no type variables
|
||||||
|
csBuilder.isProperType(currentReturnType) -> ConstraintSystemCompletionMode.FULL
|
||||||
|
|
||||||
|
else -> CalculatorForNestedCall(
|
||||||
|
this, currentReturnType, csBuilder, components.trivialConstraintTypeInferenceOracle
|
||||||
|
).computeCompletionMode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private typealias CsCompleterContext = Context
|
||||||
|
|
||||||
|
private class CalculatorForNestedCall(
|
||||||
|
private val candidate: Candidate,
|
||||||
|
private val returnType: ConeKotlinType?,
|
||||||
|
private val context: CsCompleterContext,
|
||||||
|
private val oracle: TrivialConstraintTypeInferenceOracle
|
||||||
|
) {
|
||||||
|
private enum class FixationDirection {
|
||||||
|
TO_SUBTYPE, EQUALITY
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fixationDirectionsForVariables: MutableMap<VariableWithConstraints, FixationDirection> =
|
||||||
|
newLinkedHashMapWithExpectedSize(context.notFixedTypeVariables.size)
|
||||||
|
private val variablesWithQueuedConstraints = mutableSetOf<TypeVariableMarker>()
|
||||||
|
private val typesToProcess: Queue<KotlinTypeMarker> = ArrayDeque()
|
||||||
|
|
||||||
|
private val postponedAtoms: List<PostponedResolvedAtom> by lazy {
|
||||||
|
candidate.postponedAtoms.filterNot { it.analyzed }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeCompletionMode(): ConstraintSystemCompletionMode = with(context) {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
if (!type.contains { it.typeConstructor() in notFixedTypeVariables })
|
||||||
|
continue
|
||||||
|
|
||||||
|
val fixationDirectionsFromType = mutableSetOf<FixationDirectionForVariable>()
|
||||||
|
collectRequiredDirectionsForVariables(type, TypeVariance.OUT, fixationDirectionsFromType)
|
||||||
|
|
||||||
|
for (directionForVariable in fixationDirectionsFromType) {
|
||||||
|
updateDirection(directionForVariable)
|
||||||
|
enqueueTypesFromConstraints(directionForVariable.variable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ->
|
||||||
|
if (oldDirection != FixationDirection.EQUALITY && oldDirection != newDirection)
|
||||||
|
fixationDirectionsForVariables[variable] = FixationDirection.EQUALITY
|
||||||
|
} ?: run {
|
||||||
|
fixationDirectionsForVariables[variable] = newDirection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class FixationDirectionForVariable(val variable: VariableWithConstraints, val direction: FixationDirection)
|
||||||
|
|
||||||
|
private fun CsCompleterContext.collectRequiredDirectionsForVariables(
|
||||||
|
type: KotlinTypeMarker, outerVariance: TypeVariance,
|
||||||
|
fixationDirectionsCollector: MutableSet<FixationDirectionForVariable>
|
||||||
|
) {
|
||||||
|
val typeArgumentsCount = type.argumentsCount()
|
||||||
|
if (typeArgumentsCount > 0) {
|
||||||
|
for (position in 0 until typeArgumentsCount) {
|
||||||
|
val argument = type.getArgument(position)
|
||||||
|
val parameter = type.typeConstructor().getParameter(position)
|
||||||
|
|
||||||
|
if (argument.isStarProjection())
|
||||||
|
continue
|
||||||
|
|
||||||
|
collectRequiredDirectionsForVariables(
|
||||||
|
argument.getType(),
|
||||||
|
compositeVariance(outerVariance, argument, parameter),
|
||||||
|
fixationDirectionsCollector
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
processTypeWithoutParameters(type, outerVariance, fixationDirectionsCollector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CsCompleterContext.compositeVariance(
|
||||||
|
outerVariance: TypeVariance,
|
||||||
|
argument: TypeArgumentMarker,
|
||||||
|
parameter: TypeParameterMarker
|
||||||
|
): TypeVariance {
|
||||||
|
val effectiveArgumentVariance = AbstractTypeChecker.effectiveVariance(parameter.getVariance(), argument.getVariance())
|
||||||
|
?: TypeVariance.INV // conflicting variance
|
||||||
|
return when (outerVariance) {
|
||||||
|
TypeVariance.INV -> TypeVariance.INV
|
||||||
|
TypeVariance.OUT -> effectiveArgumentVariance
|
||||||
|
TypeVariance.IN -> effectiveArgumentVariance.reversed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TypeVariance.reversed(): TypeVariance = when (this) {
|
||||||
|
TypeVariance.IN -> TypeVariance.OUT
|
||||||
|
TypeVariance.OUT -> TypeVariance.IN
|
||||||
|
TypeVariance.INV -> TypeVariance.INV
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CsCompleterContext.processTypeWithoutParameters(
|
||||||
|
type: KotlinTypeMarker, compositeVariance: TypeVariance,
|
||||||
|
newRequirementsCollector: MutableSet<FixationDirectionForVariable>
|
||||||
|
) {
|
||||||
|
val variableWithConstraints = notFixedTypeVariables[type.typeConstructor()] ?: return
|
||||||
|
val direction = when (compositeVariance) {
|
||||||
|
TypeVariance.IN -> FixationDirection.EQUALITY // Assuming that variables in contravariant positions are fixed to subtype
|
||||||
|
TypeVariance.OUT -> FixationDirection.TO_SUBTYPE
|
||||||
|
TypeVariance.INV -> FixationDirection.EQUALITY
|
||||||
|
}
|
||||||
|
val requirement = FixationDirectionForVariable(variableWithConstraints, direction)
|
||||||
|
newRequirementsCollector.add(requirement)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CsCompleterContext.hasProperConstraint(
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
direction: FixationDirection
|
||||||
|
): Boolean {
|
||||||
|
val constraints = variableWithConstraints.constraints
|
||||||
|
val variable = variableWithConstraints.typeVariable
|
||||||
|
|
||||||
|
// ILT constraint tracking is necessary to prevent incorrect full completion from Nothing constraint
|
||||||
|
// Consider ILT <: T; Nothing <: T for T requiring lower constraint
|
||||||
|
// Nothing would trigger full completion, but resulting type would be Int
|
||||||
|
// Possible restrictions on integer constant from outer calls would be ignored
|
||||||
|
|
||||||
|
var iltConstraintPresent = false
|
||||||
|
var properConstraintPresent = false
|
||||||
|
var nonNothingProperConstraintPresent = false
|
||||||
|
|
||||||
|
for (constraint in constraints) {
|
||||||
|
if (!constraint.hasRequiredKind(direction) || !isProperType(constraint.type))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (constraint.type.typeConstructor().isIntegerLiteralTypeConstructor()) {
|
||||||
|
iltConstraintPresent = true
|
||||||
|
} else if (oracle.isSuitableResultedType(constraint.type)) {
|
||||||
|
properConstraintPresent = true
|
||||||
|
nonNothingProperConstraintPresent = true
|
||||||
|
} else if (!isLowerConstraintForPartiallyAnalyzedVariable(constraint, variable)) {
|
||||||
|
properConstraintPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!properConstraintPresent) return false
|
||||||
|
|
||||||
|
return !iltConstraintPresent || nonNothingProperConstraintPresent
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Constraint.hasRequiredKind(direction: FixationDirection) = when (direction) {
|
||||||
|
FixationDirection.TO_SUBTYPE -> kind.isLower() || kind.isEqual()
|
||||||
|
FixationDirection.EQUALITY -> kind.isEqual()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CsCompleterContext.isLowerConstraintForPartiallyAnalyzedVariable(
|
||||||
|
constraint: Constraint,
|
||||||
|
variable: TypeVariableMarker
|
||||||
|
): Boolean {
|
||||||
|
val defaultType = variable.defaultType()
|
||||||
|
return constraint.kind.isLower() && postponedAtoms.any { atom ->
|
||||||
|
atom.expectedType?.contains { type -> defaultType == type } ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-70
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.types.*
|
|||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
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.components.TypeVariableDirectionCalculator
|
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder
|
import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
@@ -22,85 +23,19 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraint
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
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.isIntegerLiteralTypeConstructor
|
|
||||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
fun Candidate.computeCompletionMode(
|
|
||||||
components: InferenceComponents,
|
|
||||||
expectedType: FirTypeRef?,
|
|
||||||
currentReturnType: ConeKotlinType?
|
|
||||||
): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode {
|
|
||||||
// Presence of expected type means that we trying to complete outermost call => completion mode should be full
|
|
||||||
if (expectedType != null) return KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
|
||||||
|
|
||||||
// This is questionable as null return type can be only for error call
|
|
||||||
if (currentReturnType == null || currentReturnType is ConeIntegerLiteralType)
|
|
||||||
return KotlinConstraintSystemCompleter.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) -> KotlinConstraintSystemCompleter.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(components, currentReturnType))
|
|
||||||
KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
|
||||||
else
|
|
||||||
KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
|
||||||
|
|
||||||
// Return type has proper equal constraints => there is no need in the outer call
|
|
||||||
containsTypeVariablesWithProperEqualConstraints(components, currentReturnType) -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL
|
|
||||||
|
|
||||||
else -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val Candidate.csBuilder: NewConstraintSystemImpl get() = system.getBuilder()
|
val Candidate.csBuilder: NewConstraintSystemImpl get() = system.getBuilder()
|
||||||
|
|
||||||
private fun Candidate.containsTypeVariablesWithProperEqualConstraints(components: InferenceComponents, type: ConeKotlinType): Boolean =
|
|
||||||
with(components.ctx){
|
|
||||||
for ((variableConstructor, variableWithConstraints) in csBuilder.currentStorage().notFixedTypeVariables) {
|
|
||||||
if (!type.contains { it.typeConstructor() == 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 Candidate.hasProperNonTrivialLowerConstraints(components: InferenceComponents, typeVariable: ConeKotlinType): Boolean {
|
|
||||||
assert(csBuilder.isTypeVariable(typeVariable)) { "$typeVariable is not a type variable" }
|
|
||||||
|
|
||||||
val context = components.ctx
|
|
||||||
val constructor = typeVariable.typeConstructor(context)
|
|
||||||
val variableWithConstraints = csBuilder.currentStorage().notFixedTypeVariables[constructor] ?: return false
|
|
||||||
val constraints = variableWithConstraints.constraints
|
|
||||||
// TODO: support Exact annotation
|
|
||||||
// see KotlinCallCompleter:244
|
|
||||||
return constraints.isNotEmpty() && constraints.any {
|
|
||||||
!it.type.typeConstructor(context).isIntegerLiteralTypeConstructor(context) &&
|
|
||||||
(it.kind.isLower() || it.kind.isEqual()) && csBuilder.isProperType(it.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
||||||
private val variableFixationFinder = VariableFixationFinder(components.inferenceComponents.trivialConstraintTypeInferenceOracle)
|
private val variableFixationFinder = VariableFixationFinder(components.inferenceComponents.trivialConstraintTypeInferenceOracle)
|
||||||
|
|
||||||
fun complete(
|
fun complete(
|
||||||
c: KotlinConstraintSystemCompleter.Context,
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
|
completionMode: ConstraintSystemCompletionMode,
|
||||||
topLevelAtoms: List<FirStatement>,
|
topLevelAtoms: List<FirStatement>,
|
||||||
candidateReturnType: ConeKotlinType,
|
candidateReturnType: ConeKotlinType,
|
||||||
analyze: (PostponedResolvedAtom) -> Unit
|
analyze: (PostponedResolvedAtom) -> Unit
|
||||||
@@ -117,13 +52,13 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
|||||||
) ?: break
|
) ?: break
|
||||||
|
|
||||||
if (
|
if (
|
||||||
completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL &&
|
completionMode == ConstraintSystemCompletionMode.FULL &&
|
||||||
resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType(c, variableForFixation, postponedAtoms, analyze)
|
resolveLambdaOrCallableReferenceWithTypeVariableAsExpectedType(c, variableForFixation, postponedAtoms, analyze)
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableForFixation.hasProperConstraint || completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||||
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||||
|
|
||||||
fixVariable(c, candidateReturnType, variableWithConstraints, emptyList())
|
fixVariable(c, candidateReturnType, variableWithConstraints, emptyList())
|
||||||
@@ -137,7 +72,7 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
if (completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||||
// force resolution for all not-analyzed argument's
|
// force resolution for all not-analyzed argument's
|
||||||
getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
|
getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// KJS_WITH_FULL_RUNTIME
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// KJS_WITH_FULL_RUNTIME
|
// KJS_WITH_FULL_RUNTIME
|
||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
|
|
||||||
class Holder(val list: List<String>?)
|
class Holder(val list: List<String>?)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Failures detected in FirBodyResolveTransformerAdapter, file: /simpleIn.fir.kt
|
||||||
|
Cause: java.lang.RuntimeException: While resolving call R|<local>/outer|.set#(R?C|/infer|<R|kotlin/Any|>(String()))
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// !LANGUAGE: +NewInference
|
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
|
||||||
|
|
||||||
interface I {
|
|
||||||
fun foo()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Pair<X, Y>(val fst: X, val snd: Y)
|
|
||||||
|
|
||||||
class A(f: Pair<Int, (I) -> Unit>? = null)
|
|
||||||
|
|
||||||
class B(f: ((I) -> Unit)? = null)
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
val cond = true
|
|
||||||
A(
|
|
||||||
if (cond) {
|
|
||||||
Pair(1, { baz -> baz.<!UNRESOLVED_REFERENCE!>foo<!>() })
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
)
|
|
||||||
<!INAPPLICABLE_CANDIDATE!>B<!>(
|
|
||||||
if (cond) {
|
|
||||||
{ baz -> baz.<!UNRESOLVED_REFERENCE!>foo<!>() }
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Failures detected in FirImplicitTypeBodyResolveTransformerAdapter, file: /My.kt
|
||||||
|
Cause: java.lang.RuntimeException: While resolving call Q|Properties|.R?C|/Properties.calcVal|(<L> = calcVal@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
|
lval y: <implicit> = x#.plus#(IntegerLiteral(1))
|
||||||
|
when () {
|
||||||
|
CMP(>, y#.compareTo#(IntegerLiteral(0))) -> {
|
||||||
|
MyBase#.derivedWrapper#()
|
||||||
|
}
|
||||||
|
CMP(<, x#.compareTo#(IntegerLiteral(0))) -> {
|
||||||
|
MyBase#.exoticWrapper#(x#)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
throw java#.lang#.NullPointerException#(String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// !WITH_NEW_INFERENCE
|
||||||
|
// NI_EXPECTED_FILE
|
||||||
|
// JAVAC_EXPECTED_FILE
|
||||||
|
// FILE: Base.java
|
||||||
|
|
||||||
|
public interface Base {}
|
||||||
|
|
||||||
|
// FILE: Other.java
|
||||||
|
|
||||||
|
public interface Other {}
|
||||||
|
|
||||||
|
// FILE: Derived.java
|
||||||
|
|
||||||
|
public final class Derived<T> implements Base, Other {}
|
||||||
|
|
||||||
|
// FILE: Exotic.java
|
||||||
|
|
||||||
|
public final class Exotic implements Base, Other {
|
||||||
|
|
||||||
|
int x;
|
||||||
|
|
||||||
|
Exotic(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: Properties.java
|
||||||
|
|
||||||
|
import kotlin.jvm.functions.Function0;
|
||||||
|
|
||||||
|
class Val<T> {
|
||||||
|
|
||||||
|
Function0<T> initializer;
|
||||||
|
|
||||||
|
Val(Function0<T> initializer) {
|
||||||
|
this.initializer = initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
T getValue(Object instance, Object metadata) {
|
||||||
|
return initializer.invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Properties {
|
||||||
|
static <T> Val<T> calcVal(Function0<T> initializer) {
|
||||||
|
return new Val<T>(initializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: My.kt
|
||||||
|
|
||||||
|
open class Wrapper<out T: Base>(val v: T)
|
||||||
|
|
||||||
|
class DerivedWrapper(v: Derived<*>): Wrapper<Derived<*>>(v)
|
||||||
|
|
||||||
|
class ExoticWrapper(v: Exotic): Wrapper<Exotic>(v)
|
||||||
|
|
||||||
|
object MyBase {
|
||||||
|
|
||||||
|
fun derived() = Derived<String>()
|
||||||
|
fun exotic(x: Int) = Exotic(x)
|
||||||
|
|
||||||
|
fun derivedWrapper() = DerivedWrapper(derived())
|
||||||
|
fun exoticWrapper(x: Int) = ExoticWrapper(exotic(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
class My(val x: Int) {
|
||||||
|
val wrapper/*: Wrapper<*>*/ by Properties.calcVal {
|
||||||
|
val y = x + 1
|
||||||
|
when {
|
||||||
|
y > 0 -> MyBase.derivedWrapper()
|
||||||
|
x < 0 -> MyBase.exoticWrapper(x)
|
||||||
|
else -> throw java.lang.NullPointerException("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
// JAVAC_EXPECTED_FILE
|
// JAVAC_EXPECTED_FILE
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ FILE fqName:<root> fileName:/whenUnusedExpression.kt
|
|||||||
VALUE_PARAMETER name:b index:0 type:kotlin.Boolean
|
VALUE_PARAMETER name:b index:0 type:kotlin.Boolean
|
||||||
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
VALUE_PARAMETER name:i index:1 type:kotlin.Int
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
WHEN type=kotlin.Int? origin=IF
|
WHEN type=kotlin.Int origin=IF
|
||||||
BRANCH
|
BRANCH
|
||||||
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
if: GET_VAR 'b: kotlin.Boolean declared in <root>.test' type=kotlin.Boolean origin=null
|
||||||
then: BLOCK type=kotlin.Int origin=WHEN
|
then: BLOCK type=kotlin.Int origin=WHEN
|
||||||
|
|||||||
Reference in New Issue
Block a user