[FIR] Make type parameters inaccessible for non-inner nested types
#KT-57209
This commit is contained in:
committed by
Space Team
parent
c39ab956a0
commit
1f0d56e157
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
class Outer<O> {
|
class Outer<O> {
|
||||||
class A<X> {
|
inner class A<X> {
|
||||||
fun <Y> foo(x: X, y: Y): Map<X, Map<Y, O>>
|
fun <Y> foo(x: X, y: Y): Map<X, Map<Y, O>>
|
||||||
|
|
||||||
val map: Map<X, O>
|
val map: Map<X, O>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo(a: Outer.A<Int>) {
|
fun foo(a: Outer<String>.A<Int>) {
|
||||||
println(<expr>a</expr>)
|
println(<expr>a</expr>)
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
KtTypeScope:
|
KtTypeScope:
|
||||||
fun foo(x: kotlin.Int, y: Y): kotlin.collections.Map<kotlin.Int, kotlin.collections.Map<Y, O>>
|
fun foo(x: kotlin.Int, y: Y): kotlin.collections.Map<kotlin.Int, kotlin.collections.Map<Y, kotlin.String>>
|
||||||
val map: kotlin.collections.Map<kotlin.Int, O>
|
val map: kotlin.collections.Map<kotlin.Int, kotlin.String>
|
||||||
fun equals(other: kotlin.Any?): kotlin.Boolean
|
fun equals(other: kotlin.Any?): kotlin.Boolean
|
||||||
fun hashCode(): kotlin.Int
|
fun hashCode(): kotlin.Int
|
||||||
fun toString(): kotlin.String
|
fun toString(): kotlin.String
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
expression: a
|
expression: a
|
||||||
KtType: Outer.A<kotlin.Int>
|
KtType: Outer<kotlin.String>.A<kotlin.Int>
|
||||||
|
|
||||||
KtTypeScope:
|
KtTypeScope:
|
||||||
KtFunctionLikeSignature:
|
KtFunctionLikeSignature:
|
||||||
receiverType = null
|
receiverType = null
|
||||||
returnType = kotlin.collections.Map<kotlin.Int, kotlin.collections.Map<Y, O>>
|
returnType = kotlin.collections.Map<kotlin.Int, kotlin.collections.Map<Y, kotlin.String>>
|
||||||
symbol = /Outer.A.foo(<dispatch receiver>: Outer.A<X>, x: X, y: Y): kotlin.collections.Map<X, kotlin.collections.Map<Y, O>>
|
symbol = /Outer.A.foo(<dispatch receiver>: Outer.A<X, O>, x: X, y: Y): kotlin.collections.Map<X, kotlin.collections.Map<Y, O>>
|
||||||
valueParameters = [
|
valueParameters = [
|
||||||
KtVariableLikeSignature:
|
KtVariableLikeSignature:
|
||||||
name = x
|
name = x
|
||||||
@@ -24,7 +24,7 @@ KtFunctionLikeSignature:
|
|||||||
KtVariableLikeSignature:
|
KtVariableLikeSignature:
|
||||||
name = map
|
name = map
|
||||||
receiverType = null
|
receiverType = null
|
||||||
returnType = kotlin.collections.Map<kotlin.Int, O>
|
returnType = kotlin.collections.Map<kotlin.Int, kotlin.String>
|
||||||
symbol = val map: kotlin.collections.Map<X, O>
|
symbol = val map: kotlin.collections.Map<X, O>
|
||||||
callableIdIfNonLocal = /Outer.A.map
|
callableIdIfNonLocal = /Outer.A.map
|
||||||
KtFunctionLikeSignature:
|
KtFunctionLikeSignature:
|
||||||
|
|||||||
+6
@@ -12540,6 +12540,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("outerTypeParametersInNestedClasses.kt")
|
||||||
|
public void testOuterTypeParametersInNestedClasses() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/outerTypeParametersInNestedClasses.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Projections.kt")
|
@TestMetadata("Projections.kt")
|
||||||
public void testProjections() throws Exception {
|
public void testProjections() throws Exception {
|
||||||
|
|||||||
+6
@@ -12540,6 +12540,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("outerTypeParametersInNestedClasses.kt")
|
||||||
|
public void testOuterTypeParametersInNestedClasses() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/outerTypeParametersInNestedClasses.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Projections.kt")
|
@TestMetadata("Projections.kt")
|
||||||
public void testProjections() throws Exception {
|
public void testProjections() throws Exception {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ FILE: typeParameterVsNested.kt
|
|||||||
|
|
||||||
public final class Some : R|test/My.T| {
|
public final class Some : R|test/My.T| {
|
||||||
public constructor(): R|test/My.Some| {
|
public constructor(): R|test/My.Some| {
|
||||||
super<R|T|>()
|
super<R|test/My.T|>()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -12540,6 +12540,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("outerTypeParametersInNestedClasses.kt")
|
||||||
|
public void testOuterTypeParametersInNestedClasses() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/outerTypeParametersInNestedClasses.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Projections.kt")
|
@TestMetadata("Projections.kt")
|
||||||
public void testProjections() throws Exception {
|
public void testProjections() throws Exception {
|
||||||
|
|||||||
+6
@@ -12546,6 +12546,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("outerTypeParametersInNestedClasses.kt")
|
||||||
|
public void testOuterTypeParametersInNestedClasses() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/outerTypeParametersInNestedClasses.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Projections.kt")
|
@TestMetadata("Projections.kt")
|
||||||
public void testProjections() throws Exception {
|
public void testProjections() throws Exception {
|
||||||
|
|||||||
+2
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.fir.types.hasError
|
||||||
import org.jetbrains.kotlin.fir.types.isUnit
|
import org.jetbrains.kotlin.fir.types.isUnit
|
||||||
|
|
||||||
object FirPropertyAccessorsTypesChecker : FirPropertyChecker() {
|
object FirPropertyAccessorsTypesChecker : FirPropertyChecker() {
|
||||||
@@ -99,7 +100,7 @@ object FirPropertyAccessorsTypesChecker : FirPropertyChecker() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueSetterType != propertyType) {
|
if (valueSetterType != propertyType && !valueSetterType.hasError()) {
|
||||||
reporter.reportOn(valueSetterTypeSource, FirErrors.WRONG_SETTER_PARAMETER_TYPE, propertyType, valueSetterType, context)
|
reporter.reportOn(valueSetterTypeSource, FirErrors.WRONG_SETTER_PARAMETER_TYPE, propertyType, valueSetterType, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -6,16 +6,15 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkCondition
|
import org.jetbrains.kotlin.fir.analysis.checkers.checkCondition
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
@@ -58,7 +57,8 @@ object FirWhenConditionChecker : FirWhenExpressionChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FirTypeOperatorCall -> {
|
is FirTypeOperatorCall -> {
|
||||||
if (!checkedTypes.add(condition.conversionTypeRef.coneType to condition.operation)) {
|
val coneType = condition.conversionTypeRef.coneType
|
||||||
|
if (!checkedTypes.add(coneType to condition.operation)) {
|
||||||
reporter.reportOn(condition.conversionTypeRef.source, FirErrors.DUPLICATE_LABEL_IN_WHEN, context)
|
reporter.reportOn(condition.conversionTypeRef.source, FirErrors.DUPLICATE_LABEL_IN_WHEN, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,3 +131,8 @@ fun ConeKotlinType.renderReadableWithFqNames(): String {
|
|||||||
return builder.toString()
|
return builder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ConeKotlinType.hasError(): Boolean = when (this) {
|
||||||
|
is ConeErrorType -> true
|
||||||
|
is ConeFlexibleType -> lowerBound.hasError() || upperBound.hasError()
|
||||||
|
else -> typeArguments.any { it is ConeKotlinType && it.hasError() }
|
||||||
|
}
|
||||||
|
|||||||
+68
-33
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||||
|
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.*
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.correspondingProperty
|
|||||||
import org.jetbrains.kotlin.fir.copyWithNewSourceKind
|
import org.jetbrains.kotlin.fir.copyWithNewSourceKind
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isFromVararg
|
import org.jetbrains.kotlin.fir.declarations.utils.isFromVararg
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguouslyResolvedAnnotationFromPlugin
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguouslyResolvedAnnotationFromPlugin
|
||||||
@@ -62,8 +64,16 @@ open class FirTypeResolveTransformer(
|
|||||||
initialCurrentFile: FirFile? = null,
|
initialCurrentFile: FirFile? = null,
|
||||||
private val classDeclarationsStack: ArrayDeque<FirClass> = ArrayDeque()
|
private val classDeclarationsStack: ArrayDeque<FirClass> = ArrayDeque()
|
||||||
) : FirAbstractTreeTransformer<Any?>(FirResolvePhase.TYPES) {
|
) : FirAbstractTreeTransformer<Any?>(FirResolvePhase.TYPES) {
|
||||||
private val scopes = mutableListOf<FirScope>()
|
/**
|
||||||
private val towerScope = scopes.asReversed()
|
* All current scopes sorted from outermost to innermost.
|
||||||
|
*/
|
||||||
|
private var scopes = initialScopes.asReversed().toPersistentList()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scopes that are accessible statically, i.e. [scopes] minus type parameter scopes.
|
||||||
|
*/
|
||||||
|
private var staticScopes = scopes
|
||||||
|
|
||||||
private var currentDeclaration: FirDeclaration? = null
|
private var currentDeclaration: FirDeclaration? = null
|
||||||
|
|
||||||
private inline fun <T> withDeclaration(declaration: FirDeclaration, crossinline action: () -> T): T {
|
private inline fun <T> withDeclaration(declaration: FirDeclaration, crossinline action: () -> T): T {
|
||||||
@@ -76,10 +86,6 @@ open class FirTypeResolveTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
scopes.addAll(initialScopes.asReversed())
|
|
||||||
}
|
|
||||||
|
|
||||||
private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(session)
|
private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(session)
|
||||||
private var currentFile: FirFile? = initialCurrentFile
|
private var currentFile: FirFile? = initialCurrentFile
|
||||||
|
|
||||||
@@ -87,7 +93,7 @@ open class FirTypeResolveTransformer(
|
|||||||
checkSessionConsistency(file)
|
checkSessionConsistency(file)
|
||||||
currentFile = file
|
currentFile = file
|
||||||
return withScopeCleanup {
|
return withScopeCleanup {
|
||||||
scopes.addAll(createImportingScopes(file, session, scopeSession))
|
addScopes(createImportingScopes(file, session, scopeSession))
|
||||||
super.transformFile(file, data)
|
super.transformFile(file, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,9 +258,18 @@ open class FirTypeResolveTransformer(
|
|||||||
|
|
||||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {
|
override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {
|
||||||
return typeResolverTransformer.withFile(currentFile) {
|
return typeResolverTransformer.withFile(currentFile) {
|
||||||
|
val scopes = scopes
|
||||||
|
// optimized implementation of reversed Iterable on top of PersistentList
|
||||||
|
val reversedScopes = object : Iterable<FirScope> {
|
||||||
|
override fun iterator() = object : Iterator<FirScope> {
|
||||||
|
private val iter = scopes.listIterator(scopes.size)
|
||||||
|
override fun hasNext() = iter.hasPrevious()
|
||||||
|
override fun next() = iter.previous()
|
||||||
|
}
|
||||||
|
}
|
||||||
typeRef.transform(
|
typeRef.transform(
|
||||||
typeResolverTransformer,
|
typeResolverTransformer,
|
||||||
ScopeClassDeclaration(towerScope, classDeclarationsStack, containerDeclaration = currentDeclaration)
|
ScopeClassDeclaration(reversedScopes, classDeclarationsStack, containerDeclaration = currentDeclaration)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,13 +337,14 @@ open class FirTypeResolveTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T> withScopeCleanup(crossinline l: () -> T): T {
|
private inline fun <T> withScopeCleanup(crossinline l: () -> T): T {
|
||||||
val sizeBefore = scopes.size
|
val scopesBefore = scopes
|
||||||
|
val staticScopesBefore = staticScopes
|
||||||
|
|
||||||
val result = l()
|
val result = l()
|
||||||
val size = scopes.size
|
|
||||||
assert(size >= sizeBefore)
|
scopes = scopesBefore
|
||||||
repeat(size - sizeBefore) {
|
staticScopes = staticScopesBefore
|
||||||
scopes.removeAt(scopes.lastIndex)
|
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,21 +353,25 @@ open class FirTypeResolveTransformer(
|
|||||||
data: Any?
|
data: Any?
|
||||||
): FirStatement {
|
): FirStatement {
|
||||||
|
|
||||||
withScopeCleanup {
|
|
||||||
firClass.transformAnnotations(this, null)
|
|
||||||
|
|
||||||
if (firClass is FirRegularClass) {
|
|
||||||
firClass.addTypeParametersScope()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConstructedTypeRef should be resolved only with type parameters, but not with nested classes and classes from supertypes
|
|
||||||
for (constructor in firClass.declarations.filterIsInstance<FirConstructor>()) {
|
|
||||||
constructor.delegatedConstructor?.let(this::resolveConstructedTypeRefForDelegatedConstructorCall)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return withScopeCleanup {
|
return withScopeCleanup {
|
||||||
|
// Remove type parameter scopes for classes that are neither inner nor local
|
||||||
|
if (!firClass.isInner && !firClass.isLocal) {
|
||||||
|
this.scopes = staticScopes
|
||||||
|
}
|
||||||
|
|
||||||
|
withScopeCleanup {
|
||||||
|
firClass.transformAnnotations(this, null)
|
||||||
|
|
||||||
|
if (firClass is FirRegularClass) {
|
||||||
|
firClass.addTypeParametersScope()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructedTypeRef should be resolved only with type parameters, but not with nested classes and classes from supertypes
|
||||||
|
for (constructor in firClass.declarations.filterIsInstance<FirConstructor>()) {
|
||||||
|
constructor.delegatedConstructor?.let(this::resolveConstructedTypeRefForDelegatedConstructorCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ? Is it Ok to use original file session here ?
|
// ? Is it Ok to use original file session here ?
|
||||||
val superTypes = lookupSuperTypes(
|
val superTypes = lookupSuperTypes(
|
||||||
firClass,
|
firClass,
|
||||||
@@ -360,19 +380,26 @@ open class FirTypeResolveTransformer(
|
|||||||
substituteTypes = true,
|
substituteTypes = true,
|
||||||
useSiteSession = session
|
useSiteSession = session
|
||||||
).asReversed()
|
).asReversed()
|
||||||
|
|
||||||
|
val scopesToAdd = mutableListOf<FirScope>()
|
||||||
|
|
||||||
for (superType in superTypes) {
|
for (superType in superTypes) {
|
||||||
superType.lookupTag.getNestedClassifierScope(session, scopeSession)?.let { nestedClassifierScope ->
|
superType.lookupTag.getNestedClassifierScope(session, scopeSession)?.let { nestedClassifierScope ->
|
||||||
val scope = nestedClassifierScope.wrapNestedClassifierScopeWithSubstitutionForSuperType(superType, session)
|
val scope = nestedClassifierScope.wrapNestedClassifierScopeWithSubstitutionForSuperType(superType, session)
|
||||||
scopes.add(scope)
|
scopesToAdd.add(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session.nestedClassifierScope(firClass)?.let(scopes::add)
|
session.nestedClassifierScope(firClass)?.let(scopesToAdd::add)
|
||||||
if (firClass is FirRegularClass) {
|
if (firClass is FirRegularClass) {
|
||||||
val companionObject = firClass.companionObjectSymbol?.fir
|
val companionObject = firClass.companionObjectSymbol?.fir
|
||||||
if (companionObject != null) {
|
if (companionObject != null) {
|
||||||
session.nestedClassifierScope(companionObject)?.let(scopes::add)
|
session.nestedClassifierScope(companionObject)?.let(scopesToAdd::add)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addScopes(scopesToAdd)
|
||||||
firClass.addTypeParametersScope()
|
firClass.addTypeParametersScope()
|
||||||
|
} else {
|
||||||
|
addScopes(scopesToAdd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that annotations are still visited here
|
// Note that annotations are still visited here
|
||||||
@@ -393,10 +420,18 @@ open class FirTypeResolveTransformer(
|
|||||||
|
|
||||||
private fun FirMemberDeclaration.addTypeParametersScope() {
|
private fun FirMemberDeclaration.addTypeParametersScope() {
|
||||||
if (typeParameters.isNotEmpty()) {
|
if (typeParameters.isNotEmpty()) {
|
||||||
scopes.add(FirMemberTypeParameterScope(this))
|
scopes = scopes.add(FirMemberTypeParameterScope(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addScopes(list: List<FirScope>) {
|
||||||
|
// small optimization to skip unnecessary allocations
|
||||||
|
val scopesAreTheSame = scopes === staticScopes
|
||||||
|
|
||||||
|
scopes = scopes.addAll(list)
|
||||||
|
staticScopes = if (scopesAreTheSame) scopes else staticScopes.addAll(list)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In a scenario like
|
* In a scenario like
|
||||||
*
|
*
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
|||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
|
|
||||||
data class ScopeClassDeclaration(
|
data class ScopeClassDeclaration(
|
||||||
val scopes: List<FirScope>,
|
val scopes: Iterable<FirScope>,
|
||||||
val containingDeclarations: List<FirDeclaration>,
|
val containingDeclarations: List<FirDeclaration>,
|
||||||
val topContainer: FirDeclaration? = null,
|
val topContainer: FirDeclaration? = null,
|
||||||
val containerDeclaration: FirDeclaration? = null,
|
val containerDeclaration: FirDeclaration? = null,
|
||||||
|
|||||||
-104
@@ -1,104 +0,0 @@
|
|||||||
// !LANGUAGE: +FunctionalInterfaceConversion
|
|
||||||
|
|
||||||
fun interface Good {
|
|
||||||
fun invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface Foo1
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface Foo2 {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface Foo3 {
|
|
||||||
fun foo()
|
|
||||||
fun bar()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BaseWithSAM {
|
|
||||||
fun base()
|
|
||||||
}
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface Foo4 : BaseWithSAM {
|
|
||||||
fun oneMore()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Foo4WithDefault : BaseWithSAM {
|
|
||||||
fun oneMore() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BaseWithDefault {
|
|
||||||
fun def() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Foo4WithBaseDefault : BaseWithDefault {
|
|
||||||
fun oneMore()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface GoodWithBase : BaseWithSAM
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface Foo5 {
|
|
||||||
<!FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES!>val<!> prop: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Foo6 {
|
|
||||||
fun foo()
|
|
||||||
<!FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES!>val<!> prop: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Foo7 : BaseWithSAM {
|
|
||||||
<!FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES!>val<!> prop: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface GoodWithPropAndBase : BaseWithSAM {
|
|
||||||
val prop: Int get() = 42
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Foo8 {
|
|
||||||
fun <!FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS!><T><!> invoke(x: T)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface GoodGeneric<T> {
|
|
||||||
fun invoke(x: T)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BaseWithGeneric {
|
|
||||||
fun <T> invoke(x: T)
|
|
||||||
}
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS!>fun<!> interface Foo9 : BaseWithGeneric
|
|
||||||
|
|
||||||
fun interface GoodExtensionGeneric : GoodGeneric<String>
|
|
||||||
|
|
||||||
fun interface GoodSuspend {
|
|
||||||
suspend fun invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
class WithNestedFun<K> {
|
|
||||||
<!FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS!>fun<!> interface NestedSimple
|
|
||||||
|
|
||||||
fun interface GoodFun {
|
|
||||||
fun invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface NestedFun {
|
|
||||||
fun inovke(element: K)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> local() {
|
|
||||||
<!LOCAL_INTERFACE_NOT_ALLOWED!>fun interface LocalFun<!> {
|
|
||||||
fun invoke(element: T)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface WithDefaultValue {
|
|
||||||
fun invoke(<!FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE!>s: String = ""<!>)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface BaseWithDefaultValue {
|
|
||||||
fun invoke(s: String = "")
|
|
||||||
}
|
|
||||||
|
|
||||||
<!FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE!>fun<!> interface DeriveDefault : BaseWithDefaultValue
|
|
||||||
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !LANGUAGE: +FunctionalInterfaceConversion
|
// !LANGUAGE: +FunctionalInterfaceConversion
|
||||||
|
|
||||||
fun interface Good {
|
fun interface Good {
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class Foo<T> {
|
||||||
|
companion object {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
object O {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Nested {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Inner<R> {
|
||||||
|
fun foo(arg1: T, arg2: R) {}
|
||||||
|
|
||||||
|
<!NESTED_CLASS_NOT_ALLOWED!>class InnerNested<!> {
|
||||||
|
fun foo(arg1: <!UNRESOLVED_REFERENCE!>T<!>, arg2: <!UNRESOLVED_REFERENCE!>R<!>) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E {
|
||||||
|
;
|
||||||
|
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
val obj = object {
|
||||||
|
fun foo(arg: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> bar() {
|
||||||
|
class Local {
|
||||||
|
fun baz(arg1: T, arg2: R) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
class Foo<T> {
|
||||||
|
companion object {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
object O {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Nested {
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Inner<R> {
|
||||||
|
fun foo(arg1: T, arg2: R) {}
|
||||||
|
|
||||||
|
<!NESTED_CLASS_NOT_ALLOWED!>class InnerNested<!> {
|
||||||
|
fun foo(arg1: <!INACCESSIBLE_OUTER_CLASS_EXPRESSION!>T<!>, arg2: <!UNRESOLVED_REFERENCE!>R<!>) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class E {
|
||||||
|
;
|
||||||
|
|
||||||
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>T<!>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
val obj = object {
|
||||||
|
fun foo(arg: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> bar() {
|
||||||
|
class Local {
|
||||||
|
fun baz(arg1: T, arg2: R) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
class Outer<T> {
|
class Outer<T> {
|
||||||
class Nested {
|
class Nested {
|
||||||
fun foo(t: T) = t
|
fun foo(t: <!UNRESOLVED_REFERENCE!>T<!>) = t
|
||||||
}
|
}
|
||||||
|
|
||||||
class Nested2<T> {
|
class Nested2<T> {
|
||||||
|
|||||||
Generated
+6
@@ -12546,6 +12546,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/localClassTypeRefWithTypeParameterFromFunction.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("outerTypeParametersInNestedClasses.kt")
|
||||||
|
public void testOuterTypeParametersInNestedClasses() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/outerTypeParametersInNestedClasses.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Projections.kt")
|
@TestMetadata("Projections.kt")
|
||||||
public void testProjections() throws Exception {
|
public void testProjections() throws Exception {
|
||||||
|
|||||||
+12
-12
@@ -4,24 +4,24 @@
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
class Case1<T>() {
|
class Case1<T>() {
|
||||||
class A(t: T)
|
class A(t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class B(x: List<T>)
|
class B(x: List<<!UNRESOLVED_REFERENCE!>T<!>>)
|
||||||
class C(c: () -> T)
|
class C(c: () -> <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class E(n: Nothing, t: T)
|
class E(n: Nothing, t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 2
|
// TESTCASE NUMBER: 2
|
||||||
class Case2<T>() {
|
class Case2<T>() {
|
||||||
data class A(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: T<!>)
|
data class A(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
data class B(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>x: List<T><!>)
|
data class B(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>x: List<<!UNRESOLVED_REFERENCE!>T<!>><!>)
|
||||||
data class C(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>c: () -> T<!>)
|
data class C(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>c: () -> <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
data class E(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>n: Nothing<!>, <!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: T<!>)
|
data class E(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>n: Nothing<!>, <!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
class Case3<T>() {
|
class Case3<T>() {
|
||||||
enum class A(t: T)
|
enum class A(t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
enum class B(x: List<T>)
|
enum class B(x: List<<!UNRESOLVED_REFERENCE!>T<!>>)
|
||||||
enum class C(c: () -> T)
|
enum class C(c: () -> <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
enum class E(n: Nothing, t: T)
|
enum class E(n: Nothing, t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -13,8 +13,8 @@ data class F<T>(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: T<!>)
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 2
|
// TESTCASE NUMBER: 2
|
||||||
class Case2<T>() {
|
class Case2<T>() {
|
||||||
data class A(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: T<!>)
|
data class A(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
data class B(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>x: List<T><!>)
|
data class B(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>x: List<<!UNRESOLVED_REFERENCE!>T<!>><!>)
|
||||||
data class C(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>c: () -> T<!>)
|
data class C(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>c: () -> <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
data class E(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>n: Nothing<!>, <!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: T<!>)
|
data class E(<!DATA_CLASS_NOT_PROPERTY_PARAMETER!>n: Nothing<!>, <!DATA_CLASS_NOT_PROPERTY_PARAMETER!>t: <!UNRESOLVED_REFERENCE!>T<!><!>)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
class Case1<T>() {
|
class Case1<T>() {
|
||||||
class A(val t: T)
|
class A(val t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class B(val x: List<T>)
|
class B(val x: List<<!UNRESOLVED_REFERENCE!>T<!>>)
|
||||||
class C(val c: () -> T)
|
class C(val c: () -> <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class E(val n: Nothing, val t: T)
|
class E(val n: Nothing, val t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
class Case1<T>() {
|
class Case1<T>() {
|
||||||
class A(var t: T)
|
class A(var t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class B(var x: List<T>)
|
class B(var x: List<<!UNRESOLVED_REFERENCE!>T<!>>)
|
||||||
class C(var c: () -> T)
|
class C(var c: () -> <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
class E(var n: Nothing, var t: T)
|
class E(var n: Nothing, var t: <!UNRESOLVED_REFERENCE!>T<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@
|
|||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
class Case1<AT>(val x: AT) {
|
class Case1<AT>(val x: AT) {
|
||||||
|
|
||||||
class B(val y: AT) {
|
class B(val y: <!UNRESOLVED_REFERENCE!>AT<!>) {
|
||||||
fun case1() {
|
fun case1() {
|
||||||
val k: <!UNRESOLVED_REFERENCE!>AT<!>
|
val k: <!UNRESOLVED_REFERENCE!>AT<!>
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,6 @@ class Case1<AT>(val x: AT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class D() {
|
class D() {
|
||||||
fun case1(x: Any) : AT = TODO()
|
fun case1(x: Any) : <!UNRESOLVED_REFERENCE!>AT<!> = TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user