[FIR] Infer type arguments for captured parameters of inner classes

KT-38992
This commit is contained in:
Dmitriy Novozhilov
2020-07-13 15:59:09 +03:00
parent 1c622a5a3f
commit 1ce4eca3a6
27 changed files with 316 additions and 85 deletions
@@ -0,0 +1,29 @@
interface AbstractFirTreeBuilder
class FirTreeBuilder : AbstractFirTreeBuilder
abstract class AbstractBuilderConfigurator<T : AbstractFirTreeBuilder> {
abstract class BuilderConfigurationContext
inner class LeafBuilderConfigurationContext : BuilderConfigurationContext()
}
class BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>() {
fun test(func: (LeafBuilderConfigurationContext) -> Unit) {
val context = LeafBuilderConfigurationContext()
func(context)
}
}
class Outer<E> {
inner class Inner
fun foo(x: (Inner) -> Unit, y: Inner.() -> Unit) {
// each call reported as INAPPLICABLE because "Inner<E> is not a subtype of Inner"
bar(Inner())
x(Inner())
Inner().y()
}
fun bar(i: Inner) {}
}
@@ -0,0 +1,62 @@
FILE: invokeWithReceiverAndArgument.kt
public abstract interface AbstractFirTreeBuilder : R|kotlin/Any| {
}
public final class FirTreeBuilder : R|AbstractFirTreeBuilder| {
public constructor(): R|FirTreeBuilder| {
super<R|kotlin/Any|>()
}
}
public abstract class AbstractBuilderConfigurator<T : R|AbstractFirTreeBuilder|> : R|kotlin/Any| {
public constructor<T : R|AbstractFirTreeBuilder|>(): R|AbstractBuilderConfigurator<T>| {
super<R|kotlin/Any|>()
}
public abstract class BuilderConfigurationContext : R|kotlin/Any| {
public constructor(): R|AbstractBuilderConfigurator.BuilderConfigurationContext| {
super<R|kotlin/Any|>()
}
}
public final inner class LeafBuilderConfigurationContext<T : R|AbstractFirTreeBuilder|> : R|AbstractBuilderConfigurator.BuilderConfigurationContext| {
public constructor(): R|AbstractBuilderConfigurator.LeafBuilderConfigurationContext<T>| {
super<R|AbstractBuilderConfigurator.BuilderConfigurationContext|>()
}
}
}
public final class BuilderConfigurator : R|AbstractBuilderConfigurator<FirTreeBuilder>| {
public constructor(): R|BuilderConfigurator| {
super<R|AbstractBuilderConfigurator<FirTreeBuilder>|>()
}
public final fun test(func: R|(AbstractBuilderConfigurator.LeafBuilderConfigurationContext<FirTreeBuilder>) -> kotlin/Unit|): R|kotlin/Unit| {
lval context: R|AbstractBuilderConfigurator.LeafBuilderConfigurationContext<FirTreeBuilder>| = this@R|/BuilderConfigurator|.R|/AbstractBuilderConfigurator.LeafBuilderConfigurationContext.LeafBuilderConfigurationContext|()
R|<local>/func|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/Unit|>|(R|<local>/context|)
}
}
public final class Outer<E> : R|kotlin/Any| {
public constructor<E>(): R|Outer<E>| {
super<R|kotlin/Any|>()
}
public final inner class Inner<E> : R|kotlin/Any| {
public constructor(): R|Outer.Inner<E>| {
super<R|kotlin/Any|>()
}
}
public final fun foo(x: R|(Outer.Inner<E>) -> kotlin/Unit|, y: R|Outer.Inner<E>.() -> kotlin/Unit|): R|kotlin/Unit| {
this@R|/Outer|.R|/Outer.bar|(this@R|/Outer|.R|/Outer.Inner.Inner|())
R|<local>/x|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/Unit|>|(this@R|/Outer|.R|/Outer.Inner.Inner|())
R|<local>/y|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/Unit|>|(this@R|/Outer|.R|/Outer.Inner.Inner|())
}
public final fun bar(i: R|Outer.Inner<E>|): R|kotlin/Unit| {
}
}
@@ -23,11 +23,11 @@ FILE: qualifiedSupertypeExtendedByOtherSupertype.kt
}
public final fun test(): R|kotlin/Unit| {
this@R|/Test|.super<R|IBase|>.R|/IBase.foo|()
this@R|/Test|.super<R|IBase|>.R|/IBase.bar|()
this@R|/Test|.super<R|IDerived|>.R|/IDerived.foo|()
this@R|/Test|.super<R|IDerived|>.R|/IBase.bar|()
this@R|/Test|.super<R|IDerived|>.R|/IDerived.qux|()
this@R|/Test|.super<R|IBase<T>|>.R|/IBase.foo|()
this@R|/Test|.super<R|IBase<T>|>.R|/IBase.bar|()
this@R|/Test|.super<R|IDerived<T>|>.R|/IDerived.foo|()
this@R|/Test|.super<R|IDerived<T>|>.R|/IBase.bar|()
this@R|/Test|.super<R|IDerived<T>|>.R|/IDerived.qux|()
}
}
@@ -37,13 +37,13 @@ FILE: qualifiedSupertypeExtendedByOtherSupertype.kt
}
public final fun test(): R|kotlin/Unit| {
this@R|/Test2|.super<R|IBase|>.R|/IBase.foo|()
this@R|/Test2|.super<R|IBase|>.R|/IBase.bar|()
this@R|/Test2|.super<R|IBase<T>|>.R|/IBase.foo|()
this@R|/Test2|.super<R|IBase<T>|>.R|/IBase.bar|()
this@R|/Test2|.super<R|AliasedIBase|>.R|/IBase.foo|()
this@R|/Test2|.super<R|AliasedIBase|>.R|/IBase.bar|()
this@R|/Test2|.super<R|IDerived|>.R|/IDerived.foo|()
this@R|/Test2|.super<R|IDerived|>.R|/IBase.bar|()
this@R|/Test2|.super<R|IDerived|>.R|/IDerived.qux|()
this@R|/Test2|.super<R|IDerived<T>|>.R|/IDerived.foo|()
this@R|/Test2|.super<R|IDerived<T>|>.R|/IBase.bar|()
this@R|/Test2|.super<R|IDerived<T>|>.R|/IDerived.qux|()
}
}
@@ -13,20 +13,20 @@ FILE: typeParameterVsNested.kt
}
public abstract val x: R|test/My.T|
public get(): R|test/My.T|
public abstract val x: R|test/My.T<T>|
public get(): R|test/My.T<T>|
public abstract fun foo(arg: R|test/My.T|): R|kotlin/Unit|
public abstract fun foo(arg: R|test/My.T<T>|): R|kotlin/Unit|
public abstract val y: R|test/My.T|
public get(): R|test/My.T|
public abstract val y: R|test/My.T<ERROR CLASS: Type argument not defined>|
public get(): R|test/My.T<ERROR CLASS: Type argument not defined>|
public abstract val z: R|test/My.T|
public get(): R|test/My.T|
public abstract val z: R|test/My.T<ERROR CLASS: Type argument not defined>|
public get(): R|test/My.T<ERROR CLASS: Type argument not defined>|
public final class Some : R|test/My.T| {
public final class Some : R|test/My.T<T>| {
public constructor(): R|test/My.Some| {
super<R|test/My.T|>()
super<R|test/My.T<T>|>()
}
}
@@ -0,0 +1,13 @@
class A<T1, T2> {
inner class B<K1, K2> {
inner class C<U1, U2>
fun <R3> foo(c: C<R3, R3>) {}
}
fun <R2, R3> foo(c: B<R2, R2>.C<R3, R3>) {}
}
fun <R1, R2, R3> foo(c: A<R1, R1>.B<R2, R2>.C<R3, R3>) {}
fun <R3> foo(c: A.B.C<R3, R3>) {}
@@ -0,0 +1,31 @@
FILE: capturedParametersOfInnerClasses.kt
public final class A<T1, T2> : R|kotlin/Any| {
public constructor<T1, T2>(): R|A<T1, T2>| {
super<R|kotlin/Any|>()
}
public final inner class B<K1, K2, T1, T2> : R|kotlin/Any| {
public constructor<K1, K2>(): R|A.B<K1, K2, T1, T2>| {
super<R|kotlin/Any|>()
}
public final inner class C<U1, U2, K1, K2, T1, T2> : R|kotlin/Any| {
public constructor<U1, U2>(): R|A.B.C<U1, U2, K1, K2, T1, T2>| {
super<R|kotlin/Any|>()
}
}
public final fun <R3> foo(c: R|A.B.C<R3, R3, K1, K2, T1, T2>|): R|kotlin/Unit| {
}
}
public final fun <R2, R3> foo(c: R|A.B.C<R3, R3, R2, R2, T1, T2>|): R|kotlin/Unit| {
}
}
public final fun <R1, R2, R3> foo(c: R|A.B.C<R3, R3, R2, R2, R1, R1>|): R|kotlin/Unit| {
}
public final fun <R3> foo(c: R|A.B.C<R3, R3, ERROR CLASS: Type argument not defined, ERROR CLASS: Type argument not defined, ERROR CLASS: Type argument not defined, ERROR CLASS: Type argument not defined>|): R|kotlin/Unit| {
}
@@ -644,6 +644,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
}
@TestMetadata("invokeWithReceiverAndArgument.kt")
public void testInvokeWithReceiverAndArgument() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt");
}
@TestMetadata("objectInvoke.kt")
public void testObjectInvoke() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
@@ -2352,6 +2357,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
public void testBareWithSubjectTypeAlias() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/bareWithSubjectTypeAlias.kt");
}
@TestMetadata("capturedParametersOfInnerClasses.kt")
public void testCapturedParametersOfInnerClasses() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility")
@@ -644,6 +644,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
}
@TestMetadata("invokeWithReceiverAndArgument.kt")
public void testInvokeWithReceiverAndArgument() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeWithReceiverAndArgument.kt");
}
@TestMetadata("objectInvoke.kt")
public void testObjectInvoke() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
@@ -2352,6 +2357,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
public void testBareWithSubjectTypeAlias() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/bareWithSubjectTypeAlias.kt");
}
@TestMetadata("capturedParametersOfInnerClasses.kt")
public void testCapturedParametersOfInnerClasses() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility")
@@ -6,13 +6,12 @@
package org.jetbrains.kotlin.fir.resolve
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
interface FirTypeResolver : FirSessionComponent {
fun resolveType(typeRef: FirTypeRef, scope: FirScope): ConeKotlinType
fun resolveToSymbol(typeRef: FirTypeRef, scope: FirScope): FirClassifierSymbol<*>?
fun resolveType(typeRef: FirTypeRef, scope: FirScope, areBareTypesAllowed: Boolean): ConeKotlinType
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.bindSymbolToLookupTag
import org.jetbrains.kotlin.fir.resolve.providers.getSymbolByTypeRef
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
@@ -191,21 +192,7 @@ fun FirClassifierSymbol<*>.constructType(
fun FirClassifierSymbol<*>.constructType(parts: List<FirQualifierPart>, isNullable: Boolean): ConeKotlinType =
constructType(parts.toTypeProjections(), isNullable)
fun FirClassifierSymbol<*>.constructType(
parts: List<FirQualifierPart>,
isNullable: Boolean,
symbolOriginSession: FirSession,
attributes: ConeAttributes = ConeAttributes.Empty
): ConeKotlinType =
constructType(parts.toTypeProjections(), isNullable, attributes)
.also {
val lookupTag = it.lookupTag
if (lookupTag is ConeClassLikeLookupTagImpl && this is FirClassLikeSymbol<*>) {
lookupTag.bindSymbolToLookupTag(symbolOriginSession.firSymbolProvider, this)
}
}
private fun List<FirQualifierPart>.toTypeProjections(): Array<ConeTypeProjection> =
fun List<FirQualifierPart>.toTypeProjections(): Array<ConeTypeProjection> =
asReversed().flatMap { it.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray()
fun FirFunction<*>.constructFunctionalTypeRef(isSuspend: Boolean = false): FirResolvedTypeRef {
@@ -8,17 +8,15 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.qualifierResolver
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.providers.bindSymbolToLookupTag
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
import org.jetbrains.kotlin.name.ClassId
@@ -40,18 +38,22 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver {
}
}
override fun resolveToSymbol(
private fun resolveToSymbol(
typeRef: FirTypeRef,
scope: FirScope
): FirClassifierSymbol<*>? {
): Pair<FirClassifierSymbol<*>?, ConeSubstitutor?> {
return when (typeRef) {
is FirResolvedTypeRef -> typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag)
is FirResolvedTypeRef -> {
val resultSymbol = typeRef.coneTypeSafe<ConeLookupTagBasedType>()?.lookupTag?.let(symbolProvider::getSymbolByLookupTag)
resultSymbol to null
}
is FirUserTypeRef -> {
val qualifierResolver = session.qualifierResolver
var resolvedSymbol: FirClassifierSymbol<*>? = null
scope.processClassifiersByName(typeRef.qualifier.first().name) { symbol ->
if (resolvedSymbol != null) return@processClassifiersByName
var substitutor: ConeSubstitutor? = null
scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope ->
if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution
resolvedSymbol = when (symbol) {
is FirClassLikeSymbol<*> -> {
if (typeRef.qualifier.size == 1) {
@@ -66,25 +68,56 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver {
}
else -> error("!")
}
substitutor = substitutorFromScope
}
// TODO: Imports
resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier)
val resultSymbol: FirClassifierSymbol<*>? = resolvedSymbol ?: qualifierResolver.resolveSymbol(typeRef.qualifier)
resultSymbol to substitutor
}
is FirImplicitBuiltinTypeRef -> {
resolveBuiltInQualified(typeRef.id, session)
resolveBuiltInQualified(typeRef.id, session) to null
}
else -> null
else -> null to null
}
}
private fun resolveUserType(typeRef: FirUserTypeRef, symbol: FirClassifierSymbol<*>?): ConeKotlinType {
private fun resolveUserType(
typeRef: FirUserTypeRef,
symbol: FirClassifierSymbol<*>?,
substitutor: ConeSubstitutor?,
areBareTypesAllowed: Boolean
): ConeKotlinType {
if (symbol == null) {
return ConeKotlinErrorType("Symbol not found, for `${typeRef.render()}`")
}
return symbol.constructType(typeRef.qualifier, typeRef.isMarkedNullable, symbolOriginSession = session, typeRef.annotations.computeTypeAttributes())
var typeArguments = typeRef.qualifier.toTypeProjections()
if (symbol is FirRegularClassSymbol) {
val isPossibleBareType = areBareTypesAllowed && typeArguments.isEmpty()
if (typeArguments.size != symbol.fir.typeParameters.size && !isPossibleBareType) {
@Suppress("NAME_SHADOWING")
val substitutor = substitutor ?: ConeSubstitutor.Empty
val n = symbol.fir.typeParameters.size - typeArguments.size
if (n < 0) {
typeArguments = (1..symbol.fir.typeParameters.size).map { ConeClassErrorType("Type arguments number mismatch") }.toTypedArray()
} else {
val argumentsFromOuterClassesAndParents = symbol.fir.typeParameters.takeLast(n).map {
val type = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false)
substitutor.substituteOrNull(type) ?: ConeClassErrorType("Type argument not defined")
}.toTypedArray<ConeTypeProjection>()
typeArguments += argumentsFromOuterClassesAndParents
}
}
}
return symbol.constructType(typeArguments, typeRef.isMarkedNullable, typeRef.annotations.computeTypeAttributes())
.also {
val lookupTag = it.lookupTag
if (lookupTag is ConeClassLikeLookupTagImpl && symbol is FirClassLikeSymbol<*>) {
lookupTag.bindSymbolToLookupTag(session.firSymbolProvider, symbol)
}
}
}
private fun createFunctionalType(typeRef: FirFunctionTypeRef): ConeClassLikeType {
@@ -108,13 +141,17 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver {
override fun resolveType(
typeRef: FirTypeRef,
scope: FirScope
scope: FirScope,
areBareTypesAllowed: Boolean
): ConeKotlinType {
return when (typeRef) {
is FirResolvedTypeRef -> typeRef.type
is FirUserTypeRef -> resolveUserType(typeRef, resolveToSymbol(typeRef, scope))
is FirUserTypeRef -> {
val (symbol, substitutor) = resolveToSymbol(typeRef, scope)
resolveUserType(typeRef, symbol, substitutor, areBareTypesAllowed)
}
is FirFunctionTypeRef -> createFunctionalType(typeRef)
is FirDelegatedTypeRef -> resolveType(typeRef.typeRef, scope)
is FirDelegatedTypeRef -> resolveType(typeRef.typeRef, scope, areBareTypesAllowed)
is FirDynamicTypeRef -> ConeKotlinErrorType("Not supported: ${typeRef::class.simpleName}")
else -> error("!")
}
@@ -10,13 +10,24 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.providers.getNestedClassifierScope
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.scopes.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.scopes.impl.FirNestedClassifierScope
import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.name.Name
abstract class FirAbstractTreeTransformerWithSuperTypes(
phase: FirResolvePhase
@@ -43,8 +54,16 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(
// ? Is it Ok to use original file session here ?
val superTypes = lookupSuperTypes(firClass, lookupInterfaces = false, deep = true, useSiteSession = session).asReversed()
for (superType in superTypes) {
session.getNestedClassifierScope(superType.lookupTag)?.let {
scopes.add(it)
session.getNestedClassifierScope(superType.lookupTag)?.let { nestedClassifierScope ->
val klass = superType.lookupTag.toSymbol(session)?.fir as? FirRegularClass
val mapping = klass?.typeParameters?.map { it.symbol }?.zip(superType.typeArguments.map { it as ConeKotlinType })?.toMap()
val substitutor = mapping?.let { ConeSubstitutorByMap(it) } ?: ConeSubstitutor.Empty
val scope = if (nestedClassifierScope is FirNestedClassifierScope) {
FirNestedClassifierScopeWithSubstitution(nestedClassifierScope, substitutor)
} else {
nestedClassifierScope
}
scopes.add(scope)
}
}
if (firClass is FirRegularClass) {
@@ -67,3 +86,13 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(
}
}
}
private class FirNestedClassifierScopeWithSubstitution(
private val scope: FirNestedClassifierScope,
private val substitutor: ConeSubstitutor
) : FirScope() {
override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
val matchedClass = scope.getClassifierByName(name) ?: return
processor(matchedClass, substitutor)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.typeResolver
import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -21,16 +22,30 @@ class FirSpecificTypeResolverTransformer(
) : FirAbstractTreeTransformer<FirScope>(phase = FirResolvePhase.SUPER_TYPES) {
private val typeResolver = session.typeResolver
@set:PrivateForInline
var areBareTypesAllowed: Boolean = false
@OptIn(PrivateForInline::class)
inline fun <R> withAllowedBareTypes(block: () -> R): R {
val oldValue = areBareTypesAllowed
areBareTypesAllowed = true
return try {
block()
} finally {
areBareTypesAllowed = oldValue
}
}
override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): CompositeTransformResult<FirTypeRef> {
typeRef.transformChildren(this, data)
return transformType(typeRef, typeResolver.resolveType(typeRef, data))
return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed))
}
override fun transformFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: FirScope): CompositeTransformResult<FirTypeRef> {
functionTypeRef.transformChildren(this, data)
return buildResolvedFunctionTypeRef {
source = functionTypeRef.source
type = typeResolver.resolveType(functionTypeRef, data).takeIfAcceptable() ?: return functionTypeRef.compose()
type = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable() ?: return functionTypeRef.compose()
isMarkedNullable = functionTypeRef.isMarkedNullable
isSuspend = functionTypeRef.isSuspend
receiverTypeRef = functionTypeRef.receiverTypeRef
@@ -432,7 +432,9 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
typeOperatorCall: FirTypeOperatorCall,
data: ResolutionMode,
): CompositeTransformResult<FirStatement> {
val resolved = transformExpression(typeOperatorCall, ResolutionMode.ContextIndependent).single as FirTypeOperatorCall
val resolved = components.typeResolverTransformer.withAllowedBareTypes {
typeOperatorCall.transformConversionTypeRef(transformer, ResolutionMode.ContextIndependent)
}.transformOtherChildren(transformer, ResolutionMode.ContextIndependent)
resolved.argumentList.transformArguments(integerLiteralTypeApproximator, null)
val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument)
resolved.transformChildren(object : FirDefaultTransformer<Nothing?>() {
@@ -7,10 +7,15 @@ package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.Name
class FirNestedClassifierScope(val klass: FirClass<*>) : FirScope() {
@@ -31,6 +36,13 @@ class FirNestedClassifierScope(val klass: FirClass<*>) : FirScope() {
processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit
) {
val matchedClass = classIndex[name] ?: return
processor(matchedClass, ConeSubstitutor.Empty)
val substitution = klass.typeParameters.associate {
it.symbol to it.toConeType()
}
processor(matchedClass, ConeSubstitutorByMap(substitution))
}
fun getClassifierByName(name: Name): FirRegularClassSymbol? = classIndex[name]
}
fun FirTypeParameterRef.toConeType(): ConeKotlinType = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(symbol), isNullable = false)
-2
View File
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
fun <T> tableView(init: Table<T>.() -> Unit) {
Table<T>().init()
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_JDK6
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_JDK6
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// SKIP_JDK6
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -19,8 +19,8 @@ class A : Outer<Double, Short>() {
}
fun foo() {
Derived().foo() checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Outer<String, Int>.Inner<Char>>() }
Derived().foo() checkType { _<Outer<String, Int>.Inner<Char>>() }
Derived().baz() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Map<Char, String>>() }
A.B().bar() checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Outer<Float, Long>.Inner<String>>() }
A.B().bar() checkType { _<Outer<Float, Long>.Inner<String>>() }
A.B().x() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><Map<String, Float>>() }
}
@@ -50,6 +50,6 @@ fun test() {
var y = noParameters()
y = noParameters()
y().foo().a() checkType { <!INAPPLICABLE_CANDIDATE!>_<!><A<Any, Double, Short, Long>>() }
y().foo().a() checkType { _<A<Any, Double, Short, Long>>() }
y().bar() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!UNRESOLVED_REFERENCE!>_<!><A<Any, Double, Short, Char>>() }
}
@@ -52,7 +52,7 @@ class Outer<T> {
var y = noParameters()
y = noParameters()
y().foo().a() checkType { <!INAPPLICABLE_CANDIDATE!>_<!><A<T, F, Any, Double, Short, Long>>() }
y().foo().a() checkType { _<A<T, F, Any, Double, Short, Long>>() }
y().bar() <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><A<T, F, Any, Double, Short, Char>>() }
}
}
@@ -14,7 +14,7 @@ class Outer<E> {
fun set(inner: Inner<out E>) {}
fun inside() {
innerFactory().checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Inner<String>>() }
innerFactory().checkType { _<Inner<String>>() }
}
}
@@ -34,9 +34,9 @@ fun main() {
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><Outer<CharSequence>.Inner<CharSequence>>(outer.bar())
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><Outer<CharSequence>.Inner<CharSequence>>(outer.Inner())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.bar())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.Inner())
outer.set(outer.bar())
outer.set(outer.Inner())
val x: Outer<String>.Inner<String> = factoryString()
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(x)
outer.set(x)
}
@@ -9,7 +9,7 @@ class Outer<T> {
x.checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Inner>() }
x.checkType { _<Outer<String>.Inner>() }
z.checkType { _<Inner>() }
z.checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Outer<T>.Inner>() }
z.checkType { _<Outer<T>.Inner>() }
inner = x
}
@@ -28,9 +28,9 @@ fun main() {
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><Outer<CharSequence>.Inner>(outer.bar())
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><Outer<CharSequence>.Inner>(outer.Inner())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.bar())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.Inner())
outer.set(outer.bar())
outer.set(outer.Inner())
val x: Outer<String>.Inner = factoryString()
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(x)
outer.set(x)
}
@@ -28,13 +28,13 @@ fun main() {
checkSubtype<Outer<String>.Inner>(outer.bar())
checkSubtype<Outer<String>.Inner>(outer.Inner())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.bar())
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(outer.Inner())
outer.set(outer.bar())
outer.set(outer.Inner())
val x: Outer<String>.Inner = factoryString()
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(x)
val y: Outer<CharSequence>.Inner = infer<CharSequence>("")
outer.<!INAPPLICABLE_CANDIDATE!>set<!>(y)
outer.set(y)
outer.set(infer<Any>(""))
}
@@ -44,6 +44,6 @@ fun foo() {
strInt.instance().Inner<Double>().checkType { _<Outer<String>.Inner<Double>>() }
Outer<String>().<!INAPPLICABLE_CANDIDATE!>setInner<!>(strInt)
Outer<String>().setInner(strInt)
Outer<CharSequence>().<!INAPPLICABLE_CANDIDATE!>setInner<!>(strInt)
}