FIR resolve: add early explicit receiver type check

Before this commit, explicit extension receiver type check was performed
during found candidates analysis (together with arguments type check etc.)
Now we do it just after candidate is found, and filter the candidate
out if explicit receiver type is inappropriate.

This commit slightly changes resolve semantics,
replacing WRONG_RECEIVER with UNRESOLVED_REFERENCE in certain situations.
However, it provides significant performance boost.
This commit is contained in:
Mikhail Glukhikh
2019-05-28 20:36:17 +03:00
parent d820b6ca52
commit 374b59dee3
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.constructClassType
import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
@@ -29,12 +30,15 @@ import org.jetbrains.kotlin.fir.symbols.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol 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.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import kotlin.coroutines.* import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.createCoroutineUnintercepted import kotlin.coroutines.intrinsics.createCoroutineUnintercepted
@@ -544,14 +548,34 @@ class ExplicitReceiverTowerDataConsumer<T : ConeSymbol>(
dispatchReceiverValue: ClassDispatchReceiverValue?, dispatchReceiverValue: ClassDispatchReceiverValue?,
implicitExtensionReceiverValue: ImplicitReceiverValue? implicitExtensionReceiverValue: ImplicitReceiverValue?
): ProcessorAction { ): ProcessorAction {
val explicitReceiverType = explicitReceiver.type
if (dispatchReceiverValue == null && explicitReceiverType is ConeClassType) {
val declarationReceiverTypeRef = (symbol as? FirCallableSymbol)?.fir?.receiverTypeRef as? FirResolvedTypeRef
val declarationReceiverType = declarationReceiverTypeRef?.type
if (declarationReceiverType is ConeClassType) {
if (!AbstractTypeChecker.isSubtypeOf(
candidateFactory.inferenceComponents.ctx,
explicitReceiverType,
declarationReceiverType.lookupTag.constructClassType(
declarationReceiverType.typeArguments.map { ConeStarProjection }.toTypedArray(),
isNullable = true
)
)
) {
return ProcessorAction.NEXT
}
}
}
val candidate = candidateFactory.createCandidate(
symbol,
dispatchReceiverValue,
implicitExtensionReceiverValue,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
resultCollector.consumeCandidate( resultCollector.consumeCandidate(
group, group,
candidateFactory.createCandidate( candidate
symbol,
dispatchReceiverValue,
implicitExtensionReceiverValue,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
) )
return ProcessorAction.NEXT return ProcessorAction.NEXT
} }
@@ -690,9 +714,6 @@ enum class CandidateApplicability {
RESOLVED RESOLVED
} }
var ID = ""
class CandidateCollector(val callInfo: CallInfo, val components: InferenceComponents) { class CandidateCollector(val callInfo: CallInfo, val components: InferenceComponents) {
val groupNumbers = mutableListOf<Int>() val groupNumbers = mutableListOf<Int>()