[FIR] Implement OUTER_CLASS_ARGUMENTS_REQUIRED diagnostics

This commit is contained in:
Ivan Kochurkin
2021-06-17 17:53:42 +03:00
committed by TeamCityServer
parent f7ed2f813d
commit 0fc8be4d60
24 changed files with 225 additions and 59 deletions
@@ -452,6 +452,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<Int>("expectedCount")
parameter<FirClassLikeSymbol<*>>("classifier")
}
val OUTER_CLASS_ARGUMENTS_REQUIRED by error<PsiElement>() {
parameter<FirRegularClass>("outer")
}
val TYPE_PARAMETERS_IN_OBJECT by error<PsiElement>()
val ILLEGAL_PROJECTION_USAGE by error<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error<PsiElement>()
@@ -297,6 +297,7 @@ object FirErrors {
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<PsiElement>()
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<PsiElement, Int, FirClassLikeSymbol<*>>()
val NO_TYPE_ARGUMENTS_ON_RHS by error2<PsiElement, Int, FirClassLikeSymbol<*>>()
val OUTER_CLASS_ARGUMENTS_REQUIRED by error1<PsiElement, FirRegularClass>()
val TYPE_PARAMETERS_IN_OBJECT by error0<PsiElement>()
val ILLEGAL_PROJECTION_USAGE by error0<PsiElement>()
val TYPE_PARAMETERS_IN_ENUM by error0<PsiElement>()
@@ -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")
@@ -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()
@@ -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) {
@@ -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
}
@@ -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
}
@@ -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"
}
@@ -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<FirClassifierSymbol<*>?, 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<ConeTypeProjection>()
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())
@@ -30,6 +30,7 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(
protected val scopeSession: ScopeSession
) : FirAbstractTreeTransformer<Any?>(phase) {
protected val scopes = mutableListOf<FirScope>()
protected val classDeclarations = mutableListOf<FirRegularClass>()
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 <T> 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?
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FirSpecificTypeResolverTransformer(
override val session: FirSession,
private val errorTypeAsResolved: Boolean = true
) : FirAbstractTreeTransformer<FirScope>(phase = FirResolvePhase.SUPER_TYPES) {
) : FirAbstractTreeTransformer<ScopeClassDeclaration>(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
}
}
@@ -215,6 +215,7 @@ open class FirSupertypeResolverVisitor(
private val firProviderInterceptor: FirProviderInterceptor? = null,
) : FirDefaultVisitor<Unit, Any?>() {
private val supertypeGenerationExtensions = session.extensionService.supertypeGenerators
private val classDeclarations = mutableListOf<FirRegularClass>()
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>, FirScope) -> List<FirResolvedTypeRef>
resolveSuperTypeRefs: (FirTransformer<ScopeClassDeclaration>, ScopeClassDeclaration) -> List<FirResolvedTypeRef>
): List<FirTypeRef> {
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<FirTypeRef>
): List<FirTypeRef> {
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<ConeTypeParameterType>()
when {
typeParameterType != null ->
@@ -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 {
@@ -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<FirRegularClass>) {
}
@@ -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<FirRegularClass>()
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(
@@ -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<FirAnnotatedDeclaration> = persistentListOf()
protected val classDeclarations = mutableListOf<FirRegularClass>()
override fun beforeChildren(declaration: FirAnnotatedDeclaration): PersistentList<FirAnnotatedDeclaration> {
val current = owners
@@ -109,14 +107,15 @@ private class FirAnnotationResolveTransformer(
annotationCall: FirAnnotationCall,
data: Multimap<AnnotationFqn, FirRegularClass>
): FirStatement {
return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, scope)
return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, ScopeClassDeclaration(scope, listOf()))
}
override fun transformRegularClass(
regularClass: FirRegularClass,
data: Multimap<AnnotationFqn, FirRegularClass>
): 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(
@@ -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,
@@ -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 {
@@ -25,7 +25,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
defaultTrue("isPrimary", withGetter = true)
}
impl(typeParameterRef, "FirOuterClassTypeParameterRef")
impl(typeParameterRef, "FirOuterClassTypeParameterRef") {
publicImplementation()
}
impl(typeParameterRef, "FirConstructedClassTypeParameterRef")
noImpl(declarationStatus)
@@ -11,7 +11,7 @@ class Outer<E> {
}
class Nested {
fun bar(x: Inner) {}
fun bar(x: <!OUTER_CLASS_ARGUMENTS_REQUIRED!>Inner<!>) {}
}
}
@@ -11,13 +11,13 @@ class A<T> {
}
class Nested {
val x: B<String>? = null
val y: B<String>.C<String>? = null
val z: B<String>.D? = null
val x: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'A'")!>B<String>?<!> = null
val y: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'A'")!>B<String>.C<String>?<!> = null
val z: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'A'")!>B<String>.D?<!> = null
val c: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>C<Int>?<!> = null
val d: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>D?<!> = null
val c: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'B'")!>C<Int>?<!> = null
val d: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'B'")!>D?<!> = null
val innerMost: <!WRONG_NUMBER_OF_TYPE_ARGUMENTS!>Innermost<String>?<!> = null
val innerMost: <!OUTER_CLASS_ARGUMENTS_REQUIRED("class 'B'")!>Innermost<String>?<!> = null
}
}
@@ -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,
@@ -956,6 +956,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val classifier: KtClassLikeSymbol
}
abstract class OuterClassArgumentsRequired : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = OuterClassArgumentsRequired::class
abstract val outer: KtNamedClassOrObjectSymbol
}
abstract class TypeParametersInObject : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = TypeParametersInObject::class
}
@@ -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<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class TypeParametersInObjectImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,