diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 1990beb0a0b..e00a9cd1cbf 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -452,6 +452,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("expectedCount") parameter>("classifier") } + val OUTER_CLASS_ARGUMENTS_REQUIRED by error() { + parameter("outer") + } val TYPE_PARAMETERS_IN_OBJECT by error() val ILLEGAL_PROJECTION_USAGE by error() val TYPE_PARAMETERS_IN_ENUM by error() diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index a8f46f3bd25..1960dd208fa 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -297,6 +297,7 @@ object FirErrors { val TYPE_ARGUMENTS_NOT_ALLOWED by error0() val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2>() val NO_TYPE_ARGUMENTS_ON_RHS by error2>() + val OUTER_CLASS_ARGUMENTS_REQUIRED by error1() val TYPE_PARAMETERS_IN_OBJECT by error0() val ILLEGAL_PROJECTION_USAGE by error0() val TYPE_PARAMETERS_IN_ENUM by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 220156bb29a..8adc13bcbe4 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNC import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_COLLECTION_OF_TYPES import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL @@ -255,6 +256,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_OF_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ONLY_ONE_CLASS_BOUND_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPERATOR_RENAMED_ON_IMPORT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OTHER_ERROR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_MEMBER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_CANNOT_BE_IMPORTED @@ -717,6 +719,11 @@ class FirDefaultErrorMessages { null, SYMBOL ) + map.put( + OUTER_CLASS_ARGUMENTS_REQUIRED, + "Type arguments should be specified for an outer {0}. Use full class name to specify them", + RENDER_CLASS_OR_OBJECT_NAME + ) map.put(TYPE_PARAMETERS_IN_OBJECT, "Type parameters are not allowed for objects") // map.put(ILLEGAL_PROJECTION_USAGE, ...) // & map.put(TYPE_PARAMETERS_IN_ENUM, "Enum class cannot have type parameters") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt index d9739c88ccc..e097f284588 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticRenderers.kt @@ -12,8 +12,9 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderer import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.impl.* @@ -79,6 +80,25 @@ object FirDiagnosticRenderers { "$classOrObject $name" } + val RENDER_CLASS_OR_OBJECT_NAME = Renderer { firClassLike: FirClassLikeDeclaration -> + val name = firClassLike.classId.relativeClassName.shortName().asString() + val prefix = when (firClassLike) { + is FirTypeAlias -> "typealias" + is FirRegularClass -> { + when { + firClassLike.isCompanion -> "companion object" + firClassLike.isInterface -> "interface" + firClassLike.isEnumClass -> "enum class" + firClassLike.isFromEnumClass -> "enum entry" + firClassLike.isLocalClassOrAnonymousObject() -> "object" + else -> "class" + } + } + else -> AssertionError("Unexpected class: $firClassLike") + } + "$prefix '$name'" + } + val RENDER_TYPE = Renderer { t: ConeKotlinType -> // TODO: need a way to tune granuality, e.g., without parameter names in functional types. t.render() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 0c0dc655884..6babbf24959 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -69,6 +69,8 @@ private fun ConeDiagnostic.toFirDiagnostic( is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.createOn(source, this.name.asString()) is ConeWrongNumberOfTypeArgumentsError -> FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(qualifiedAccessSource ?: source, this.desiredCount, this.type) + is ConeOuterClassArgumentsRequired -> + FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED.createOn(qualifiedAccessSource ?: source, this.type) is ConeNoTypeArgumentsOnRhsError -> FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.createOn(qualifiedAccessSource ?: source, this.desiredCount, this.type) is ConeSimpleDiagnostic -> when (source.kind) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt index 60f5054d3d2..39f0ae62261 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirTypeResolver.kt @@ -6,10 +6,11 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSessionComponent +import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef abstract class FirTypeResolver : FirSessionComponent { - abstract fun resolveType(typeRef: FirTypeRef, scope: FirScope, areBareTypesAllowed: Boolean): ConeKotlinType + abstract fun resolveType(typeRef: FirTypeRef, scopeClassDeclaration: ScopeClassDeclaration, areBareTypesAllowed: Boolean): ConeKotlinType } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index aaf05bed102..d2c85a31291 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic @@ -447,3 +448,44 @@ fun FirFunction.getAsForbiddenNamedArgumentsTarget(session: FirSession): Forbidd // org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto // org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto fun FirFunction.getHasStableParameterNames(session: FirSession): Boolean = getAsForbiddenNamedArgumentsTarget(session) == null + +fun isValidTypeParameter(typeParameter: FirTypeParameterRef, classDeclaration: FirRegularClass?, session: FirSession): Boolean { + if (typeParameter !is FirOuterClassTypeParameterRef || classDeclaration == null) { + return true + } + + fun containsTypeParameter(currentClassDeclaration: FirRegularClass): Boolean { + val result = currentClassDeclaration.typeParameters.any { it.symbol == typeParameter.symbol } + if (result) { + return true + } + + for (superTypeRef in currentClassDeclaration.superTypeRefs) { + val superClassFir = superTypeRef.firClassLike(session) + if (superClassFir == null || superClassFir is FirRegularClass && containsTypeParameter(superClassFir)) { + return true + } + } + + return false + } + + return containsTypeParameter(classDeclaration) +} + +fun getClassThatContainsTypeParameter(klass: FirRegularClass, typeParameter: FirTypeParameterRef): FirRegularClass? { + if (klass.typeParameters.any { param -> param.symbol == typeParameter.symbol }) { + return klass + } + + for (declaration in klass.declarations) { + if (declaration is FirRegularClass) { + val result = getClassThatContainsTypeParameter(declaration, typeParameter) + if (result != null) { + return result + } + } + } + + return null +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt index 417b77d07df..82468946a00 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/diagnostics/FirDiagnostics.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.diagnostics import kotlinx.collections.immutable.ImmutableList import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.calls.Candidate @@ -113,6 +114,12 @@ class ConeNoTypeArgumentsOnRhsError( override val reason: String get() = "No type arguments on RHS" } +class ConeOuterClassArgumentsRequired( + val type: FirRegularClass, +) : ConeDiagnostic() { + override val reason: String = "Type arguments should be specified for an outer class" +} + class ConeInstanceAccessBeforeSuperCall(val target: String) : ConeDiagnostic() { override val reason: String get() = "Cannot access ''${target}'' before superclass constructor has been called" } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt index 83dfdad47bf..79e52810f6a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt @@ -8,15 +8,17 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.ThreadSafeMutableState +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef import org.jetbrains.kotlin.fir.diagnostics.ConeUnexpectedTypeArgumentsError import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOuterClassArgumentsRequired import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedQualifierError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedDynamicType import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeWrongNumberOfTypeArgumentsError -import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor -import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* @@ -46,7 +48,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { private fun resolveToSymbol( typeRef: FirTypeRef, - scope: FirScope + scopeClassDeclaration: ScopeClassDeclaration ): Pair?, ConeSubstitutor?> { return when (typeRef) { is FirResolvedTypeRef -> { @@ -58,7 +60,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { val qualifierResolver = session.qualifierResolver var resolvedSymbol: FirClassifierSymbol<*>? = null var substitutor: ConeSubstitutor? = null - scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope -> + scopeClassDeclaration.scope.processClassifiersByNameWithSubstitution(typeRef.qualifier.first().name) { symbol, substitutorFromScope -> if (resolvedSymbol != null) return@processClassifiersByNameWithSubstitution resolvedSymbol = when (symbol) { is FirClassLikeSymbol<*> -> { @@ -94,7 +96,8 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { typeRef: FirUserTypeRef, symbol: FirClassifierSymbol<*>?, substitutor: ConeSubstitutor?, - areBareTypesAllowed: Boolean + areBareTypesAllowed: Boolean, + scopeClassDeclaration: ScopeClassDeclaration ): ConeKotlinType { if (symbol == null) { return ConeKotlinErrorType(ConeUnresolvedQualifierError(typeRef.render())) @@ -117,24 +120,43 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { return ConeClassErrorType(ConeWrongNumberOfTypeArgumentsError(symbol.fir.typeParameters.size, symbol)) } else { val substitutor = substitutor ?: ConeSubstitutor.Empty + var problemTypeParameter: FirTypeParameterRef? = null + val classDeclarations = scopeClassDeclaration.classDeclarations val argumentsFromOuterClassesAndParents = symbol.fir.typeParameters.drop(typeArguments.size).mapNotNull { - val type = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) - // we should report ConeSimpleDiagnostic(..., WrongNumberOfTypeArguments) - // but genericArgumentNumberMismatch.kt test fails with - // index out of bounds exception for start offset of - // the source - substitutor.substituteOrNull(type) - + if (isValidTypeParameter(it, classDeclarations.lastOrNull(), session)) { + val type = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) + // we should report ConeSimpleDiagnostic(..., WrongNumberOfTypeArguments) + // but genericArgumentNumberMismatch.kt test fails with + // index out of bounds exception for start offset of + // the source + substitutor.substituteOrNull(type) + } else { + if (problemTypeParameter == null) { + problemTypeParameter = it + } + null + } }.toTypedArray() typeArguments += argumentsFromOuterClassesAndParents if (typeArguments.size != symbol.fir.typeParameters.size) { - return ConeClassErrorType( - ConeWrongNumberOfTypeArgumentsError( - desiredCount = symbol.fir.typeParameters.size - argumentsFromOuterClassesAndParents.size, - type = symbol + if (problemTypeParameter != null) { + var outerClass: FirRegularClass? = null + classDeclarations.forEach { + getClassThatContainsTypeParameter(it, problemTypeParameter!!)?.let { result -> + outerClass = result + return@forEach + } + } + return ConeClassErrorType(ConeOuterClassArgumentsRequired(outerClass!!)) + } else { + return ConeClassErrorType( + ConeWrongNumberOfTypeArgumentsError( + desiredCount = symbol.fir.typeParameters.size - argumentsFromOuterClassesAndParents.size, + type = symbol + ) ) - ) + } } } } @@ -174,14 +196,14 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { override fun resolveType( typeRef: FirTypeRef, - scope: FirScope, + scopeClassDeclaration: ScopeClassDeclaration, areBareTypesAllowed: Boolean ): ConeKotlinType { return when (typeRef) { is FirResolvedTypeRef -> typeRef.type is FirUserTypeRef -> { - val (symbol, substitutor) = resolveToSymbol(typeRef, scope) - resolveUserType(typeRef, symbol, substitutor, areBareTypesAllowed) + val (symbol, substitutor) = resolveToSymbol(typeRef, scopeClassDeclaration) + resolveUserType(typeRef, symbol, substitutor, areBareTypesAllowed, scopeClassDeclaration) } is FirFunctionTypeRef -> createFunctionalType(typeRef) is FirDynamicTypeRef -> ConeKotlinErrorType(ConeUnsupportedDynamicType()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt index 7bd6bf53084..67cf4bbcc54 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirAbstractTreeTransformerWithSuperTypes.kt @@ -30,6 +30,7 @@ abstract class FirAbstractTreeTransformerWithSuperTypes( protected val scopeSession: ScopeSession ) : FirAbstractTreeTransformer(phase) { protected val scopes = mutableListOf() + protected val classDeclarations = mutableListOf() protected val towerScope = FirCompositeScope(scopes.asReversed()) protected open fun needReplacePhase(firDeclaration: FirDeclaration): Boolean = transformerPhase > firDeclaration.resolvePhase @@ -45,6 +46,13 @@ abstract class FirAbstractTreeTransformerWithSuperTypes( return result } + protected inline fun withClassDeclarationCleanup(declaration: FirRegularClass, crossinline l: () -> T): T { + classDeclarations.add(declaration) + val result = l() + classDeclarations.removeAt(classDeclarations.lastIndex) + return result + } + protected fun resolveNestedClassesSupertypes( firClass: FirClass, data: Any? diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt index 987019d86f1..ec2622ca5ef 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt @@ -20,7 +20,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs class FirSpecificTypeResolverTransformer( override val session: FirSession, private val errorTypeAsResolved: Boolean = true -) : FirAbstractTreeTransformer(phase = FirResolvePhase.SUPER_TYPES) { +) : FirAbstractTreeTransformer(phase = FirResolvePhase.SUPER_TYPES) { private val typeResolver = session.typeResolver @set:PrivateForInline @@ -53,8 +53,8 @@ class FirSpecificTypeResolverTransformer( } @OptIn(PrivateForInline::class) - override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): FirResolvedTypeRef { - session.lookupTracker?.recordTypeLookup(typeRef, data.scopeOwnerLookupNames, currentFile?.source) + override fun transformTypeRef(typeRef: FirTypeRef, data: ScopeClassDeclaration): FirResolvedTypeRef { + session.lookupTracker?.recordTypeLookup(typeRef, data.scope.scopeOwnerLookupNames, currentFile?.source) typeRef.transformChildren(this, data) return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed)) } @@ -62,10 +62,10 @@ class FirSpecificTypeResolverTransformer( @OptIn(PrivateForInline::class) override fun transformFunctionTypeRef( functionTypeRef: FirFunctionTypeRef, - data: FirScope + data: ScopeClassDeclaration ): FirResolvedTypeRef { functionTypeRef.transformChildren(this, data) - session.lookupTracker?.recordTypeLookup(functionTypeRef, data.scopeOwnerLookupNames, currentFile?.source) + session.lookupTracker?.recordTypeLookup(functionTypeRef, data.scope.scopeOwnerLookupNames, currentFile?.source) val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable() return if (resolvedType != null && resolvedType !is ConeClassErrorType) { buildResolvedTypeRef { @@ -118,11 +118,11 @@ class FirSpecificTypeResolverTransformer( !errorTypeAsResolved && it is ConeClassErrorType } - override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: FirScope): FirTypeRef { + override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: ScopeClassDeclaration): FirTypeRef { return resolvedTypeRef } - override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: FirScope): FirTypeRef { + override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: ScopeClassDeclaration): FirTypeRef { return implicitTypeRef } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index c56fb1072ac..f23052d2694 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -215,6 +215,7 @@ open class FirSupertypeResolverVisitor( private val firProviderInterceptor: FirProviderInterceptor? = null, ) : FirDefaultVisitor() { private val supertypeGenerationExtensions = session.extensionService.supertypeGenerators + private val classDeclarations = mutableListOf() private fun getFirClassifierContainerFileIfAny(symbol: FirClassLikeSymbol<*>): FirFile? = if (firProviderInterceptor != null) firProviderInterceptor.getFirClassifierContainerFileIfAny(symbol) @@ -291,7 +292,7 @@ open class FirSupertypeResolverVisitor( private fun resolveSpecificClassLikeSupertypes( classLikeDeclaration: FirClassLikeDeclaration, - resolveSuperTypeRefs: (FirTransformer, FirScope) -> List + resolveSuperTypeRefs: (FirTransformer, ScopeClassDeclaration) -> List ): List { when (val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration)) { is SupertypeComputationStatus.Computed -> return status.supertypeRefs @@ -308,7 +309,7 @@ open class FirSupertypeResolverVisitor( val scopes = prepareScopes(classLikeDeclaration) val transformer = FirSpecificTypeResolverTransformer(session) - val resolvedTypesRefs = resolveSuperTypeRefs(transformer, FirCompositeScope(scopes)) + val resolvedTypesRefs = resolveSuperTypeRefs(transformer, ScopeClassDeclaration(FirCompositeScope(scopes), classDeclarations)) supertypeComputationSession.storeSupertypes(classLikeDeclaration, resolvedTypesRefs) return resolvedTypesRefs @@ -319,8 +320,10 @@ open class FirSupertypeResolverVisitor( } override fun visitRegularClass(regularClass: FirRegularClass, data: Any?) { + classDeclarations.add(regularClass) resolveSpecificClassLikeSupertypes(regularClass, regularClass.superTypeRefs) visitDeclarationContent(regularClass, null) + classDeclarations.removeAt(classDeclarations.lastIndex) } override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?) { @@ -332,12 +335,12 @@ open class FirSupertypeResolverVisitor( classLikeDeclaration: FirClassLikeDeclaration, supertypeRefs: List ): List { - return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer, scope -> + return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer, scopeDeclaration -> if (!classLikeDeclaration.isLocalClassOrAnonymousObject()) { session.lookupTracker?.let { val fileSource = getFirClassifierContainerFileIfAny(classLikeDeclaration.symbol)?.source for (supertypeRef in supertypeRefs) { - it.recordTypeLookup(supertypeRef, scope.scopeOwnerLookupNames, fileSource) + it.recordTypeLookup(supertypeRef, scopeDeclaration.scope.scopeOwnerLookupNames, fileSource) } } } @@ -348,7 +351,7 @@ open class FirSupertypeResolverVisitor( So we create a copy of supertypeRefs to avoid it */ supertypeRefs.createCopy().mapTo(mutableListOf()) { - val superTypeRef = transformer.transformTypeRef(it, scope) + val superTypeRef = transformer.transformTypeRef(it, scopeDeclaration) val typeParameterType = superTypeRef.coneTypeSafe() when { typeParameterType != null -> diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index afed9b09139..d95b1713640 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -64,15 +64,17 @@ open class FirTypeResolveTransformer( } override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): FirStatement { - withScopeCleanup { - regularClass.addTypeParametersScope() - regularClass.typeParameters.forEach { - it.accept(this, data) + return withClassDeclarationCleanup(regularClass) { + withScopeCleanup { + regularClass.addTypeParametersScope() + regularClass.typeParameters.forEach { + it.accept(this, data) + } + unboundCyclesInTypeParametersSupertypes(regularClass) } - unboundCyclesInTypeParametersSupertypes(regularClass) - } - return resolveNestedClassesSupertypes(regularClass, data) + resolveNestedClassesSupertypes(regularClass, data) + } } override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): FirStatement { @@ -185,7 +187,12 @@ open class FirTypeResolveTransformer( } override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef { - return typeResolverTransformer.withFile(currentFile) { typeRef.transform(typeResolverTransformer, towerScope) } + return typeResolverTransformer.withFile(currentFile) { + typeRef.transform( + typeResolverTransformer, + ScopeClassDeclaration(towerScope, classDeclarations) + ) + } } override fun transformValueParameter(valueParameter: FirValueParameter, data: Any?): FirStatement { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt new file mode 100644 index 00000000000..58d90ea50f6 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ScopeClassDeclaration.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2010-2021 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.resolve.transformers + +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.scopes.FirScope + +data class ScopeClassDeclaration(val scope: FirScope, val classDeclarations: List) { +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 2a7013aa985..f433501694e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.resolve.dfa.DataFlowAnalyzerContext import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptor import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve +import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.impl.createCurrentScopeList import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef @@ -46,6 +47,7 @@ open class FirBodyResolveTransformer( internal open val expressionsTransformer = FirExpressionsResolveTransformer(this) protected open val declarationsTransformer = FirDeclarationsResolveTransformer(this) private val controlFlowStatementsTransformer = FirControlFlowStatementsResolveTransformer(this) + private val classDeclarations = mutableListOf() override fun transformFile(file: FirFile, data: ResolutionMode): FirFile { checkSessionConsistency(file) @@ -68,7 +70,7 @@ open class FirBodyResolveTransformer( typeRef } else { typeResolverTransformer.withFile(context.file) { - transformTypeRef(typeRef, FirCompositeScope(components.createCurrentScopeList())) + transformTypeRef(typeRef, ScopeClassDeclaration(FirCompositeScope(components.createCurrentScopeList()), classDeclarations)) } } return resolvedTypeRef.transformAnnotations(this, data) @@ -261,7 +263,10 @@ open class FirBodyResolveTransformer( } override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): FirStatement { - return declarationsTransformer.transformRegularClass(regularClass, data) + classDeclarations.add(regularClass) + val result = declarationsTransformer.transformRegularClass(regularClass, data) + classDeclarations.removeAt(classDeclarations.lastIndex) + return result } override fun transformAnonymousObject( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt index 8c6e7c12f38..1496f6440c7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt @@ -21,10 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.extensions.* import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.fqName -import org.jetbrains.kotlin.fir.resolve.transformers.FirAbstractPhaseTransformer -import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer -import org.jetbrains.kotlin.fir.resolve.transformers.FirSpecificTypeResolverTransformer -import org.jetbrains.kotlin.fir.resolve.transformers.FirTransformerBasedResolveProcessor +import org.jetbrains.kotlin.fir.resolve.transformers.* import org.jetbrains.kotlin.name.FqName class FirPluginAnnotationsResolveProcessor(session: FirSession, scopeSession: ScopeSession) : FirTransformerBasedResolveProcessor(session, scopeSession) { @@ -93,6 +90,7 @@ private class FirAnnotationResolveTransformer( ) private var owners: PersistentList = persistentListOf() + protected val classDeclarations = mutableListOf() override fun beforeChildren(declaration: FirAnnotatedDeclaration): PersistentList { val current = owners @@ -109,14 +107,15 @@ private class FirAnnotationResolveTransformer( annotationCall: FirAnnotationCall, data: Multimap ): FirStatement { - return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, scope) + return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, ScopeClassDeclaration(scope, listOf())) } override fun transformRegularClass( regularClass: FirRegularClass, data: Multimap ): FirStatement { - return super.transformRegularClass(regularClass, data).also { + classDeclarations.add(regularClass) + val result = super.transformRegularClass(regularClass, data).also { if (regularClass.classKind == ClassKind.ANNOTATION_CLASS && metaAnnotations.isNotEmpty()) { val annotations = regularClass.annotations.mapNotNull { it.fqName(session) } for (annotation in annotations.filter { it in metaAnnotations }) { @@ -124,6 +123,8 @@ private class FirAnnotationResolveTransformer( } } } + classDeclarations.removeAt(classDeclarations.lastIndex) + return result } override fun transformAnnotatedDeclaration( diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirOuterClassTypeParameterRefBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirOuterClassTypeParameterRefBuilder.kt index 4c0f983890e..973970ea80c 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirOuterClassTypeParameterRefBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/builder/FirOuterClassTypeParameterRefBuilder.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.declarations.builder import kotlin.contracts.* +import org.jetbrains.kotlin.fir.FirImplementationDetail import org.jetbrains.kotlin.fir.FirPureAbstractElement import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.builder.FirBuilderDsl @@ -24,6 +25,7 @@ class FirOuterClassTypeParameterRefBuilder { var source: FirSourceElement? = null lateinit var symbol: FirTypeParameterSymbol + @OptIn(FirImplementationDetail::class) fun build(): FirTypeParameterRef { return FirOuterClassTypeParameterRef( source, diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirOuterClassTypeParameterRef.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirOuterClassTypeParameterRef.kt index 7829b8c4ea8..a1a23bd3f04 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirOuterClassTypeParameterRef.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/declarations/impl/FirOuterClassTypeParameterRef.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.declarations.impl +import org.jetbrains.kotlin.fir.FirImplementationDetail import org.jetbrains.kotlin.fir.FirPureAbstractElement import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef @@ -16,7 +17,7 @@ import org.jetbrains.kotlin.fir.visitors.* * DO NOT MODIFY IT MANUALLY */ -internal class FirOuterClassTypeParameterRef( +class FirOuterClassTypeParameterRef @FirImplementationDetail constructor( override val source: FirSourceElement?, override val symbol: FirTypeParameterSymbol, ) : FirPureAbstractElement(), FirTypeParameterRef { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index 89f1cccfb9a..5bd7bd68428 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -25,7 +25,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() defaultTrue("isPrimary", withGetter = true) } - impl(typeParameterRef, "FirOuterClassTypeParameterRef") + impl(typeParameterRef, "FirOuterClassTypeParameterRef") { + publicImplementation() + } impl(typeParameterRef, "FirConstructedClassTypeParameterRef") noImpl(declarationStatus) diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/importedInner.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/importedInner.fir.kt index 131b56d7afc..277db844910 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/importedInner.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/importedInner.fir.kt @@ -11,7 +11,7 @@ class Outer { } class Nested { - fun bar(x: Inner) {} + fun bar(x: Inner) {} } } diff --git a/compiler/testData/diagnostics/tests/generics/innerClasses/outerArgumentsRequired.fir.kt b/compiler/testData/diagnostics/tests/generics/innerClasses/outerArgumentsRequired.fir.kt index 259d8335b9d..7df2d4765d9 100644 --- a/compiler/testData/diagnostics/tests/generics/innerClasses/outerArgumentsRequired.fir.kt +++ b/compiler/testData/diagnostics/tests/generics/innerClasses/outerArgumentsRequired.fir.kt @@ -11,13 +11,13 @@ class A { } class Nested { - val x: B? = null - val y: B.C? = null - val z: B.D? = null + val x: B? = null + val y: B.C? = null + val z: B.D? = null - val c: C? = null - val d: D? = null + val c: C? = null + val d: D? = null - val innerMost: Innermost? = null + val innerMost: Innermost? = null } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index 419b3f6e12e..f5a5661321b 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1349,6 +1349,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED) { firDiagnostic -> + OuterClassArgumentsRequiredImpl( + firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a) as KtNamedClassOrObjectSymbol, + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.TYPE_PARAMETERS_IN_OBJECT) { firDiagnostic -> TypeParametersInObjectImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 4c1382d5453..4edebcd6880 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -956,6 +956,11 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val classifier: KtClassLikeSymbol } + abstract class OuterClassArgumentsRequired : KtFirDiagnostic() { + override val diagnosticClass get() = OuterClassArgumentsRequired::class + abstract val outer: KtNamedClassOrObjectSymbol + } + abstract class TypeParametersInObject : KtFirDiagnostic() { override val diagnosticClass get() = TypeParametersInObject::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 869f1406839..ca4863bfc43 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1536,6 +1536,14 @@ internal class NoTypeArgumentsOnRhsImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class OuterClassArgumentsRequiredImpl( + override val outer: KtNamedClassOrObjectSymbol, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.OuterClassArgumentsRequired(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class TypeParametersInObjectImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,