[FIR] Cleanup FIR modules. Part 1 (calls package)
This commit is contained in:
+10
-15
@@ -20,12 +20,6 @@ abstract class AbstractConeCallConflictResolver(
|
|||||||
private val specificityComparator: TypeSpecificityComparator,
|
private val specificityComparator: TypeSpecificityComparator,
|
||||||
protected val inferenceComponents: InferenceComponents
|
protected val inferenceComponents: InferenceComponents
|
||||||
) : ConeCallConflictResolver() {
|
) : ConeCallConflictResolver() {
|
||||||
protected fun Collection<Candidate>.setIfOneOrEmpty(): Set<Candidate>? = when (size) {
|
|
||||||
0 -> emptySet()
|
|
||||||
1 -> setOf(single())
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
* Returns `true` if [call1] is definitely more or equally specific [call2],
|
||||||
* `false` otherwise.
|
* `false` otherwise.
|
||||||
@@ -56,6 +50,7 @@ abstract class AbstractConeCallConflictResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("PrivatePropertyName")
|
||||||
private val SpecificityComparisonWithNumerics = object : SpecificityComparisonCallbacks {
|
private val SpecificityComparisonWithNumerics = object : SpecificityComparisonCallbacks {
|
||||||
override fun isNonSubtypeNotLessSpecific(specific: KotlinTypeMarker, general: KotlinTypeMarker): Boolean {
|
override fun isNonSubtypeNotLessSpecific(specific: KotlinTypeMarker, general: KotlinTypeMarker): Boolean {
|
||||||
requireOrDescribe(specific is ConeKotlinType, specific)
|
requireOrDescribe(specific is ConeKotlinType, specific)
|
||||||
@@ -83,18 +78,18 @@ abstract class AbstractConeCallConflictResolver(
|
|||||||
when {
|
when {
|
||||||
//TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float) -> return true
|
//TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float) -> return true
|
||||||
specificClassId == int -> {
|
specificClassId == int -> {
|
||||||
when {
|
when (generalClassId) {
|
||||||
generalClassId == long -> return true
|
long -> return true
|
||||||
generalClassId == byte -> return true
|
byte -> return true
|
||||||
generalClassId == short -> return true
|
short -> return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
specificClassId == short && generalClassId == byte -> return true
|
specificClassId == short && generalClassId == byte -> return true
|
||||||
specificClassId == uInt -> {
|
specificClassId == uInt -> {
|
||||||
when {
|
when (generalClassId) {
|
||||||
generalClassId == uLong -> return true
|
uLong -> return true
|
||||||
generalClassId == uByte -> return true
|
uByte -> return true
|
||||||
generalClassId == uShort -> return true
|
uShort -> return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
specificClassId == uShort && generalClassId == uByte -> return true
|
specificClassId == uShort && generalClassId == uByte -> return true
|
||||||
@@ -117,7 +112,7 @@ abstract class AbstractConeCallConflictResolver(
|
|||||||
return FlatSignature(
|
return FlatSignature(
|
||||||
call,
|
call,
|
||||||
(variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(),
|
(variable as? FirProperty)?.typeParameters?.map { it.symbol }.orEmpty(),
|
||||||
listOfNotNull<ConeKotlinType>(variable.receiverTypeRef?.coneTypeUnsafe()),
|
listOfNotNull(variable.receiverTypeRef?.coneTypeUnsafe()),
|
||||||
variable.receiverTypeRef != null,
|
variable.receiverTypeRef != null,
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
|
|||||||
@@ -291,7 +291,6 @@ internal fun Candidate.resolveArgument(
|
|||||||
argument: FirExpression,
|
argument: FirExpression,
|
||||||
parameter: FirValueParameter?,
|
parameter: FirValueParameter?,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isSafeCall: Boolean,
|
|
||||||
sink: CheckerSink
|
sink: CheckerSink
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.fir.returnExpressions
|
|||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirErrorFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirErrorFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirErrorPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirErrorPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
@@ -113,12 +111,17 @@ class CandidateFactory private constructor(
|
|||||||
|
|
||||||
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(statement: FirStatement) {
|
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(statement: FirStatement) {
|
||||||
when (statement) {
|
when (statement) {
|
||||||
is FirFunctionCall, is FirQualifiedAccessExpression, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirCallableReferenceAccess ->
|
is FirFunctionCall,
|
||||||
(statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
is FirQualifiedAccessExpression,
|
||||||
|
is FirWhenExpression,
|
||||||
|
is FirTryExpression,
|
||||||
|
is FirCheckNotNullCall,
|
||||||
|
is FirCallableReferenceAccess
|
||||||
|
-> (statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
||||||
|
|
||||||
is FirSafeCallExpression -> addSubsystemFromExpression(statement.regularQualifiedAccess)
|
is FirSafeCallExpression -> addSubsystemFromExpression(statement.regularQualifiedAccess)
|
||||||
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
||||||
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
||||||
else -> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-5
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.FirDeclaredUpperBoundConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.FirDeclaredUpperBoundConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
|
||||||
|
|
||||||
internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val declaration = candidate.symbol.fir
|
val declaration = candidate.symbol.fir
|
||||||
@@ -41,7 +40,6 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// optimization
|
// optimization
|
||||||
if (candidate.typeArgumentMapping == TypeArgumentMapping.NoExplicitArguments /*&& knownTypeParametersResultingSubstitutor == null*/) {
|
if (candidate.typeArgumentMapping == TypeArgumentMapping.NoExplicitArguments /*&& knownTypeParametersResultingSubstitutor == null*/) {
|
||||||
return
|
return
|
||||||
@@ -62,8 +60,6 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
|||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
when (val typeArgument = candidate.typeArgumentMapping[index]) {
|
when (val typeArgument = candidate.typeArgumentMapping[index]) {
|
||||||
is FirTypeProjectionWithVariance -> csBuilder.addEqualityConstraint(
|
is FirTypeProjectionWithVariance -> csBuilder.addEqualityConstraint(
|
||||||
freshVariable.defaultType,
|
freshVariable.defaultType,
|
||||||
@@ -111,7 +107,7 @@ internal object CreateFreshTypeVariableSubstitutorStage : ResolutionStage() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createToFreshVariableSubstitutorAndAddInitialConstraints(
|
private fun createToFreshVariableSubstitutorAndAddInitialConstraints(
|
||||||
declaration: FirTypeParameterRefsOwner,
|
declaration: FirTypeParameterRefsOwner,
|
||||||
candidate: Candidate,
|
candidate: Candidate,
|
||||||
csBuilder: ConstraintSystemOperation,
|
csBuilder: ConstraintSystemOperation,
|
||||||
|
|||||||
-1
@@ -18,7 +18,6 @@ import kotlin.collections.component1
|
|||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
|
||||||
data class ArgumentMapping(
|
data class ArgumentMapping(
|
||||||
// This map should be ordered by arguments as written, e.g.:
|
// This map should be ordered by arguments as written, e.g.:
|
||||||
// fun foo(a: Int, b: Int) {}
|
// fun foo(a: Int, b: Int) {}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionWithSmartcast
|
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionWithSmartcast
|
||||||
@@ -23,11 +22,8 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
|
||||||
|
|
||||||
interface Receiver {
|
interface Receiver
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReceiverValue : Receiver {
|
interface ReceiverValue : Receiver {
|
||||||
val type: ConeKotlinType
|
val type: ConeKotlinType
|
||||||
@@ -38,26 +34,6 @@ interface ReceiverValue : Receiver {
|
|||||||
type.scope(useSiteSession, scopeSession)
|
type.scope(useSiteSession, scopeSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun receiverExpression(symbol: AbstractFirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression =
|
|
||||||
buildThisReceiverExpression {
|
|
||||||
calleeReference = buildImplicitThisReference {
|
|
||||||
boundSymbol = symbol
|
|
||||||
}
|
|
||||||
typeRef = buildResolvedTypeRef {
|
|
||||||
this.type = type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClassDispatchReceiverValue(klassSymbol: FirClassSymbol<*>) : ReceiverValue {
|
|
||||||
override val type: ConeKotlinType = ConeClassLikeTypeImpl(
|
|
||||||
klassSymbol.toLookupTag(),
|
|
||||||
(klassSymbol.fir as? FirTypeParameterRefsOwner)?.typeParameters?.map { ConeStarProjection }?.toTypedArray().orEmpty(),
|
|
||||||
isNullable = false
|
|
||||||
)
|
|
||||||
|
|
||||||
override val receiverExpression: FirExpression = receiverExpression(klassSymbol, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: should inherit just Receiver, not ReceiverValue
|
// TODO: should inherit just Receiver, not ReceiverValue
|
||||||
abstract class AbstractExplicitReceiver<E : FirExpression> : Receiver {
|
abstract class AbstractExplicitReceiver<E : FirExpression> : Receiver {
|
||||||
abstract val explicitReceiver: FirExpression
|
abstract val explicitReceiver: FirExpression
|
||||||
@@ -85,8 +61,7 @@ sealed class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>(
|
|||||||
final override var type: ConeKotlinType = type
|
final override var type: ConeKotlinType = type
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession)
|
private var implicitScope: FirTypeScope? = type.scope(useSiteSession, scopeSession)
|
||||||
private set
|
|
||||||
|
|
||||||
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = implicitScope
|
override fun scope(useSiteSession: FirSession, scopeSession: ScopeSession): FirTypeScope? = implicitScope
|
||||||
|
|
||||||
@@ -113,6 +88,16 @@ sealed class ImplicitReceiverValue<S : AbstractFirBasedSymbol<*>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun receiverExpression(symbol: AbstractFirBasedSymbol<*>, type: ConeKotlinType): FirThisReceiverExpression =
|
||||||
|
buildThisReceiverExpression {
|
||||||
|
calleeReference = buildImplicitThisReference {
|
||||||
|
boundSymbol = symbol
|
||||||
|
}
|
||||||
|
typeRef = buildResolvedTypeRef {
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ImplicitDispatchReceiverValue internal constructor(
|
class ImplicitDispatchReceiverValue internal constructor(
|
||||||
boundSymbol: FirClassSymbol<*>,
|
boundSymbol: FirClassSymbol<*>,
|
||||||
type: ConeKotlinType,
|
type: ConeKotlinType,
|
||||||
|
|||||||
+3
-10
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
|
|
||||||
|
|
||||||
fun FirClassLikeDeclaration<*>.fullyExpandedClass(useSiteSession: FirSession): FirRegularClass? {
|
fun FirClassLikeDeclaration<*>.fullyExpandedClass(useSiteSession: FirSession): FirRegularClass? {
|
||||||
if (this is FirTypeAlias) return this.expandedConeType?.lookupTag?.toSymbol(useSiteSession)?.fir?.fullyExpandedClass(useSiteSession)
|
if (this is FirTypeAlias) return this.expandedConeType?.lookupTag?.toSymbol(useSiteSession)?.fir?.fullyExpandedClass(useSiteSession)
|
||||||
if (this is FirRegularClass) return this
|
if (this is FirRegularClass) return this
|
||||||
@@ -33,21 +32,17 @@ fun createQualifierReceiver(
|
|||||||
useSiteSession: FirSession,
|
useSiteSession: FirSession,
|
||||||
scopeSession: ScopeSession,
|
scopeSession: ScopeSession,
|
||||||
): QualifierReceiver? {
|
): QualifierReceiver? {
|
||||||
|
|
||||||
val classLikeSymbol = explicitReceiver.symbol
|
val classLikeSymbol = explicitReceiver.symbol
|
||||||
when {
|
return when {
|
||||||
classLikeSymbol != null -> {
|
classLikeSymbol != null -> {
|
||||||
val classSymbol = classLikeSymbol.fir.fullyExpandedClass(useSiteSession)?.symbol ?: return null
|
val classSymbol = classLikeSymbol.fir.fullyExpandedClass(useSiteSession)?.symbol ?: return null
|
||||||
return ClassQualifierReceiver(explicitReceiver, classSymbol, classLikeSymbol, useSiteSession, scopeSession)
|
ClassQualifierReceiver(explicitReceiver, classSymbol, classLikeSymbol, useSiteSession, scopeSession)
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
return PackageQualifierReceiver(explicitReceiver, useSiteSession)
|
|
||||||
}
|
}
|
||||||
|
else -> PackageQualifierReceiver(explicitReceiver, useSiteSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class QualifierReceiver(final override val explicitReceiver: FirExpression) : AbstractExplicitReceiver<FirResolvedQualifier>() {
|
abstract class QualifierReceiver(final override val explicitReceiver: FirExpression) : AbstractExplicitReceiver<FirResolvedQualifier>() {
|
||||||
|
|
||||||
abstract fun classifierScope(): FirScope?
|
abstract fun classifierScope(): FirScope?
|
||||||
abstract fun callableScope(): FirScope?
|
abstract fun callableScope(): FirScope?
|
||||||
}
|
}
|
||||||
@@ -70,10 +65,8 @@ class ClassQualifierReceiver(
|
|||||||
val klass = classSymbol.fir
|
val klass = classSymbol.fir
|
||||||
return klass.scopeProvider.getNestedClassifierScope(klass, useSiteSession, scopeSession)
|
return klass.scopeProvider.getNestedClassifierScope(klass, useSiteSession, scopeSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PackageQualifierReceiver(
|
class PackageQualifierReceiver(
|
||||||
explicitReceiver: FirResolvedQualifier,
|
explicitReceiver: FirResolvedQualifier,
|
||||||
useSiteSession: FirSession
|
useSiteSession: FirSession
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ abstract class InapplicableArgumentDiagnostic : ResolutionDiagnostic(CandidateAp
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MixingNamedAndPositionArguments(override val argument: FirExpression) : InapplicableArgumentDiagnostic()
|
class MixingNamedAndPositionArguments(override val argument: FirExpression) : InapplicableArgumentDiagnostic()
|
||||||
|
|
||||||
class TooManyArguments(
|
class TooManyArguments(
|
||||||
val argument: FirExpression,
|
val argument: FirExpression,
|
||||||
val function: FirFunction<*>
|
val function: FirFunction<*>
|
||||||
@@ -48,4 +49,4 @@ class NoValueForParameter(
|
|||||||
class NameNotFound(
|
class NameNotFound(
|
||||||
override val argument: FirExpression,
|
override val argument: FirExpression,
|
||||||
val function: FirFunction<*>
|
val function: FirFunction<*>
|
||||||
) : InapplicableArgumentDiagnostic()
|
) : InapplicableArgumentDiagnostic()
|
||||||
|
|||||||
+79
-81
@@ -41,13 +41,6 @@ abstract class ResolutionStage {
|
|||||||
|
|
||||||
abstract class CheckerStage : ResolutionStage()
|
abstract class CheckerStage : ResolutionStage()
|
||||||
|
|
||||||
internal fun FirExpression.isSuperReferenceExpression(): Boolean {
|
|
||||||
return if (this is FirQualifiedAccessExpression) {
|
|
||||||
val calleeReference = calleeReference
|
|
||||||
calleeReference is FirSuperReference
|
|
||||||
} else false
|
|
||||||
}
|
|
||||||
|
|
||||||
internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
internal object CheckExplicitReceiverConsistency : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val receiverKind = candidate.explicitReceiverKind
|
val receiverKind = candidate.explicitReceiverKind
|
||||||
@@ -101,7 +94,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
|||||||
override fun Candidate.getReceiverType(): ConeKotlinType? {
|
override fun Candidate.getReceiverType(): ConeKotlinType? {
|
||||||
val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null
|
val callableSymbol = symbol as? FirCallableSymbol<*> ?: return null
|
||||||
val callable = callableSymbol.fir
|
val callable = callableSymbol.fir
|
||||||
val receiverType = (callable.receiverTypeRef as FirResolvedTypeRef?)?.type
|
val receiverType = callable.receiverTypeRef?.coneTypeUnsafe<ConeKotlinType>()
|
||||||
if (receiverType != null) return receiverType
|
if (receiverType != null) return receiverType
|
||||||
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
|
val returnTypeRef = callable.returnTypeRef as? FirResolvedTypeRef ?: return null
|
||||||
if (!returnTypeRef.isExtensionFunctionType(bodyResolveComponents.session)) return null
|
if (!returnTypeRef.isExtensionFunctionType(bodyResolveComponents.session)) return null
|
||||||
@@ -153,6 +146,13 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FirExpression.isSuperReferenceExpression(): Boolean {
|
||||||
|
return if (this is FirQualifiedAccessExpression) {
|
||||||
|
val calleeReference = calleeReference
|
||||||
|
calleeReference is FirSuperReference
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
|
||||||
internal object MapArguments : ResolutionStage() {
|
internal object MapArguments : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val symbol = candidate.symbol as? FirFunctionSymbol<*> ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
val symbol = candidate.symbol as? FirFunctionSymbol<*> ?: return sink.reportApplicability(CandidateApplicability.HIDDEN)
|
||||||
@@ -184,14 +184,13 @@ internal object MapArguments : ResolutionStage() {
|
|||||||
internal object CheckArguments : CheckerStage() {
|
internal object CheckArguments : CheckerStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val argumentMapping =
|
val argumentMapping =
|
||||||
candidate.argumentMapping ?: throw IllegalStateException("Argument should be already mapped while checking arguments!")
|
candidate.argumentMapping ?: error("Argument should be already mapped while checking arguments!")
|
||||||
for (argument in callInfo.arguments) {
|
for (argument in callInfo.arguments) {
|
||||||
val parameter = argumentMapping[argument]
|
val parameter = argumentMapping[argument]
|
||||||
candidate.resolveArgument(
|
candidate.resolveArgument(
|
||||||
argument,
|
argument,
|
||||||
parameter,
|
parameter,
|
||||||
isReceiver = false,
|
isReceiver = false,
|
||||||
isSafeCall = false,
|
|
||||||
sink = sink
|
sink = sink
|
||||||
)
|
)
|
||||||
if (candidate.system.hasContradiction) {
|
if (candidate.system.hasContradiction) {
|
||||||
@@ -205,9 +204,11 @@ internal object CheckArguments : CheckerStage() {
|
|||||||
internal object EagerResolveOfCallableReferences : CheckerStage() {
|
internal object EagerResolveOfCallableReferences : CheckerStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
if (candidate.postponedAtoms.isEmpty()) return
|
if (candidate.postponedAtoms.isEmpty()) return
|
||||||
for (atom in candidate.postponedAtoms.filterIsInstance<ResolvedCallableReferenceAtom>()) {
|
for (atom in candidate.postponedAtoms) {
|
||||||
if (!candidate.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) {
|
if (atom is ResolvedCallableReferenceAtom) {
|
||||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
if (!candidate.bodyResolveComponents.callResolver.resolveCallableReference(candidate.csBuilder, atom)) {
|
||||||
|
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,7 +225,7 @@ internal object CheckCallableReferenceExpectedType : CheckerStage() {
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
val fir = with(candidate.bodyResolveComponents) {
|
val fir: FirCallableDeclaration<*> = with(candidate.bodyResolveComponents) {
|
||||||
candidateSymbol.phasedFir
|
candidateSymbol.phasedFir
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,18 +333,29 @@ internal object DiscriminateSynthetics : CheckerStage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal object CheckVisibility : CheckerStage() {
|
internal object CheckVisibility : CheckerStage() {
|
||||||
private fun AbstractFirBasedSymbol<*>.packageFqName(): FqName {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
return when (this) {
|
val symbol = candidate.symbol
|
||||||
is FirClassLikeSymbol<*> -> classId.packageFqName
|
val declaration = symbol.fir
|
||||||
is FirCallableSymbol<*> -> callableId.packageName
|
if (declaration is FirMemberDeclaration) {
|
||||||
else -> error("No package fq name for $this")
|
if (!checkVisibility(declaration, symbol, sink, candidate)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (declaration is FirConstructor) {
|
||||||
|
val ownerClassId = declaration.symbol.callableId.classId!!
|
||||||
|
val provider = declaration.session.firSymbolProvider
|
||||||
|
val classSymbol = provider.getClassLikeSymbolByFqName(ownerClassId)
|
||||||
|
|
||||||
|
if (classSymbol is FirRegularClassSymbol) {
|
||||||
|
if (classSymbol.fir.classKind.isSingleton) {
|
||||||
|
sink.yieldApplicability(CandidateApplicability.HIDDEN)
|
||||||
|
}
|
||||||
|
checkVisibility(classSymbol.fir, classSymbol, sink, candidate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'local' isn't taken into account here
|
|
||||||
private fun ClassId.isSame(other: ClassId): Boolean =
|
|
||||||
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
|
|
||||||
|
|
||||||
private fun canSeePrivateMemberOf(
|
private fun canSeePrivateMemberOf(
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
ownerId: ClassId,
|
ownerId: ClassId,
|
||||||
@@ -364,6 +376,10 @@ internal object CheckVisibility : CheckerStage() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 'local' isn't taken into account here
|
||||||
|
private fun ClassId.isSame(other: ClassId): Boolean =
|
||||||
|
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
|
||||||
|
|
||||||
private fun ClassId.ownerIfCompanion(session: FirSession): ClassId? {
|
private fun ClassId.ownerIfCompanion(session: FirSession): ClassId? {
|
||||||
if (outerClassId == null || isLocal) return null
|
if (outerClassId == null || isLocal) return null
|
||||||
val ownerSymbol = session.firSymbolProvider.getClassLikeSymbolByFqName(this) as? FirRegularClassSymbol
|
val ownerSymbol = session.firSymbolProvider.getClassLikeSymbolByFqName(this) as? FirRegularClassSymbol
|
||||||
@@ -371,14 +387,6 @@ internal object CheckVisibility : CheckerStage() {
|
|||||||
return outerClassId.takeIf { ownerSymbol?.fir?.isCompanion == true }
|
return outerClassId.takeIf { ownerSymbol?.fir?.isCompanion == true }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirClass<*>.isSubClass(ownerId: ClassId, session: FirSession): Boolean {
|
|
||||||
if (classId.isSame(ownerId)) return true
|
|
||||||
|
|
||||||
return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType ->
|
|
||||||
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerId) == true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canSeeProtectedMemberOf(
|
private fun canSeeProtectedMemberOf(
|
||||||
containingUseSiteClass: FirClass<*>,
|
containingUseSiteClass: FirClass<*>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: ReceiverValue?,
|
||||||
@@ -392,46 +400,17 @@ internal object CheckVisibility : CheckerStage() {
|
|||||||
return containingUseSiteClass.isSubClass(ownerId, session)
|
return containingUseSiteClass.isSubClass(ownerId, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canSeeProtectedMemberOf(
|
private fun FirClass<*>.isSubClass(ownerId: ClassId, session: FirSession): Boolean {
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
if (classId.isSame(ownerId)) return true
|
||||||
dispatchReceiver: ReceiverValue?,
|
|
||||||
ownerId: ClassId, session: FirSession
|
|
||||||
): Boolean {
|
|
||||||
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerId, session)) return true
|
|
||||||
|
|
||||||
for (containingDeclaration in containingDeclarationOfUseSite) {
|
return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType ->
|
||||||
if (containingDeclaration !is FirClass<*>) continue
|
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerId) == true
|
||||||
val boundSymbol = containingDeclaration.symbol
|
|
||||||
if (canSeeProtectedMemberOf(boundSymbol.fir, dispatchReceiver, ownerId, session)) return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ClassId? =
|
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ClassId? =
|
||||||
(this?.type as? ConeClassLikeType)?.lookupTag?.classId?.ownerIfCompanion(session)
|
(this?.type as? ConeClassLikeType)?.lookupTag?.classId?.ownerIfCompanion(session)
|
||||||
|
|
||||||
private fun AbstractFirBasedSymbol<*>.getOwnerId(): ClassId? {
|
|
||||||
return when (this) {
|
|
||||||
is FirClassLikeSymbol<*> -> {
|
|
||||||
val ownerId = classId.outerClassId
|
|
||||||
if (classId.isLocal) {
|
|
||||||
ownerId?.asLocal() ?: classId
|
|
||||||
} else {
|
|
||||||
ownerId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirCallableSymbol<*> -> {
|
|
||||||
callableId.classId
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
throw AssertionError("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ClassId.asLocal(): ClassId = ClassId(packageFqName, relativeClassName, true)
|
|
||||||
|
|
||||||
private suspend fun checkVisibility(
|
private suspend fun checkVisibility(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
symbol: AbstractFirBasedSymbol<*>,
|
symbol: AbstractFirBasedSymbol<*>,
|
||||||
@@ -489,26 +468,44 @@ internal object CheckVisibility : CheckerStage() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
private fun AbstractFirBasedSymbol<*>.getOwnerId(): ClassId? {
|
||||||
val symbol = candidate.symbol
|
return when (this) {
|
||||||
val declaration = symbol.fir
|
is FirClassLikeSymbol<*> -> {
|
||||||
if (declaration is FirMemberDeclaration) {
|
val ownerId = classId.outerClassId
|
||||||
if (!checkVisibility(declaration, symbol, sink, candidate)) {
|
if (classId.isLocal) {
|
||||||
return
|
ownerId?.asLocal() ?: classId
|
||||||
|
} else {
|
||||||
|
ownerId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
is FirCallableSymbol<*> -> callableId.classId
|
||||||
|
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClassId.asLocal(): ClassId = ClassId(packageFqName, relativeClassName, true)
|
||||||
|
|
||||||
|
private fun canSeeProtectedMemberOf(
|
||||||
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
|
dispatchReceiver: ReceiverValue?,
|
||||||
|
ownerId: ClassId, session: FirSession
|
||||||
|
): Boolean {
|
||||||
|
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerId, session)) return true
|
||||||
|
|
||||||
|
for (containingDeclaration in containingDeclarationOfUseSite) {
|
||||||
|
if (containingDeclaration !is FirClass<*>) continue
|
||||||
|
val boundSymbol = containingDeclaration.symbol
|
||||||
|
if (canSeeProtectedMemberOf(boundSymbol.fir, dispatchReceiver, ownerId, session)) return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaration is FirConstructor) {
|
return false
|
||||||
val ownerClassId = declaration.symbol.callableId.classId!!
|
}
|
||||||
val provider = declaration.session.firSymbolProvider
|
|
||||||
val classSymbol = provider.getClassLikeSymbolByFqName(ownerClassId)
|
|
||||||
|
|
||||||
if (classSymbol is FirRegularClassSymbol) {
|
private fun AbstractFirBasedSymbol<*>.packageFqName(): FqName {
|
||||||
if (classSymbol.fir.classKind.isSingleton) {
|
return when (this) {
|
||||||
sink.yieldApplicability(CandidateApplicability.HIDDEN)
|
is FirClassLikeSymbol<*> -> classId.packageFqName
|
||||||
}
|
is FirCallableSymbol<*> -> callableId.packageName
|
||||||
checkVisibility(classSymbol.fir, classSymbol, sink, candidate)
|
else -> error("No package fq name for $this")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,8 +520,9 @@ internal object CheckLowPriorityInOverloadResolution : CheckerStage() {
|
|||||||
is FirProperty -> fir.annotations
|
is FirProperty -> fir.annotations
|
||||||
else -> return
|
else -> return
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasLowPriorityAnnotation = annotations.any {
|
val hasLowPriorityAnnotation = annotations.any {
|
||||||
val lookupTag = ((it.annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag ?: return@any false
|
val lookupTag = it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return@any false
|
||||||
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
|
lookupTag.classId == LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_CLASS_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,44 @@ class FirSyntheticPropertiesScope(
|
|||||||
private val baseScope: FirTypeScope
|
private val baseScope: FirTypeScope
|
||||||
) : FirScope() {
|
) : FirScope() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val GETTER_PREFIX = "get"
|
||||||
|
private const val IS_PREFIX = "is"
|
||||||
|
|
||||||
|
fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
|
||||||
|
if (name.isSpecial) return emptyList()
|
||||||
|
val identifier = name.identifier
|
||||||
|
val capitalizedAsciiName = identifier.capitalizeAsciiOnly()
|
||||||
|
val capitalizedFirstWordName = identifier.capitalizeFirstWord(asciiOnly = true)
|
||||||
|
return listOfNotNull(
|
||||||
|
Name.identifier(GETTER_PREFIX + capitalizedAsciiName),
|
||||||
|
if (capitalizedFirstWordName == capitalizedAsciiName) null else Name.identifier(GETTER_PREFIX + capitalizedFirstWordName),
|
||||||
|
name.takeIf { identifier.startsWith(IS_PREFIX) }
|
||||||
|
).filter {
|
||||||
|
propertyNameByGetMethodName(it) == name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setterNameByGetterName(name: Name): Name {
|
||||||
|
val identifier = name.identifier
|
||||||
|
val prefix = when {
|
||||||
|
identifier.startsWith("get") -> "get"
|
||||||
|
identifier.startsWith("is") -> "is"
|
||||||
|
else -> throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
return Name.identifier("set" + identifier.removePrefix(prefix))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||||
|
val getterNames = possibleGetterNamesByPropertyName(name)
|
||||||
|
for (getterName in getterNames) {
|
||||||
|
baseScope.processFunctionsByName(getterName) {
|
||||||
|
checkGetAndCreateSynthetic(name, getterName, it, processor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkGetAndCreateSynthetic(
|
private fun checkGetAndCreateSynthetic(
|
||||||
propertyName: Name,
|
propertyName: Name,
|
||||||
getterName: Name,
|
getterName: Name,
|
||||||
@@ -95,43 +133,4 @@ class FirSyntheticPropertiesScope(
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
|
||||||
val getterNames = possibleGetterNamesByPropertyName(name)
|
|
||||||
for (getterName in getterNames) {
|
|
||||||
baseScope.processFunctionsByName(getterName) {
|
|
||||||
checkGetAndCreateSynthetic(name, getterName, it, processor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun possibleGetterNamesByPropertyName(name: Name): List<Name> {
|
|
||||||
if (name.isSpecial) return emptyList()
|
|
||||||
val identifier = name.identifier
|
|
||||||
val capitalizedAsciiName = identifier.capitalizeAsciiOnly()
|
|
||||||
val capitalizedFirstWordName = identifier.capitalizeFirstWord(asciiOnly = true)
|
|
||||||
return listOfNotNull(
|
|
||||||
Name.identifier(GETTER_PREFIX + capitalizedAsciiName),
|
|
||||||
if (capitalizedFirstWordName == capitalizedAsciiName) null else Name.identifier(GETTER_PREFIX + capitalizedFirstWordName),
|
|
||||||
name.takeIf { identifier.startsWith(IS_PREFIX) }
|
|
||||||
).filter {
|
|
||||||
propertyNameByGetMethodName(it) == name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setterNameByGetterName(name: Name): Name {
|
|
||||||
val identifier = name.identifier
|
|
||||||
val prefix = when {
|
|
||||||
identifier.startsWith("get") -> "get"
|
|
||||||
identifier.startsWith("is") -> "is"
|
|
||||||
else -> throw IllegalArgumentException()
|
|
||||||
}
|
|
||||||
return Name.identifier("set" + identifier.removePrefix(prefix))
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val GETTER_PREFIX = "get"
|
|
||||||
|
|
||||||
private const val IS_PREFIX = "is"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -6,12 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParametersOwner
|
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
import org.jetbrains.kotlin.fir.types.impl.FirTypePlaceholderProjection
|
||||||
|
|
||||||
sealed class TypeArgumentMapping {
|
sealed class TypeArgumentMapping {
|
||||||
|
|
||||||
abstract operator fun get(typeParameterIndex: Int): FirTypeProjection
|
abstract operator fun get(typeParameterIndex: Int): FirTypeProjection
|
||||||
|
|
||||||
object NoExplicitArguments : TypeArgumentMapping() {
|
object NoExplicitArguments : TypeArgumentMapping() {
|
||||||
@@ -25,7 +23,6 @@ sealed class TypeArgumentMapping {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal object MapTypeArguments : ResolutionStage() {
|
internal object MapTypeArguments : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
val typeArguments = callInfo.typeArguments
|
val typeArguments = callInfo.typeArguments
|
||||||
@@ -47,10 +44,9 @@ internal object MapTypeArguments : ResolutionStage() {
|
|||||||
|
|
||||||
internal object NoTypeArguments : ResolutionStage() {
|
internal object NoTypeArguments : ResolutionStage() {
|
||||||
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
override suspend fun check(candidate: Candidate, sink: CheckerSink, callInfo: CallInfo) {
|
||||||
|
|
||||||
if (callInfo.typeArguments.isNotEmpty()) {
|
if (callInfo.typeArguments.isNotEmpty()) {
|
||||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||||
}
|
}
|
||||||
candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments
|
candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ sealed class TowerGroupKind(private val index: Int) : Comparable<TowerGroupKind>
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
companion object {
|
companion object {
|
||||||
// These two groups intentionally have the same priority
|
// These two groups intentionally have the same priority
|
||||||
fun Implicit(depth: Int): TowerGroupKind = ImplicitOrNonLocal(depth, "Implicit")
|
fun Implicit(depth: Int): TowerGroupKind = ImplicitOrNonLocal(depth, "Implicit")
|
||||||
|
|||||||
Reference in New Issue
Block a user