Introduce specific error for calls which could be resolved only with unrestricted builder inference

^KT-47747 Fixed
This commit is contained in:
Victor Petukhov
2021-07-15 12:57:31 +03:00
committed by teamcityserver
parent 357fda2efa
commit 6a1ec92d39
15 changed files with 38 additions and 11 deletions
@@ -241,7 +241,9 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
if (resolvedAtom != null) { if (resolvedAtom != null) {
c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom)) c.addError(
NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom, c.couldBeResolvedWithUnrestrictedBuilderInference())
)
} }
val resultErrorType = when (typeVariable) { val resultErrorType = when (typeVariable) {
@@ -816,6 +816,7 @@ public interface Errors {
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, String> NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, String> COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR);
@@ -919,6 +919,7 @@ public class DefaultErrorMessages {
MAP.put(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES, "Type inference failed: {0}", TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER); MAP.put(TYPE_INFERENCE_CANNOT_CAPTURE_TYPES, "Type inference failed: {0}", TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER);
MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER); MAP.put(TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Type inference failed: {0}", TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER);
MAP.put(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Not enough information to infer type variable {0}", STRING); MAP.put(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, "Not enough information to infer type variable {0}", STRING);
MAP.put(COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE, "Builder inference lambda contains inapplicable calls so {1} can't be inferred. It could be resolved only with unrestricted builder inference. Please use -Xunrestricted-builder-inference compiler flag to enable it.", STRING);
MAP.put(TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR, "Type inference failed: {0}", TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER); MAP.put(TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR, "Type inference failed: {0}", TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER);
MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly."); MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly.");
@@ -493,7 +493,13 @@ class DiagnosticReporterByTrackingStrategy(
expression.statements.lastOrNull() ?: expression expression.statements.lastOrNull() ?: expression
} else expression } else expression
trace.reportDiagnosticOnce(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(unwrappedExpression, typeVariableName)) val diagnostic = if (error.couldBeResolvedWithUnrestrictedBuilderInference) {
COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE
} else {
NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER
}
trace.reportDiagnosticOnce(diagnostic.on(unwrappedExpression, typeVariableName))
} }
} }
@@ -15,6 +15,7 @@ interface ConstraintSystemOperation {
val hasContradiction: Boolean val hasContradiction: Boolean
fun registerVariable(variable: TypeVariableMarker) fun registerVariable(variable: TypeVariableMarker)
fun markPostponedVariable(variable: TypeVariableMarker) fun markPostponedVariable(variable: TypeVariableMarker)
fun markCouldBeResolvedWithUnrestrictedBuilderInference()
fun unmarkPostponedVariable(variable: TypeVariableMarker) fun unmarkPostponedVariable(variable: TypeVariableMarker)
fun removePostponedVariables() fun removePostponedVariables()
@@ -32,4 +32,6 @@ interface ConstraintSystemCompletionContext : VariableFixationFinder.Context, Re
fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, position: FixVariableConstraintPosition<*>) fun fixVariable(variable: TypeVariableMarker, resultType: KotlinTypeMarker, position: FixVariableConstraintPosition<*>)
fun asConstraintSystemCompletionContext(): ConstraintSystemCompletionContext fun asConstraintSystemCompletionContext(): ConstraintSystemCompletionContext
fun couldBeResolvedWithUnrestrictedBuilderInference(): Boolean
} }
@@ -118,7 +118,8 @@ class CapturedTypeFromSubtyping(
open class NotEnoughInformationForTypeParameter<T>( open class NotEnoughInformationForTypeParameter<T>(
val typeVariable: TypeVariableMarker, val typeVariable: TypeVariableMarker,
val resolvedAtom: T val resolvedAtom: T,
val couldBeResolvedWithUnrestrictedBuilderInference: Boolean
) : ConstraintSystemError(INAPPLICABLE) ) : ConstraintSystemError(INAPPLICABLE)
class ConstrainingTypeIsError( class ConstrainingTypeIsError(
@@ -38,6 +38,8 @@ class NewConstraintSystemImpl(
private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create() private val properTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create() private val notProperTypesCache: MutableSet<KotlinTypeMarker> = SmartSet.create()
private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false
private enum class State { private enum class State {
BUILDING, BUILDING,
TRANSACTION, TRANSACTION,
@@ -118,6 +120,13 @@ class NewConstraintSystemImpl(
storage.postponedTypeVariables += variable storage.postponedTypeVariables += variable
} }
override fun markCouldBeResolvedWithUnrestrictedBuilderInference() {
couldBeResolvedWithUnrestrictedBuilderInference = true
}
override fun couldBeResolvedWithUnrestrictedBuilderInference() =
couldBeResolvedWithUnrestrictedBuilderInference
override fun unmarkPostponedVariable(variable: TypeVariableMarker) { override fun unmarkPostponedVariable(variable: TypeVariableMarker) {
storage.postponedTypeVariables -= variable storage.postponedTypeVariables -= variable
} }
@@ -148,6 +148,7 @@ class PostponedArgumentsAnalyzer(
if (hasInapplicableCallForBuilderInference) { if (hasInapplicableCallForBuilderInference) {
inferenceSession?.initializeLambda(lambda) inferenceSession?.initializeLambda(lambda)
c.getBuilder().markCouldBeResolvedWithUnrestrictedBuilderInference()
c.getBuilder().removePostponedVariables() c.getBuilder().removePostponedVariables()
return return
} }
@@ -316,7 +316,9 @@ class KotlinConstraintSystemCompleter(
val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull() val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
if (resolvedAtom != null) { if (resolvedAtom != null) {
c.addError(NotEnoughInformationForTypeParameterImpl(typeVariable, resolvedAtom)) c.addError(
NotEnoughInformationForTypeParameterImpl(typeVariable, resolvedAtom, c.couldBeResolvedWithUnrestrictedBuilderInference())
)
} }
val resultErrorType = when { val resultErrorType = when {
@@ -54,5 +54,6 @@ class DelegatedPropertyConstraintPositionImpl(topLevelCall: KotlinCall) : Delega
class NotEnoughInformationForTypeParameterImpl( class NotEnoughInformationForTypeParameterImpl(
typeVariable: TypeVariableMarker, typeVariable: TypeVariableMarker,
resolvedAtom: ResolvedAtom resolvedAtom: ResolvedAtom,
) : NotEnoughInformationForTypeParameter<ResolvedAtom>(typeVariable, resolvedAtom) couldBeResolvedWithUnrestrictedBuilderInference: Boolean
) : NotEnoughInformationForTypeParameter<ResolvedAtom>(typeVariable, resolvedAtom, couldBeResolvedWithUnrestrictedBuilderInference)
@@ -26,7 +26,7 @@ inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit) = Unit a
fun test() { fun test() {
val x: Flow<String> = flow { val x: Flow<String> = flow {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>produce<!> { <!COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE!>produce<!> {
select<Unit> { select<Unit> {
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>onSend<!>("") { <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>onSend<!>("") {
@@ -24,12 +24,12 @@ val test2 = generate {
notYield(3) notYield(3)
} }
val test3 = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> { val test3 = <!COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE!>generate<!> {
yield(3) yield(3)
yieldBarReturnType(3) yieldBarReturnType(3)
} }
val test4 = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> { val test4 = <!COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE!>generate<!> {
yield(3) yield(3)
barReturnType() barReturnType()
} }
@@ -28,7 +28,7 @@ val memberWithoutAnn = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER{NI}, TYPE_IN
add(42) add(42)
} }
val extension = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER{OI}!>build<!> { val extension = <!COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE, NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER{OI}, TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER{OI}!>build<!> {
extensionAdd("foo") extensionAdd("foo")
} }
@@ -23,7 +23,7 @@ val normal = generate {
yield(42) yield(42)
} }
val extension = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>generate<!> { val extension = <!COULD_BE_INFERRED_ONLY_WITH_UNRESTRICTED_BUILDER_INFERENCE!>generate<!> {
extensionYield("foo") extensionYield("foo")
} }