diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt index 82a3b95babc..ebf21bb5b44 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/ConeTypeCompatibilityChecker.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.isPrimitiveType import org.jetbrains.kotlin.fir.languageVersionSettings diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index ba05cce527d..7765f61f803 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -34,7 +34,6 @@ import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature -import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* @@ -810,46 +809,6 @@ fun FirElement.isLhsOfAssignment(context: CheckerContext): Boolean { return lastQualified is FirVariableAssignment && lastQualified.lValue == this } -/** - * Collects the upper bounds as [ConeClassLikeType]. - */ -fun ConeKotlinType?.collectUpperBounds(): Set { - if (this == null) return emptySet() - - val upperBounds = mutableSetOf() - val seen = mutableSetOf() - fun collect(type: ConeKotlinType) { - if (!seen.add(type)) return // Avoid infinite recursion. - - when (type) { - is ConeErrorType -> return // Ignore error types - is ConeLookupTagBasedType -> when (type) { - is ConeClassLikeType -> upperBounds.add(type) - is ConeTypeParameterType -> { - val symbol = type.lookupTag.typeParameterSymbol - symbol.resolvedBounds.forEach { collect(it.coneType) } - } - else -> error("missing branch for ${javaClass.name}") - } - is ConeTypeVariableType -> { - val symbol = (type.typeConstructor.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol ?: return - symbol.resolvedBounds.forEach { collect(it.coneType) } - } - is ConeDefinitelyNotNullType -> collect(type.original) - is ConeIntersectionType -> type.intersectedTypes.forEach(::collect) - is ConeFlexibleType -> collect(type.upperBound) - is ConeCapturedType -> type.constructor.supertypes?.forEach(::collect) - is ConeIntegerConstantOperatorType -> upperBounds.add(type.getApproximatedType()) - is ConeStubType, is ConeIntegerLiteralConstantType -> { - error("$type should not reach here") - } - } - } - - collect(this) - return upperBounds -} - fun ConeKotlinType.leastUpperBound(session: FirSession): ConeKotlinType { val upperBounds = collectUpperBounds().takeIf { it.isNotEmpty() } ?: return session.builtinTypes.nullableAnyType.type return ConeTypeIntersector.intersectTypes(session.typeContext, upperBounds) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFiniteBoundRestrictionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFiniteBoundRestrictionChecker.kt index 9b066aaf74e..7a3c7e00acc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFiniteBoundRestrictionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFiniteBoundRestrictionChecker.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds +import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNonExpansiveInheritanceRestrictionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNonExpansiveInheritanceRestrictionChecker.kt index 0616c8c12ae..9d353d5a33f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNonExpansiveInheritanceRestrictionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNonExpansiveInheritanceRestrictionChecker.kt @@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds +import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FirRegularClass diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt index e9e7a01784e..6cf42530f5f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirEqualityCompatibilityChecker.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory2 import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds +import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirMissingDependencySupertypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirMissingDependencySupertypeChecker.kt index fbe18136ffc..ae0de1ecfa4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirMissingDependencySupertypeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirMissingDependencySupertypeChecker.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn -import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds +import org.jetbrains.kotlin.fir.collectUpperBounds import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index cff3f46b6e7..cbe6b482808 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -668,11 +668,9 @@ internal fun captureFromTypeParameterUpperBoundIfNeeded( ): ConeKotlinType { val expectedTypeClassId = expectedType.upperBoundIfFlexible().classId ?: return argumentType val simplifiedArgumentType = argumentType.lowerBoundIfFlexible() as? ConeTypeParameterType ?: return argumentType - val typeParameter = simplifiedArgumentType.lookupTag.typeParameterSymbol.fir - val context = session.typeContext - val chosenSupertype = typeParameter.symbol.resolvedBounds.map { it.coneType } + val chosenSupertype = simplifiedArgumentType.collectUpperBounds() .singleOrNull { it.hasSupertypeWithGivenClassId(expectedTypeClassId, context) } ?: return argumentType val capturedType = context.captureFromExpression(chosenSupertype) ?: return argumentType diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/TypeUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/TypeUtils.kt new file mode 100644 index 00000000000..0350c56c106 --- /dev/null +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/TypeUtils.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2023 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 + +import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag +import org.jetbrains.kotlin.fir.types.* + +/** + * Collects the upper bounds as [ConeClassLikeType]. + */ +fun ConeKotlinType?.collectUpperBounds(): Set { + if (this == null) return emptySet() + + val upperBounds = mutableSetOf() + val seen = mutableSetOf() + fun collect(type: ConeKotlinType) { + if (!seen.add(type)) return // Avoid infinite recursion. + + when (type) { + is ConeErrorType -> return // Ignore error types + is ConeLookupTagBasedType -> when (type) { + is ConeClassLikeType -> upperBounds.add(type) + is ConeTypeParameterType -> { + val symbol = type.lookupTag.typeParameterSymbol + symbol.resolvedBounds.forEach { collect(it.coneType) } + } + else -> error("missing branch for ${javaClass.name}") + } + is ConeTypeVariableType -> { + val symbol = (type.typeConstructor.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol ?: return + symbol.resolvedBounds.forEach { collect(it.coneType) } + } + is ConeDefinitelyNotNullType -> collect(type.original) + is ConeIntersectionType -> type.intersectedTypes.forEach(::collect) + is ConeFlexibleType -> collect(type.upperBound) + is ConeCapturedType -> type.constructor.supertypes?.forEach(::collect) + is ConeIntegerConstantOperatorType -> upperBounds.add(type.getApproximatedType()) + is ConeStubType, is ConeIntegerLiteralConstantType -> { + error("$type should not reach here") + } + } + } + + collect(this) + return upperBounds +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.fir.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.fir.kt deleted file mode 100644 index 65b618ee02c..00000000000 --- a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -interface Inv - -fun > foo(x: X, y: Y) { - val rX = bar(x) - rX.length - - val rY = bar(y) - rY.length -} - -fun bar(l: Inv): Y = TODO() diff --git a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt index df2833eb45b..02b17b33995 100644 --- a/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt +++ b/compiler/testData/diagnostics/tests/inference/capturedTypes/captureFromTypeParameterUpperBound.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface Inv fun > foo(x: X, y: Y) {