[NI] Postpone calls with not enough information in builder inference

This commit is contained in:
Dmitriy Novozhilov
2020-01-13 15:47:25 +03:00
parent f4b3e9b4b2
commit 3428a17759
16 changed files with 206 additions and 35 deletions
@@ -19,18 +19,12 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
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.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.*
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.types.StubType
import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.utils.addToStdlib.cast
@@ -58,7 +52,20 @@ class CoroutineInferenceSession(
private val commonCalls = arrayListOf<PSICompletedCallInfo>()
private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
override fun shouldRunCompletion(candidate: KotlinResolutionCandidate): Boolean = true
override fun shouldRunCompletion(candidate: KotlinResolutionCandidate): Boolean {
val system = candidate.getSystem() as NewConstraintSystemImpl
val storage = system.getBuilder().currentStorage()
fun ResolvedAtom.hasPostponed(): Boolean {
if (this is PostponedResolvedAtom && !analyzed) return true
return subResolvedAtoms?.any { it.hasPostponed() } == true
}
return !storage.notFixedTypeVariables.keys.any {
val variable = storage.allTypeVariables[it]
val isPostponed = variable != null && variable in storage.postponedTypeVariables
!isPostponed && !kotlinConstraintSystemCompleter.variableFixationFinder.isTypeVariableHasProperConstraint(system, it)
} || candidate.getSubResolvedAtoms().any { it.hasPostponed() }
}
override fun addCompletedCallInfo(callInfo: CompletedCallInfo) {
require(callInfo is PSICompletedCallInfo) { "Wrong instance of callInfo: $callInfo" }
@@ -100,7 +107,11 @@ class CoroutineInferenceSession(
val commonSystem = buildCommonSystem(initialStorage)
val context = commonSystem.asConstraintSystemCompleterContext()
kotlinConstraintSystemCompleter.completeConstraintSystem(context, builtIns.unitType)
kotlinConstraintSystemCompleter.completeConstraintSystem(
context,
builtIns.unitType,
partiallyResolvedCallsInfo.map { it.callResolutionResult.resultCallAtom }
)
updateCalls(lambda, commonSystem)
@@ -132,7 +143,7 @@ class CoroutineInferenceSession(
*
* while substitutor from parameter map non-fixed types to the original type variable
* */
val callSubstitutor = storage.buildResultingSubstitutor(commonSystem) // substitutor only for fixed variables
val callSubstitutor = storage.buildResultingSubstitutor(commonSystem, transformTypeVariablesToErrorTypes = false)
for (initialConstraint in storage.initialConstraints) {
val lower = nonFixedToVariablesSubstitutor.safeSubstitute(callSubstitutor.safeSubstitute(initialConstraint.a as UnwrappedType)) // TODO: SUB
@@ -164,6 +175,9 @@ class CoroutineInferenceSession(
for (call in commonCalls) {
integrateConstraints(commonSystem, call.callResolutionResult.constraintSystem, nonFixedToVariablesSubstitutor)
}
for (call in partiallyResolvedCallsInfo) {
integrateConstraints(commonSystem, call.callResolutionResult.constraintSystem, nonFixedToVariablesSubstitutor)
}
for (diagnostic in diagnostics) {
commonSystem.addError(diagnostic)
}
@@ -192,6 +206,16 @@ class CoroutineInferenceSession(
}
val lambdaAtomCompleter = createResolvedAtomCompleter(nonFixedTypesToResultSubstitutor, topLevelCallContext)
for (callInfo in partiallyResolvedCallsInfo) {
val resolvedCall = completeCall(callInfo, lambdaAtomCompleter) ?: continue
kotlinToResolvedCallTransformer.reportCallDiagnostic(
callInfo.context,
trace,
callInfo.callResolutionResult.resultCallAtom,
resolvedCall.resultingDescriptor,
commonSystem.diagnostics
)
}
lambdaAtomCompleter.completeAll(lambda)
}
@@ -203,20 +227,29 @@ class CoroutineInferenceSession(
val resultingCallSubstitutor = completedCall.callResolutionResult.constraintSystem.fixedTypeVariables.entries
.associate { it.key to nonFixedTypesToResultSubstitutor.safeSubstitute(it.value as UnwrappedType) } // TODO: SUB
val resultingSubstitutor = NewTypeSubstitutorByConstructorMap((resultingCallSubstitutor + nonFixedTypesToResult).cast()) // TODO: SUB
val resultingSubstitutor =
NewTypeSubstitutorByConstructorMap((resultingCallSubstitutor + nonFixedTypesToResult).cast()) // TODO: SUB
val atomCompleter = createResolvedAtomCompleter(resultingSubstitutor, completedCall.context)
val resultCallAtom = completedCall.callResolutionResult.resultCallAtom
completeCall(completedCall, atomCompleter)
}
private fun completeCall(
callInfo: CallInfo,
atomCompleter: ResolvedAtomCompleter
): ResolvedCall<*>? {
val resultCallAtom = callInfo.callResolutionResult.resultCallAtom
resultCallAtom.subResolvedAtoms?.forEach { subResolvedAtom ->
atomCompleter.completeAll(subResolvedAtom)
}
atomCompleter.completeResolvedCall(resultCallAtom, completedCall.callResolutionResult.diagnostics)
val resolvedCall = atomCompleter.completeResolvedCall(resultCallAtom, callInfo.callResolutionResult.diagnostics)
val callTrace = completedCall.context.trace
val callTrace = callInfo.context.trace
if (callTrace is TemporaryBindingTrace) {
callTrace.commit()
}
return resolvedCall
}
private fun createResolvedAtomCompleter(
@@ -26,7 +26,7 @@ abstract class ManyCandidatesResolver<D : CallableDescriptor>(
protected val callComponents: KotlinCallComponents,
val builtIns: KotlinBuiltIns
) : InferenceSession {
private val partiallyResolvedCallsInfo = arrayListOf<PSIPartialCallInfo>()
protected val partiallyResolvedCallsInfo = arrayListOf<PSIPartialCallInfo>()
private val errorCallsInfo = arrayListOf<PSIErrorCallInfo<D>>()
private val completedCalls = hashSetOf<ResolvedAtom>()
@@ -170,18 +170,24 @@ data class ResolutionResultCallInfo<D : CallableDescriptor>(
val overloadResolutionResults: OverloadResolutionResults<D>
)
class PSIPartialCallInfo(
override val callResolutionResult: PartialCallResolutionResult,
abstract class CallInfo(
open val callResolutionResult: SingleCallResolutionResult,
val context: BasicCallResolutionContext,
val tracingStrategy: TracingStrategy
) : PartialCallInfo
)
class PSIPartialCallInfo(
override val callResolutionResult: PartialCallResolutionResult,
context: BasicCallResolutionContext,
tracingStrategy: TracingStrategy
) : CallInfo(callResolutionResult, context, tracingStrategy), PartialCallInfo
class PSICompletedCallInfo(
override val callResolutionResult: CompletedCallResolutionResult,
val context: BasicCallResolutionContext,
context: BasicCallResolutionContext,
val resolvedCall: ResolvedCall<*>,
val tracingStrategy: TracingStrategy
) : CompletedCallInfo
tracingStrategy: TracingStrategy
) : CallInfo(callResolutionResult, context, tracingStrategy), CompletedCallInfo
class PSIErrorCallInfo<D : CallableDescriptor>(
override val callResolutionResult: CallResolutionResult,
@@ -30,20 +30,25 @@ fun ConstraintStorage.buildCurrentSubstitutor(
return context.typeSubstitutorByTypeConstructor(fixedTypeVariables.entries.associate { it.key to it.value } + additionalBindings)
}
fun ConstraintStorage.buildAbstractResultingSubstitutor(context: TypeSystemInferenceExtensionContext): TypeSubstitutorMarker =
fun ConstraintStorage.buildAbstractResultingSubstitutor(context: TypeSystemInferenceExtensionContext, transformTypeVariablesToErrorTypes: Boolean = true): TypeSubstitutorMarker =
with(context) {
if (allTypeVariables.isEmpty()) return createEmptySubstitutor()
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
it.key to it.value
}
val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to context.createErrorTypeWithCustomConstructor(
"Uninferred type",
(typeVariable.typeVariable).freshTypeConstructor()
)
val uninferredSubstitutorMap = if (transformTypeVariablesToErrorTypes) {
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to context.createErrorTypeWithCustomConstructor(
"Uninferred type",
(typeVariable.typeVariable).freshTypeConstructor()
)
}
} else {
notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to typeVariable.typeVariable.defaultType(this)
}
}
return context.typeSubstitutorByTypeConstructor(currentSubstitutorMap + uninferredSubstitutorMap)
}
@@ -52,8 +57,8 @@ fun ConstraintStorage.buildNotFixedVariablesToNonSubtypableTypesSubstitutor(cont
notFixedTypeVariables.mapValues { context.createStubType(it.value.typeVariable) }
)
fun ConstraintStorage.buildResultingSubstitutor(context: TypeSystemInferenceExtensionContext): NewTypeSubstitutor {
return buildAbstractResultingSubstitutor(context) as NewTypeSubstitutor
fun ConstraintStorage.buildResultingSubstitutor(context: TypeSystemInferenceExtensionContext, transformTypeVariablesToErrorTypes: Boolean = true): NewTypeSubstitutor {
return buildAbstractResultingSubstitutor(context, transformTypeVariablesToErrorTypes) as NewTypeSubstitutor
}
val CallableDescriptor.returnTypeOrNothing: UnwrappedType
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinConstraintSystemCompleter(
private val resultTypeResolver: ResultTypeResolver,
private val variableFixationFinder: VariableFixationFinder,
val variableFixationFinder: VariableFixationFinder,
private val statelessCallbacks: KotlinResolutionStatelessCallbacks
) {
enum class ConstraintSystemCompletionMode {
@@ -55,8 +55,8 @@ class KotlinConstraintSystemCompleter(
runCompletion(c, completionMode, topLevelAtoms, topLevelType, collectVariablesFromContext = false, analyze = analyze)
}
fun completeConstraintSystem(c: Context, topLevelType: UnwrappedType) {
runCompletion(c, ConstraintSystemCompletionMode.FULL, emptyList(), topLevelType, collectVariablesFromContext = true) {
fun completeConstraintSystem(c: Context, topLevelType: UnwrappedType, topLevelAtoms: List<ResolvedAtom>) {
runCompletion(c, ConstraintSystemCompletionMode.FULL, topLevelAtoms, topLevelType, collectVariablesFromContext = true) {
error("Shouldn't be called in complete constraint system mode")
}
}
@@ -50,7 +50,7 @@ class VariableFixationFinder(
topLevelType: KotlinTypeMarker
): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
private enum class TypeVariableFixationReadiness {
enum class TypeVariableFixationReadiness {
FORBIDDEN,
WITHOUT_PROPER_ARGUMENT_CONSTRAINT, // proper constraint from arguments -- not from upper bound for type parameters
WITH_COMPLEX_DEPENDENCY, // if type variable T has constraint with non fixed type variable inside (non-top-level): T <: Foo<S>
@@ -74,6 +74,18 @@ class VariableFixationFinder(
else -> TypeVariableFixationReadiness.READY_FOR_FIXATION
}
fun isTypeVariableHasProperConstraint(context: Context, typeVariable: TypeConstructorMarker): Boolean {
return with(context) {
val dependencyProvider = TypeVariableDependencyInformationProvider(
notFixedTypeVariables, emptyList(), topLevelType = null, context
)
when (getTypeVariableReadiness(typeVariable, dependencyProvider)) {
TypeVariableFixationReadiness.FORBIDDEN, TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT -> false
else -> true
}
}
}
private fun Context.findTypeVariableForFixation(
allTypeVariables: List<TypeConstructorMarker>,
postponedArguments: List<PostponedResolvedAtomMarker>,
+26
View File
@@ -0,0 +1,26 @@
// !LANGUAGE: +NewInference
// !USE_EXPERIMENTAL: kotlin.Experimental
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// ISSUE: KT-35684
import kotlin.experimental.ExperimentalTypeInference
fun test() {
sequence {
yield(materialize())
yield(materialize<Int>())
}
}
@UseExperimental(ExperimentalTypeInference::class)
fun <U> sequence(@BuilderInference block: suspend Inv<U>.() -> Unit) {}
interface Inv<T> {
fun yield(element: T)
}
fun <K> materialize(): Inv<K> = TODO()
fun box(): String = "OK"
@@ -0,0 +1,35 @@
// !LANGUAGE: +NewInference
// !USE_EXPERIMENTAL: kotlin.Experimental
// !DIAGNOSTICS: -UNUSED_PARAMETER
// ISSUE: KT-35684
import kotlin.experimental.ExperimentalTypeInference
fun test_1() {
<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>sequence {
yield(<!DEBUG_INFO_EXPRESSION_TYPE("Inv<kotlin.Int>")!>materialize()<!>)
yield(materialize<Int>())
}<!>
}
fun test_2() {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>sequence<!> {
yield(<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materialize<!>())
}
}
fun test_3() {
sequence {
yield(materialize<Int>())
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>materialize<!>()
}
}
@UseExperimental(ExperimentalTypeInference::class)
fun <U> sequence(@BuilderInference block: suspend Inv<U>.() -> Unit): U = null!!
interface Inv<T> {
fun yield(element: T)
}
fun <K> materialize(): Inv<K> = TODO()
@@ -0,0 +1,14 @@
package
public fun </*0*/ K> materialize(): Inv<K>
@kotlin.UseExperimental(markerClass = {kotlin.experimental.ExperimentalTypeInference::class}) public fun </*0*/ U> sequence(/*0*/ @kotlin.BuilderInference block: suspend Inv<U>.() -> kotlin.Unit): U
public fun test_1(): kotlin.Unit
public fun test_2(): kotlin.Unit
public fun test_3(): kotlin.Unit
public interface Inv</*0*/ 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 abstract fun yield(/*0*/ element: T): kotlin.Unit
}
@@ -1952,6 +1952,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt32271.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt35684.kt");
}
@TestMetadata("nestedLambdaInferenceWithListMap.kt")
public void testNestedLambdaInferenceWithListMap() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/nestedLambdaInferenceWithListMap.kt");
@@ -1952,6 +1952,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt32271.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt35684.kt");
}
@TestMetadata("nestedLambdaInferenceWithListMap.kt")
public void testNestedLambdaInferenceWithListMap() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/nestedLambdaInferenceWithListMap.kt");
@@ -12591,6 +12591,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inference/kt32429.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");
@@ -12591,6 +12591,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inference/kt32429.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");
@@ -11441,6 +11441,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inference/kt32429.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");
@@ -11441,6 +11441,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inference/kt32429.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");
@@ -9846,6 +9846,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inference/kt10822.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");
@@ -10986,6 +10986,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inference/kt10822.kt");
}
@TestMetadata("kt35684.kt")
public void testKt35684() throws Exception {
runTest("compiler/testData/codegen/box/inference/kt35684.kt");
}
@TestMetadata("lastExpressionOfLambdaWithNothingConstraint.kt")
public void testLastExpressionOfLambdaWithNothingConstraint() throws Exception {
runTest("compiler/testData/codegen/box/inference/lastExpressionOfLambdaWithNothingConstraint.kt");