FIR: Report INFERENCE_NO_INFORMATION_FOR_PARAMETER diagnostic
This commit is contained in:
committed by
TeamCityServer
parent
6e901e3785
commit
c420957eac
+4
@@ -341,6 +341,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
|
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
|
||||||
|
|
||||||
|
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error<KtElement> {
|
||||||
|
parameter<String>("name")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ object FirErrors {
|
|||||||
val ASSIGNMENT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
val ASSIGNMENT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||||
val RESULT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
val RESULT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||||
|
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
|
||||||
|
|
||||||
// Ambiguity
|
// Ambiguity
|
||||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
+24
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.isOperator
|
|||||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeVariableForLambdaReturnType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||||
@@ -191,6 +193,7 @@ private fun mapSystemHasContradictionError(
|
|||||||
qualifiedAccessSource,
|
qualifiedAccessSource,
|
||||||
diagnostic.candidate.callInfo.session.typeContext,
|
diagnostic.candidate.callInfo.session.typeContext,
|
||||||
errorsToIgnore,
|
errorsToIgnore,
|
||||||
|
diagnostic.candidate,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -202,6 +205,7 @@ private fun mapSystemHasContradictionError(
|
|||||||
is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} <!: ${it.upperType}"
|
is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} <!: ${it.upperType}"
|
||||||
// Error should be reported on the error type itself
|
// Error should be reported on the error type itself
|
||||||
is ConstrainingTypeIsError -> return@firstNotNullOfOrNull null
|
is ConstrainingTypeIsError -> return@firstNotNullOfOrNull null
|
||||||
|
is NotEnoughInformationForTypeParameter<*> -> return@firstNotNullOfOrNull null
|
||||||
else -> "Inference error: ${it::class.simpleName}"
|
else -> "Inference error: ${it::class.simpleName}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +227,7 @@ private fun ConstraintSystemError.toDiagnostic(
|
|||||||
qualifiedAccessSource: FirSourceElement?,
|
qualifiedAccessSource: FirSourceElement?,
|
||||||
typeContext: ConeTypeContext,
|
typeContext: ConeTypeContext,
|
||||||
errorsToIgnore: MutableSet<ConstraintSystemError>,
|
errorsToIgnore: MutableSet<ConstraintSystemError>,
|
||||||
|
candidate: Candidate,
|
||||||
): FirDiagnostic<FirSourceElement>? {
|
): FirDiagnostic<FirSourceElement>? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is NewConstraintError -> {
|
is NewConstraintError -> {
|
||||||
@@ -270,6 +275,25 @@ private fun ConstraintSystemError.toDiagnostic(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is NotEnoughInformationForTypeParameter<*> -> {
|
||||||
|
val isDiagnosticRedundant = candidate.system.errors.any { otherError ->
|
||||||
|
(otherError is ConstrainingTypeIsError && otherError.typeVariable == this.typeVariable)
|
||||||
|
|| otherError is NewConstraintError
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDiagnosticRedundant) return null
|
||||||
|
|
||||||
|
val typeVariableName = when (val typeVariable = this.typeVariable) {
|
||||||
|
is ConeTypeParameterBasedTypeVariable -> typeVariable.typeParameterSymbol.name.asString()
|
||||||
|
is ConeTypeVariableForLambdaReturnType -> "return type of lambda"
|
||||||
|
else -> error("Unsupported type variable: $typeVariable")
|
||||||
|
}
|
||||||
|
|
||||||
|
FirErrors.NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(
|
||||||
|
source,
|
||||||
|
typeVariableName,
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ typealias ConeKotlinErrorType = ConeClassErrorType
|
|||||||
|
|
||||||
class ConeClassLikeErrorLookupTag(override val classId: ClassId) : ConeClassLikeLookupTag()
|
class ConeClassLikeErrorLookupTag(override val classId: ClassId) : ConeClassLikeLookupTag()
|
||||||
|
|
||||||
class ConeClassErrorType(val diagnostic: ConeDiagnostic) : ConeClassLikeType() {
|
class ConeClassErrorType(val diagnostic: ConeDiagnostic, val isUninferredParameter: Boolean = false) : ConeClassLikeType() {
|
||||||
override val lookupTag: ConeClassLikeLookupTag
|
override val lookupTag: ConeClassLikeLookupTag
|
||||||
get() = ConeClassLikeErrorLookupTag(ClassId.fromString("<error>"))
|
get() = ConeClassLikeErrorLookupTag(ClassId.fromString("<error>"))
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -99,8 +99,9 @@ object ConeConstraintSystemUtilContext : ConstraintSystemUtilContext {
|
|||||||
argument: PostponedAtomWithRevisableExpectedType,
|
argument: PostponedAtomWithRevisableExpectedType,
|
||||||
index: Int
|
index: Int
|
||||||
): TypeVariableMarker {
|
): TypeVariableMarker {
|
||||||
return ConeTypeVariableForPostponedAtom(
|
return ConeTypeVariableForLambdaParameterType(
|
||||||
PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE + index
|
PostponedArgumentInputTypesResolver.TYPE_VARIABLE_NAME_PREFIX_FOR_LAMBDA_PARAMETER_TYPE + index,
|
||||||
|
index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+76
-7
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.inference
|
package org.jetbrains.kotlin.fir.resolve.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||||
|
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
@@ -15,10 +18,12 @@ import org.jetbrains.kotlin.fir.returnExpressions
|
|||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
import org.jetbrains.kotlin.resolve.calls.inference.components.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
|
||||||
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.PostponedAtomWithRevisableExpectedType
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedAtomWithRevisableExpectedType
|
||||||
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.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
@@ -219,19 +224,83 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
|||||||
fixVariable(asConstraintSystemCompletionContext(), topLevelType, variableWithConstraints, postponedArguments)
|
fixVariable(asConstraintSystemCompletionContext(), topLevelType, variableWithConstraints, postponedArguments)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
// TODO("Not enough information for parameter")
|
processVariableWhenNotEnoughInformation(this, variableWithConstraints, topLevelAtoms)
|
||||||
fixVariable(
|
|
||||||
asConstraintSystemCompletionContext(),
|
|
||||||
topLevelType,
|
|
||||||
variableWithConstraints,
|
|
||||||
postponedArguments
|
|
||||||
) // means Nothing/Any instead of Error type
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processVariableWhenNotEnoughInformation(
|
||||||
|
c: ConstraintSystemCompletionContext,
|
||||||
|
variableWithConstraints: VariableWithConstraints,
|
||||||
|
topLevelAtoms: List<FirStatement>,
|
||||||
|
) {
|
||||||
|
val typeVariable = variableWithConstraints.typeVariable
|
||||||
|
val resolvedAtom =
|
||||||
|
findResolvedAtomBy(typeVariable, topLevelAtoms) ?: topLevelAtoms.firstOrNull()
|
||||||
|
|
||||||
|
if (resolvedAtom != null) {
|
||||||
|
c.addError(NotEnoughInformationForTypeParameter(typeVariable, resolvedAtom))
|
||||||
|
}
|
||||||
|
|
||||||
|
val resultErrorType = when (typeVariable) {
|
||||||
|
is ConeTypeParameterBasedTypeVariable ->
|
||||||
|
createCannotInferErrorType(
|
||||||
|
"Cannot infer argument for type parameter ${typeVariable.typeParameterSymbol.name}",
|
||||||
|
isUninferredParameter = true,
|
||||||
|
)
|
||||||
|
is ConeTypeVariableForLambdaParameterType -> createCannotInferErrorType("Cannot infer lambda parameter type")
|
||||||
|
else -> createCannotInferErrorType("Cannot infer type variable $typeVariable")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.fixVariable(typeVariable, resultErrorType, ConeFixVariableConstraintPosition(typeVariable))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCannotInferErrorType(message: String, isUninferredParameter: Boolean = false) =
|
||||||
|
ConeClassErrorType(
|
||||||
|
ConeSimpleDiagnostic(
|
||||||
|
message,
|
||||||
|
DiagnosticKind.CannotInferParameterType,
|
||||||
|
),
|
||||||
|
isUninferredParameter,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun findResolvedAtomBy(
|
||||||
|
typeVariable: TypeVariableMarker,
|
||||||
|
topLevelAtoms: List<FirStatement>
|
||||||
|
): FirStatement? {
|
||||||
|
|
||||||
|
fun FirStatement.findFirstAtomContainingVariable(): FirStatement? {
|
||||||
|
|
||||||
|
var result: FirStatement? = null
|
||||||
|
|
||||||
|
fun suggestElement(element: FirElement) {
|
||||||
|
if (result == null && element is FirStatement) {
|
||||||
|
result = element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this@findFirstAtomContainingVariable.processAllContainingCallCandidates(processBlocks = true) { candidate ->
|
||||||
|
if (typeVariable in candidate.freshVariables) {
|
||||||
|
suggestElement(candidate.callInfo.callSite)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (postponedAtom in candidate.postponedAtoms) {
|
||||||
|
if (postponedAtom is ResolvedLambdaAtom) {
|
||||||
|
if (postponedAtom.typeVariableForLambdaReturnType == typeVariable) {
|
||||||
|
suggestElement(postponedAtom.atom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
return topLevelAtoms.firstNotNullOfOrNull(FirStatement::findFirstAtomContainingVariable)
|
||||||
|
}
|
||||||
|
|
||||||
private fun analyzeRemainingNotAnalyzedPostponedArgument(
|
private fun analyzeRemainingNotAnalyzedPostponedArgument(
|
||||||
postponedArguments: List<PostponedResolvedAtom>,
|
postponedArguments: List<PostponedResolvedAtom>,
|
||||||
analyze: (PostponedResolvedAtom) -> Unit
|
analyze: (PostponedResolvedAtom) -> Unit
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
|||||||
|
|
||||||
class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
class ConeTypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
||||||
class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name)
|
class ConeTypeVariableForPostponedAtom(name: String) : ConeTypeVariable(name)
|
||||||
|
class ConeTypeVariableForLambdaParameterType(name: String, val index: Int) : ConeTypeVariable(name)
|
||||||
|
|
||||||
// -------------------------- Atoms --------------------------
|
// -------------------------- Atoms --------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
|
|||||||
|
|
||||||
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
override fun KotlinTypeMarker.isUninferredParameter(): Boolean {
|
||||||
assert(this is ConeKotlinType)
|
assert(this is ConeKotlinType)
|
||||||
return false // TODO
|
return this is ConeClassErrorType && this.isUninferredParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
override fun FlexibleTypeMarker.asDynamicType(): DynamicTypeMarker? {
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ class CapturedTypeFromSubtyping(
|
|||||||
val position: ConstraintPosition
|
val position: ConstraintPosition
|
||||||
) : ConstraintSystemError(INAPPLICABLE)
|
) : ConstraintSystemError(INAPPLICABLE)
|
||||||
|
|
||||||
abstract class NotEnoughInformationForTypeParameter<T>(
|
open class NotEnoughInformationForTypeParameter<T>(
|
||||||
val typeVariable: TypeVariableMarker,
|
val typeVariable: TypeVariableMarker,
|
||||||
val resolvedAtom: T
|
val resolvedAtom: T
|
||||||
) : ConstraintSystemError(INAPPLICABLE)
|
) : ConstraintSystemError(INAPPLICABLE)
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
fun <T: Any> fooT22() : T? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun foo1() {
|
|
||||||
fooT22()
|
|
||||||
}
|
|
||||||
|
|
||||||
val n : Nothing = null.sure()
|
|
||||||
|
|
||||||
fun <T : Any> T?.sure() : T = this!!
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
fun <T: Any> fooT22() : T? {
|
fun <T: Any> fooT22() : T? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package noInformationForParameter
|
|
||||||
//+JDK
|
|
||||||
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
val n = newList()
|
|
||||||
|
|
||||||
val n1 : List<String> = newList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> newList() : ArrayList<S> {
|
|
||||||
return ArrayList<S>()
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
package noInformationForParameter
|
package noInformationForParameter
|
||||||
//+JDK
|
//+JDK
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
|
||||||
//KT-2445 Calling method with function with generic parameter causes compile-time exception
|
|
||||||
package a
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
test {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> test(callback: (R) -> Unit):Unit = callback(null!!)
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
||||||
//KT-2445 Calling method with function with generic parameter causes compile-time exception
|
//KT-2445 Calling method with function with generic parameter causes compile-time exception
|
||||||
package a
|
package a
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
//KT-832 Provide better diagnostics when type inference fails for an expression that returns a function
|
|
||||||
package a
|
|
||||||
|
|
||||||
fun <T> fooT2() : (t : T) -> T {
|
|
||||||
return {it}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test() {
|
|
||||||
fooT2()(1) // here 1 should not be marked with an error
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
//KT-832 Provide better diagnostics when type inference fails for an expression that returns a function
|
//KT-832 Provide better diagnostics when type inference fails for an expression that returns a function
|
||||||
package a
|
package a
|
||||||
|
|
||||||
|
|||||||
-6
@@ -1,6 +0,0 @@
|
|||||||
// NI_EXPECTED_FILE
|
|
||||||
val x get() = foo()
|
|
||||||
val y get() = bar()
|
|
||||||
|
|
||||||
fun <E> foo(): E = null!!
|
|
||||||
fun <E> bar(): List<E> = null!!
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
val x get() = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>()
|
val x get() = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>foo<!>()
|
||||||
val y get() = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!>()
|
val y get() = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!>()
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// KT-353 Generic type argument inference sometimes doesn't work
|
|
||||||
|
|
||||||
interface A {
|
|
||||||
fun <T> gen() : T
|
|
||||||
}
|
|
||||||
|
|
||||||
fun foo(a: A) {
|
|
||||||
val g : () -> Unit = {
|
|
||||||
a.gen() //it works: Unit is derived
|
|
||||||
}
|
|
||||||
|
|
||||||
val u: Unit = a.gen() // Unit should be inferred
|
|
||||||
|
|
||||||
if (true) {
|
|
||||||
a.gen() // Shouldn't work: no info for inference
|
|
||||||
}
|
|
||||||
|
|
||||||
val b : () -> Unit = {
|
|
||||||
if (true) {
|
|
||||||
a.gen() // unit can be inferred
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Unit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val f : () -> Int = {
|
|
||||||
a.gen() //type mismatch, but Int can be derived
|
|
||||||
}
|
|
||||||
|
|
||||||
a.gen() // Shouldn't work: no info for inference
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// KT-353 Generic type argument inference sometimes doesn't work
|
// KT-353 Generic type argument inference sometimes doesn't work
|
||||||
|
|
||||||
interface A {
|
interface A {
|
||||||
|
|||||||
-51
@@ -1,51 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
|
||||||
// NI_EXPECTED_FILE
|
|
||||||
|
|
||||||
@file:OptIn(ExperimentalTypeInference::class)
|
|
||||||
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
|
||||||
|
|
||||||
interface Base<K>
|
|
||||||
|
|
||||||
interface Controller<T> : Base<T> {
|
|
||||||
suspend fun yield(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SpecificController<T> : Base<String> {
|
|
||||||
suspend fun yield(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> generate(@BuilderInference g: suspend Controller<S>.() -> Unit): S = TODO()
|
|
||||||
fun <S> generateSpecific(@BuilderInference g: suspend SpecificController<S>.() -> Unit): S = TODO()
|
|
||||||
|
|
||||||
fun Base<*>.starBase() {}
|
|
||||||
fun Base<String>.stringBase() {}
|
|
||||||
|
|
||||||
val test1 = generate {
|
|
||||||
starBase()
|
|
||||||
yield("foo")
|
|
||||||
}
|
|
||||||
|
|
||||||
val test2 = generate {
|
|
||||||
starBase()
|
|
||||||
}
|
|
||||||
|
|
||||||
val test3 = generate {
|
|
||||||
yield("bar")
|
|
||||||
stringBase()
|
|
||||||
}
|
|
||||||
|
|
||||||
val test4 = generateSpecific {
|
|
||||||
yield(42)
|
|
||||||
starBase()
|
|
||||||
}
|
|
||||||
|
|
||||||
val test5 = generateSpecific {
|
|
||||||
yield(42)
|
|
||||||
stringBase()
|
|
||||||
}
|
|
||||||
|
|
||||||
val test6 = generateSpecific {
|
|
||||||
stringBase()
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
|||||||
Vendored
-23
@@ -1,23 +0,0 @@
|
|||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
|
||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
|
||||||
// NI_EXPECTED_FILE
|
|
||||||
|
|
||||||
@file:OptIn(ExperimentalTypeInference::class)
|
|
||||||
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
|
||||||
|
|
||||||
class GenericController<T> {
|
|
||||||
suspend fun yield(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> generate(@BuilderInference g: suspend GenericController<S>.() -> Unit): List<S> = TODO()
|
|
||||||
|
|
||||||
@BuilderInference
|
|
||||||
suspend fun <S> GenericController<List<S>>.yieldGenerate(g: suspend GenericController<S>.() -> Unit): Unit = TODO()
|
|
||||||
|
|
||||||
val test1 = generate {
|
|
||||||
// TODO: KT-15185
|
|
||||||
yieldGenerate {
|
|
||||||
yield(4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
|||||||
-12
@@ -1,12 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
// NI_EXPECTED_FILE
|
|
||||||
|
|
||||||
class Controller<T : Number> {
|
|
||||||
suspend fun yield(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S : Number> generate(g: suspend Controller<S>.() -> Unit): S = TODO()
|
|
||||||
|
|
||||||
val test = generate {
|
|
||||||
yield(<!ARGUMENT_TYPE_MISMATCH!>"foo"<!>)
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
|
||||||
|
|||||||
Vendored
-20
@@ -1,20 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE
|
|
||||||
// NI_EXPECTED_FILE
|
|
||||||
|
|
||||||
class GenericController<T> {
|
|
||||||
suspend fun yield(t: T) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> generate(g: suspend GenericController<S>.(S) -> Unit): S = TODO()
|
|
||||||
|
|
||||||
val test1 = generate {
|
|
||||||
yield(<!ARGUMENT_TYPE_MISMATCH!>4<!>)
|
|
||||||
}
|
|
||||||
|
|
||||||
val test2 = generate<Int> {
|
|
||||||
yield(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
val test3 = generate { bar: Int ->
|
|
||||||
yield(4)
|
|
||||||
}
|
|
||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER -UNUSED_VARIABLE
|
||||||
// NI_EXPECTED_FILE
|
// NI_EXPECTED_FILE
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
// !LANGUAGE: +NewInference
|
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
|
||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
|
||||||
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
|
||||||
|
|
||||||
fun test1() {
|
|
||||||
sequence {
|
|
||||||
val a: Array<Int> = arrayOf(1, 2, 3)
|
|
||||||
val b = arrayOf(1, 2, 3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test2() = sequence { arrayOf(1, 2, 3) }
|
|
||||||
|
|
||||||
|
|
||||||
class Foo<T>
|
|
||||||
|
|
||||||
fun <T> f1(f: Foo<T>.() -> Unit) {}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalTypeInference::class)
|
|
||||||
fun <T> f2(@BuilderInference f: Foo<T>.() -> Unit) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test3() {
|
|
||||||
f1 {
|
|
||||||
val a: Array<Int> = arrayOf(1, 2, 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
f2 {
|
|
||||||
val a: Array<Int> = arrayOf(1, 2, 3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +NewInference
|
// !LANGUAGE: +NewInference
|
||||||
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
|
||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
|
||||||
|
|||||||
+7
@@ -1082,6 +1082,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER) { firDiagnostic ->
|
||||||
|
NewInferenceNoInformationForParameterImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic ->
|
add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic ->
|
||||||
OverloadResolutionAmbiguityImpl(
|
OverloadResolutionAmbiguityImpl(
|
||||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||||
|
|||||||
+5
@@ -774,6 +774,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = ManyLambdaExpressionArguments::class
|
override val diagnosticClass get() = ManyLambdaExpressionArguments::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class NewInferenceNoInformationForParameter : KtFirDiagnostic<KtElement>() {
|
||||||
|
override val diagnosticClass get() = NewInferenceNoInformationForParameter::class
|
||||||
|
abstract val name: String
|
||||||
|
}
|
||||||
|
|
||||||
abstract class OverloadResolutionAmbiguity : KtFirDiagnostic<PsiElement>() {
|
abstract class OverloadResolutionAmbiguity : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = OverloadResolutionAmbiguity::class
|
override val diagnosticClass get() = OverloadResolutionAmbiguity::class
|
||||||
abstract val candidates: List<KtSymbol>
|
abstract val candidates: List<KtSymbol>
|
||||||
|
|||||||
+8
@@ -1246,6 +1246,14 @@ internal class ManyLambdaExpressionArgumentsImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class NewInferenceNoInformationForParameterImpl(
|
||||||
|
override val name: String,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.NewInferenceNoInformationForParameter(), KtAbstractFirDiagnostic<KtElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class OverloadResolutionAmbiguityImpl(
|
internal class OverloadResolutionAmbiguityImpl(
|
||||||
override val candidates: List<KtSymbol>,
|
override val candidates: List<KtSymbol>,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
|||||||
Reference in New Issue
Block a user