[FIR] Check type arguments in inner/outer local classes as in K1
^KT-59922 ^KT-59951
This commit is contained in:
committed by
Space Team
parent
cfa48b5cc0
commit
9383d0bfa4
+12
@@ -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<in Foo>
|
||||
|
||||
@@ -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<FirClassLikeSymbol<*>> =
|
||||
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)
|
||||
|
||||
+16
-7
@@ -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
|
||||
|
||||
+17
-6
@@ -1,16 +1,16 @@
|
||||
fun <E> foo(x: Any, y: Any) : Any {
|
||||
class C
|
||||
// without E?
|
||||
if(x is <!NO_TYPE_ARGUMENTS_ON_RHS!>C<!>) {
|
||||
if (x is <!CANNOT_CHECK_FOR_ERASED!>C<!>) {
|
||||
return x
|
||||
}
|
||||
|
||||
if (1 == 2) {
|
||||
x as C
|
||||
x <!UNCHECKED_CAST!>as C<!>
|
||||
}
|
||||
|
||||
if (2 == 3) {
|
||||
x as? C
|
||||
x <!UNCHECKED_CAST!>as? C<!>
|
||||
}
|
||||
|
||||
class Outer<F> {
|
||||
@@ -18,16 +18,27 @@ fun <E> foo(x: Any, y: Any) : Any {
|
||||
}
|
||||
|
||||
// bare type
|
||||
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer<!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
if (y is <!CANNOT_CHECK_FOR_ERASED!>Outer<*><!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer.Inner<!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
if (y is Outer<*>.Inner) {
|
||||
if (y is <!CANNOT_CHECK_FOR_ERASED!>Outer<*>.Inner<!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
y as Outer<*>.Inner
|
||||
y as Outer.Inner
|
||||
y <!UNCHECKED_CAST!>as Outer<*><!>
|
||||
y as <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer<!>
|
||||
|
||||
y <!UNCHECKED_CAST!>as Outer<*>.Inner<!>
|
||||
y as <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer.Inner<!>
|
||||
|
||||
return C()
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,7 +1,7 @@
|
||||
fun <E> foo(x: Any, y: Any) : Any {
|
||||
class C
|
||||
// without E?
|
||||
if(x is <!CANNOT_CHECK_FOR_ERASED!>C<!>) {
|
||||
if (x is <!CANNOT_CHECK_FOR_ERASED!>C<!>) {
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -18,6 +18,14 @@ fun <E> foo(x: Any, y: Any) : Any {
|
||||
}
|
||||
|
||||
// bare type
|
||||
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer<!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
if (y is <!CANNOT_CHECK_FOR_ERASED!>Outer<*><!>) {
|
||||
return y
|
||||
}
|
||||
|
||||
if (y is <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer.Inner<!>) {
|
||||
return y
|
||||
}
|
||||
@@ -26,6 +34,9 @@ fun <E> foo(x: Any, y: Any) : Any {
|
||||
return y
|
||||
}
|
||||
|
||||
y <!UNCHECKED_CAST!>as Outer<*><!>
|
||||
y <!USELESS_CAST!>as <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer<!><!>
|
||||
|
||||
y <!UNCHECKED_CAST!>as Outer<*>.Inner<!>
|
||||
y <!USELESS_CAST!>as <!NO_TYPE_ARGUMENTS_ON_RHS!>Outer.Inner<!><!>
|
||||
|
||||
|
||||
@@ -30,6 +30,6 @@ fun testWrong4(x: List<Any>) = x is <!NO_TYPE_ARGUMENTS_ON_RHS!>ReadableList<!>
|
||||
fun <T> testLocal(x: Any) {
|
||||
class C
|
||||
typealias CA = C
|
||||
if (x is <!NO_TYPE_ARGUMENTS_ON_RHS!>C<!>) {}
|
||||
if (x is <!CANNOT_CHECK_FOR_ERASED!>C<!>) {}
|
||||
if (x is <!UNRESOLVED_REFERENCE!>CA<!>) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user