[FIR] Properly approximate return type of callable declarations

- approximate intersection types in all non-local declarations
- approximate local types in non-private non-local declarations
This commit is contained in:
Dmitriy Novozhilov
2022-11-10 15:34:40 +02:00
committed by Space Team
parent 0f70635fcb
commit 01c6c7dc59
19 changed files with 190 additions and 230 deletions
@@ -112,7 +112,7 @@ private fun ConeKotlinType.needLocalTypeApproximation(
session: FirSession,
useSitePosition: PsiElement
): Boolean {
if (!shouldApproximateLocalTypesOfNonLocalDeclaration(visibilityForApproximation, isInlineFunction)) return false
if (!shouldApproximateAnonymousTypesOfNonLocalDeclaration(visibilityForApproximation, isInlineFunction)) return false
val localTypes: List<ConeKotlinType> = if (isLocal(session)) listOf(this) else {
typeArguments.mapNotNull {
if (it is ConeKotlinTypeProjection && it.type.isLocal(session)) {
@@ -1,17 +1,12 @@
[direct super types]
A
B
kotlin.Any
[approximated direct super types]
A
B
kotlin.Any
[all super types]
A
B
kotlin.Any
[approximated all super types]
A
B
kotlin.Any
@@ -38397,6 +38397,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/moreOnlyInputTypes.kt");
}
@Test
@TestMetadata("noInferAndLowPriority.kt")
public void testNoInferAndLowPriority() throws Exception {
@@ -35,13 +35,13 @@ FILE: referenceToExtension.kt
}
public final fun test_1(): R|kotlin/Unit| {
lval memberValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|SubstitutionOverride</GenericTest.B.memberVal: R|GenericTest.A<CapturedType(*)>|>|
lval memberFunRef: R|kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|SubstitutionOverride</GenericTest.B.memberFun: R|GenericTest.A<CapturedType(*)>|>|
lval memberValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<out kotlin/Any?>>| = Q|GenericTest.B|::R|SubstitutionOverride</GenericTest.B.memberVal: R|GenericTest.A<CapturedType(*)>|>|
lval memberFunRef: R|kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<out kotlin/Any?>>| = Q|GenericTest.B|::R|SubstitutionOverride</GenericTest.B.memberFun: R|GenericTest.A<CapturedType(*)>|>|
}
public final fun test_2(): R|kotlin/Unit| {
lval extensionValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionVal<CapturedType(*)>|
lval extensionFunRef: R|@ExtensionFunctionType kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionFun<CapturedType(*)>|
lval extensionValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<out kotlin/Any?>>| = Q|GenericTest.B|::R|/GenericTest.extensionVal<CapturedType(*)>|
lval extensionFunRef: R|kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<out kotlin/Any?>>| = Q|GenericTest.B|::R|/GenericTest.extensionFun<CapturedType(*)>|
}
}
@@ -38397,6 +38397,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/moreOnlyInputTypes.kt");
}
@Test
@TestMetadata("noInferAndLowPriority.kt")
public void testNoInferAndLowPriority() throws Exception {
@@ -38397,6 +38397,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/moreOnlyInputTypes.kt");
}
@Test
@TestMetadata("noInferAndLowPriority.kt")
public void testNoInferAndLowPriority() throws Exception {
@@ -11,26 +11,42 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousObjectSymbol
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.shouldApproximateLocalTypesOfNonLocalDeclaration
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.types.visibilityForApproximation
import org.jetbrains.kotlin.fir.types.*
object FirAmbiguousAnonymousTypeChecker : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration !is FirSimpleFunction && declaration !is FirProperty) return
if (declaration !is FirFunction && declaration !is FirProperty) return
require(declaration is FirCallableDeclaration)
// if source is not null then this type was declared in source
// so it can not be inferred to anonymous type
if (declaration.symbol.hasExplicitReturnType) return
if (context.containingDeclarations.any { it.isLocalMember || it is FirAnonymousObject }) return
if (!shouldApproximateLocalTypesOfNonLocalDeclaration(
if (!shouldApproximateAnonymousTypesOfNonLocalDeclaration(
declaration.visibilityForApproximation(context.containingDeclarations.lastOrNull()),
declaration.isInline
)
) return
val classSymbol = declaration.returnTypeRef.coneType.toSymbol(context.session) ?: return
if (classSymbol is FirAnonymousObjectSymbol) {
/*
* Here we want to check only cases when type of declaration was inferred from single-expression block
* There are three possible cases for it:
* 1. `fun foo() = ...`
* 2. `val x = ...`
* 3. `val x get() = ...`
*/
val typeRef = when (declaration) {
is FirProperty -> declaration.initializer?.typeRef ?: declaration.getter?.body?.singleExpressionType
is FirFunction -> declaration.body?.singleExpressionType
else -> error("Should not be there")
} ?: return
val classSymbol = typeRef.coneType.toSymbol(context.session) ?: return
if (classSymbol is FirAnonymousObjectSymbol && classSymbol.resolvedSuperTypeRefs.size > 1) {
// Any anonymous object that has only one super type is already approximated to the super type by
// org.jetbrains.kotlin.fir.types.TypeUtilsKt#hideLocalTypeIfNeeded. Hence, any remaining anonymous object must have more than
// one super types and hence are ambiguous.
@@ -42,4 +58,7 @@ object FirAmbiguousAnonymousTypeChecker : FirBasicDeclarationChecker() {
)
}
}
private val FirBlock.singleExpressionType
get() = ((this as? FirSingleExpressionBlock)?.statement as? FirReturnExpression)?.result?.typeRef
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.approximateDeclarationType
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -992,7 +993,12 @@ class CallAndReferenceGenerator(
val typeParameter = access.findTypeParameter(index)
val argumentFirType = (argument as FirTypeProjectionWithVariance).typeRef
val argumentIrType = if (typeParameter?.isReified == true) {
argumentFirType.approximatedForPublicPosition(approximator).toIrType()
argumentFirType.approximateDeclarationType(
session,
containingCallableVisibility = null,
isLocal = false,
stripEnhancedNullability = false
).toIrType()
} else {
argumentFirType.toIrType()
}
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.diagnostics.ConeRecursiveTypeParameterDuringErasureError
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
@@ -270,10 +269,6 @@ fun ConeKotlinType.toFirResolvedTypeRef(
}
}
fun FirTypeRef.isUnsafeVarianceType(session: FirSession): Boolean {
return coneTypeSafe<ConeKotlinType>()?.isUnsafeVarianceType(session) == true
}
fun FirTypeRef.hasEnhancedNullability(): Boolean =
coneTypeSafe<ConeKotlinType>()?.hasEnhancedNullability == true
@@ -330,101 +325,7 @@ fun FirTypeRef.withReplacedConeType(
}
}
fun FirTypeRef.approximated(
typeApproximator: ConeTypeApproximator,
toSuper: Boolean,
): FirTypeRef {
val alternativeType = (coneType as? ConeIntersectionType)?.alternativeType ?: coneType
if (alternativeType !== coneType && !alternativeType.requiresApproximationInPublicPosition()) {
return withReplacedConeType(alternativeType)
}
val approximatedType = if (toSuper)
typeApproximator.approximateToSuperType(alternativeType, TypeApproximatorConfiguration.PublicDeclaration.SaveAnonymousTypes)
else
typeApproximator.approximateToSubType(alternativeType, TypeApproximatorConfiguration.PublicDeclaration.SaveAnonymousTypes)
return withReplacedConeType(approximatedType)
}
fun FirTypeRef.approximatedIfNeededOrSelf(
approximator: ConeTypeApproximator,
containingCallableVisibility: Visibility?,
session: FirSession,
isInlineFunction: Boolean = false
): FirTypeRef {
val approximated = if (containingCallableVisibility == Visibilities.Public || containingCallableVisibility == Visibilities.Protected)
approximatedForPublicPosition(approximator)
else
this
return approximated.hideLocalTypeIfNeeded(containingCallableVisibility, session, isInlineFunction).withoutEnhancedNullability()
}
fun FirTypeRef.approximatedForPublicPosition(approximator: ConeTypeApproximator): FirTypeRef =
if (this is FirResolvedTypeRef && type.requiresApproximationInPublicPosition())
this.approximated(approximator, toSuper = true)
else
this
private fun ConeKotlinType.requiresApproximationInPublicPosition(): Boolean = contains {
it is ConeIntegerLiteralType || it is ConeCapturedType || it is ConeDefinitelyNotNullType || it is ConeIntersectionType
}
/*
* Suppose a function without an explicit return type just returns an anonymous object:
*
* fun foo(...) = object : ObjectSuperType {
* override fun ...
* }
*
* Without unwrapping, the return type ended up with that anonymous object (<no name provided>), while the resolved super type, which
* acts like an implementing interface, is a better fit. In fact, exposing an anonymous object types is prohibited for certain cases,
* e.g., KT-33917. We can also apply this to any local types.
*/
private fun FirTypeRef.hideLocalTypeIfNeeded(
containingCallableVisibility: Visibility?,
session: FirSession,
isInlineFunction: Boolean = false
): FirTypeRef {
if (this !is FirResolvedTypeRef || !shouldApproximateLocalTypesOfNonLocalDeclaration(containingCallableVisibility, isInlineFunction)) return this
return withReplacedConeType(type.approximateToOnlySupertype(session))
}
private fun ConeKotlinType.approximateToOnlySupertype(session: FirSession): ConeKotlinType? {
if (this is ConeFlexibleType) {
val lower = lowerBound.approximateToOnlySupertype(session)?.coneLowerBoundIfFlexible()
val upper = upperBound.approximateToOnlySupertype(session)?.coneUpperBoundIfFlexible()
if (lower == null && upper == null) {
return null
}
return coneFlexibleOrSimpleType(session.typeContext, lower ?: lowerBound, upper ?: upperBound)
}
if (this !is ConeClassLikeType) {
return null
}
val firClass = (lookupTag as? ConeClassLookupTagWithFixedSymbol)?.symbol?.fir
if (firClass !is FirAnonymousObject) {
// NB: local classes are acceptable here, but reported by EXPOSED_* checkers as errors
return null
}
if (firClass.superTypeRefs.size > 1) {
// NB: don't approximate so members can be resolved. The error is reported by FirAmbiguousAnonymousTypeChecker.
return null
}
val superType = firClass.superTypeRefs.single()
if (superType !is FirResolvedTypeRef) {
return null
}
val result = superType.type.withNullability(nullability, session.typeContext)
if (typeArguments.isNotEmpty() && typeArguments.size == firClass.typeParameters.size) {
val substitution = firClass.typeParameters.zip(typeArguments).associate { (parameter, argument) ->
parameter.symbol to argument.type!!
}
return ConeSubstitutorByMap(substitution, session).substituteOrSelf(result)
}
return result
}
fun shouldApproximateLocalTypesOfNonLocalDeclaration(containingCallableVisibility: Visibility?, isInlineFunction: Boolean): Boolean {
fun shouldApproximateAnonymousTypesOfNonLocalDeclaration(containingCallableVisibility: Visibility?, isInlineFunction: Boolean): Boolean {
// Approximate types for non-private (all but package private or private) members.
// Also private inline functions, as per KT-33917.
return when (containingCallableVisibility) {
@@ -71,8 +71,6 @@ class FirCallCompletionResultsWriterTransformer(
private val mode: Mode = Mode.Normal
) : FirAbstractTreeTransformer<ExpectedArgumentType?>(phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
private val declarationWriter by lazy { FirDeclarationCompletionResultsWriter(finalSubstitutor, typeApproximator, session.typeContext) }
private val arrayOfCallTransformer = FirArrayOfCallTransformer()
private var enableArrayOfCallTransformation = false
@@ -187,10 +185,6 @@ class FirCallCompletionResultsWriterTransformer(
session.lookupTracker?.recordTypeResolveAsLookup(resultType, qualifiedAccessExpression.source, context.file.source)
if (mode == Mode.DelegatedPropertyCompletion) {
subCandidate.symbol.fir.transformSingle(
declarationWriter,
FirDeclarationCompletionResultsWriter.ApproximationData.NoApproximation
)
val typeUpdater = TypeUpdaterForDelegateArguments()
result.transformExplicitReceiver(typeUpdater, null)
}
@@ -243,10 +237,6 @@ class FirCallCompletionResultsWriterTransformer(
session.lookupTracker?.recordTypeResolveAsLookup(resultType, functionCall.source, context.file.source)
if (mode == Mode.DelegatedPropertyCompletion) {
subCandidate.symbol.fir.transformSingle(
declarationWriter,
FirDeclarationCompletionResultsWriter.ApproximationData.NoApproximation
)
val typeUpdater = TypeUpdaterForDelegateArguments()
result.argumentList.transformArguments(typeUpdater, null)
result.transformExplicitReceiver(typeUpdater, null)
@@ -914,63 +904,3 @@ private fun ExpectedArgumentType.getExpectedType(argument: FirElement): ConeKotl
}
fun ConeKotlinType.toExpectedType(): ExpectedArgumentType = ExpectedArgumentType.ExpectedType(this)
internal class FirDeclarationCompletionResultsWriter(
private val finalSubstitutor: ConeSubstitutor,
private val typeApproximator: ConeTypeApproximator,
private val typeContext: ConeInferenceContext
) : FirDefaultTransformer<FirDeclarationCompletionResultsWriter.ApproximationData>() {
override fun <E : FirElement> transformElement(element: E, data: ApproximationData): E {
return element
}
override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: ApproximationData): FirStatement {
return super.transformAnonymousObject(anonymousObject, ApproximationData.NoApproximation)
}
override fun transformSimpleFunction(simpleFunction: FirSimpleFunction, data: ApproximationData): FirStatement {
val newData = if (simpleFunction.isLocal || data == ApproximationData.NoApproximation) ApproximationData.NoApproximation
else ApproximationData.ApproximateByStatus(simpleFunction.visibility, simpleFunction.isInline)
simpleFunction.transformReturnTypeRef(this, newData)
simpleFunction.transformValueParameters(this, ApproximationData.NoApproximation)
simpleFunction.transformReceiverParameter(this, newData)
return simpleFunction
}
override fun transformProperty(property: FirProperty, data: ApproximationData): FirStatement {
val newData = if (property.isLocal || data == ApproximationData.NoApproximation) ApproximationData.NoApproximation
else ApproximationData.ApproximateByStatus(property.visibility, false)
property.transformGetter(this, newData)
property.transformSetter(this, newData)
property.transformReturnTypeRef(this, newData)
property.transformReceiverParameter(this, newData)
return property
}
override fun transformPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: ApproximationData): FirStatement {
propertyAccessor.transformReturnTypeRef(this, data)
propertyAccessor.transformValueParameters(this, ApproximationData.NoApproximation)
return propertyAccessor
}
override fun transformValueParameter(valueParameter: FirValueParameter, data: ApproximationData): FirStatement {
valueParameter.transformReturnTypeRef(this, ApproximationData.NoApproximation)
return valueParameter
}
override fun transformTypeRef(typeRef: FirTypeRef, data: ApproximationData): FirTypeRef {
val result = finalSubstitutor.substituteOrNull(typeRef.coneType)?.let {
typeRef.resolvedTypeFromPrototype(it)
} ?: typeRef
if (data is ApproximationData.ApproximateByStatus) {
return result.approximatedIfNeededOrSelf(typeApproximator, data.visibility, this.typeContext.session, data.isInline)
}
return result
}
sealed class ApproximationData {
class ApproximateByStatus(val visibility: Visibility?, val isInline: Boolean) : ApproximationData()
object NoApproximation : ApproximationData()
object Default : ApproximationData()
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2022 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.transformers.body.resolve
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
fun FirTypeRef.approximateDeclarationType(
session: FirSession,
containingCallableVisibility: Visibility?,
isLocal: Boolean,
isInlineFunction: Boolean = false,
stripEnhancedNullability: Boolean = true
): FirTypeRef {
val baseType = (this as? FirResolvedTypeRef)?.type ?: return this
val configuration = when (isLocal) {
true -> TypeApproximatorConfiguration.LocalDeclaration
false -> when (shouldApproximateAnonymousTypesOfNonLocalDeclaration(containingCallableVisibility, isInlineFunction)) {
true -> TypeApproximatorConfiguration.PublicDeclaration.ApproximateAnonymousTypes
false -> TypeApproximatorConfiguration.PublicDeclaration.SaveAnonymousTypes
}
}
val preparedType = if (isLocal) baseType else baseType.substituteAlternativesInPublicType(session)
val approximatedType = session.typeApproximator.approximateToSuperType(preparedType, configuration) ?: preparedType
return this.withReplacedConeType(approximatedType).applyIf(stripEnhancedNullability) { withoutEnhancedNullability() }
}
private fun ConeKotlinType.substituteAlternativesInPublicType(session: FirSession): ConeKotlinType {
val substitutor = object : AbstractConeSubstitutor(session.typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeIntersectionType) return null
val alternativeType = type.alternativeType ?: return null
return substituteOrSelf(alternativeType)
}
}
return substitutor.substituteOrSelf(this)
}
@@ -287,6 +287,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
val stubTypeCompletionResultsWriter = FirStubTypeTransformer(finalSubstitutor)
property.transformSingle(stubTypeCompletionResultsWriter, null)
property.replaceReturnTypeRef(property.returnTypeRef.approximateDeclarationType(session, property.visibilityForApproximation(), property.isLocal))
val callCompletionResultsWriter = callCompleter.createCompletionResultsWriter(
finalSubstitutor,
@@ -296,9 +297,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
it.transformSingle(callCompletionResultsWriter, null)
}
val declarationCompletionResultsWriter =
FirDeclarationCompletionResultsWriter(finalSubstitutor, session.typeApproximator, session.typeContext)
property.transformSingle(declarationCompletionResultsWriter, FirDeclarationCompletionResultsWriter.ApproximationData.Default)
property
}
}
@@ -648,10 +647,10 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
result.transformReturnTypeRef(
transformer,
withExpectedType(
returnExpression.resultType.approximatedIfNeededOrSelf(
session.typeApproximator,
simpleFunction?.visibilityForApproximation(),
returnExpression.resultType.approximateDeclarationType(
session,
simpleFunction?.visibilityForApproximation(),
isLocal = simpleFunction?.isLocal == true,
isInlineFunction = simpleFunction?.isInline == true
)
)
@@ -814,7 +813,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
val initialReturnTypeRef = lambda.returnTypeRef
val valueParameters = when {
resolvedLambdaAtom != null -> obtainValueParametersFromResolvedLambdaAtom(resolvedLambdaAtom, lambda)
else -> lambda.valueParameters
else -> obtainValueParametersFromExpectedType(expectedTypeRef.coneTypeSafe(), lambda)
}
val returnTypeRefFromResolvedAtom = resolvedLambdaAtom?.returnType?.let { lambda.returnTypeRef.resolvedTypeFromPrototype(it) }
lambda = buildAnonymousFunctionCopy(lambda) {
@@ -928,17 +927,37 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
listOf(itParam)
}
else -> {
lambda.valueParameters.mapIndexed { index, param ->
if (param.returnTypeRef is FirResolvedTypeRef) {
param
} else {
val resolvedType =
param.returnTypeRef.resolvedTypeFromPrototype(resolvedLambdaAtom.parameters[index])
param.replaceReturnTypeRef(resolvedType)
param
}
}
else -> obtainValueParametersFromExpectedParameterTypes(resolvedLambdaAtom.parameters, lambda)
}
}
private fun obtainValueParametersFromExpectedType(
expectedType: ConeKotlinType?,
lambda: FirAnonymousFunction
): List<FirValueParameter> {
if (expectedType == null) return lambda.valueParameters
if (!expectedType.isFunctionalOrSuspendFunctionalType(session)) return lambda.valueParameters
val parameterTypes = expectedType.typeArguments
.mapTo(mutableListOf()) { it.type ?: session.builtinTypes.nullableAnyType.type }
.also { it.removeLastOrNull() }
if (expectedType.isExtensionFunctionType) {
parameterTypes.removeFirstOrNull()
}
return obtainValueParametersFromExpectedParameterTypes(parameterTypes, lambda)
}
private fun obtainValueParametersFromExpectedParameterTypes(
expectedTypeParameterTypes: List<ConeKotlinType>,
lambda: FirAnonymousFunction
): List<FirValueParameter> {
return lambda.valueParameters.mapIndexed { index, param ->
if (param.returnTypeRef is FirResolvedTypeRef) {
param
} else {
val resolvedType =
param.returnTypeRef.resolvedTypeFromPrototype(expectedTypeParameterTypes[index])
param.replaceReturnTypeRef(resolvedType)
param
}
}
}
@@ -1024,11 +1043,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
return backingField.transformReturnTypeRef(
transformer,
withExpectedType(
expectedType.approximatedIfNeededOrSelf(
session.typeApproximator,
backingField.visibilityForApproximation(),
session
)
expectedType.approximateDeclarationType(session, backingField.visibilityForApproximation(), isLocal = false)
)
)
}
@@ -1050,11 +1065,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
withExpectedType(
resultType?.let {
val expectedType = it.toExpectedTypeRef()
expectedType.approximatedIfNeededOrSelf(
session.typeApproximator,
variable.visibilityForApproximation(),
session
)
expectedType.approximateDeclarationType(session, variable.visibilityForApproximation(), variable.isLocal)
} ?: buildErrorTypeRef {
diagnostic = ConeLocalVariableNoTypeOrInitializer(variable)
source = variable.source
@@ -1067,6 +1078,13 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve
}
}
private val FirVariable.isLocal: Boolean
get() = when (this) {
is FirProperty -> this.isLocal
is FirValueParameter -> true
else -> false
}
private fun FirTypeRef.toExpectedTypeRef(): FirResolvedTypeRef {
return when (this) {
is FirImplicitTypeRef -> buildErrorTypeRef {
@@ -70,13 +70,13 @@ public abstract interface I /* I*/ {
public final class InvalidPublicSupertype /* InvalidPublicSupertype*/ {
@org.jetbrains.annotations.NotNull()
private final java.lang.Object x;
private final java.lang.Runnable x;
@org.jetbrains.annotations.NotNull()
public final java.lang.Object bar();// bar()
public final java.lang.Runnable bar();// bar()
@org.jetbrains.annotations.NotNull()
public final java.lang.Object getX();// getX()
public final java.lang.Runnable getX();// getX()
public InvalidPublicSupertype();// .ctor()
@@ -36,11 +36,11 @@ fun test2(b: Boolean) {
}
fun test3(b: Boolean) {
var x = <!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>")!>foo3 { 1 }<!>
var x = <!DEBUG_INFO_EXPRESSION_TYPE("I1")!>foo3 { 1 }<!>
if (b) {
x = <!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>")!>foo3 { 2 }<!>
x = <!DEBUG_INFO_EXPRESSION_TYPE("I1")!>foo3 { 2 }<!>
}
x.bar()
x.<!UNRESOLVED_REFERENCE!>bar<!>()
}
fun test4(b: Boolean) {
@@ -36,11 +36,11 @@ fun test2(b: Boolean) {
}
fun test3(b: Boolean) {
var x = <!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>")!>foo3 { 1 }<!>
var x = <!DEBUG_INFO_EXPRESSION_TYPE("I1")!>foo3 { 1 }<!>
if (b) {
x = <!DEBUG_INFO_EXPRESSION_TYPE("<anonymous>")!>foo3 { 2 }<!>
x = <!DEBUG_INFO_EXPRESSION_TYPE("I1")!>foo3 { 2 }<!>
}
x.bar()
x.<!UNRESOLVED_REFERENCE!>bar<!>()
}
fun test4(b: Boolean) {
@@ -0,0 +1,14 @@
// FIR_IDENTICAL
// WITH_STDLIB
private val PRIMITIVE_CLASSES = listOf(Boolean::class, Byte::class, Char::class, Double::class, Float::class, Int::class, Long::class, Short::class)
// Map
private val PRIMITIVE_TO_WRAPPER = PRIMITIVE_CLASSES.map { it.javaPrimitiveType to it.javaObjectType }.toMap()
private val WRAPPER_TO_PRIMITIVE = PRIMITIVE_CLASSES.map { it.javaObjectType to it.javaPrimitiveType }.toMap()
val Class<*>.primitiveByWrapper: Class<*>?
get() = WRAPPER_TO_PRIMITIVE[this]
val Class<*>.wrapperByPrimitive: Class<*>?
get() = PRIMITIVE_TO_WRAPPER[this]
@@ -0,0 +1,7 @@
package
private val PRIMITIVE_CLASSES: kotlin.collections.List<kotlin.reflect.KClass<out kotlin.Any>>
private val PRIMITIVE_TO_WRAPPER: kotlin.collections.Map<java.lang.Class<out kotlin.Any>?, java.lang.Class<out kotlin.Any>>
private val WRAPPER_TO_PRIMITIVE: kotlin.collections.Map<java.lang.Class<out kotlin.Any>, java.lang.Class<out kotlin.Any>?>
public val java.lang.Class<*>.primitiveByWrapper: java.lang.Class<*>?
public val java.lang.Class<*>.wrapperByPrimitive: java.lang.Class<*>?
@@ -38487,6 +38487,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/moreOnlyInputTypes.kt");
}
@Test
@TestMetadata("noInferAndLowPriority.kt")
public void testNoInferAndLowPriority() throws Exception {
@@ -255,7 +255,7 @@ fun <K, V> Map<K, V>.compactIfPossible(): Map<K, V> =
else -> this
}
inline fun <T> T.applyIf(`if`: Boolean, body: T.() -> T): T =
inline fun <T, R : T> R.applyIf(`if`: Boolean, body: R.() -> T): T =
if (`if`) body() else this