[NI] Improvements for "not enough information" diagnostic
#KT-30590 Fixed
This commit is contained in:
@@ -63,6 +63,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext {
|
|||||||
return this is ConeClassErrorType || this is ConeKotlinErrorType || this.typeConstructor() is ErrorTypeConstructor
|
return this is ConeClassErrorType || this is ConeKotlinErrorType || this.typeConstructor() is ErrorTypeConstructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
||||||
|
assert(this is ConeKotlinType)
|
||||||
|
return false // TODO
|
||||||
|
}
|
||||||
|
|
||||||
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
||||||
assert(this is ConeKotlinType)
|
assert(this is ConeKotlinType)
|
||||||
return null // TODO
|
return null // TODO
|
||||||
|
|||||||
+5
-1
@@ -229,6 +229,7 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperKotlinType, constraintError.lowerKotlinType))
|
trace.report(UPPER_BOUND_VIOLATED.on(typeArgumentReference, constraintError.upperKotlinType, constraintError.lowerKotlinType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CapturedTypeFromSubtyping::class.java -> {
|
CapturedTypeFromSubtyping::class.java -> {
|
||||||
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
||||||
val position = capturedError.position
|
val position = capturedError.position
|
||||||
@@ -248,6 +249,9 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
NotEnoughInformationForTypeParameter::class.java -> {
|
NotEnoughInformationForTypeParameter::class.java -> {
|
||||||
|
if (allDiagnostics.any {it is ConstrainingTypeIsError || it is NewConstraintError || it is WrongCountOfTypeArguments})
|
||||||
|
return
|
||||||
|
|
||||||
val error = diagnostic as NotEnoughInformationForTypeParameter
|
val error = diagnostic as NotEnoughInformationForTypeParameter
|
||||||
val call = error.resolvedAtom.atom?.safeAs<PSIKotlinCall>()?.psiCall ?: call
|
val call = error.resolvedAtom.atom?.safeAs<PSIKotlinCall>()?.psiCall ?: call
|
||||||
val expression = call.calleeExpression ?: return
|
val expression = call.calleeExpression ?: return
|
||||||
@@ -256,7 +260,7 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
is TypeVariableForLambdaReturnType -> "return type of lambda"
|
is TypeVariableForLambdaReturnType -> "return type of lambda"
|
||||||
else -> error("Unsupported type variable: $typeVariable")
|
else -> error("Unsupported type variable: $typeVariable")
|
||||||
}
|
}
|
||||||
trace.report(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(expression, typeVariableName))
|
trace.reportDiagnosticOnce(NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(expression, typeVariableName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -166,6 +166,11 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
|
|||||||
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
|
||||||
|
|
||||||
var targetType = type
|
var targetType = type
|
||||||
|
if (targetType.isUninferredParameter()) {
|
||||||
|
// there already should be an error, so there is no point in reporting one more
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (targetType.isError()) {
|
if (targetType.isError()) {
|
||||||
c.addError(ConstrainingTypeIsError(typeVariable, targetType, position))
|
c.addError(ConstrainingTypeIsError(typeVariable, targetType, position))
|
||||||
return
|
return
|
||||||
|
|||||||
+53
-4
@@ -6,8 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.inference.components
|
package org.jetbrains.kotlin.resolve.calls.inference.components
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableFromCallableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.TypeConstructor
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
@@ -84,11 +86,11 @@ class KotlinConstraintSystemCompleter(
|
|||||||
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
|
||||||
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
val variableWithConstraints = c.notFixedTypeVariables.getValue(variableForFixation.variable)
|
||||||
|
|
||||||
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
if (variableForFixation.hasProperConstraint)
|
||||||
|
fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
|
||||||
|
else
|
||||||
|
processVariableWhenNotEnoughInformation(c, variableWithConstraints, topLevelAtoms)
|
||||||
|
|
||||||
if (!variableForFixation.hasProperConstraint) {
|
|
||||||
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable, topLevelAtoms.first()))
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,4 +220,51 @@ class KotlinConstraintSystemCompleter(
|
|||||||
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
|
||||||
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processVariableWhenNotEnoughInformation(
|
||||||
|
c: Context,
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
topLevelAtoms: List<ResolvedAtom>
|
||||||
|
) {
|
||||||
|
val typeVariable = variableWithConstraints.typeVariable
|
||||||
|
|
||||||
|
val resolvedAtom = findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
|
||||||
|
if (resolvedAtom != null) {
|
||||||
|
c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom))
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultErrorType = if (typeVariable is TypeVariableFromCallableDescriptor)
|
||||||
|
ErrorUtils.createUninferredParameterType(typeVariable.originalTypeParameter)
|
||||||
|
else
|
||||||
|
ErrorUtils.createErrorType("Cannot infer type variable $typeVariable")
|
||||||
|
|
||||||
|
c.fixVariable(typeVariable, resultErrorType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findResolvedAtomBy(typeVariable: TypeVariableMarker, topLevelAtoms: List<ResolvedAtom>): ResolvedAtom? {
|
||||||
|
fun ResolvedAtom.check(): ResolvedAtom? {
|
||||||
|
val suitableCall = when (this) {
|
||||||
|
is ResolvedCallAtom -> typeVariable in substitutor.freshVariables
|
||||||
|
is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables?.let { typeVariable in it } ?: false
|
||||||
|
is ResolvedLambdaAtom -> typeVariable == typeVariableForLambdaReturnType
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suitableCall) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
subResolvedAtoms.forEach { subResolvedAtom ->
|
||||||
|
subResolvedAtom.check()?.let { result -> return@check result }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
for (topLevelAtom in topLevelAtoms) {
|
||||||
|
topLevelAtom.check()?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-4
@@ -18,10 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection
|
import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirectionCalculator.ResolveDirection
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.checkConstraint
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
|||||||
+46
-14
@@ -5,12 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.inference.model
|
package org.jetbrains.kotlin.resolve.calls.inference.model
|
||||||
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
|
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||||
import org.jetbrains.kotlin.types.TypeConstructor
|
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
|
||||||
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
|
||||||
@@ -38,16 +35,22 @@ class MutableVariableWithConstraints(
|
|||||||
fun addConstraint(constraint: Constraint): Constraint? {
|
fun addConstraint(constraint: Constraint): Constraint? {
|
||||||
val previousConstraintWithSameType = constraints.filter { it.typeHashCode == constraint.typeHashCode && it.type == constraint.type }
|
val previousConstraintWithSameType = constraints.filter { it.typeHashCode == constraint.typeHashCode && it.type == constraint.type }
|
||||||
|
|
||||||
if (previousConstraintWithSameType.any { newConstraintIsUseless(it.kind, constraint.kind) }) {
|
if (previousConstraintWithSameType.any { previous -> newConstraintIsUseless(previous, constraint) })
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
val addAsEqualityConstraint = previousConstraintWithSameType.any { previous ->
|
||||||
|
when (previous.kind) {
|
||||||
|
ConstraintKind.LOWER -> constraint.kind.isUpper()
|
||||||
|
ConstraintKind.UPPER -> constraint.kind.isLower()
|
||||||
|
ConstraintKind.EQUALITY -> true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val actualConstraint = if (previousConstraintWithSameType.isNotEmpty()) {
|
val actualConstraint = if (addAsEqualityConstraint)
|
||||||
// i.e. previous is LOWER and new is UPPER or opposite situation
|
|
||||||
Constraint(ConstraintKind.EQUALITY, constraint.type, constraint.position, constraint.typeHashCode)
|
Constraint(ConstraintKind.EQUALITY, constraint.type, constraint.position, constraint.typeHashCode)
|
||||||
} else {
|
else
|
||||||
constraint
|
constraint
|
||||||
}
|
|
||||||
mutableConstraints.add(actualConstraint)
|
mutableConstraints.add(actualConstraint)
|
||||||
simplifiedConstraints = null
|
simplifiedConstraints = null
|
||||||
return actualConstraint
|
return actualConstraint
|
||||||
@@ -66,18 +69,47 @@ class MutableVariableWithConstraints(
|
|||||||
simplifiedConstraints = null
|
simplifiedConstraints = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newConstraintIsUseless(oldKind: ConstraintKind, newKind: ConstraintKind) =
|
private fun newConstraintIsUseless(old: Constraint, new: Constraint): Boolean {
|
||||||
when (oldKind) {
|
// Constraints from declared upper bound are quite special -- they aren't considered as a proper ones
|
||||||
|
// In other words, user-defined constraints have "higher" priority and here we're trying not to loose them
|
||||||
|
if (old.position.from is DeclaredUpperBoundConstraintPosition && new.position.from !is DeclaredUpperBoundConstraintPosition)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return when (old.kind) {
|
||||||
ConstraintKind.EQUALITY -> true
|
ConstraintKind.EQUALITY -> true
|
||||||
ConstraintKind.LOWER -> newKind == ConstraintKind.LOWER
|
ConstraintKind.LOWER -> new.kind.isLower()
|
||||||
ConstraintKind.UPPER -> newKind == ConstraintKind.UPPER
|
ConstraintKind.UPPER -> new.kind.isUpper()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun simplifyConstraints(): List<Constraint> {
|
private fun simplifyConstraints(): List<Constraint> {
|
||||||
val equalityConstraints = mutableConstraints
|
val distinctConstraints = removeDuplicatesFromDeclaredUpperBoundConstraints(mutableConstraints)
|
||||||
|
|
||||||
|
val equalityConstraints = distinctConstraints
|
||||||
.filter { it.kind == ConstraintKind.EQUALITY }
|
.filter { it.kind == ConstraintKind.EQUALITY }
|
||||||
.groupBy { it.typeHashCode }
|
.groupBy { it.typeHashCode }
|
||||||
return mutableConstraints.filter { isUsefulConstraint(it, equalityConstraints) }
|
return distinctConstraints.filter { isUsefulConstraint(it, equalityConstraints) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeDuplicatesFromDeclaredUpperBoundConstraints(constraints: List<Constraint>): MutableList<Constraint> {
|
||||||
|
val currentConstraints = constraints.toMutableList()
|
||||||
|
val iterator = currentConstraints.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val potentialDuplicate = iterator.next()
|
||||||
|
|
||||||
|
if (potentialDuplicate.position.from !is DeclaredUpperBoundConstraintPosition) continue
|
||||||
|
val hasDuplicate = currentConstraints.any { other ->
|
||||||
|
potentialDuplicate !== other &&
|
||||||
|
potentialDuplicate.typeHashCode == other.typeHashCode &&
|
||||||
|
potentialDuplicate.type == other.type &&
|
||||||
|
potentialDuplicate.kind == other.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDuplicate)
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentConstraints
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isUsefulConstraint(constraint: Constraint, equalityConstraints: Map<Int, List<Constraint>>): Boolean {
|
private fun isUsefulConstraint(constraint: Constraint, equalityConstraints: Map<Int, List<Constraint>>): Boolean {
|
||||||
|
|||||||
+2
-4
@@ -1,11 +1,9 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
// !LANGUAGE: +NewInference
|
// NI_EXPECTED_FILE
|
||||||
// Issue: KT-30590
|
|
||||||
|
|
||||||
interface A
|
interface A
|
||||||
fun <T: A, R: T> emptyStrangeMap(): Map<T, R> = TODO()
|
fun <T: A, R: T> emptyStrangeMap(): Map<T, R> = TODO()
|
||||||
fun test7() : Map<A, A> = emptyStrangeMap()
|
fun test7() : Map<A, A> = emptyStrangeMap()
|
||||||
|
|
||||||
fun test() = emptyStrangeMap()
|
fun test() = <!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>emptyStrangeMap<!>()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun </*0*/ T : A, /*1*/ R : T> emptyStrangeMap(): kotlin.collections.Map<T, R>
|
||||||
|
public fun test(): kotlin.collections.Map<???, ???>
|
||||||
|
public fun test7(): kotlin.collections.Map<A, A>
|
||||||
|
|
||||||
|
public interface A {
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public fun </*0*/ T : A, /*1*/ R : T> emptyStrangeMap(): kotlin.collections.Map<T, R>
|
public fun </*0*/ T : A, /*1*/ R : T> emptyStrangeMap(): kotlin.collections.Map<T, R>
|
||||||
|
public fun test(): [ERROR : Error function type]
|
||||||
public fun test7(): kotlin.collections.Map<A, A>
|
public fun test7(): kotlin.collections.Map<A, A>
|
||||||
|
|
||||||
public interface A {
|
public interface A {
|
||||||
|
|||||||
+6
-2
@@ -2,8 +2,12 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
fun <K> id2(x: K, s: String): K = x
|
fun <K> id2(x: K, s: String): K = x
|
||||||
|
fun <K> ret(s: String): K = TODO()
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
<!NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER, NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>id2<!>(<!UNRESOLVED_REFERENCE!>unresolved<!>, "foo")
|
id2(<!UNRESOLVED_REFERENCE!>unresolved<!>, "foo")
|
||||||
<!NI;UNREACHABLE_CODE!><!NI;IMPLICIT_NOTHING_AS_TYPE_PARAMETER, NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>id2<!>(<!UNRESOLVED_REFERENCE!>unresolved<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!>)<!>
|
id2(<!UNRESOLVED_REFERENCE!>unresolved<!>, <!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!>)
|
||||||
|
|
||||||
|
<!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, OI;TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>ret<!>("foo")
|
||||||
|
<!OI;TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR!>ret<!>(<!CONSTANT_EXPECTED_TYPE_MISMATCH!>42<!>)
|
||||||
}
|
}
|
||||||
+1
@@ -1,4 +1,5 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public fun </*0*/ K> id2(/*0*/ x: K, /*1*/ s: kotlin.String): K
|
public fun </*0*/ K> id2(/*0*/ x: K, /*1*/ s: kotlin.String): K
|
||||||
|
public fun </*0*/ K> ret(/*0*/ s: kotlin.String): K
|
||||||
public fun test(): kotlin.Unit
|
public fun test(): kotlin.Unit
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext {
|
|||||||
return this.isError
|
return this.isError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
||||||
|
require(this is KotlinType, this::errorMessage)
|
||||||
|
return ErrorUtils.isUninferredParameter(this)
|
||||||
|
}
|
||||||
|
|
||||||
override fun SimpleTypeMarker.isStubType(): Boolean {
|
override fun SimpleTypeMarker.isStubType(): Boolean {
|
||||||
require(this is SimpleType, this::errorMessage)
|
require(this is SimpleType, this::errorMessage)
|
||||||
return this is StubType
|
return this is StubType
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
|
|||||||
fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker?
|
fun KotlinTypeMarker.asFlexibleType(): FlexibleTypeMarker?
|
||||||
|
|
||||||
fun KotlinTypeMarker.isError(): Boolean
|
fun KotlinTypeMarker.isError(): Boolean
|
||||||
|
fun KotlinTypeMarker.isUninferredParameter(): Boolean
|
||||||
|
|
||||||
fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker?
|
fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user