diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt index e992859c1fb..c740e493b4f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirCastDiagnosticsHelpers.kt @@ -7,9 +7,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isInterface +import org.jetbrains.kotlin.fir.declarations.utils.isLocal +import org.jetbrains.kotlin.fir.getContainingClassLookupTag import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.getClassAndItsOuterClassesWhenLocal import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap +import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol import org.jetbrains.kotlin.fir.scopes.platformClassMapper import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol @@ -169,6 +174,13 @@ fun isCastErased(supertype: ConeKotlinType, subtype: ConeKotlinType, context: Ch else if (subtype is ConeTypeParameterType) return false val regularClassSymbol = subtype.toRegularClassSymbol(context.session) ?: return true + + val outerClasses = regularClassSymbol.getClassAndItsOuterClassesWhenLocal(context.session) + + if (regularClassSymbol.isLocal && regularClassSymbol.typeParameterSymbols.any { it.containingDeclarationSymbol !in outerClasses }) { + return true + } + val staticallyKnownSubtype = findStaticallyKnownSubtype(supertype, regularClassSymbol, context) // If the substitution failed, it means that the result is an impossible type, e.g. something like Out diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt index a1efb0651e3..91d6fd2ee77 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/LookupTagUtils.kt @@ -12,9 +12,12 @@ import org.jetbrains.kotlin.fir.FirFunctionTypeParameter import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.getAnnotationsByClassId +import org.jetbrains.kotlin.fir.declarations.utils.isInner +import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression +import org.jetbrains.kotlin.fir.getContainingClassLookupTag import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.symbols.* @@ -64,6 +67,12 @@ fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSym fun ConeClassLikeLookupTag.toFirRegularClassSymbol(session: FirSession): FirRegularClassSymbol? = toSymbol(session) as? FirRegularClassSymbol + +fun FirClassLikeSymbol<*>.getClassAndItsOuterClassesWhenLocal(session: FirSession): Set> = + generateSequence(this.takeIf { it.isLocal }) { + if (it.isInner) it.getContainingClassLookupTag()?.toFirRegularClassSymbol(session) else null + }.toSet() + @OptIn(LookupTagInternals::class) fun ConeClassLikeLookupTagImpl.bindSymbolToLookupTag(session: FirSession, symbol: FirClassLikeSymbol<*>?) { boundSymbol = WeakPair(session, symbol) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 27c3b12a406..10a952a3fb6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -12,9 +12,14 @@ import org.jetbrains.kotlin.fakeElement import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isExternal +import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.diagnostics.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.expressions.FirOperation.AS +import org.jetbrains.kotlin.fir.expressions.FirOperation.IS +import org.jetbrains.kotlin.fir.expressions.FirOperation.NOT_IS +import org.jetbrains.kotlin.fir.expressions.FirOperation.SAFE_AS import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList import org.jetbrains.kotlin.fir.expressions.impl.toAnnotationArgumentMapping @@ -842,8 +847,12 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT if (firClass.typeParameters.isEmpty()) return this val originalType = argument.unwrapExpression().resolvedType + val outerClasses by lazy(LazyThreadSafetyMode.NONE) { firClass.symbol.getClassAndItsOuterClassesWhenLocal(session) } val newType = components.computeRepresentativeTypeForBareType(type, originalType) - ?: if (firClass.isLocal && (operation == FirOperation.AS || operation == FirOperation.SAFE_AS)) { + ?: if ( + firClass.isLocal && firClass.typeParameters.none { it.symbol.containingDeclarationSymbol in outerClasses } && + (operation == NOT_IS || operation == IS || operation == AS || operation == SAFE_AS) + ) { (firClass as FirClass).defaultType() } else return buildErrorTypeRef { source = this@withTypeArgumentsForBareType.source @@ -857,7 +866,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT data: ResolutionMode, ): FirStatement { val resolved = components.typeResolverTransformer.withBareTypes { - if (typeOperatorCall.operation == FirOperation.IS || typeOperatorCall.operation == FirOperation.NOT_IS) { + if (typeOperatorCall.operation == IS || typeOperatorCall.operation == NOT_IS) { components.typeResolverTransformer.withIsOperandOfIsOperator { typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent) } @@ -882,13 +891,13 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT }, null) when (resolved.operation) { - FirOperation.IS, FirOperation.NOT_IS -> { + IS, NOT_IS -> { resolved.resultType = session.builtinTypes.booleanType.type } - FirOperation.AS -> { + AS -> { resolved.resultType = conversionTypeRef.coneType } - FirOperation.SAFE_AS -> { + SAFE_AS -> { resolved.resultType = conversionTypeRef.coneType.withNullability( ConeNullability.NULLABLE, session.typeContext, ) @@ -900,7 +909,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT } private fun FirTypeOperatorCall.transformTypeOperatorCallChildren(): FirTypeOperatorCall { - if (operation == FirOperation.AS || operation == FirOperation.SAFE_AS) { + if (operation == AS || operation == SAFE_AS) { val argument = argumentList.arguments.singleOrNull() ?: error("Not a single argument: ${this.render()}") // For calls in the form of (materialize() as MyClass) we've got a special rule that adds expect type to the `materialize()` call @@ -914,7 +923,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT it.typeArguments.isNotEmpty() || (it.lookupTag.toSymbol(session)?.fir as? FirTypeParameterRefsOwner)?.typeParameters?.isEmpty() == true }?.let { - if (operation == FirOperation.SAFE_AS) + if (operation == SAFE_AS) it.withNullability(ConeNullability.NULLABLE, session.typeContext) else it diff --git a/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.fir.kt b/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.fir.kt index 6b2ad475fd3..3b07dcadf07 100644 --- a/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.fir.kt @@ -1,16 +1,16 @@ fun foo(x: Any, y: Any) : Any { class C // without E? - if(x is C) { + if (x is C) { return x } if (1 == 2) { - x as C + x as C } if (2 == 3) { - x as? C + x as? C } class Outer { @@ -18,16 +18,27 @@ fun foo(x: Any, y: Any) : Any { } // bare type + if (y is Outer) { + return y + } + + if (y is Outer<*>) { + return y + } + if (y is Outer.Inner) { return y } - if (y is Outer<*>.Inner) { + if (y is Outer<*>.Inner) { return y } - y as Outer<*>.Inner - y as Outer.Inner + y as Outer<*> + y as Outer + + y as Outer<*>.Inner + y as Outer.Inner return C() } diff --git a/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.kt b/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.kt index 102c56b2db3..23d5a0e7706 100644 --- a/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.kt +++ b/compiler/testData/diagnostics/tests/generics/capturedParameters/uncheckedCast.kt @@ -1,7 +1,7 @@ fun foo(x: Any, y: Any) : Any { class C // without E? - if(x is C) { + if (x is C) { return x } @@ -18,6 +18,14 @@ fun foo(x: Any, y: Any) : Any { } // bare type + if (y is Outer) { + return y + } + + if (y is Outer<*>) { + return y + } + if (y is Outer.Inner) { return y } @@ -26,6 +34,9 @@ fun foo(x: Any, y: Any) : Any { return y } + y as Outer<*> + y as Outer + y as Outer<*>.Inner y as Outer.Inner diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.fir.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.fir.kt index 4a8494415b0..f292e21645d 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.fir.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasAsBareType.fir.kt @@ -30,6 +30,6 @@ fun testWrong4(x: List) = x is ReadableList fun testLocal(x: Any) { class C typealias CA = C - if (x is C) {} + if (x is C) {} if (x is CA) {} }