[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:
committed by
Space Team
parent
0f70635fcb
commit
01c6c7dc59
+1
-1
@@ -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)) {
|
||||
|
||||
+3
-8
@@ -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
|
||||
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+4
-4
@@ -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(*)>|
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+27
-8
@@ -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
|
||||
}
|
||||
|
||||
+7
-1
@@ -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) {
|
||||
|
||||
-70
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+46
@@ -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)
|
||||
}
|
||||
+46
-28
@@ -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 {
|
||||
|
||||
+3
-3
@@ -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()
|
||||
|
||||
|
||||
+3
-3
@@ -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) {
|
||||
|
||||
Vendored
+14
@@ -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]
|
||||
compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/moreOnlyInputTypes.txt
Vendored
+7
@@ -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<*>?
|
||||
Generated
+6
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user