Reformat 'resolution' module according to new codestyle

This commit is contained in:
Dmitry Savvinov
2018-01-17 16:12:58 +03:00
parent e2b83aecd7
commit c704f2de9a
89 changed files with 1941 additions and 1530 deletions
@@ -38,10 +38,10 @@ interface ContractDescriptionElement {
interface EffectDeclaration : ContractDescriptionElement { interface EffectDeclaration : ContractDescriptionElement {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitEffectDeclaration(this, data) contractDescriptionVisitor.visitEffectDeclaration(this, data)
} }
interface BooleanExpression : ContractDescriptionElement { interface BooleanExpression : ContractDescriptionElement {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitBooleanExpression(this, data) contractDescriptionVisitor.visitBooleanExpression(this, data)
} }
@@ -74,7 +74,7 @@ class ContractDescriptionRenderer(private val builder: StringBuilder) : Contract
} }
private fun ContractDescriptionElement.isAtom(): Boolean = private fun ContractDescriptionElement.isAtom(): Boolean =
this is VariableReference || this is ConstantReference || this is IsNullPredicate || this is IsInstancePredicate this is VariableReference || this is ConstantReference || this is IsNullPredicate || this is IsInstancePredicate
private fun needsBrackets(parent: ContractDescriptionElement, child: ContractDescriptionElement): Boolean { private fun needsBrackets(parent: ContractDescriptionElement, child: ContractDescriptionElement): Boolean {
if (child.isAtom()) return false if (child.isAtom()) return false
@@ -87,8 +87,7 @@ class ContractDescriptionRenderer(private val builder: StringBuilder) : Contract
builder.append("(") builder.append("(")
block() block()
builder.append(")") builder.append(")")
} } else {
else {
block() block()
} }
} }
@@ -25,7 +25,10 @@ interface ContractDescriptionVisitor<out R, in D> {
// Effects // Effects
fun visitEffectDeclaration(effectDeclaration: EffectDeclaration, data: D): R = visitContractDescriptionElement(effectDeclaration, data) fun visitEffectDeclaration(effectDeclaration: EffectDeclaration, data: D): R = visitContractDescriptionElement(effectDeclaration, data)
fun visitConditionalEffectDeclaration(conditionalEffect: ConditionalEffectDeclaration, data: D): R = visitEffectDeclaration(conditionalEffect, data)
fun visitConditionalEffectDeclaration(conditionalEffect: ConditionalEffectDeclaration, data: D): R =
visitEffectDeclaration(conditionalEffect, data)
fun visitReturnsEffectDeclaration(returnsEffect: ReturnsEffectDeclaration, data: D): R = visitEffectDeclaration(returnsEffect, data) fun visitReturnsEffectDeclaration(returnsEffect: ReturnsEffectDeclaration, data: D): R = visitEffectDeclaration(returnsEffect, data)
fun visitCallsEffectDeclaration(callsEffect: CallsEffectDeclaration, data: D): R = visitEffectDeclaration(callsEffect, data) fun visitCallsEffectDeclaration(callsEffect: CallsEffectDeclaration, data: D): R = visitEffectDeclaration(callsEffect, data)
@@ -43,7 +46,10 @@ interface ContractDescriptionVisitor<out R, in D> {
fun visitValue(value: ContractDescriptionValue, data: D): R = visitContractDescriptionElement(value, data) fun visitValue(value: ContractDescriptionValue, data: D): R = visitContractDescriptionElement(value, data)
fun visitConstantDescriptor(constantReference: ConstantReference, data: D): R = visitValue(constantReference, data) fun visitConstantDescriptor(constantReference: ConstantReference, data: D): R = visitValue(constantReference, data)
fun visitBooleanConstantDescriptor(booleanConstantDescriptor: BooleanConstantReference, data: D): R = visitConstantDescriptor(booleanConstantDescriptor, data) fun visitBooleanConstantDescriptor(booleanConstantDescriptor: BooleanConstantReference, data: D): R =
visitConstantDescriptor(booleanConstantDescriptor, data)
fun visitVariableReference(variableReference: VariableReference, data: D): R = visitValue(variableReference, data) fun visitVariableReference(variableReference: VariableReference, data: D): R = visitValue(variableReference, data)
fun visitBooleanVariableReference(booleanVariableReference: BooleanVariableReference, data: D): R = visitVariableReference(booleanVariableReference, data) fun visitBooleanVariableReference(booleanVariableReference: BooleanVariableReference, data: D): R =
visitVariableReference(booleanVariableReference, data)
} }
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.contracts.description.expressions.VariableReference
*/ */
class ConditionalEffectDeclaration(val effect: EffectDeclaration, val condition: BooleanExpression) : EffectDeclaration { class ConditionalEffectDeclaration(val effect: EffectDeclaration, val condition: BooleanExpression) : EffectDeclaration {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data) contractDescriptionVisitor.visitConditionalEffectDeclaration(this, data)
} }
@@ -44,7 +44,7 @@ class ConditionalEffectDeclaration(val effect: EffectDeclaration, val condition:
*/ */
class ReturnsEffectDeclaration(val value: ConstantReference) : EffectDeclaration { class ReturnsEffectDeclaration(val value: ConstantReference) : EffectDeclaration {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data) contractDescriptionVisitor.visitReturnsEffectDeclaration(this, data)
} }
@@ -55,7 +55,7 @@ class ReturnsEffectDeclaration(val value: ConstantReference) : EffectDeclaration
*/ */
class CallsEffectDeclaration(val variableReference: VariableReference, val kind: InvocationKind) : EffectDeclaration { class CallsEffectDeclaration(val variableReference: VariableReference, val kind: InvocationKind) : EffectDeclaration {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitCallsEffectDeclaration(this, data) contractDescriptionVisitor.visitCallsEffectDeclaration(this, data)
} }
enum class InvocationKind { enum class InvocationKind {
@@ -46,7 +46,7 @@ class LazyContractProvider(private val computation: () -> Any?) : ContractProvid
companion object { companion object {
fun createInitialized(contract: ContractDescription?): LazyContractProvider = fun createInitialized(contract: ContractDescription?): LazyContractProvider =
LazyContractProvider({}).apply { setContractDescription(contract) } LazyContractProvider({}).apply { setContractDescription(contract) }
} }
} }
@@ -21,15 +21,15 @@ import org.jetbrains.kotlin.contracts.description.ContractDescriptionVisitor
class LogicalOr(val left: BooleanExpression, val right: BooleanExpression) : BooleanExpression { class LogicalOr(val left: BooleanExpression, val right: BooleanExpression) : BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitLogicalOr(this, data) contractDescriptionVisitor.visitLogicalOr(this, data)
} }
class LogicalAnd(val left: BooleanExpression, val right: BooleanExpression) : BooleanExpression { class LogicalAnd(val left: BooleanExpression, val right: BooleanExpression) : BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitLogicalAnd(this, data) contractDescriptionVisitor.visitLogicalAnd(this, data)
} }
class LogicalNot(val arg: BooleanExpression) : BooleanExpression { class LogicalNot(val arg: BooleanExpression) : BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitLogicalNot(this, data) contractDescriptionVisitor.visitLogicalNot(this, data)
} }
@@ -22,14 +22,14 @@ import org.jetbrains.kotlin.types.KotlinType
class IsInstancePredicate(val arg: VariableReference, val type: KotlinType, val isNegated: Boolean) : BooleanExpression { class IsInstancePredicate(val arg: VariableReference, val type: KotlinType, val isNegated: Boolean) : BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitIsInstancePredicate(this, data) contractDescriptionVisitor.visitIsInstancePredicate(this, data)
fun negated(): IsInstancePredicate = IsInstancePredicate(arg, type, isNegated.not()) fun negated(): IsInstancePredicate = IsInstancePredicate(arg, type, isNegated.not())
} }
class IsNullPredicate(val arg: VariableReference, val isNegated: Boolean) : BooleanExpression { class IsNullPredicate(val arg: VariableReference, val isNegated: Boolean) : BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitIsNullPredicate(this, data) contractDescriptionVisitor.visitIsNullPredicate(this, data)
fun negated(): IsNullPredicate = IsNullPredicate(arg, isNegated.not()) fun negated(): IsNullPredicate = IsNullPredicate(arg, isNegated.not())
} }
@@ -24,12 +24,12 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor
interface ContractDescriptionValue : ContractDescriptionElement { interface ContractDescriptionValue : ContractDescriptionElement {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitValue(this, data) contractDescriptionVisitor.visitValue(this, data)
} }
open class ConstantReference(val name: String) : ContractDescriptionValue { open class ConstantReference(val name: String) : ContractDescriptionValue {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitConstantDescriptor(this, data) contractDescriptionVisitor.visitConstantDescriptor(this, data)
companion object { companion object {
val NULL = ConstantReference("NULL") val NULL = ConstantReference("NULL")
@@ -40,7 +40,7 @@ open class ConstantReference(val name: String) : ContractDescriptionValue {
class BooleanConstantReference(name: String) : ConstantReference(name), BooleanExpression { class BooleanConstantReference(name: String) : ConstantReference(name), BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitBooleanConstantDescriptor(this, data) contractDescriptionVisitor.visitBooleanConstantDescriptor(this, data)
companion object { companion object {
val TRUE = BooleanConstantReference("TRUE") val TRUE = BooleanConstantReference("TRUE")
@@ -50,10 +50,10 @@ class BooleanConstantReference(name: String) : ConstantReference(name), BooleanE
open class VariableReference(val descriptor: ParameterDescriptor) : ContractDescriptionValue { open class VariableReference(val descriptor: ParameterDescriptor) : ContractDescriptionValue {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D) = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D) =
contractDescriptionVisitor.visitVariableReference(this, data) contractDescriptionVisitor.visitVariableReference(this, data)
} }
class BooleanVariableReference(descriptor: ParameterDescriptor) : VariableReference(descriptor), BooleanExpression { class BooleanVariableReference(descriptor: ParameterDescriptor) : VariableReference(descriptor), BooleanExpression {
override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R = override fun <R, D> accept(contractDescriptionVisitor: ContractDescriptionVisitor<R, D>, data: D): R =
contractDescriptionVisitor.visitBooleanVariableReference(this, data) contractDescriptionVisitor.visitBooleanVariableReference(this, data)
} }
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.functors.IsFunctor import org.jetbrains.kotlin.contracts.model.functors.IsFunctor
import org.jetbrains.kotlin.contracts.model.structure.* import org.jetbrains.kotlin.contracts.model.structure.*
internal class ConditionInterpreter(private val dispatcher: ContractInterpretationDispatcher) : ContractDescriptionVisitor<ESExpression?, Unit> { internal class ConditionInterpreter(private val dispatcher: ContractInterpretationDispatcher) :
ContractDescriptionVisitor<ESExpression?, Unit> {
override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit): ESExpression? { override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit): ESExpression? {
val left = logicalOr.left.accept(this, data) ?: return null val left = logicalOr.left.accept(this, data) ?: return null
val right = logicalOr.right.accept(this, data) ?: return null val right = logicalOr.right.accept(this, data) ?: return null
@@ -51,8 +52,8 @@ internal class ConditionInterpreter(private val dispatcher: ContractInterpretati
} }
override fun visitBooleanConstantDescriptor(booleanConstantDescriptor: BooleanConstantReference, data: Unit): ESExpression? = override fun visitBooleanConstantDescriptor(booleanConstantDescriptor: BooleanConstantReference, data: Unit): ESExpression? =
dispatcher.interpretConstant(booleanConstantDescriptor) dispatcher.interpretConstant(booleanConstantDescriptor)
override fun visitBooleanVariableReference(booleanVariableReference: BooleanVariableReference, data: Unit): ESExpression? = override fun visitBooleanVariableReference(booleanVariableReference: BooleanVariableReference, data: Unit): ESExpression? =
dispatcher.interpretVariable(booleanVariableReference) dispatcher.interpretVariable(booleanVariableReference)
} }
@@ -25,7 +25,7 @@ internal class ConstantValuesInterpreter {
fun interpretConstant(constantReference: ConstantReference): ESConstant? = when (constantReference) { fun interpretConstant(constantReference: ConstantReference): ESConstant? = when (constantReference) {
BooleanConstantReference.TRUE -> true.lift() BooleanConstantReference.TRUE -> true.lift()
BooleanConstantReference.FALSE -> false.lift() BooleanConstantReference.FALSE -> false.lift()
ConstantReference.NULL-> ESConstant.NULL ConstantReference.NULL -> ESConstant.NULL
ConstantReference.NOT_NULL -> ESConstant.NOT_NULL ConstantReference.NOT_NULL -> ESConstant.NOT_NULL
ConstantReference.WILDCARD -> ESConstant.WILDCARD ConstantReference.WILDCARD -> ESConstant.WILDCARD
else -> null else -> null
@@ -35,9 +35,10 @@ class ContractInterpretationDispatcher {
private val conditionInterpreter = ConditionInterpreter(this) private val conditionInterpreter = ConditionInterpreter(this)
private val conditionalEffectInterpreter = ConditionalEffectInterpreter(this) private val conditionalEffectInterpreter = ConditionalEffectInterpreter(this)
private val effectsInterpreters: List<EffectDeclarationInterpreter> = listOf( private val effectsInterpreters: List<EffectDeclarationInterpreter> = listOf(
ReturnsEffectInterpreter(this), ReturnsEffectInterpreter(this),
CallsEffectInterpreter(this) CallsEffectInterpreter(this)
) )
fun resolveFunctor(functionDescriptor: FunctionDescriptor): Functor? { fun resolveFunctor(functionDescriptor: FunctionDescriptor): Functor? {
val contractDescriptor = functionDescriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return null val contractDescriptor = functionDescriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return null
return convertContractDescriptorToFunctor(contractDescriptor) return convertContractDescriptorToFunctor(contractDescriptor)
@@ -47,8 +48,7 @@ class ContractInterpretationDispatcher {
val resultingClauses = contractDescription.effects.map { effect -> val resultingClauses = contractDescription.effects.map { effect ->
if (effect is ConditionalEffectDeclaration) { if (effect is ConditionalEffectDeclaration) {
conditionalEffectInterpreter.interpret(effect) ?: return null conditionalEffectInterpreter.interpret(effect) ?: return null
} } else {
else {
effectsInterpreters.mapNotNull { it.tryInterpret(effect) }.singleOrNull() ?: return null effectsInterpreters.mapNotNull { it.tryInterpret(effect) }.singleOrNull() ?: return null
} }
} }
@@ -62,10 +62,10 @@ class ContractInterpretationDispatcher {
} }
internal fun interpretConstant(constantReference: ConstantReference): ESConstant? = internal fun interpretConstant(constantReference: ConstantReference): ESConstant? =
constantsInterpreter.interpretConstant(constantReference) constantsInterpreter.interpretConstant(constantReference)
internal fun interpretCondition(booleanExpression: BooleanExpression): ESExpression? = internal fun interpretCondition(booleanExpression: BooleanExpression): ESExpression? =
booleanExpression.accept(conditionInterpreter, Unit) booleanExpression.accept(conditionInterpreter, Unit)
internal fun interpretVariable(variableReference: VariableReference): ESVariable? = ESVariable(variableReference.descriptor) internal fun interpretVariable(variableReference: VariableReference): ESVariable? = ESVariable(variableReference.descriptor)
} }
@@ -29,20 +29,20 @@ import org.jetbrains.kotlin.types.KotlinType
* Also, it's abstracted away from PSI * Also, it's abstracted away from PSI
*/ */
class MutableContextInfo private constructor( class MutableContextInfo private constructor(
val firedEffects: MutableList<ESEffect>, val firedEffects: MutableList<ESEffect>,
val subtypes: MutableMap<ESValue, MutableSet<KotlinType>>, val subtypes: MutableMap<ESValue, MutableSet<KotlinType>>,
val notSubtypes: MutableMap<ESValue, MutableSet<KotlinType>>, val notSubtypes: MutableMap<ESValue, MutableSet<KotlinType>>,
val equalValues: MutableMap<ESValue, MutableSet<ESValue>>, val equalValues: MutableMap<ESValue, MutableSet<ESValue>>,
val notEqualValues: MutableMap<ESValue, MutableSet<ESValue>> val notEqualValues: MutableMap<ESValue, MutableSet<ESValue>>
) { ) {
companion object { companion object {
val EMPTY: MutableContextInfo val EMPTY: MutableContextInfo
get() = MutableContextInfo( get() = MutableContextInfo(
firedEffects = mutableListOf(), firedEffects = mutableListOf(),
subtypes = mutableMapOf(), subtypes = mutableMapOf(),
notSubtypes = mutableMapOf(), notSubtypes = mutableMapOf(),
equalValues = mutableMapOf(), equalValues = mutableMapOf(),
notEqualValues = mutableMapOf() notEqualValues = mutableMapOf()
) )
} }
@@ -63,19 +63,19 @@ class MutableContextInfo private constructor(
fun fire(effect: ESEffect) = apply { firedEffects += effect } fun fire(effect: ESEffect) = apply { firedEffects += effect }
fun or(other: MutableContextInfo): MutableContextInfo = MutableContextInfo( fun or(other: MutableContextInfo): MutableContextInfo = MutableContextInfo(
firedEffects = firedEffects.intersect(other.firedEffects).toMutableList(), firedEffects = firedEffects.intersect(other.firedEffects).toMutableList(),
subtypes = subtypes.intersect(other.subtypes), subtypes = subtypes.intersect(other.subtypes),
notSubtypes = notSubtypes.intersect(other.notSubtypes), notSubtypes = notSubtypes.intersect(other.notSubtypes),
equalValues = equalValues.intersect(other.equalValues), equalValues = equalValues.intersect(other.equalValues),
notEqualValues = notEqualValues.intersect(other.notEqualValues) notEqualValues = notEqualValues.intersect(other.notEqualValues)
) )
fun and(other: MutableContextInfo): MutableContextInfo = MutableContextInfo( fun and(other: MutableContextInfo): MutableContextInfo = MutableContextInfo(
firedEffects = firedEffects.union(other.firedEffects).toMutableList(), firedEffects = firedEffects.union(other.firedEffects).toMutableList(),
subtypes = subtypes.union(other.subtypes), subtypes = subtypes.union(other.subtypes),
notSubtypes = notSubtypes.union(other.notSubtypes), notSubtypes = notSubtypes.union(other.notSubtypes),
equalValues = equalValues.union(other.equalValues), equalValues = equalValues.union(other.equalValues),
notEqualValues = notEqualValues.union(other.notEqualValues) notEqualValues = notEqualValues.union(other.notEqualValues)
) )
private fun <D> MutableMap<ESValue, MutableSet<D>>.intersect(that: MutableMap<ESValue, MutableSet<D>>): MutableMap<ESValue, MutableSet<D>> { private fun <D> MutableMap<ESValue, MutableSet<D>>.intersect(that: MutableMap<ESValue, MutableSet<D>>): MutableMap<ESValue, MutableSet<D>> {
@@ -120,7 +120,7 @@ class MutableContextInfo private constructor(
} }
append("Fired effects: ") append("Fired effects: ")
append(info.firedEffects.joinToString(separator = ", " )) append(info.firedEffects.joinToString(separator = ", "))
appendln("") appendln("")
subtypes.printMapEntriesWithSeparator("is") subtypes.printMapEntriesWithSeparator("is")
@@ -56,5 +56,8 @@ abstract class AbstractBinaryFunctor : AbstractReducingFunctor() {
} }
protected abstract fun invokeWithConstant(computation: Computation, constant: ESConstant): List<ESEffect> protected abstract fun invokeWithConstant(computation: Computation, constant: ESConstant): List<ESEffect>
protected abstract fun invokeWithReturningEffects(left: List<ConditionalEffect>, right: List<ConditionalEffect>): List<ConditionalEffect> protected abstract fun invokeWithReturningEffects(
left: List<ConditionalEffect>,
right: List<ConditionalEffect>
): List<ConditionalEffect>
} }
@@ -30,5 +30,5 @@ abstract class AbstractReducingFunctor : Functor {
override fun invokeWithArguments(arguments: List<Computation>): List<ESEffect> = reducer.reduceEffects(doInvocation(arguments)) override fun invokeWithArguments(arguments: List<Computation>): List<ESEffect> = reducer.reduceEffects(doInvocation(arguments))
abstract protected fun doInvocation(arguments: List<Computation>): List<ESEffect> protected abstract fun doInvocation(arguments: List<Computation>): List<ESEffect>
} }
@@ -30,7 +30,7 @@ class AndFunctor : AbstractBinaryFunctor() {
ESConstant.TRUE -> computation.effects ESConstant.TRUE -> computation.effects
ESConstant.FALSE -> emptyList() ESConstant.FALSE -> emptyList()
// This means that expression isn't typechecked properly // This means that expression isn't typechecked properly
else -> computation.effects else -> computation.effects
} }
@@ -84,7 +84,11 @@ class EqualsFunctor(val isNegated: Boolean) : AbstractReducingFunctor() {
resultingClauses.add(trueClause) resultingClauses.add(trueClause)
} }
if (effect.simpleEffect.value != constant && effect.simpleEffect.value is ESConstant && isSafeToProduceFalse(call, effect.simpleEffect.value, constant)) { if (effect.simpleEffect.value != constant && effect.simpleEffect.value is ESConstant && isSafeToProduceFalse(
call,
effect.simpleEffect.value,
constant
)) {
val falseClause = ConditionalEffect(effect.condition, ESReturns(isNegated.lift())) val falseClause = ConditionalEffect(effect.condition, ESReturns(isNegated.lift()))
resultingClauses.add(falseClause) resultingClauses.add(falseClause)
} }
@@ -96,10 +100,10 @@ class EqualsFunctor(val isNegated: Boolean) : AbstractReducingFunctor() {
// It is safe to produce false if we're comparing types which are isomorphic to Boolean. For such types we can be sure, that // It is safe to produce false if we're comparing types which are isomorphic to Boolean. For such types we can be sure, that
// if leftConstant != rightConstant, then this is the only way to produce 'false'. // if leftConstant != rightConstant, then this is the only way to produce 'false'.
private fun isSafeToProduceFalse(leftCall: Computation, leftConstant: ESConstant, rightConstant: ESConstant): Boolean = when { private fun isSafeToProduceFalse(leftCall: Computation, leftConstant: ESConstant, rightConstant: ESConstant): Boolean = when {
// Comparison of Boolean // Comparison of Boolean
KotlinBuiltIns.isBoolean(rightConstant.type) && leftCall.type != null && KotlinBuiltIns.isBoolean(leftCall.type!!) -> true KotlinBuiltIns.isBoolean(rightConstant.type) && leftCall.type != null && KotlinBuiltIns.isBoolean(leftCall.type!!) -> true
// Comparison of NULL/NOT_NULL, which is essentially Boolean // Comparison of NULL/NOT_NULL, which is essentially Boolean
leftConstant.isNullConstant() && rightConstant.isNullConstant() -> true leftConstant.isNullConstant() && rightConstant.isNullConstant() -> true
else -> false else -> false
@@ -107,8 +111,8 @@ class EqualsFunctor(val isNegated: Boolean) : AbstractReducingFunctor() {
private fun equateValues(left: ESValue, right: ESValue): List<ESEffect> { private fun equateValues(left: ESValue, right: ESValue): List<ESEffect> {
return listOf( return listOf(
ConditionalEffect(ESEqual(left, right, isNegated), ESReturns(true.lift())), ConditionalEffect(ESEqual(left, right, isNegated), ESReturns(true.lift())),
ConditionalEffect(ESEqual(left, right, isNegated.not()), ESReturns(false.lift())) ConditionalEffect(ESEqual(left, right, isNegated.not()), ESReturns(false.lift()))
) )
} }
} }
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.contracts.model.ESExpression
* Applies [operation] to [first] and [second] if both not-null, otherwise returns null * Applies [operation] to [first] and [second] if both not-null, otherwise returns null
*/ */
internal fun <F, S, R> applyIfBothNotNull(first: F?, second: S?, operation: (F, S) -> R): R? = internal fun <F, S, R> applyIfBothNotNull(first: F?, second: S?, operation: (F, S) -> R): R? =
if (first == null || second == null) null else operation(first, second) if (first == null || second == null) null else operation(first, second)
/** /**
* If both [first] and [second] are null, then return null * If both [first] and [second] are null, then return null
@@ -40,15 +40,18 @@ internal fun <F : R, S : R, R> applyWithDefault(first: F?, second: S?, operation
} }
internal fun foldConditionsWithOr(list: List<ConditionalEffect>): ESExpression? = internal fun foldConditionsWithOr(list: List<ConditionalEffect>): ESExpression? =
if (list.isEmpty()) if (list.isEmpty())
null null
else else
list.map { it.condition }.reduce { acc, condition -> ESOr(acc, condition) } list.map { it.condition }.reduce { acc, condition -> ESOr(acc, condition) }
/** /**
* Places all clauses that equal to `firstModel` into first list, and all clauses that equal to `secondModel` into second list * Places all clauses that equal to `firstModel` into first list, and all clauses that equal to `secondModel` into second list
*/ */
internal fun List<ConditionalEffect>.strictPartition(firstModel: ESEffect, secondModel: ESEffect): Pair<List<ConditionalEffect>, List<ConditionalEffect>> { internal fun List<ConditionalEffect>.strictPartition(
firstModel: ESEffect,
secondModel: ESEffect
): Pair<List<ConditionalEffect>, List<ConditionalEffect>> {
val first = mutableListOf<ConditionalEffect>() val first = mutableListOf<ConditionalEffect>()
val second = mutableListOf<ConditionalEffect>() val second = mutableListOf<ConditionalEffect>()
@@ -30,7 +30,7 @@ class OrFunctor : AbstractBinaryFunctor() {
ESConstant.FALSE -> computation.effects ESConstant.FALSE -> computation.effects
ESConstant.TRUE -> emptyList() ESConstant.TRUE -> emptyList()
// This means that expression isn't typechecked properly // This means that expression isn't typechecked properly
else -> computation.effects else -> computation.effects
} }
@@ -30,11 +30,13 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
class SubstitutingFunctor(private val basicEffects: List<ESEffect>, private val ownerFunction: FunctionDescriptor) : AbstractReducingFunctor() { class SubstitutingFunctor(private val basicEffects: List<ESEffect>, private val ownerFunction: FunctionDescriptor) :
AbstractReducingFunctor() {
override fun doInvocation(arguments: List<Computation>): List<ESEffect> { override fun doInvocation(arguments: List<Computation>): List<ESEffect> {
if (basicEffects.isEmpty()) return emptyList() if (basicEffects.isEmpty()) return emptyList()
val receiver = listOfNotNull(ownerFunction.dispatchReceiverParameter?.toESVariable(), ownerFunction.extensionReceiverParameter?.toESVariable()) val receiver =
listOfNotNull(ownerFunction.dispatchReceiverParameter?.toESVariable(), ownerFunction.extensionReceiverParameter?.toESVariable())
val parameters = receiver + ownerFunction.valueParameters.map { it.toESVariable() } val parameters = receiver + ownerFunction.valueParameters.map { it.toESVariable() }
assert(parameters.size == arguments.size) { assert(parameters.size == arguments.size) {
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.ESValue import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.SimpleEffect import org.jetbrains.kotlin.contracts.model.SimpleEffect
data class ESCalls(val callable: ESValue, val kind: InvocationKind): SimpleEffect() { data class ESCalls(val callable: ESValue, val kind: InvocationKind) : SimpleEffect() {
override fun isImplies(other: ESEffect): Boolean? { override fun isImplies(other: ESEffect): Boolean? {
if (other !is ESCalls) return null if (other !is ESCalls) return null
@@ -33,7 +33,7 @@ data class ESCalls(val callable: ESValue, val kind: InvocationKind): SimpleEffec
} }
data class ESReturns(val value: ESValue): SimpleEffect() { data class ESReturns(val value: ESValue) : SimpleEffect() {
override fun isImplies(other: ESEffect): Boolean? { override fun isImplies(other: ESEffect): Boolean? {
if (other !is ESReturns) return null if (other !is ESReturns) return null
@@ -22,28 +22,28 @@ import org.jetbrains.kotlin.contracts.model.ESOperator
import org.jetbrains.kotlin.contracts.model.ESValue import org.jetbrains.kotlin.contracts.model.ESValue
import org.jetbrains.kotlin.contracts.model.functors.* import org.jetbrains.kotlin.contracts.model.functors.*
class ESAnd(val left: ESExpression, val right: ESExpression): ESOperator { class ESAnd(val left: ESExpression, val right: ESExpression) : ESOperator {
override val functor: AndFunctor = AndFunctor() override val functor: AndFunctor = AndFunctor()
override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitAnd(this) override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitAnd(this)
} }
class ESOr(val left: ESExpression, val right: ESExpression): ESOperator { class ESOr(val left: ESExpression, val right: ESExpression) : ESOperator {
override val functor: OrFunctor = OrFunctor() override val functor: OrFunctor = OrFunctor()
override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitOr(this) override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitOr(this)
} }
class ESNot(val arg: ESExpression): ESOperator { class ESNot(val arg: ESExpression) : ESOperator {
override val functor = NotFunctor() override val functor = NotFunctor()
override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitNot(this) override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitNot(this)
} }
class ESIs(val left: ESValue, override val functor: IsFunctor): ESOperator { class ESIs(val left: ESValue, override val functor: IsFunctor) : ESOperator {
val type = functor.type val type = functor.type
override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitIs(this) override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitIs(this)
} }
class ESEqual(val left: ESValue, val right: ESValue, isNegated: Boolean): ESOperator { class ESEqual(val left: ESValue, val right: ESValue, isNegated: Boolean) : ESOperator {
override val functor: EqualsFunctor = EqualsFunctor(isNegated) override val functor: EqualsFunctor = EqualsFunctor(isNegated)
override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitEqual(this) override fun <T> accept(visitor: ESExpressionVisitor<T>): T = visitor.visitEqual(this)
} }
@@ -24,7 +24,9 @@ class InfoCollector(private val observedEffect: ESEffect) : ESExpressionVisitor<
private var isInverted: Boolean = false private var isInverted: Boolean = false
fun collectFromSchema(schema: List<ESEffect>): MutableContextInfo = fun collectFromSchema(schema: List<ESEffect>): MutableContextInfo =
schema.mapNotNull { collectFromEffect(it) }.fold(MutableContextInfo.EMPTY, { resultingInfo, clauseInfo -> resultingInfo.and(clauseInfo) }) schema.mapNotNull { collectFromEffect(it) }.fold(
MutableContextInfo.EMPTY,
{ resultingInfo, clauseInfo -> resultingInfo.and(clauseInfo) })
private fun collectFromEffect(effect: ESEffect): MutableContextInfo? { private fun collectFromEffect(effect: ESEffect): MutableContextInfo? {
if (effect !is ConditionalEffect) { if (effect !is ConditionalEffect) {
@@ -33,16 +35,19 @@ class InfoCollector(private val observedEffect: ESEffect) : ESExpressionVisitor<
// Check for information from conditional effects // Check for information from conditional effects
return when (observedEffect.isImplies(effect.simpleEffect)) { return when (observedEffect.isImplies(effect.simpleEffect)) {
// observed effect implies clause's effect => clause's effect was fired => clause's condition is true // observed effect implies clause's effect => clause's effect was fired => clause's condition is true
true -> effect.condition.accept(this) true -> effect.condition.accept(this)
// Observed effect *may* or *doesn't* implies clause's - no useful information // Observed effect *may* or *doesn't* implies clause's - no useful information
null, false -> null null, false -> null
} }
} }
override fun visitIs(isOperator: ESIs): MutableContextInfo = with(isOperator) { override fun visitIs(isOperator: ESIs): MutableContextInfo = with(isOperator) {
if (functor.isNegated != isInverted) MutableContextInfo.EMPTY.notSubtype(left, type) else MutableContextInfo.EMPTY.subtype(left, type) if (functor.isNegated != isInverted) MutableContextInfo.EMPTY.notSubtype(left, type) else MutableContextInfo.EMPTY.subtype(
left,
type
)
} }
override fun visitEqual(equal: ESEqual): MutableContextInfo = with(equal) { override fun visitEqual(equal: ESEqual): MutableContextInfo = with(equal) {
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
*/ */
class Reducer : ESExpressionVisitor<ESExpression?> { class Reducer : ESExpressionVisitor<ESExpression?> {
fun reduceEffects(schema: List<ESEffect>): List<ESEffect> = fun reduceEffects(schema: List<ESEffect>): List<ESEffect> =
schema.mapNotNull { reduceEffect(it) } schema.mapNotNull { reduceEffect(it) }
private fun reduceEffect(effect: ESEffect): ESEffect? { private fun reduceEffect(effect: ESEffect): ESEffect? {
when (effect) { when (effect) {
@@ -54,8 +54,7 @@ class Substitutor(private val substitutions: Map<ESVariable, Computation>) : ESE
return CallComputation(DefaultBuiltIns.Instance.booleanType, or.functor.invokeWithArguments(left, right)) return CallComputation(DefaultBuiltIns.Instance.booleanType, or.functor.invokeWithArguments(left, right))
} }
override fun visitVariable(esVariable: ESVariable): Computation? override fun visitVariable(esVariable: ESVariable): Computation? = substitutions[esVariable] ?: esVariable
= substitutions[esVariable] ?: esVariable
override fun visitConstant(esConstant: ESConstant): Computation? = esConstant override fun visitConstant(esConstant: ESConstant): Computation? = esConstant
} }
@@ -28,29 +28,35 @@ import java.lang.UnsupportedOperationException
class KotlinCallResolver( class KotlinCallResolver(
private val towerResolver: TowerResolver, private val towerResolver: TowerResolver,
private val kotlinCallCompleter: KotlinCallCompleter, private val kotlinCallCompleter: KotlinCallCompleter,
private val overloadingConflictResolver: NewOverloadingConflictResolver, private val overloadingConflictResolver: NewOverloadingConflictResolver,
private val callComponents: KotlinCallComponents private val callComponents: KotlinCallComponents
) { ) {
fun resolveCall( fun resolveCall(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>, factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>,
collectAllCandidates: Boolean collectAllCandidates: Boolean
): CallResolutionResult { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
val processor = when(kotlinCall.callKind) { val processor = when (kotlinCall.callKind) {
KotlinCallKind.VARIABLE -> { KotlinCallKind.VARIABLE -> {
createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver) createVariableAndObjectProcessor(scopeTower, kotlinCall.name, candidateFactory, kotlinCall.explicitReceiver?.receiver)
} }
KotlinCallKind.FUNCTION -> { KotlinCallKind.FUNCTION -> {
createFunctionProcessor(scopeTower, kotlinCall.name, candidateFactory, factoryProviderForInvoke, kotlinCall.explicitReceiver?.receiver) createFunctionProcessor(
scopeTower,
kotlinCall.name,
candidateFactory,
factoryProviderForInvoke,
kotlinCall.explicitReceiver?.receiver
)
} }
KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException() KotlinCallKind.UNSUPPORTED -> throw UnsupportedOperationException()
} }
@@ -60,18 +66,23 @@ class KotlinCallResolver(
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks) return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
} }
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED, name = kotlinCall.name) val candidates = towerResolver.runResolve(
scopeTower,
processor,
useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED,
name = kotlinCall.name
)
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
} }
fun resolveGivenCandidates( fun resolveGivenCandidates(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
givenCandidates: Collection<GivenCandidate>, givenCandidates: Collection<GivenCandidate>,
collectAllCandidates: Boolean collectAllCandidates: Boolean
): CallResolutionResult { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
@@ -79,23 +90,27 @@ class KotlinCallResolver(
val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() } val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
if (collectAllCandidates) { if (collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), val allCandidates = towerResolver.runWithEmptyTowerData(
TowerResolver.AllCandidatesCollector(), KnownResultProcessor(resolutionCandidates),
useOrder = false) TowerResolver.AllCandidatesCollector(),
useOrder = false
)
return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks) return kotlinCallCompleter.createAllCandidatesResult(allCandidates, expectedType, resolutionCallbacks)
} }
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), val candidates = towerResolver.runWithEmptyTowerData(
TowerResolver.SuccessfulResultCollector(), KnownResultProcessor(resolutionCandidates),
useOrder = true) TowerResolver.SuccessfulResultCollector(),
useOrder = true
)
return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
} }
private fun choseMostSpecific( private fun choseMostSpecific(
candidateFactory: SimpleCandidateFactory, candidateFactory: SimpleCandidateFactory,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
candidates: Collection<KotlinResolutionCandidate> candidates: Collection<KotlinResolutionCandidate>
): CallResolutionResult { ): CallResolutionResult {
val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext
@@ -108,10 +123,11 @@ class KotlinCallResolver(
} }
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates( val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
refinedCandidates, refinedCandidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
discriminateGenerics = true, // todo discriminateGenerics = true, // todo
isDebuggerContext = isDebuggerContext) isDebuggerContext = isDebuggerContext
)
return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks) return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
} }
@@ -89,7 +89,7 @@ object NewCommonSuperTypeCalculator {
private fun commonSuperTypeForNotNullTypes(types: List<SimpleType>, depth: Int): SimpleType { private fun commonSuperTypeForNotNullTypes(types: List<SimpleType>, depth: Int): SimpleType {
val uniqueTypes = types.uniquify() val uniqueTypes = types.uniquify()
val filteredType = uniqueTypes.filterNot { type -> val filteredType = uniqueTypes.filterNot { type ->
uniqueTypes.any { other -> type != other && NewKotlinTypeChecker.isSubtypeOf(type, other)} uniqueTypes.any { other -> type != other && NewKotlinTypeChecker.isSubtypeOf(type, other) }
} }
// seems like all types are equal // seems like all types are equal
if (filteredType.isEmpty()) return uniqueTypes.first() if (filteredType.isEmpty()) return uniqueTypes.first()
@@ -125,11 +125,16 @@ object NewCommonSuperTypeCalculator {
} }
private fun superTypeWithGivenConstructor( private fun superTypeWithGivenConstructor(
types: List<SimpleType>, types: List<SimpleType>,
constructor: TypeConstructor, constructor: TypeConstructor,
depth: Int depth: Int
): SimpleType { ): SimpleType {
if (constructor.parameters.isEmpty()) return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, emptyList(), nullable = false) if (constructor.parameters.isEmpty()) return KotlinTypeFactory.simpleType(
Annotations.EMPTY,
constructor,
emptyList(),
nullable = false
)
val typeCheckerContext = TypeCheckerContext(false) val typeCheckerContext = TypeCheckerContext(false)
@@ -158,12 +163,11 @@ object NewCommonSuperTypeCalculator {
} }
val argument = val argument =
if (thereIsStar || typeProjections.isEmpty()) { if (thereIsStar || typeProjections.isEmpty()) {
StarProjectionImpl(parameter) StarProjectionImpl(parameter)
} } else {
else { calculateArgument(parameter, typeProjections, depth)
calculateArgument(parameter, typeProjections, depth) }
}
arguments.add(argument) arguments.add(argument)
} }
@@ -185,20 +189,17 @@ object NewCommonSuperTypeCalculator {
val asOut: Boolean val asOut: Boolean
if (parameter.variance != Variance.INVARIANT) { if (parameter.variance != Variance.INVARIANT) {
asOut = parameter.variance == Variance.OUT_VARIANCE asOut = parameter.variance == Variance.OUT_VARIANCE
} } else {
else {
val thereIsOut = arguments.any { it.projectionKind == Variance.OUT_VARIANCE } val thereIsOut = arguments.any { it.projectionKind == Variance.OUT_VARIANCE }
val thereIsIn = arguments.any { it.projectionKind == Variance.IN_VARIANCE } val thereIsIn = arguments.any { it.projectionKind == Variance.IN_VARIANCE }
if (thereIsOut) { if (thereIsOut) {
if (thereIsIn) { if (thereIsIn) {
// CS(Inv<out X>, Inv<in Y>) = Inv<*> // CS(Inv<out X>, Inv<in Y>) = Inv<*>
return StarProjectionImpl(parameter) return StarProjectionImpl(parameter)
} } else {
else {
asOut = true asOut = true
} }
} } else {
else {
asOut = !thereIsIn asOut = !thereIsIn
} }
} }
@@ -207,11 +208,16 @@ object NewCommonSuperTypeCalculator {
// CS(In<X>, In<Y>) = In<X & Y> // CS(In<X>, In<Y>) = In<X & Y>
if (asOut) { if (asOut) {
val type = commonSuperType(arguments.map { it.type.unwrap() }, depth + 1) val type = commonSuperType(arguments.map { it.type.unwrap() }, depth + 1)
return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(Variance.OUT_VARIANCE, type) return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(
} Variance.OUT_VARIANCE,
else { type
)
} else {
val type = intersectTypes(arguments.map { it.type.unwrap() }) val type = intersectTypes(arguments.map { it.type.unwrap() })
return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(Variance.IN_VARIANCE, type) return if (parameter.variance != Variance.INVARIANT) return type.asTypeProjection() else TypeProjectionImpl(
Variance.IN_VARIANCE,
type
)
} }
} }
} }
@@ -29,18 +29,18 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
class AdditionalDiagnosticReporter(private val languageVersionSettings: LanguageVersionSettings) { class AdditionalDiagnosticReporter(private val languageVersionSettings: LanguageVersionSettings) {
fun reportAdditionalDiagnostics( fun reportAdditionalDiagnostics(
candidate: ResolvedCallAtom, candidate: ResolvedCallAtom,
resultingDescriptor: CallableDescriptor, resultingDescriptor: CallableDescriptor,
kotlinDiagnosticsHolder: KotlinDiagnosticsHolder, kotlinDiagnosticsHolder: KotlinDiagnosticsHolder,
diagnostics: Collection<KotlinCallDiagnostic> diagnostics: Collection<KotlinCallDiagnostic>
) { ) {
reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder, diagnostics) reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder, diagnostics)
} }
private fun createSmartCastDiagnostic( private fun createSmartCastDiagnostic(
candidate: ResolvedCallAtom, candidate: ResolvedCallAtom,
argument: KotlinCallArgument, argument: KotlinCallArgument,
expectedResultType: UnwrappedType expectedResultType: UnwrappedType
): SmartCastDiagnostic? { ): SmartCastDiagnostic? {
if (argument !is ExpressionKotlinCallArgument) return null if (argument !is ExpressionKotlinCallArgument) return null
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) { if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(argument.receiver.receiverValue.type, expectedResultType)) {
@@ -50,10 +50,10 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language
} }
private fun reportSmartCastOnReceiver( private fun reportSmartCastOnReceiver(
candidate: ResolvedCallAtom, candidate: ResolvedCallAtom,
receiver: SimpleKotlinCallArgument?, receiver: SimpleKotlinCallArgument?,
parameter: ReceiverParameterDescriptor?, parameter: ReceiverParameterDescriptor?,
diagnostics: Collection<KotlinCallDiagnostic> diagnostics: Collection<KotlinCallDiagnostic>
): SmartCastDiagnostic? { ): SmartCastDiagnostic? {
if (receiver == null || parameter == null) return null if (receiver == null || parameter == null) return null
val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it } val expectedType = parameter.type.unwrap().let { if (receiver.isSafeCall) it.makeNullableAsSpecified(true) else it }
@@ -65,24 +65,34 @@ class AdditionalDiagnosticReporter(private val languageVersionSettings: Language
diagnostics.filterIsInstance<UnsafeCallError>().none { diagnostics.filterIsInstance<UnsafeCallError>().none {
it.receiver == receiver it.receiver == receiver
} }
&& &&
diagnostics.filterIsInstance<UnstableSmartCast>().none { diagnostics.filterIsInstance<UnstableSmartCast>().none {
it.argument == receiver it.argument == receiver
} }
} }
} }
private fun reportSmartCasts( private fun reportSmartCasts(
candidate: ResolvedCallAtom, candidate: ResolvedCallAtom,
resultingDescriptor: CallableDescriptor, resultingDescriptor: CallableDescriptor,
kotlinDiagnosticsHolder: KotlinDiagnosticsHolder, kotlinDiagnosticsHolder: KotlinDiagnosticsHolder,
diagnostics: Collection<KotlinCallDiagnostic> diagnostics: Collection<KotlinCallDiagnostic>
) { ) {
kotlinDiagnosticsHolder.addDiagnosticIfNotNull( kotlinDiagnosticsHolder.addDiagnosticIfNotNull(
reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter, diagnostics) reportSmartCastOnReceiver(
candidate,
candidate.extensionReceiverArgument,
resultingDescriptor.extensionReceiverParameter,
diagnostics
)
) )
kotlinDiagnosticsHolder.addDiagnosticIfNotNull( kotlinDiagnosticsHolder.addDiagnosticIfNotNull(
reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter, diagnostics) reportSmartCastOnReceiver(
candidate,
candidate.dispatchReceiverArgument,
resultingDescriptor.dispatchReceiverParameter,
diagnostics
)
) )
for (parameter in resultingDescriptor.valueParameters) { for (parameter in resultingDescriptor.valueParameters) {
@@ -27,29 +27,28 @@ import java.util.*
class ArgumentsToParametersMapper { class ArgumentsToParametersMapper {
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) {}
// foo(b = bar(), a = qux()) // foo(b = bar(), a = qux())
// parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ] // parameterToCallArgumentMap.values() should be [ 'bar()', 'foo()' ]
val parameterToCallArgumentMap: Map<ValueParameterDescriptor, ResolvedCallArgument>, val parameterToCallArgumentMap: Map<ValueParameterDescriptor, ResolvedCallArgument>,
val diagnostics: List<KotlinCallDiagnostic> val diagnostics: List<KotlinCallDiagnostic>
) )
val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList()) val EmptyArgumentMapping = ArgumentMapping(emptyMap(), emptyList())
fun mapArguments(call: KotlinCall, descriptor: CallableDescriptor): ArgumentMapping = fun mapArguments(call: KotlinCall, descriptor: CallableDescriptor): ArgumentMapping =
mapArguments(call.argumentsInParenthesis, call.externalArgument, descriptor) mapArguments(call.argumentsInParenthesis, call.externalArgument, descriptor)
fun mapArguments( fun mapArguments(
argumentsInParenthesis: List<KotlinCallArgument>, argumentsInParenthesis: List<KotlinCallArgument>,
externalArgument: KotlinCallArgument?, externalArgument: KotlinCallArgument?,
descriptor: CallableDescriptor descriptor: CallableDescriptor
): ArgumentMapping { ): ArgumentMapping {
// optimization for case of variable // optimization for case of variable
if (argumentsInParenthesis.isEmpty() && externalArgument == null && descriptor.valueParameters.isEmpty()) { if (argumentsInParenthesis.isEmpty() && externalArgument == null && descriptor.valueParameters.isEmpty()) {
return EmptyArgumentMapping return EmptyArgumentMapping
} } else {
else {
val processor = CallArgumentProcessor(descriptor) val processor = CallArgumentProcessor(descriptor)
processor.processArgumentsInParenthesis(argumentsInParenthesis) processor.processArgumentsInParenthesis(argumentsInParenthesis)
@@ -171,8 +170,7 @@ class ArgumentsToParametersMapper {
return valueParameter return valueParameter
} }
} }
} } else {
else {
parameter.getOverriddenParameterWithOtherName()?.let { parameter.getOverriddenParameterWithOtherName()?.let {
addDiagnostic(NameForAmbiguousParameter(argument, parameter, it)) addDiagnostic(NameForAmbiguousParameter(argument, parameter, it))
} }
@@ -237,8 +235,7 @@ class ArgumentsToParametersMapper {
if (!parameter.isVararg) { if (!parameter.isVararg) {
if (resolvedArgument !is ResolvedCallArgument.SimpleArgument) { if (resolvedArgument !is ResolvedCallArgument.SimpleArgument) {
error("Incorrect resolved argument for parameter $parameter :$resolvedArgument") error("Incorrect resolved argument for parameter $parameter :$resolvedArgument")
} } else {
else {
if (resolvedArgument.callArgument.isSpread) { if (resolvedArgument.callArgument.isSpread) {
addDiagnostic(NonVarargSpread(resolvedArgument.callArgument)) addDiagnostic(NonVarargSpread(resolvedArgument.callArgument))
} }
@@ -250,11 +247,9 @@ class ArgumentsToParametersMapper {
if (!result.containsKey(parameter.original)) { if (!result.containsKey(parameter.original)) {
if (parameter.hasDefaultValue()) { if (parameter.hasDefaultValue()) {
result[parameter.original] = ResolvedCallArgument.DefaultArgument result[parameter.original] = ResolvedCallArgument.DefaultArgument
} } else if (parameter.isVararg) {
else if (parameter.isVararg) {
result[parameter.original] = ResolvedCallArgument.VarargArgument(emptyList()) result[parameter.original] = ResolvedCallArgument.VarargArgument(emptyList())
} } else {
else {
addDiagnostic(NoValueForParameter(parameter, descriptor)) addDiagnostic(NoValueForParameter(parameter, descriptor))
} }
} }
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing = internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing =
error("Unexpected argument type: $argument, ${argument.javaClass.canonicalName}.") error("Unexpected argument type: $argument, ${argument.javaClass.canonicalName}.")
// if expression is not stable and has smart casts, then we create this type // if expression is not stable and has smart casts, then we create this type
internal val ReceiverValueWithSmartCastInfo.unstableType: UnwrappedType? internal val ReceiverValueWithSmartCastInfo.unstableType: UnwrappedType?
@@ -49,19 +49,18 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
} }
internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor, languageVersionSettings: LanguageVersionSettings) = internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor, languageVersionSettings: LanguageVersionSettings) =
if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) { if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
parameter.type.unwrap() parameter.type.unwrap()
} } else {
else { parameter.safeAs<ValueParameterDescriptor>()?.varargElementType?.unwrap() ?: parameter.type.unwrap()
parameter.safeAs<ValueParameterDescriptor>()?.varargElementType?.unwrap() ?: parameter.type.unwrap() }
}
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
val ParameterDescriptor.isVararg: Boolean get() = this.safeAs<ValueParameterDescriptor>()?.isVararg ?: false val ParameterDescriptor.isVararg: Boolean get() = this.safeAs<ValueParameterDescriptor>()?.isVararg ?: false
private fun KotlinCallArgument.isArrayAssignedAsNamedArgumentInAnnotation( private fun KotlinCallArgument.isArrayAssignedAsNamedArgumentInAnnotation(
parameter: ParameterDescriptor, parameter: ParameterDescriptor,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
): Boolean { ): Boolean {
if (!languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false if (!languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
@@ -46,7 +46,8 @@ sealed class CallableReceiver(val receiver: ReceiverValueWithSmartCastInfo) {
class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) class UnboundReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) class BoundValueReference(val qualifier: QualifierReceiver, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) class ScopeReceiver(receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver)
class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) : CallableReceiver(receiver) class ExplicitValueReceiver(val lhsArgument: SimpleKotlinCallArgument, receiver: ReceiverValueWithSmartCastInfo) :
CallableReceiver(receiver)
} }
// todo investigate similar code in CheckVisibility // todo investigate similar code in CheckVisibility
@@ -62,13 +63,13 @@ private val CallableReceiver.asReceiverValueForVisibilityChecks: ReceiverValue
* For class B with companion object B::companionM dispatchReceiver = BoundValueReference * For class B with companion object B::companionM dispatchReceiver = BoundValueReference
*/ */
class CallableReferenceCandidate( class CallableReferenceCandidate(
val candidate: CallableDescriptor, val candidate: CallableDescriptor,
val dispatchReceiver: CallableReceiver?, val dispatchReceiver: CallableReceiver?,
val extensionReceiver: CallableReceiver?, val extensionReceiver: CallableReceiver?,
val explicitReceiverKind: ExplicitReceiverKind, val explicitReceiverKind: ExplicitReceiverKind,
val reflectionCandidateType: UnwrappedType, val reflectionCandidateType: UnwrappedType,
val numDefaults: Int, val numDefaults: Int,
val diagnostics: List<KotlinCallDiagnostic> val diagnostics: List<KotlinCallDiagnostic>
) : Candidate { ) : Candidate {
override val resultingApplicability = getResultApplicability(diagnostics) override val resultingApplicability = getResultApplicability(diagnostics)
override val isSuccessful get() = resultingApplicability.isSuccess override val isSuccessful get() = resultingApplicability.isSuccess
@@ -113,13 +114,13 @@ fun createCallableReferenceProcessor(factory: CallableReferencesCandidateFactory
} }
fun ConstraintSystemOperation.checkCallableReference( fun ConstraintSystemOperation.checkCallableReference(
argument: CallableReferenceKotlinCallArgument, argument: CallableReferenceKotlinCallArgument,
dispatchReceiver: CallableReceiver?, dispatchReceiver: CallableReceiver?,
extensionReceiver: CallableReceiver?, extensionReceiver: CallableReceiver?,
candidateDescriptor: CallableDescriptor, candidateDescriptor: CallableDescriptor,
reflectionCandidateType: UnwrappedType, reflectionCandidateType: UnwrappedType,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
ownerDescriptor: DeclarationDescriptor ownerDescriptor: DeclarationDescriptor
): Pair<FreshVariableNewTypeSubstitutor, KotlinCallDiagnostic?> { ): Pair<FreshVariableNewTypeSubstitutor, KotlinCallDiagnostic?> {
val position = ArgumentConstraintPosition(argument) val position = ArgumentConstraintPosition(argument)
@@ -132,17 +133,19 @@ fun ConstraintSystemOperation.checkCallableReference(
addReceiverConstraint(toFreshSubstitutor, dispatchReceiver, candidateDescriptor.dispatchReceiverParameter, position) addReceiverConstraint(toFreshSubstitutor, dispatchReceiver, candidateDescriptor.dispatchReceiverParameter, position)
addReceiverConstraint(toFreshSubstitutor, extensionReceiver, candidateDescriptor.extensionReceiverParameter, position) addReceiverConstraint(toFreshSubstitutor, extensionReceiver, candidateDescriptor.extensionReceiverParameter, position)
val invisibleMember = Visibilities.findInvisibleMember(dispatchReceiver?.asReceiverValueForVisibilityChecks, val invisibleMember = Visibilities.findInvisibleMember(
candidateDescriptor, ownerDescriptor) dispatchReceiver?.asReceiverValueForVisibilityChecks,
candidateDescriptor, ownerDescriptor
)
return toFreshSubstitutor to invisibleMember?.let(::VisibilityError) return toFreshSubstitutor to invisibleMember?.let(::VisibilityError)
} }
private fun ConstraintSystemOperation.addReceiverConstraint( private fun ConstraintSystemOperation.addReceiverConstraint(
toFreshSubstitutor: FreshVariableNewTypeSubstitutor, toFreshSubstitutor: FreshVariableNewTypeSubstitutor,
receiverArgument: CallableReceiver?, receiverArgument: CallableReceiver?,
receiverParameter: ReceiverParameterDescriptor?, receiverParameter: ReceiverParameterDescriptor?,
position: ArgumentConstraintPosition position: ArgumentConstraintPosition
) { ) {
if (receiverArgument == null || receiverParameter == null) { if (receiverArgument == null || receiverParameter == null) {
assert(receiverArgument == null) { "Receiver argument should be null if parameter is: $receiverArgument" } assert(receiverArgument == null) { "Receiver argument should be null if parameter is: $receiverArgument" }
@@ -156,41 +159,45 @@ private fun ConstraintSystemOperation.addReceiverConstraint(
} }
class CallableReferencesCandidateFactory( class CallableReferencesCandidateFactory(
val argument: CallableReferenceKotlinCallArgument, val argument: CallableReferenceKotlinCallArgument,
val callComponents: KotlinCallComponents, val callComponents: KotlinCallComponents,
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit, val compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit,
val expectedType: UnwrappedType? val expectedType: UnwrappedType?
) : CandidateFactory<CallableReferenceCandidate> { ) : CandidateFactory<CallableReferenceCandidate> {
fun createCallableProcessor(explicitReceiver: DetailedReceiver?) = fun createCallableProcessor(explicitReceiver: DetailedReceiver?) =
createCallableReferenceProcessor(scopeTower, argument.rhsName, this, explicitReceiver) createCallableReferenceProcessor(scopeTower, argument.rhsName, this, explicitReceiver)
override fun createCandidate( override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver, towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): CallableReferenceCandidate { ): CallableReferenceCandidate {
val dispatchCallableReceiver = towerCandidate.dispatchReceiver?.let { toCallableReceiver(it, explicitReceiverKind == DISPATCH_RECEIVER) } val dispatchCallableReceiver =
towerCandidate.dispatchReceiver?.let { toCallableReceiver(it, explicitReceiverKind == DISPATCH_RECEIVER) }
val extensionCallableReceiver = extensionReceiver?.let { toCallableReceiver(it, explicitReceiverKind == EXTENSION_RECEIVER) } val extensionCallableReceiver = extensionReceiver?.let { toCallableReceiver(it, explicitReceiverKind == EXTENSION_RECEIVER) }
val candidateDescriptor = towerCandidate.descriptor val candidateDescriptor = towerCandidate.descriptor
val diagnostics = SmartList<KotlinCallDiagnostic>() val diagnostics = SmartList<KotlinCallDiagnostic>()
val (reflectionCandidateType, defaults) = buildReflectionType( val (reflectionCandidateType, defaults) = buildReflectionType(
candidateDescriptor, candidateDescriptor,
dispatchCallableReceiver, dispatchCallableReceiver,
extensionCallableReceiver, extensionCallableReceiver,
expectedType) expectedType
)
if (defaults != 0) { if (defaults != 0) {
diagnostics.add(CallableReferencesDefaultArgumentUsed(argument, candidateDescriptor, defaults)) diagnostics.add(CallableReferencesDefaultArgumentUsed(argument, candidateDescriptor, defaults))
} }
if (candidateDescriptor !is CallableMemberDescriptor) { if (candidateDescriptor !is CallableMemberDescriptor) {
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, return CallableReferenceCandidate(
explicitReceiverKind, reflectionCandidateType, defaults, candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
listOf(NotCallableMemberReference(argument, candidateDescriptor))) explicitReceiverKind, reflectionCandidateType, defaults,
listOf(NotCallableMemberReference(argument, candidateDescriptor))
)
} }
diagnostics.addAll(towerCandidate.diagnostics) diagnostics.addAll(towerCandidate.diagnostics)
@@ -200,22 +207,32 @@ class CallableReferencesCandidateFactory(
if (it.hasContradiction) return@compatibilityChecker if (it.hasContradiction) return@compatibilityChecker
val (_, visibilityError) = it.checkCallableReference( val (_, visibilityError) = it.checkCallableReference(
argument, dispatchCallableReceiver, extensionCallableReceiver, candidateDescriptor, argument, dispatchCallableReceiver, extensionCallableReceiver, candidateDescriptor,
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor) reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor
)
diagnostics.addIfNotNull(visibilityError) diagnostics.addIfNotNull(visibilityError)
if (it.hasContradiction) diagnostics.add(CallableReferenceNotCompatible(argument, candidateDescriptor, expectedType, reflectionCandidateType)) if (it.hasContradiction) diagnostics.add(
CallableReferenceNotCompatible(
argument,
candidateDescriptor,
expectedType,
reflectionCandidateType
)
)
} }
return CallableReferenceCandidate(candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver, return CallableReferenceCandidate(
explicitReceiverKind, reflectionCandidateType, defaults, diagnostics) candidateDescriptor, dispatchCallableReceiver, extensionCallableReceiver,
explicitReceiverKind, reflectionCandidateType, defaults, diagnostics
)
} }
private fun getArgumentAndReturnTypeUseMappingByExpectedType( private fun getArgumentAndReturnTypeUseMappingByExpectedType(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
unboundReceiverCount: Int unboundReceiverCount: Int
): Triple<Array<KotlinType>, CoercionStrategy, Int>? { ): Triple<Array<KotlinType>, CoercionStrategy, Int>? {
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
@@ -223,7 +240,8 @@ class CallableReferencesCandidateFactory(
if (expectedArgumentCount < 0) return null if (expectedArgumentCount < 0) return null
val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) } val fakeArguments = (0..(expectedArgumentCount - 1)).map { FakeKotlinCallArgumentForCallableReference(it) }
val argumentMapping = callComponents.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor) val argumentMapping =
callComponents.argumentsToParametersMapper.mapArguments(fakeArguments, externalArgument = null, descriptor = descriptor)
if (argumentMapping.diagnostics.any { !it.candidateApplicability.isSuccess }) return null if (argumentMapping.diagnostics.any { !it.candidateApplicability.isSuccess }) return null
/** /**
@@ -253,10 +271,10 @@ class CallableReferencesCandidateFactory(
} }
private fun buildReflectionType( private fun buildReflectionType(
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
dispatchReceiver: CallableReceiver?, dispatchReceiver: CallableReceiver?,
extensionReceiver: CallableReceiver?, extensionReceiver: CallableReceiver?,
expectedType: UnwrappedType? expectedType: UnwrappedType?
): Pair<UnwrappedType, /*defaults*/ Int> { ): Pair<UnwrappedType, /*defaults*/ Int> {
val argumentsAndReceivers = ArrayList<KotlinType>(descriptor.valueParameters.size + 2) val argumentsAndReceivers = ArrayList<KotlinType>(descriptor.valueParameters.size + 2)
@@ -268,30 +286,38 @@ class CallableReferencesCandidateFactory(
} }
val descriptorReturnType = descriptor.returnType val descriptorReturnType = descriptor.returnType
?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor") ?: ErrorUtils.createErrorType("Error return type for descriptor: $descriptor")
when (descriptor) { when (descriptor) {
is PropertyDescriptor -> { is PropertyDescriptor -> {
val mutable = descriptor.isVar && run { val mutable = descriptor.isVar && run {
val setter = descriptor.setter val setter = descriptor.setter
setter == null || Visibilities.isVisible(dispatchReceiver?.asReceiverValueForVisibilityChecks, setter, setter == null || Visibilities.isVisible(
scopeTower.lexicalScope.ownerDescriptor) dispatchReceiver?.asReceiverValueForVisibilityChecks, setter,
scopeTower.lexicalScope.ownerDescriptor
)
} }
return callComponents.reflectionTypes.getKPropertyType(Annotations.EMPTY, argumentsAndReceivers, descriptorReturnType, mutable) to 0 return callComponents.reflectionTypes.getKPropertyType(
Annotations.EMPTY,
argumentsAndReceivers,
descriptorReturnType,
mutable
) to 0
} }
is FunctionDescriptor -> { is FunctionDescriptor -> {
val returnType: KotlinType val returnType: KotlinType
val defaults: Int val defaults: Int
val argumentsAndExpectedTypeCoercion = getArgumentAndReturnTypeUseMappingByExpectedType(descriptor, expectedType, val argumentsAndExpectedTypeCoercion = getArgumentAndReturnTypeUseMappingByExpectedType(
unboundReceiverCount = argumentsAndReceivers.size) descriptor, expectedType,
unboundReceiverCount = argumentsAndReceivers.size
)
if (argumentsAndExpectedTypeCoercion == null) { if (argumentsAndExpectedTypeCoercion == null) {
descriptor.valueParameters.mapTo(argumentsAndReceivers) { it.type } descriptor.valueParameters.mapTo(argumentsAndReceivers) { it.type }
returnType = descriptorReturnType returnType = descriptorReturnType
defaults = 0 defaults = 0
} } else {
else {
val (arguments, coercion) = argumentsAndExpectedTypeCoercion val (arguments, coercion) = argumentsAndExpectedTypeCoercion
defaults = argumentsAndExpectedTypeCoercion.third defaults = argumentsAndExpectedTypeCoercion.third
argumentsAndReceivers.addAll(arguments) argumentsAndReceivers.addAll(arguments)
@@ -299,8 +325,10 @@ class CallableReferencesCandidateFactory(
returnType = if (coercion == CoercionStrategy.COERCION_TO_UNIT) descriptor.builtIns.unitType else descriptorReturnType returnType = if (coercion == CoercionStrategy.COERCION_TO_UNIT) descriptor.builtIns.unitType else descriptorReturnType
} }
return callComponents.reflectionTypes.getKFunctionType(Annotations.EMPTY, null, argumentsAndReceivers, null, return callComponents.reflectionTypes.getKFunctionType(
returnType, descriptor.builtIns) to defaults Annotations.EMPTY, null, argumentsAndReceivers, null,
returnType, descriptor.builtIns
) to defaults
} }
else -> error("Unsupported descriptor type: $descriptor") else -> error("Unsupported descriptor type: $descriptor")
} }
@@ -315,8 +343,7 @@ class CallableReferencesCandidateFactory(
is LHSResult.Type -> { is LHSResult.Type -> {
if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) { if (lhsResult.qualifier.classValueReceiver?.type == receiver.receiverValue.type) {
CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver) CallableReceiver.BoundValueReference(lhsResult.qualifier, receiver)
} } else {
else {
CallableReceiver.UnboundReference(lhsResult.qualifier, receiver) CallableReceiver.UnboundReference(lhsResult.qualifier, receiver)
} }
} }
@@ -331,11 +358,9 @@ fun getFunctionTypeFromCallableReferenceExpectedType(expectedType: UnwrappedType
return if (expectedType.isFunctionType) { return if (expectedType.isFunctionType) {
expectedType expectedType
} } else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
else if (ReflectionTypes.isNumberedKFunction(expectedType)) {
expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap() expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
} } else {
else {
null null
} }
} }
@@ -32,36 +32,36 @@ import org.jetbrains.kotlin.types.UnwrappedType
class CallableReferenceOverloadConflictResolver( class CallableReferenceOverloadConflictResolver(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
specificityComparator: TypeSpecificityComparator, specificityComparator: TypeSpecificityComparator,
statelessCallbacks: KotlinResolutionStatelessCallbacks, statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector constraintInjector: ConstraintInjector
) : OverloadingConflictResolver<CallableReferenceCandidate>( ) : OverloadingConflictResolver<CallableReferenceCandidate>(
builtIns, builtIns,
specificityComparator, specificityComparator,
{ it.candidate }, { it.candidate },
{ SimpleConstraintSystemImpl(constraintInjector, builtIns) }, { SimpleConstraintSystemImpl(constraintInjector, builtIns) },
Companion::createFlatSignature, Companion::createFlatSignature,
{ null }, { null },
{ statelessCallbacks.isDescriptorFromSource(it) } { statelessCallbacks.isDescriptorFromSource(it) }
) { ) {
companion object { companion object {
private fun createFlatSignature(candidate: CallableReferenceCandidate) = private fun createFlatSignature(candidate: CallableReferenceCandidate) =
FlatSignature.createFromReflectionType(candidate, candidate.candidate, candidate.numDefaults, candidate.reflectionCandidateType) FlatSignature.createFromReflectionType(candidate, candidate.candidate, candidate.numDefaults, candidate.reflectionCandidateType)
} }
} }
class CallableReferenceResolver( class CallableReferenceResolver(
private val towerResolver: TowerResolver, private val towerResolver: TowerResolver,
private val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver, private val callableReferenceOverloadConflictResolver: CallableReferenceOverloadConflictResolver,
private val callComponents: KotlinCallComponents private val callComponents: KotlinCallComponents
) { ) {
fun processCallableReferenceArgument( fun processCallableReferenceArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
resolvedAtom: ResolvedCallableReferenceAtom, resolvedAtom: ResolvedCallableReferenceAtom,
diagnosticsHolder: KotlinDiagnosticsHolder diagnosticsHolder: KotlinDiagnosticsHolder
) { ) {
val argument = resolvedAtom.atom val argument = resolvedAtom.atom
val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) } val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) }
@@ -73,17 +73,17 @@ class CallableReferenceResolver(
val chosenCandidate = candidates.singleOrNull() val chosenCandidate = candidates.singleOrNull()
if (chosenCandidate != null) { if (chosenCandidate != null) {
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) { val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) {
csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate, csBuilder.checkCallableReference(
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor) argument, dispatchReceiver, extensionReceiver, candidate,
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor
)
} }
diagnosticsHolder.addDiagnosticIfNotNull(diagnostic) diagnosticsHolder.addDiagnosticIfNotNull(diagnostic)
chosenCandidate.freshSubstitutor = toFreshSubstitutor chosenCandidate.freshSubstitutor = toFreshSubstitutor
} } else {
else {
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
diagnosticsHolder.addDiagnostic(NoneCallableReferenceCandidates(argument)) diagnosticsHolder.addDiagnostic(NoneCallableReferenceCandidates(argument))
} } else {
else {
diagnosticsHolder.addDiagnostic(CallableReferenceCandidatesAmbiguity(argument, candidates)) diagnosticsHolder.addDiagnostic(CallableReferenceCandidatesAmbiguity(argument, candidates))
} }
} }
@@ -97,7 +97,7 @@ class CallableReferenceResolver(
private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? { private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? {
if (lhsResult !is LHSResult.Expression) return null if (lhsResult !is LHSResult.Expression) return null
val lshCallArgument = lhsResult.lshCallArgument val lshCallArgument = lhsResult.lshCallArgument
return when(lshCallArgument) { return when (lshCallArgument) {
is SubKotlinCallArgument -> lshCallArgument.callResult is SubKotlinCallArgument -> lshCallArgument.callResult
is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument) is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument)
else -> unexpectedArgument(lshCallArgument) else -> unexpectedArgument(lshCallArgument)
@@ -105,19 +105,20 @@ class CallableReferenceResolver(
} }
private fun runRHSResolution( private fun runRHSResolution(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
callableReference: CallableReferenceKotlinCallArgument, callableReference: CallableReferenceKotlinCallArgument,
expectedType: UnwrappedType?, // this type can have not fixed type variable inside expectedType: UnwrappedType?, // this type can have not fixed type variable inside
compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be rolled back compatibilityChecker: ((ConstraintSystemOperation) -> Unit) -> Unit // you can run anything throw this operation and all this operation will be rolled back
): Set<CallableReferenceCandidate> { ): Set<CallableReferenceCandidate> {
val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType) val factory = CallableReferencesCandidateFactory(callableReference, callComponents, scopeTower, compatibilityChecker, expectedType)
val processor = createCallableReferenceProcessor(factory) val processor = createCallableReferenceProcessor(factory)
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true, name = callableReference.rhsName) val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = true, name = callableReference.rhsName)
return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates( return callableReferenceOverloadConflictResolver.chooseMaximallySpecificCandidates(
candidates, candidates,
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
discriminateGenerics = false, // we can't specify generics explicitly for callable references discriminateGenerics = false, // we can't specify generics explicitly for callable references
isDebuggerContext = scopeTower.isDebuggerContext) isDebuggerContext = scopeTower.isDebuggerContext
)
} }
} }
@@ -38,11 +38,11 @@ interface KotlinResolutionStatelessCallbacks {
// This components hold state (trace). Work with this carefully. // This components hold state (trace). Work with this carefully.
interface KotlinResolutionCallbacks { interface KotlinResolutionCallbacks {
fun analyzeAndGetLambdaReturnArguments( fun analyzeAndGetLambdaReturnArguments(
lambdaArgument: LambdaKotlinCallArgument, lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean, isSuspend: Boolean,
receiverType: UnwrappedType?, receiverType: UnwrappedType?,
parameters: List<UnwrappedType>, parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables
): List<SimpleKotlinCallArgument> ): List<SimpleKotlinCallArgument>
fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
@@ -27,15 +27,15 @@ import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
class KotlinCallCompleter( class KotlinCallCompleter(
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter
) { ) {
fun runCompletion( fun runCompletion(
factory: SimpleCandidateFactory, factory: SimpleCandidateFactory,
candidates: Collection<KotlinResolutionCandidate>, candidates: Collection<KotlinResolutionCandidate>,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): CallResolutionResult { ): CallResolutionResult {
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
@@ -54,14 +54,20 @@ class KotlinCallCompleter(
if (candidate == null || candidate.csBuilder.hasContradiction) { if (candidate == null || candidate.csBuilder.hasContradiction) {
val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution() val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution()
candidateForCompletion.prepareForCompletion(expectedType, resolutionCallbacks) candidateForCompletion.prepareForCompletion(expectedType, resolutionCallbacks)
runCompletion(candidateForCompletion.resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, candidateForCompletion.getSystem(), resolutionCallbacks) runCompletion(
candidateForCompletion.resolvedCall,
ConstraintSystemCompletionMode.FULL,
diagnosticHolder,
candidateForCompletion.getSystem(),
resolutionCallbacks
)
val systemStorage = candidate?.getSystem()?.asReadOnlyStorage() ?: ConstraintStorage.Empty val systemStorage = candidate?.getSystem()?.asReadOnlyStorage() ?: ConstraintStorage.Empty
return CallResolutionResult( return CallResolutionResult(
CallResolutionResult.Type.ERROR, CallResolutionResult.Type.ERROR,
candidate?.resolvedCall, candidate?.resolvedCall,
diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts,
systemStorage systemStorage
) )
} }
@@ -71,57 +77,62 @@ class KotlinCallCompleter(
return if (completionType == ConstraintSystemCompletionMode.FULL) { return if (completionType == ConstraintSystemCompletionMode.FULL) {
CallResolutionResult( CallResolutionResult(
CallResolutionResult.Type.COMPLETED, CallResolutionResult.Type.COMPLETED,
candidate.resolvedCall, candidate.resolvedCall,
diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts,
constraintSystem.asReadOnlyStorage() constraintSystem.asReadOnlyStorage()
) )
} } else {
else {
CallResolutionResult( CallResolutionResult(
CallResolutionResult.Type.PARTIAL, CallResolutionResult.Type.PARTIAL,
candidate.resolvedCall, candidate.resolvedCall,
diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts, diagnosticHolder.getDiagnostics() + diagnosticsFromResolutionParts,
constraintSystem.asReadOnlyStorage() constraintSystem.asReadOnlyStorage()
) )
} }
} }
fun createAllCandidatesResult( fun createAllCandidatesResult(
candidates: Collection<KotlinResolutionCandidate>, candidates: Collection<KotlinResolutionCandidate>,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): CallResolutionResult { ): CallResolutionResult {
val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticsHolder = KotlinDiagnosticsHolder.SimpleHolder()
for (candidate in candidates) { for (candidate in candidates) {
candidate.prepareForCompletion(expectedType, resolutionCallbacks) candidate.prepareForCompletion(expectedType, resolutionCallbacks)
runCompletion( runCompletion(
candidate.resolvedCall, candidate.resolvedCall,
ConstraintSystemCompletionMode.FULL, ConstraintSystemCompletionMode.FULL,
diagnosticsHolder, diagnosticsHolder,
candidate.getSystem(), candidate.getSystem(),
resolutionCallbacks, resolutionCallbacks,
skipPostponedArguments = true) skipPostponedArguments = true
)
} }
return CallResolutionResult(CallResolutionResult.Type.ALL_CANDIDATES, null, emptyList(), ConstraintStorage.Empty, candidates) return CallResolutionResult(CallResolutionResult.Type.ALL_CANDIDATES, null, emptyList(), ConstraintStorage.Empty, candidates)
} }
private fun runCompletion( private fun runCompletion(
resolvedCallAtom: ResolvedCallAtom, resolvedCallAtom: ResolvedCallAtom,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
constraintSystem: NewConstraintSystem, constraintSystem: NewConstraintSystem,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
skipPostponedArguments: Boolean = false skipPostponedArguments: Boolean = false
) { ) {
val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType
kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) { kotlinConstraintSystemCompleter.runCompletion(
constraintSystem.asConstraintSystemCompleterContext(),
completionMode,
resolvedCallAtom,
returnType
) {
if (!skipPostponedArguments) { if (!skipPostponedArguments) {
postponedArgumentsAnalyzer.analyze( postponedArgumentsAnalyzer.analyze(
constraintSystem.asPostponedArgumentsAnalyzerContext(), constraintSystem.asPostponedArgumentsAnalyzerContext(),
resolutionCallbacks, resolutionCallbacks,
it, it,
diagnosticsHolder diagnosticsHolder
) )
} }
} }
@@ -132,8 +143,8 @@ class KotlinCallCompleter(
// true if we should complete this call // true if we should complete this call
private fun KotlinResolutionCandidate.prepareForCompletion( private fun KotlinResolutionCandidate.prepareForCompletion(
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): ConstraintSystemCompletionMode { ): ConstraintSystemCompletionMode {
val unsubstitutedReturnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL val unsubstitutedReturnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL
val withSmartCastInfo = resolutionCallbacks.createReceiverWithSmartCastInfo(resolvedCall) val withSmartCastInfo = resolutionCallbacks.createReceiverWithSmartCastInfo(resolvedCall)
@@ -141,14 +152,16 @@ class KotlinCallCompleter(
val actualType = withSmartCastInfo?.stableType ?: unsubstitutedReturnType val actualType = withSmartCastInfo?.stableType ?: unsubstitutedReturnType
val returnType = resolvedCall.substitutor.substituteKeepAnnotations(actualType) val returnType = resolvedCall.substitutor.substituteKeepAnnotations(actualType)
if (expectedType != null && !TypeUtils.noExpectedType(expectedType) && !resolutionCallbacks.isCompileTimeConstant(resolvedCall, expectedType)) { if (expectedType != null && !TypeUtils.noExpectedType(expectedType) && !resolutionCallbacks.isCompileTimeConstant(
resolvedCall,
expectedType
)) {
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom)) csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
} }
return if (expectedType != null || csBuilder.isProperType(returnType)) { return if (expectedType != null || csBuilder.isProperType(returnType)) {
ConstraintSystemCompletionMode.FULL ConstraintSystemCompletionMode.FULL
} } else {
else {
ConstraintSystemCompletionMode.PARTIAL ConstraintSystemCompletionMode.PARTIAL
} }
} }
@@ -28,21 +28,21 @@ import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
class NewOverloadingConflictResolver( class NewOverloadingConflictResolver(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
specificityComparator: TypeSpecificityComparator, specificityComparator: TypeSpecificityComparator,
statelessCallbacks: KotlinResolutionStatelessCallbacks, statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector constraintInjector: ConstraintInjector
) : OverloadingConflictResolver<KotlinResolutionCandidate>( ) : OverloadingConflictResolver<KotlinResolutionCandidate>(
builtIns, builtIns,
specificityComparator, specificityComparator,
{ {
// todo investigate // todo investigate
it.resolvedCall.candidateDescriptor it.resolvedCall.candidateDescriptor
}, },
{ SimpleConstraintSystemImpl(constraintInjector, builtIns) }, { SimpleConstraintSystemImpl(constraintInjector, builtIns) },
Companion::createFlatSignature, Companion::createFlatSignature,
{ it.variableCandidateIfInvoke }, { it.variableCandidateIfInvoke },
{ statelessCallbacks.isDescriptorFromSource(it) } { statelessCallbacks.isDescriptorFromSource(it) }
) { ) {
companion object { companion object {
@@ -57,8 +57,7 @@ class NewOverloadingConflictResolver(
for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) { for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) {
if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) { if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) {
numDefaults++ numDefaults++
} } else {
else {
val originalValueParameter = originalValueParameters[valueParameter.index] val originalValueParameter = originalValueParameters[valueParameter.index]
val parameterType = originalValueParameter.argumentValueType val parameterType = originalValueParameter.argumentValueType
for (valueArgument in resolvedValueArgument.arguments) { for (valueArgument in resolvedValueArgument.arguments) {
@@ -71,7 +70,7 @@ class NewOverloadingConflictResolver(
originalDescriptor, originalDescriptor,
numDefaults, numDefaults,
resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } + resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] }) listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] })
) )
} }
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun resolveKtPrimitive( fun resolveKtPrimitive(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: KotlinCallArgument, argument: KotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): ResolvedAtom = when (argument) { ): ResolvedAtom = when (argument) {
is SimpleKotlinCallArgument -> checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) is SimpleKotlinCallArgument -> checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType) is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType)
@@ -43,10 +43,10 @@ fun resolveKtPrimitive(
// if expected type isn't function type, then may be it is Function<R>, Any or just `T` // if expected type isn't function type, then may be it is Function<R>, Any or just `T`
private fun preprocessLambdaArgument( private fun preprocessLambdaArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: LambdaKotlinCallArgument, argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
forceResolution: Boolean = false forceResolution: Boolean = false
): ResolvedAtom { ): ResolvedAtom {
if (expectedType != null && !forceResolution && csBuilder.isTypeVariable(expectedType)) { if (expectedType != null && !forceResolution && csBuilder.isTypeVariable(expectedType)) {
return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType) return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType)
@@ -55,8 +55,10 @@ private fun preprocessLambdaArgument(
val resolvedArgument = extractLambdaInfoFromFunctionalType(expectedType, argument) ?: extraLambdaInfo(expectedType, argument, csBuilder) val resolvedArgument = extractLambdaInfoFromFunctionalType(expectedType, argument) ?: extraLambdaInfo(expectedType, argument, csBuilder)
if (expectedType != null) { if (expectedType != null) {
val lambdaType = createFunctionType(csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver, val lambdaType = createFunctionType(
resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend) csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver,
resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend
)
csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument)) csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument))
} }
@@ -64,9 +66,9 @@ private fun preprocessLambdaArgument(
} }
private fun extraLambdaInfo( private fun extraLambdaInfo(
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
argument: LambdaKotlinCallArgument, argument: LambdaKotlinCallArgument,
csBuilder: ConstraintSystemBuilder csBuilder: ConstraintSystemBuilder
): ResolvedLambdaAtom { ): ResolvedLambdaAtom {
val builtIns = csBuilder.builtIns val builtIns = csBuilder.builtIns
val isSuspend = expectedType?.isSuspendFunctionType ?: false val isSuspend = expectedType?.isSuspendFunctionType ?: false
@@ -77,9 +79,9 @@ private fun extraLambdaInfo(
val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L") val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L")
val receiverType = argumentAsFunctionExpression?.receiverType val receiverType = argumentAsFunctionExpression?.receiverType
val returnType = argumentAsFunctionExpression?.returnType ?: val returnType =
expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?: argumentAsFunctionExpression?.returnType ?: expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype }
typeVariable.defaultType ?: typeVariable.defaultType
val parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList() val parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList()
@@ -97,7 +99,14 @@ private fun extractLambdaInfoFromFunctionalType(expectedType: UnwrappedType?, ar
val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.getReceiverTypeFromFunctionType()?.unwrap() val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.getReceiverTypeFromFunctionType()?.unwrap()
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap() val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
return ResolvedLambdaAtom(argument, expectedType.isSuspendFunctionType, receiverType, parameters, returnType, typeVariableForLambdaReturnType = null) return ResolvedLambdaAtom(
argument,
expectedType.isSuspendFunctionType,
receiverType,
parameters,
returnType,
typeVariableForLambdaReturnType = null
)
} }
private fun extractLambdaParameters(expectedType: UnwrappedType, argument: LambdaKotlinCallArgument): List<UnwrappedType> { private fun extractLambdaParameters(expectedType: UnwrappedType, argument: LambdaKotlinCallArgument): List<UnwrappedType> {
@@ -122,15 +131,16 @@ fun LambdaWithTypeVariableAsExpectedTypeAtom.transformToResolvedLambda(csBuilder
} }
private fun preprocessCallableReference( private fun preprocessCallableReference(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: CallableReferenceKotlinCallArgument, argument: CallableReferenceKotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder diagnosticsHolder: KotlinDiagnosticsHolder
): ResolvedAtom { ): ResolvedAtom {
val result = ResolvedCallableReferenceAtom(argument, expectedType) val result = ResolvedCallableReferenceAtom(argument, expectedType)
if (expectedType == null) return result if (expectedType == null) return result
val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) } val notCallableTypeConstructor =
csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) }
if (notCallableTypeConstructor != null) { if (notCallableTypeConstructor != null) {
diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor)) diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor))
} }
@@ -138,8 +148,8 @@ private fun preprocessCallableReference(
} }
private fun preprocessCollectionLiteralArgument( private fun preprocessCollectionLiteralArgument(
collectionLiteralArgument: CollectionLiteralKotlinCallArgument, collectionLiteralArgument: CollectionLiteralKotlinCallArgument,
expectedType: UnwrappedType? expectedType: UnwrappedType?
): ResolvedAtom { ): ResolvedAtom {
// todo add some checks about expected type // todo add some checks about expected type
return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType) return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType)
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
class PostponedArgumentsAnalyzer( class PostponedArgumentsAnalyzer(
private val callableReferenceResolver: CallableReferenceResolver private val callableReferenceResolver: CallableReferenceResolver
) { ) {
interface Context { interface Context {
fun buildCurrentSubstitutor(): NewTypeSubstitutor fun buildCurrentSubstitutor(): NewTypeSubstitutor
@@ -36,10 +36,16 @@ class PostponedArgumentsAnalyzer(
// mutable operations // mutable operations
fun addOtherSystem(otherSystem: ConstraintStorage) fun addOtherSystem(otherSystem: ConstraintStorage)
fun getBuilder(): ConstraintSystemBuilder fun getBuilder(): ConstraintSystemBuilder
} }
fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom, diagnosticsHolder: KotlinDiagnosticsHolder) { fun analyze(
c: Context,
resolutionCallbacks: KotlinResolutionCallbacks,
argument: ResolvedAtom,
diagnosticsHolder: KotlinDiagnosticsHolder
) {
when (argument) { when (argument) {
is ResolvedLambdaAtom -> is ResolvedLambdaAtom ->
analyzeLambda(c, resolutionCallbacks, argument, diagnosticsHolder) analyzeLambda(c, resolutionCallbacks, argument, diagnosticsHolder)
@@ -56,7 +62,12 @@ class PostponedArgumentsAnalyzer(
} }
} }
private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom, diagnosticHolder: KotlinDiagnosticsHolder) { private fun analyzeLambda(
c: Context,
resolutionCallbacks: KotlinResolutionCallbacks,
lambda: ResolvedLambdaAtom,
diagnosticHolder: KotlinDiagnosticsHolder
) {
val currentSubstitutor = c.buildCurrentSubstitutor() val currentSubstitutor = c.buildCurrentSubstitutor()
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type) fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
@@ -64,7 +75,8 @@ class PostponedArgumentsAnalyzer(
val parameters = lambda.parameters.map(::substitute) val parameters = lambda.parameters.map(::substitute)
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute) val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
val returnArguments = resolutionCallbacks.analyzeAndGetLambdaReturnArguments(lambda.atom, lambda.isSuspend, receiver, parameters, expectedType) val returnArguments =
resolutionCallbacks.analyzeAndGetLambdaReturnArguments(lambda.atom, lambda.isSuspend, receiver, parameters, expectedType)
returnArguments.forEach { c.addSubsystemFromArgument(it) } returnArguments.forEach { c.addSubsystemFromArgument(it) }
@@ -55,12 +55,19 @@ internal object CheckVisibility : ResolutionPart() {
if (scopeTower.isDebuggerContext) return if (scopeTower.isDebuggerContext) return
val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return val invisibleMember =
Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) { if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType) val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType)
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) { if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
addDiagnostic(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType, resolvedCall.atom)) addDiagnostic(
SmartCastDiagnostic(
dispatchReceiverArgument,
dispatchReceiverArgument.receiver.stableType,
resolvedCall.atom
)
)
return return
} }
} }
@@ -147,16 +154,23 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType) val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType)
if (knownTypeArgument != null) { if (knownTypeArgument != null) {
csBuilder.addEqualityConstraint(freshVariable.defaultType, knownTypeArgument.unwrap(), KnownTypeParameterConstraintPosition(knownTypeArgument)) csBuilder.addEqualityConstraint(
freshVariable.defaultType,
knownTypeArgument.unwrap(),
KnownTypeParameterConstraintPosition(knownTypeArgument)
)
continue continue
} }
val typeArgument = resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter) val typeArgument = resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
if (typeArgument is SimpleTypeArgument) { if (typeArgument is SimpleTypeArgument) {
csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument)) csBuilder.addEqualityConstraint(
} freshVariable.defaultType,
else { typeArgument.type,
ExplicitTypeParameterConstraintPosition(typeArgument)
)
} else {
assert(typeArgument == TypeArgumentPlaceholder) { assert(typeArgument == TypeArgumentPlaceholder) {
"Unexpected typeArgument: $typeArgument, ${typeArgument.javaClass.canonicalName}" "Unexpected typeArgument: $typeArgument, ${typeArgument.javaClass.canonicalName}"
} }
@@ -165,8 +179,8 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
} }
fun createToFreshVariableSubstitutorAndAddInitialConstraints( fun createToFreshVariableSubstitutorAndAddInitialConstraints(
candidateDescriptor: CallableDescriptor, candidateDescriptor: CallableDescriptor,
csBuilder: ConstraintSystemOperation csBuilder: ConstraintSystemOperation
): FreshVariableNewTypeSubstitutor { ): FreshVariableNewTypeSubstitutor {
val typeParameters = candidateDescriptor.typeParameters val typeParameters = candidateDescriptor.typeParameters
@@ -193,9 +207,11 @@ internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
internal object CheckExplicitReceiverKindConsistency : ResolutionPart() { internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
private fun KotlinResolutionCandidate.hasError(): Nothing = private fun KotlinResolutionCandidate.hasError(): Nothing =
error("Inconsistent call: $kotlinCall. \n" + error(
"Candidate: $candidateDescriptor, explicitReceiverKind: ${resolvedCall.explicitReceiverKind}.\n" + "Inconsistent call: $kotlinCall. \n" +
"Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}") "Candidate: $candidateDescriptor, explicitReceiverKind: ${resolvedCall.explicitReceiverKind}.\n" +
"Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}"
)
override fun KotlinResolutionCandidate.process(workIndex: Int) { override fun KotlinResolutionCandidate.process(workIndex: Int) {
when (resolvedCall.explicitReceiverKind) { when (resolvedCall.explicitReceiverKind) {
@@ -207,20 +223,25 @@ internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
} }
private fun KotlinResolutionCandidate.resolveKotlinArgument( private fun KotlinResolutionCandidate.resolveKotlinArgument(
argument: KotlinCallArgument, argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor?, candidateParameter: ParameterDescriptor?,
isReceiver: Boolean isReceiver: Boolean
) { ) {
val expectedType = candidateParameter?.let { val expectedType = candidateParameter?.let {
resolvedCall.substitutor.substituteKeepAnnotations(argument.getExpectedType(candidateParameter, callComponents.languageVersionSettings)) resolvedCall.substitutor.substituteKeepAnnotations(
argument.getExpectedType(
candidateParameter,
callComponents.languageVersionSettings
)
)
} }
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver)) addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
} }
internal object CheckReceivers : ResolutionPart() { internal object CheckReceivers : ResolutionPart() {
private fun KotlinResolutionCandidate.checkReceiver( private fun KotlinResolutionCandidate.checkReceiver(
receiverArgument: SimpleKotlinCallArgument?, receiverArgument: SimpleKotlinCallArgument?,
receiverParameter: ReceiverParameterDescriptor? receiverParameter: ReceiverParameterDescriptor?
) { ) {
if ((receiverArgument == null) != (receiverParameter == null)) { if ((receiverArgument == null) != (receiverParameter == null)) {
error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor") error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor")
@@ -33,11 +33,11 @@ import org.jetbrains.kotlin.types.upperIfFlexible
fun checkSimpleArgument( fun checkSimpleArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: SimpleKotlinCallArgument, argument: SimpleKotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): ResolvedAtom = when (argument) { ): ResolvedAtom = when (argument) {
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver) is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
@@ -45,11 +45,11 @@ fun checkSimpleArgument(
} }
private fun checkExpressionArgument( private fun checkExpressionArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
expressionArgument: ExpressionKotlinCallArgument, expressionArgument: ExpressionKotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): ResolvedAtom { ): ResolvedAtom {
val resolvedKtExpression = ResolvedExpressionAtom(expressionArgument) val resolvedKtExpression = ResolvedExpressionAtom(expressionArgument)
if (expectedType == null) return resolvedKtExpression if (expectedType == null) return resolvedKtExpression
@@ -58,7 +58,7 @@ private fun checkExpressionArgument(
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType) val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
fun unstableSmartCastOrSubtypeError( fun unstableSmartCastOrSubtypeError(
unstableType: UnwrappedType?, actualExpectedType: UnwrappedType, position: ConstraintPosition unstableType: UnwrappedType?, actualExpectedType: UnwrappedType, position: ConstraintPosition
): KotlinCallDiagnostic? { ): KotlinCallDiagnostic? {
if (unstableType != null) { if (unstableType != null) {
if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, actualExpectedType, position)) { if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, actualExpectedType, position)) {
@@ -74,25 +74,30 @@ private fun checkExpressionArgument(
if (expressionArgument.isSafeCall) { if (expressionArgument.isSafeCall) {
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
diagnosticsHolder.addDiagnosticIfNotNull( diagnosticsHolder.addDiagnosticIfNotNull(
unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)) unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)
)
} }
return resolvedKtExpression return resolvedKtExpression
} }
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
if (!isReceiver) { if (!isReceiver) {
diagnosticsHolder.addDiagnosticIfNotNull(unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)) diagnosticsHolder.addDiagnosticIfNotNull(
unstableSmartCastOrSubtypeError(
expressionArgument.receiver.unstableType,
expectedType,
position
)
)
return resolvedKtExpression return resolvedKtExpression
} }
val unstableType = expressionArgument.receiver.unstableType val unstableType = expressionArgument.receiver.unstableType
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) { if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType)) diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType))
} } else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument)) diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument))
} } else {
else {
csBuilder.addSubtypeConstraint(argumentType, expectedType, position) csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
} }
} }
@@ -122,7 +127,7 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy
if (argumentType.lowerIfFlexible().constructor.declarationDescriptor is TypeParameterDescriptor) { if (argumentType.lowerIfFlexible().constructor.declarationDescriptor is TypeParameterDescriptor) {
val chosenSupertype = argumentType.lowerIfFlexible().supertypes().singleOrNull { val chosenSupertype = argumentType.lowerIfFlexible().supertypes().singleOrNull {
it.constructor.declarationDescriptor is ClassifierDescriptorWithTypeParameters && it.constructor.declarationDescriptor is ClassifierDescriptorWithTypeParameters &&
it.unwrap().hasSupertypeWithGivenTypeConstructor(expectedTypeConstructor) it.unwrap().hasSupertypeWithGivenTypeConstructor(expectedTypeConstructor)
} }
if (chosenSupertype != null) { if (chosenSupertype != null) {
return captureFromExpression(chosenSupertype.unwrap()) ?: argumentType return captureFromExpression(chosenSupertype.unwrap()) ?: argumentType
@@ -133,11 +138,11 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy
} }
private fun checkSubCallArgument( private fun checkSubCallArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
subCallArgument: SubKotlinCallArgument, subCallArgument: SubKotlinCallArgument,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder, diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): ResolvedAtom { ): ResolvedAtom {
val subCallResult = subCallArgument.callResult val subCallResult = subCallArgument.callResult
@@ -156,7 +161,7 @@ private fun checkSubCallArgument(
if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) && if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) &&
csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position) csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position)
) { ) {
diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument)) diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument))
return subCallResult return subCallResult
} }
@@ -29,15 +29,15 @@ class TypeArgumentsToParametersMapper {
object NoExplicitArguments : TypeArgumentsMapping(emptyList()) { object NoExplicitArguments : TypeArgumentsMapping(emptyList()) {
override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument = override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument =
TypeArgumentPlaceholder TypeArgumentPlaceholder
} }
class TypeArgumentsMappingImpl( class TypeArgumentsMappingImpl(
diagnostics: List<KotlinCallDiagnostic>, diagnostics: List<KotlinCallDiagnostic>,
private val typeParameterToArgumentMap: Map<TypeParameterDescriptor, TypeArgument> private val typeParameterToArgumentMap: Map<TypeParameterDescriptor, TypeArgument>
): TypeArgumentsMapping(diagnostics) { ) : TypeArgumentsMapping(diagnostics) {
override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument = override fun getTypeArgument(typeParameterDescriptor: TypeParameterDescriptor): TypeArgument =
typeParameterToArgumentMap[typeParameterDescriptor] ?: TypeArgumentPlaceholder typeParameterToArgumentMap[typeParameterDescriptor] ?: TypeArgumentPlaceholder
} }
} }
@@ -48,9 +48,9 @@ class TypeArgumentsToParametersMapper {
if (call.typeArguments.size != descriptor.typeParameters.size) { if (call.typeArguments.size != descriptor.typeParameters.size) {
return TypeArgumentsMapping.TypeArgumentsMappingImpl( return TypeArgumentsMapping.TypeArgumentsMappingImpl(
listOf(WrongCountOfTypeArguments(descriptor, call.typeArguments.size)), emptyMap()) listOf(WrongCountOfTypeArguments(descriptor, call.typeArguments.size)), emptyMap()
} )
else { } else {
val typeParameterToArgumentMap = descriptor.typeParameters.zip(call.typeArguments).associate { it } val typeParameterToArgumentMap = descriptor.typeParameters.zip(call.typeArguments).associate { it }
return TypeArgumentsMapping.TypeArgumentsMappingImpl(listOf(), typeParameterToArgumentMap) return TypeArgumentsMapping.TypeArgumentsMappingImpl(listOf(), typeParameterToArgumentMap)
} }
@@ -47,11 +47,15 @@ interface ConstraintSystemBuilder : ConstraintSystemOperation {
fun buildCurrentSubstitutor(): NewTypeSubstitutor fun buildCurrentSubstitutor(): NewTypeSubstitutor
} }
fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) = fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(
runTransaction { lowerType: UnwrappedType,
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position) upperType: UnwrappedType,
!hasContradiction position: ConstraintPosition
} ) =
runTransaction {
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position)
!hasContradiction
}
fun PostponedArgumentsAnalyzer.Context.addSubsystemFromArgument(argument: KotlinCallArgument?) { fun PostponedArgumentsAnalyzer.Context.addSubsystemFromArgument(argument: KotlinCallArgument?) {
@@ -33,7 +33,10 @@ fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor {
it.key to it.value it.key to it.value
} }
val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) -> val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor) freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor(
"Uninferred type",
typeVariable.typeVariable.freshTypeConstructor
)
} }
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap) return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
@@ -61,10 +64,10 @@ fun CallableDescriptor.substituteAndApproximateCapturedTypes(substitutor: NewTyp
override fun get(key: KotlinType): TypeProjection? = null override fun get(key: KotlinType): TypeProjection? = null
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType -> substitutor.safeSubstitute(topLevelType.unwrap()).let { substitutedType ->
TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: TypeApproximator().approximateToSuperType(substitutedType, TypeApproximatorConfiguration.CapturedTypesApproximation)
substitutedType ?: substitutedType
} }
} }
return substitute(TypeSubstitutor.create(wrappedSubstitution)) return substitute(TypeSubstitutor.create(wrappedSubstitution))
@@ -32,6 +32,7 @@ interface NewConstraintSystem {
// after this method we shouldn't mutate system via ConstraintSystemBuilder // after this method we shouldn't mutate system via ConstraintSystemBuilder
fun asReadOnlyStorage(): ConstraintStorage fun asReadOnlyStorage(): ConstraintStorage
fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context
} }
@@ -102,30 +102,38 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
} }
private fun generateNewConstraint( private fun generateNewConstraint(
c: Context, c: Context,
targetVariable: NewTypeVariable, targetVariable: NewTypeVariable,
baseConstraint: Constraint, baseConstraint: Constraint,
otherVariable: NewTypeVariable, otherVariable: NewTypeVariable,
otherConstraint: Constraint otherConstraint: Constraint
) { ) {
val typeForApproximation = when (otherConstraint.kind) { val typeForApproximation = when (otherConstraint.kind) {
ConstraintKind.EQUALITY -> { ConstraintKind.EQUALITY -> {
baseConstraint.type.substitute(otherVariable, otherConstraint.type) baseConstraint.type.substitute(otherVariable, otherConstraint.type)
} }
ConstraintKind.UPPER -> { ConstraintKind.UPPER -> {
val newCapturedTypeConstructor = NewCapturedTypeConstructor(TypeProjectionImpl(Variance.OUT_VARIANCE, otherConstraint.type), val newCapturedTypeConstructor = NewCapturedTypeConstructor(
listOf(otherConstraint.type)) TypeProjectionImpl(Variance.OUT_VARIANCE, otherConstraint.type),
val temporaryCapturedType = NewCapturedType(CaptureStatus.FOR_INCORPORATION, listOf(otherConstraint.type)
newCapturedTypeConstructor, )
lowerType = null) val temporaryCapturedType = NewCapturedType(
CaptureStatus.FOR_INCORPORATION,
newCapturedTypeConstructor,
lowerType = null
)
baseConstraint.type.substitute(otherVariable, temporaryCapturedType) baseConstraint.type.substitute(otherVariable, temporaryCapturedType)
} }
ConstraintKind.LOWER -> { ConstraintKind.LOWER -> {
val newCapturedTypeConstructor = NewCapturedTypeConstructor(TypeProjectionImpl(Variance.IN_VARIANCE, otherConstraint.type), val newCapturedTypeConstructor = NewCapturedTypeConstructor(
emptyList()) TypeProjectionImpl(Variance.IN_VARIANCE, otherConstraint.type),
val temporaryCapturedType = NewCapturedType(CaptureStatus.FOR_INCORPORATION, emptyList()
newCapturedTypeConstructor, )
lowerType = otherConstraint.type) val temporaryCapturedType = NewCapturedType(
CaptureStatus.FOR_INCORPORATION,
newCapturedTypeConstructor,
lowerType = otherConstraint.type
)
baseConstraint.type.substitute(otherVariable, temporaryCapturedType) baseConstraint.type.substitute(otherVariable, temporaryCapturedType)
} }
} }
@@ -145,8 +153,8 @@ class ConstraintIncorporator(val typeApproximator: TypeApproximator) {
} }
private fun approximateCapturedTypes(type: UnwrappedType, toSuper: Boolean): UnwrappedType = private fun approximateCapturedTypes(type: UnwrappedType, toSuper: Boolean): UnwrappedType =
if (toSuper) typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type if (toSuper) typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type
else typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type else typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.IncorporationConfiguration) ?: type
} }
@@ -63,7 +63,12 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
} }
private fun addSubTypeConstraintAndIncorporateIt(c: Context, lowerType: UnwrappedType, upperType: UnwrappedType, incorporatePosition: IncorporationConstraintPosition) { private fun addSubTypeConstraintAndIncorporateIt(
c: Context,
lowerType: UnwrappedType,
upperType: UnwrappedType,
incorporatePosition: IncorporationConstraintPosition
) {
val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>() val possibleNewConstraints = Stack<Pair<NewTypeVariable, Constraint>>()
val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType, possibleNewConstraints) val typeCheckerContext = TypeCheckerContext(c, incorporatePosition, lowerType, upperType, possibleNewConstraints)
typeCheckerContext.runIsSubtypeOf(lowerType, upperType) typeCheckerContext.runIsSubtypeOf(lowerType, upperType)
@@ -72,7 +77,8 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
val (typeVariable, constraint) = possibleNewConstraints.pop() val (typeVariable, constraint) = possibleNewConstraints.pop()
if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue if (c.shouldWeSkipConstraint(typeVariable, constraint)) continue
val constraints = c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable) val constraints =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor] ?: typeCheckerContext.fixedTypeVariable(typeVariable)
// it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints // it is important, that we add constraint here(not inside TypeCheckerContext), because inside incorporation we read constraints
constraints.addConstraint(constraint)?.let { constraints.addConstraint(constraint)?.let {
@@ -105,14 +111,15 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
return false return false
} }
private fun Context.isAllowedType(type: UnwrappedType) = type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION private fun Context.isAllowedType(type: UnwrappedType) =
type.typeDepth() <= maxTypeDepthFromInitialConstraints + ALLOWED_DEPTH_DELTA_FOR_INCORPORATION
private inner class TypeCheckerContext( private inner class TypeCheckerContext(
val c: Context, val c: Context,
val position: IncorporationConstraintPosition, val position: IncorporationConstraintPosition,
val baseLowerType: UnwrappedType, val baseLowerType: UnwrappedType,
val baseUpperType: UnwrappedType, val baseUpperType: UnwrappedType,
val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>> val possibleNewConstraints: MutableList<Pair<NewTypeVariable, Constraint>>
) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context { ) : TypeCheckerContextForConstraintSystem(), ConstraintIncorporator.Context {
fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) { fun runIsSubtypeOf(lowerType: UnwrappedType, upperType: UnwrappedType) {
@@ -126,36 +133,39 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
// from TypeCheckerContextForConstraintSystem // from TypeCheckerContextForConstraintSystem
override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor) override fun isMyTypeVariable(type: SimpleType): Boolean = c.allTypeVariables.containsKey(type.constructor)
override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) = override fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) =
addConstraint(typeVariable, superType, UPPER) addConstraint(typeVariable, superType, UPPER)
override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) = override fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) =
addConstraint(typeVariable, subType, LOWER) addConstraint(typeVariable, subType, LOWER)
private fun isCapturedTypeFromSubtyping(type: UnwrappedType) = private fun isCapturedTypeFromSubtyping(type: UnwrappedType) =
when ((type as? NewCapturedType)?.captureStatus) { when ((type as? NewCapturedType)?.captureStatus) {
null, CaptureStatus.FROM_EXPRESSION -> false null, CaptureStatus.FROM_EXPRESSION -> false
CaptureStatus.FOR_SUBTYPING -> true CaptureStatus.FOR_SUBTYPING -> true
CaptureStatus.FOR_INCORPORATION -> CaptureStatus.FOR_INCORPORATION ->
error("Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint()) error("Captured type for incorporation shouldn't escape from incorporation: $type\n" + renderBaseConstraint())
} }
private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) { private fun addConstraint(typeVariableConstructor: TypeConstructor, type: UnwrappedType, kind: ConstraintKind) {
val typeVariable = c.allTypeVariables[typeVariableConstructor] val typeVariable = c.allTypeVariables[typeVariableConstructor]
?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}") ?: error("Should by type variableConstructor: $typeVariableConstructor. ${c.allTypeVariables.values}")
var targetType = type var targetType = type
if (type.contains(this::isCapturedTypeFromSubtyping)) { if (type.contains(this::isCapturedTypeFromSubtyping)) {
// TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type // TypeVariable <: type -> if TypeVariable <: subType => TypeVariable <: type
if (kind == UPPER) { if (kind == UPPER) {
val subType = typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation) val subType =
typeApproximator.approximateToSubType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) { if (subType != null && !KotlinBuiltIns.isNothingOrNullableNothing(subType)) {
targetType = subType targetType = subType
} }
} }
if (kind == LOWER) { if (kind == LOWER) {
val superType = typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation) val superType =
typeApproximator.approximateToSuperType(type, TypeApproximatorConfiguration.SubtypeCapturedTypesApproximation)
if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases if (superType != null && !KotlinBuiltIns.isAnyOrNullableAny(superType)) { // todo rethink error reporting for Any cases
targetType = superType targetType = superType
} }
@@ -189,12 +199,14 @@ class ConstraintInjector(val constraintIncorporator: ConstraintIncorporator, val
} }
override fun getConstraintsForVariable(typeVariable: NewTypeVariable) = override fun getConstraintsForVariable(typeVariable: NewTypeVariable) =
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.constraints c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.constraints
?: fixedTypeVariable(typeVariable) ?: fixedTypeVariable(typeVariable)
fun fixedTypeVariable(variable: NewTypeVariable): Nothing { fun fixedTypeVariable(variable: NewTypeVariable): Nothing {
error("Type variable $variable should not be fixed!\n" + error(
renderBaseConstraint()) "Type variable $variable should not be fixed!\n" +
renderBaseConstraint()
)
} }
private fun renderBaseConstraint() = "Base constraint: $baseLowerType <: $baseUpperType from position: $position" private fun renderBaseConstraint() = "Base constraint: $baseLowerType <: $baseUpperType from position: $position"
@@ -27,8 +27,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinConstraintSystemCompleter( class KotlinConstraintSystemCompleter(
private val resultTypeResolver: ResultTypeResolver, private val resultTypeResolver: ResultTypeResolver,
private val variableFixationFinder: VariableFixationFinder private val variableFixationFinder: VariableFixationFinder
) { ) {
enum class ConstraintSystemCompletionMode { enum class ConstraintSystemCompletionMode {
FULL, FULL,
@@ -43,15 +43,16 @@ class KotlinConstraintSystemCompleter(
// mutable operations // mutable operations
fun addError(error: KotlinCallDiagnostic) fun addError(error: KotlinCallDiagnostic)
fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType)
} }
fun runCompletion( fun runCompletion(
c: Context, c: Context,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelPrimitive: ResolvedAtom, topLevelPrimitive: ResolvedAtom,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
analyze: (PostponedResolvedAtom) -> Unit analyze: (PostponedResolvedAtom) -> Unit
) { ) {
while (true) { while (true) {
if (analyzePostponeArgumentIfPossible(c, topLevelPrimitive, analyze)) continue if (analyzePostponeArgumentIfPossible(c, topLevelPrimitive, analyze)) continue
@@ -59,7 +60,8 @@ class KotlinConstraintSystemCompleter(
val allTypeVariables = getOrderedAllTypeVariables(c, topLevelPrimitive) val allTypeVariables = getOrderedAllTypeVariables(c, topLevelPrimitive)
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive) val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)
val variableForFixation = variableFixationFinder.findFirstVariableForFixation( val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType
)
if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) { if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
if (forcePostponedAtomResolution<ResolvedCallableReferenceAtom>(topLevelPrimitive, analyze)) continue if (forcePostponedAtomResolution<ResolvedCallableReferenceAtom>(topLevelPrimitive, analyze)) continue
@@ -88,8 +90,8 @@ class KotlinConstraintSystemCompleter(
} }
private fun shouldForceCallableReferenceOrLambdaResolution( private fun shouldForceCallableReferenceOrLambdaResolution(
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
variableForFixation: VariableFixationFinder.VariableForFixation? variableForFixation: VariableFixationFinder.VariableForFixation?
): Boolean { ): Boolean {
if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false if (completionMode == ConstraintSystemCompletionMode.PARTIAL) return false
if (variableForFixation != null && variableForFixation.hasProperConstraint) return false if (variableForFixation != null && variableForFixation.hasProperConstraint) return false
@@ -98,7 +100,11 @@ class KotlinConstraintSystemCompleter(
} }
// true if we do analyze // true if we do analyze
private fun analyzePostponeArgumentIfPossible(c: Context, topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean { private fun analyzePostponeArgumentIfPossible(
c: Context,
topLevelPrimitive: ResolvedAtom,
analyze: (PostponedResolvedAtom) -> Unit
): Boolean {
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)) { for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)) {
if (canWeAnalyzeIt(c, argument)) { if (canWeAnalyzeIt(c, argument)) {
analyze(argument) analyze(argument)
@@ -110,8 +116,8 @@ class KotlinConstraintSystemCompleter(
// true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful // true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful
private inline fun <reified T : PostponedResolvedAtom> forcePostponedAtomResolution( private inline fun <reified T : PostponedResolvedAtom> forcePostponedAtomResolution(
topLevelPrimitive: ResolvedAtom, topLevelPrimitive: ResolvedAtom,
analyze: (PostponedResolvedAtom) -> Unit analyze: (PostponedResolvedAtom) -> Unit
): Boolean { ): Boolean {
val postponedArgument = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).firstIsInstanceOrNull<T>() ?: return false val postponedArgument = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).firstIsInstanceOrNull<T>() ?: return false
analyze(postponedArgument) analyze(postponedArgument)
@@ -129,7 +135,7 @@ class KotlinConstraintSystemCompleter(
return arrayListOf<PostponedResolvedAtom>().apply { topLevelPrimitive.process(this) } return arrayListOf<PostponedResolvedAtom>().apply { topLevelPrimitive.process(this) }
} }
private fun getOrderedAllTypeVariables(c: Context, topLevelPrimitive: ResolvedAtom) : List<TypeConstructor> { private fun getOrderedAllTypeVariables(c: Context, topLevelPrimitive: ResolvedAtom): List<TypeConstructor> {
fun ResolvedAtom.process(to: MutableList<TypeConstructor>) { fun ResolvedAtom.process(to: MutableList<TypeConstructor>) {
val typeVariables = when (this) { val typeVariables = when (this) {
is ResolvedCallAtom -> substitutor.freshVariables is ResolvedCallAtom -> substitutor.freshVariables
@@ -146,6 +152,7 @@ class KotlinConstraintSystemCompleter(
subResolvedAtoms.forEach { it.process(to) } subResolvedAtoms.forEach { it.process(to) }
} }
} }
val result = arrayListOf<TypeConstructor>().apply { topLevelPrimitive.process(this) } val result = arrayListOf<TypeConstructor>().apply { topLevelPrimitive.process(this) }
assert(result.size == c.notFixedTypeVariables.size) { assert(result.size == c.notFixedTypeVariables.size) {
@@ -164,10 +171,10 @@ class KotlinConstraintSystemCompleter(
} }
private fun fixVariable( private fun fixVariable(
c: Context, c: Context,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
variableWithConstraints: VariableWithConstraints, variableWithConstraints: VariableWithConstraints,
postponedResolveKtPrimitives: List<PostponedResolvedAtom> postponedResolveKtPrimitives: List<PostponedResolvedAtom>
) { ) {
val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints) val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
@@ -29,26 +29,27 @@ interface NewTypeSubstitutor {
fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type, runCapturedChecks = true, keepAnnotation = false) ?: type fun safeSubstitute(type: UnwrappedType): UnwrappedType = substitute(type, runCapturedChecks = true, keepAnnotation = false) ?: type
fun substituteKeepAnnotations(type: UnwrappedType): UnwrappedType = fun substituteKeepAnnotations(type: UnwrappedType): UnwrappedType =
substitute(type, runCapturedChecks = true, keepAnnotation = true) ?: type substitute(type, runCapturedChecks = true, keepAnnotation = true) ?: type
private fun substitute(type: UnwrappedType, keepAnnotation: Boolean, runCapturedChecks: Boolean): UnwrappedType? = private fun substitute(type: UnwrappedType, keepAnnotation: Boolean, runCapturedChecks: Boolean): UnwrappedType? =
when (type) { when (type) {
is SimpleType -> substitute(type, keepAnnotation, runCapturedChecks) is SimpleType -> substitute(type, keepAnnotation, runCapturedChecks)
is FlexibleType -> if (type is DynamicType || type is RawType) { is FlexibleType -> if (type is DynamicType || type is RawType) {
null
} else {
val lowerBound = substitute(type.lowerBound, keepAnnotation, runCapturedChecks)
val upperBound = substitute(type.upperBound, keepAnnotation, runCapturedChecks)
if (lowerBound == null && upperBound == null) {
null null
} } else {
else { // todo discuss lowerIfFlexible and upperIfFlexible
val lowerBound = substitute(type.lowerBound, keepAnnotation, runCapturedChecks) KotlinTypeFactory.flexibleType(
val upperBound = substitute(type.upperBound, keepAnnotation, runCapturedChecks) lowerBound?.lowerIfFlexible() ?: type.lowerBound,
if (lowerBound == null && upperBound == null) { upperBound?.upperIfFlexible() ?: type.upperBound
null )
}
else {
// todo discuss lowerIfFlexible and upperIfFlexible
KotlinTypeFactory.flexibleType(lowerBound?.lowerIfFlexible() ?: type.lowerBound, upperBound?.upperIfFlexible() ?: type.upperBound)
}
} }
} }
}
private fun substitute(type: SimpleType, keepAnnotation: Boolean, runCapturedChecks: Boolean): UnwrappedType? { private fun substitute(type: SimpleType, keepAnnotation: Boolean, runCapturedChecks: Boolean): UnwrappedType? {
if (type.isError) return null if (type.isError) return null
@@ -57,10 +58,11 @@ interface NewTypeSubstitutor {
val substitutedExpandedType = substitute(type.expandedType, keepAnnotation, runCapturedChecks) val substitutedExpandedType = substitute(type.expandedType, keepAnnotation, runCapturedChecks)
val substitutedAbbreviation = substitute(type.abbreviation, keepAnnotation, runCapturedChecks) val substitutedAbbreviation = substitute(type.abbreviation, keepAnnotation, runCapturedChecks)
if (substitutedExpandedType is SimpleType? && substitutedAbbreviation is SimpleType?) { if (substitutedExpandedType is SimpleType? && substitutedAbbreviation is SimpleType?) {
return AbbreviatedType(substitutedExpandedType ?: type.expandedType, return AbbreviatedType(
substitutedAbbreviation ?: type.abbreviation) substitutedExpandedType ?: type.expandedType,
} substitutedAbbreviation ?: type.abbreviation
else { )
} else {
return substitutedExpandedType return substitutedExpandedType
} }
} }
@@ -74,21 +76,26 @@ interface NewTypeSubstitutor {
if (typeConstructor is NewCapturedTypeConstructor) { if (typeConstructor is NewCapturedTypeConstructor) {
if (!runCapturedChecks) return null if (!runCapturedChecks) return null
assert(type is NewCapturedType || (type is DefinitelyNotNullType && type.original is NewCapturedType)) { // KT-16147 assert(type is NewCapturedType || (type is DefinitelyNotNullType && type.original is NewCapturedType)) {
// KT-16147
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " + "Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
"and class: ${type::class.java.canonicalName}. type.toString() = $type" "and class: ${type::class.java.canonicalName}. type.toString() = $type"
} }
val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType val capturedType = if (type is DefinitelyNotNullType) type.original as NewCapturedType else type as NewCapturedType
val lower = capturedType.lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) } val lower = capturedType.lowerType?.let { substitute(it, keepAnnotation, runCapturedChecks = false) }
if (lower != null) throw IllegalStateException("Illegal type substitutor: $this, " + if (lower != null) throw IllegalStateException(
"because for captured type '$type' lower type approximation should be null, but it is: '$lower'," + "Illegal type substitutor: $this, " +
"original lower type: '${capturedType.lowerType}") "because for captured type '$type' lower type approximation should be null, but it is: '$lower'," +
"original lower type: '${capturedType.lowerType}"
)
typeConstructor.supertypes.forEach { supertype -> typeConstructor.supertypes.forEach { supertype ->
substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let { substitute(supertype, keepAnnotation, runCapturedChecks = false)?.let {
throw IllegalStateException("Illegal type substitutor: $this, " + throw IllegalStateException(
"because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," + "Illegal type substitutor: $this, " +
"original supertype: '$supertype'") "because for captured type '$type' supertype approximation should be null, but it is: '$supertype'," +
"original supertype: '$supertype'"
)
} }
} }
@@ -120,9 +127,9 @@ interface NewTypeSubstitutor {
} }
private fun substituteParametrizedType( private fun substituteParametrizedType(
type: SimpleType, type: SimpleType,
keepAnnotation: Boolean, keepAnnotation: Boolean,
runCapturedChecks: Boolean runCapturedChecks: Boolean
): UnwrappedType? { ): UnwrappedType? {
val parameters = type.constructor.parameters val parameters = type.constructor.parameters
val arguments = type.arguments val arguments = type.arguments
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.types.checker.intersectTypes
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
class ResultTypeResolver( class ResultTypeResolver(
val typeApproximator: TypeApproximator val typeApproximator: TypeApproximator
) { ) {
interface Context { interface Context {
fun isProperType(type: UnwrappedType): Boolean fun isProperType(type: UnwrappedType): Boolean
@@ -49,8 +49,7 @@ class ResultTypeResolver(
val superType = findSuperType(c, variableWithConstraints) val superType = findSuperType(c, variableWithConstraints)
val result = if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) { val result = if (direction == ResolveDirection.TO_SUBTYPE || direction == ResolveDirection.UNKNOWN) {
c.resultType(subType, superType, variableWithConstraints) c.resultType(subType, superType, variableWithConstraints)
} } else {
else {
c.resultType(superType, subType, variableWithConstraints) c.resultType(superType, subType, variableWithConstraints)
} }
@@ -58,9 +57,9 @@ class ResultTypeResolver(
} }
private fun Context.resultType( private fun Context.resultType(
firstCandidate: UnwrappedType?, firstCandidate: UnwrappedType?,
secondCandidate: UnwrappedType?, secondCandidate: UnwrappedType?,
variableWithConstraints: VariableWithConstraints variableWithConstraints: VariableWithConstraints
): UnwrappedType? { ): UnwrappedType? {
if (firstCandidate == null || secondCandidate == null) return firstCandidate ?: secondCandidate if (firstCandidate == null || secondCandidate == null) return firstCandidate ?: secondCandidate
@@ -68,8 +67,7 @@ class ResultTypeResolver(
if (isSuitableType(secondCandidate, variableWithConstraints)) { if (isSuitableType(secondCandidate, variableWithConstraints)) {
return secondCandidate return secondCandidate
} } else {
else {
return firstCandidate return firstCandidate
} }
} }
@@ -105,8 +103,11 @@ class ResultTypeResolver(
* *
*/ */
return typeApproximator.approximateToSuperType(adjustedCommonSuperType, TypeApproximatorConfiguration.CapturedTypesApproximation) return typeApproximator.approximateToSuperType(
?: adjustedCommonSuperType adjustedCommonSuperType,
TypeApproximatorConfiguration.CapturedTypesApproximation
)
?: adjustedCommonSuperType
} }
return null return null
@@ -150,9 +151,9 @@ class ResultTypeResolver(
} }
fun findResultIfThereIsEqualsConstraint( fun findResultIfThereIsEqualsConstraint(
c: Context, c: Context,
variableWithConstraints: VariableWithConstraints, variableWithConstraints: VariableWithConstraints,
allowedFixToNotProperType: Boolean = false allowedFixToNotProperType: Boolean = false
): UnwrappedType? { ): UnwrappedType? {
val properEqualsConstraint = variableWithConstraints.constraints.filter { val properEqualsConstraint = variableWithConstraints.constraints.filter {
it.kind == ConstraintKind.EQUALITY && c.isProperType(it.type) it.kind == ConstraintKind.EQUALITY && c.isProperType(it.type)
@@ -160,7 +161,7 @@ class ResultTypeResolver(
if (properEqualsConstraint.isNotEmpty()) { if (properEqualsConstraint.isNotEmpty()) {
return properEqualsConstraint.map { it.type }.singleBestRepresentative()?.unwrap() return properEqualsConstraint.map { it.type }.singleBestRepresentative()?.unwrap()
?: properEqualsConstraint.first().type // seems like constraint system has contradiction ?: properEqualsConstraint.first().type // seems like constraint system has contradiction
} }
if (!allowedFixToNotProperType) return null if (!allowedFixToNotProperType) return null
@@ -31,6 +31,7 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
// super and sub type isSingleClassifierType // super and sub type isSingleClassifierType
abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType) abstract fun addUpperConstraint(typeVariable: TypeConstructor, superType: UnwrappedType)
abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType) abstract fun addLowerConstraint(typeVariable: TypeConstructor, subType: UnwrappedType)
override fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when { override fun getLowerCapturedTypePolicy(subType: SimpleType, superType: NewCapturedType) = when {
@@ -65,10 +66,10 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
} }
private fun UnwrappedType.isTypeVariableWithExact() = private fun UnwrappedType.isTypeVariableWithExact() =
anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasExactAnnotation() anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasExactAnnotation()
private fun UnwrappedType.isTypeVariableWithNoInfer() = private fun UnwrappedType.isTypeVariableWithNoInfer() =
anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasNoInferAnnotation() anyBound(this@TypeCheckerContextForConstraintSystem::isMyTypeVariable) && hasNoInferAnnotation()
private fun internalAddSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? { private fun internalAddSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType): Boolean? {
assertInputTypes(subType, superType) assertInputTypes(subType, superType)
@@ -81,8 +82,7 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
if (subType.anyBound(this::isMyTypeVariable)) { if (subType.anyBound(this::isMyTypeVariable)) {
return simplifyUpperConstraint(subType, superType) && (answer ?: true) return simplifyUpperConstraint(subType, superType) && (answer ?: true)
} } else {
else {
return simplifyConstraintForPossibleIntersectionSubType(subType, superType) ?: answer return simplifyConstraintForPossibleIntersectionSubType(subType, superType) ?: answer
} }
} }
@@ -174,7 +174,7 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
if (typeVariable.isMarkedNullable) { if (typeVariable.isMarkedNullable) {
// here is important that superType is singleClassifierType // here is important that superType is singleClassifierType
return superType.anyBound(this::isMyTypeVariable) || return superType.anyBound(this::isMyTypeVariable) ||
isSubtypeOfByTypeChecker(typeVariable.builtIns.nullableNothingType, superType) isSubtypeOfByTypeChecker(typeVariable.builtIns.nullableNothingType, superType)
} }
return true return true
@@ -222,11 +222,14 @@ abstract class TypeCheckerContextForConstraintSystem : TypeCheckerContext(errorT
} }
private fun isSubtypeOfByTypeChecker(subType: UnwrappedType, superType: UnwrappedType) = private fun isSubtypeOfByTypeChecker(subType: UnwrappedType, superType: UnwrappedType) =
with(NewKotlinTypeChecker) { this@TypeCheckerContextForConstraintSystem.isSubtypeOf(subType, superType) } with(NewKotlinTypeChecker) { this@TypeCheckerContextForConstraintSystem.isSubtypeOf(subType, superType) }
private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) { private fun assertInputTypes(subType: UnwrappedType, superType: UnwrappedType) {
fun correctSubType(subType: SimpleType) = subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError fun correctSubType(subType: SimpleType) =
fun correctSuperType(superType: SimpleType) = superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError subType.isSingleClassifierType || subType.isIntersectionType || isMyTypeVariable(subType) || subType.isError
fun correctSuperType(superType: SimpleType) =
superType.isSingleClassifierType || superType.isIntersectionType || isMyTypeVariable(superType) || superType.isError
assert(subType.bothBounds(::correctSubType)) { assert(subType.bothBounds(::correctSubType)) {
"Not singleClassifierType and not intersection subType: $subType" "Not singleClassifierType and not intersection subType: $subType"
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.SmartSet
class TypeVariableDependencyInformationProvider( class TypeVariableDependencyInformationProvider(
private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>, private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>,
private val postponedKtPrimitives: List<PostponedResolvedAtom>, private val postponedKtPrimitives: List<PostponedResolvedAtom>,
private val topLevelType: UnwrappedType? private val topLevelType: UnwrappedType?
) { ) {
// not oriented edges // not oriented edges
private val constrainEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf() private val constrainEdges: MutableMap<TypeConstructor, MutableSet<TypeConstructor>> = hashMapOf()
@@ -32,9 +32,9 @@ import org.jetbrains.kotlin.utils.SmartList
private typealias Variable = VariableWithConstraints private typealias Variable = VariableWithConstraints
class TypeVariableDirectionCalculator( class TypeVariableDirectionCalculator(
private val c: VariableFixationFinder.Context, private val c: VariableFixationFinder.Context,
private val postponedKtPrimitives: List<PostponedResolvedAtom>, private val postponedKtPrimitives: List<PostponedResolvedAtom>,
topLevelType: UnwrappedType topLevelType: UnwrappedType
) { ) {
enum class ResolveDirection { enum class ResolveDirection {
TO_SUBTYPE, TO_SUBTYPE,
@@ -53,7 +53,7 @@ class TypeVariableDirectionCalculator(
} }
fun getDirection(typeVariable: Variable): ResolveDirection = fun getDirection(typeVariable: Variable): ResolveDirection =
directions.getOrDefault(typeVariable, ResolveDirection.UNKNOWN) directions.getOrDefault(typeVariable, ResolveDirection.UNKNOWN)
private fun setupDirections(topReturnType: UnwrappedType) { private fun setupDirections(topReturnType: UnwrappedType) {
topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction -> topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
@@ -87,32 +87,35 @@ class TypeVariableDirectionCalculator(
} }
private fun getConstraintDependencies( private fun getConstraintDependencies(
variable: Variable, variable: Variable,
direction: ResolveDirection direction: ResolveDirection
): List<NodeWithDirection> = ): List<NodeWithDirection> =
SmartList<NodeWithDirection>().also { result -> SmartList<NodeWithDirection>().also { result ->
for (constraint in variable.constraints) { for (constraint in variable.constraints) {
if (!isInterestingConstraint(direction, constraint)) continue if (!isInterestingConstraint(direction, constraint)) continue
constraint.type.visitType(direction) { nodeVariable, nodeDirection -> constraint.type.visitType(direction) { nodeVariable, nodeDirection ->
result.add(NodeWithDirection(nodeVariable, nodeDirection)) result.add(NodeWithDirection(nodeVariable, nodeDirection))
}
} }
} }
}
private fun isInterestingConstraint(direction: ResolveDirection, constraint: Constraint): Boolean = private fun isInterestingConstraint(direction: ResolveDirection, constraint: Constraint): Boolean =
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) && !(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
!(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER) !(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
private fun UnwrappedType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) = private fun UnwrappedType.visitType(
when (this) { startDirection: ResolveDirection,
is SimpleType -> visitType(startDirection, action) action: (variable: Variable, direction: ResolveDirection) -> Unit
is FlexibleType -> { ) =
lowerBound.visitType(startDirection, action) when (this) {
upperBound.visitType(startDirection, action) is SimpleType -> visitType(startDirection, action)
} is FlexibleType -> {
lowerBound.visitType(startDirection, action)
upperBound.visitType(startDirection, action)
} }
}
private fun SimpleType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) { private fun SimpleType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) {
if (isIntersectionType) { if (isIntersectionType) {
@@ -34,11 +34,11 @@ class VariableFixationFinder {
data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean) data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean)
fun findFirstVariableForFixation( fun findFirstVariableForFixation(
c: Context, c: Context,
allTypeVariables: List<TypeConstructor>, allTypeVariables: List<TypeConstructor>,
postponedKtPrimitives: List<PostponedResolvedAtom>, postponedKtPrimitives: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType topLevelType: UnwrappedType
): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType) ): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
private enum class TypeVariableFixationReadiness { private enum class TypeVariableFixationReadiness {
@@ -50,11 +50,11 @@ class VariableFixationFinder {
} }
private fun Context.getTypeVariableReadiness( private fun Context.getTypeVariableReadiness(
variable: TypeConstructor, variable: TypeConstructor,
dependencyProvider: TypeVariableDependencyInformationProvider dependencyProvider: TypeVariableDependencyInformationProvider
): TypeVariableFixationReadiness = when { ): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) || !notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT !variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY hasDependencyToOtherTypeVariables(variable) -> TypeVariableFixationReadiness.WITH_COMPLEX_DEPENDENCY
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
@@ -62,10 +62,10 @@ class VariableFixationFinder {
} }
private fun Context.findTypeVariableForFixation( private fun Context.findTypeVariableForFixation(
allTypeVariables: List<TypeConstructor>, allTypeVariables: List<TypeConstructor>,
postponedKtPrimitives: List<PostponedResolvedAtom>, postponedKtPrimitives: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType topLevelType: UnwrappedType
): VariableForFixation? { ): VariableForFixation? {
val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedKtPrimitives, val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedKtPrimitives,
topLevelType.takeIf { completionMode == PARTIAL }) topLevelType.takeIf { completionMode == PARTIAL })
@@ -89,12 +89,12 @@ class VariableFixationFinder {
} }
private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructor): Boolean = private fun Context.variableHasProperArgumentConstraints(variable: TypeConstructor): Boolean =
notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false notFixedTypeVariables[variable]?.constraints?.any { isProperArgumentConstraint(it) } ?: false
private fun Context.isProperArgumentConstraint(c: Constraint) = private fun Context.isProperArgumentConstraint(c: Constraint) =
isProperType(c.type) && c.position.initialConstraint.position !is DeclaredUpperBoundConstraintPosition isProperType(c.type) && c.position.initialConstraint.position !is DeclaredUpperBoundConstraintPosition
private fun Context.isProperType(type: UnwrappedType): Boolean = private fun Context.isProperType(type: UnwrappedType): Boolean =
!type.contains { notFixedTypeVariables.containsKey(it.constructor) } !type.contains { notFixedTypeVariables.containsKey(it.constructor) }
} }
@@ -30,12 +30,15 @@ sealed class ConstraintPosition
class ExplicitTypeParameterConstraintPosition(val typeArgument: SimpleTypeArgument) : ConstraintPosition() { class ExplicitTypeParameterConstraintPosition(val typeArgument: SimpleTypeArgument) : ConstraintPosition() {
override fun toString() = "TypeParameter $typeArgument" override fun toString() = "TypeParameter $typeArgument"
} }
class ExpectedTypeConstraintPosition(val topLevelCall: KotlinCall) : ConstraintPosition() { class ExpectedTypeConstraintPosition(val topLevelCall: KotlinCall) : ConstraintPosition() {
override fun toString() = "ExpectedType for call $topLevelCall" override fun toString() = "ExpectedType for call $topLevelCall"
} }
class DeclaredUpperBoundConstraintPosition(val typeParameterDescriptor: TypeParameterDescriptor) : ConstraintPosition() { class DeclaredUpperBoundConstraintPosition(val typeParameterDescriptor: TypeParameterDescriptor) : ConstraintPosition() {
override fun toString() = "DeclaredUpperBound ${typeParameterDescriptor.name} from ${typeParameterDescriptor.containingDeclaration}" override fun toString() = "DeclaredUpperBound ${typeParameterDescriptor.name} from ${typeParameterDescriptor.containingDeclaration}"
} }
class ArgumentConstraintPosition(val argument: KotlinCallArgument) : ConstraintPosition() { class ArgumentConstraintPosition(val argument: KotlinCallArgument) : ConstraintPosition() {
override fun toString() = "Argument $argument" override fun toString() = "Argument $argument"
} }
@@ -47,9 +50,11 @@ class ReceiverConstraintPosition(val argument: KotlinCallArgument) : ConstraintP
class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintPosition() { class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintPosition() {
override fun toString() = "Fix variable $variable" override fun toString() = "Fix variable $variable"
} }
class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() { class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() {
override fun toString() = "TypeArgument $typeArgument" override fun toString() = "TypeArgument $typeArgument"
} }
class LambdaArgumentConstraintPosition(val lambda: ResolvedLambdaAtom) : ConstraintPosition() { class LambdaArgumentConstraintPosition(val lambda: ResolvedLambdaAtom) : ConstraintPosition() {
override fun toString(): String { override fun toString(): String {
return "LambdaArgument $lambda" return "LambdaArgument $lambda"
@@ -68,15 +73,15 @@ abstract class ConstraintSystemCallDiagnostic(applicability: ResolutionCandidate
} }
class NewConstraintError( class NewConstraintError(
val lowerType: UnwrappedType, val lowerType: UnwrappedType,
val upperType: UnwrappedType, val upperType: UnwrappedType,
val position: IncorporationConstraintPosition val position: IncorporationConstraintPosition
) : ConstraintSystemCallDiagnostic(if (position.from is ReceiverConstraintPosition) INAPPLICABLE_WRONG_RECEIVER else INAPPLICABLE) ) : ConstraintSystemCallDiagnostic(if (position.from is ReceiverConstraintPosition) INAPPLICABLE_WRONG_RECEIVER else INAPPLICABLE)
class CapturedTypeFromSubtyping( class CapturedTypeFromSubtyping(
val typeVariable: NewTypeVariable, val typeVariable: NewTypeVariable,
val constraintType: UnwrappedType, val constraintType: UnwrappedType,
val position: ConstraintPosition val position: ConstraintPosition
) : ConstraintSystemCallDiagnostic(INAPPLICABLE) ) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : ConstraintSystemCallDiagnostic(INAPPLICABLE) class NotEnoughInformationForTypeParameter(val typeVariable: NewTypeVariable) : ConstraintSystemCallDiagnostic(INAPPLICABLE)
@@ -70,10 +70,10 @@ enum class ConstraintKind {
} }
class Constraint( class Constraint(
val kind: ConstraintKind, val kind: ConstraintKind,
val type: UnwrappedType, // flexible types here is allowed val type: UnwrappedType, // flexible types here is allowed
val position: IncorporationConstraintPosition, val position: IncorporationConstraintPosition,
val typeHashCode: Int = type.hashCode() val typeHashCode: Int = type.hashCode()
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
@@ -100,18 +100,18 @@ interface VariableWithConstraints {
} }
class InitialConstraint( class InitialConstraint(
val a: UnwrappedType, val a: UnwrappedType,
val b: UnwrappedType, val b: UnwrappedType,
val constraintKind: ConstraintKind, // see [checkConstraint] val constraintKind: ConstraintKind, // see [checkConstraint]
val position: ConstraintPosition val position: ConstraintPosition
) { ) {
override fun toString(): String { override fun toString(): String {
val sign = val sign =
when (constraintKind) { when (constraintKind) {
ConstraintKind.EQUALITY -> "==" ConstraintKind.EQUALITY -> "=="
ConstraintKind.LOWER -> ":>" ConstraintKind.LOWER -> ":>"
ConstraintKind.UPPER -> "<:" ConstraintKind.UPPER -> "<:"
} }
return "$a $sign $b from $position" return "$a $sign $b from $position"
} }
} }
@@ -25,15 +25,16 @@ import kotlin.collections.ArrayList
class MutableVariableWithConstraints( class MutableVariableWithConstraints(
override val typeVariable: NewTypeVariable, override val typeVariable: NewTypeVariable,
constraints: Collection<Constraint> = emptyList() constraints: Collection<Constraint> = emptyList()
) : VariableWithConstraints { ) : VariableWithConstraints {
override val constraints: List<Constraint> get() { override val constraints: List<Constraint>
if (simplifiedConstraints == null) { get() {
simplifiedConstraints = simplifyConstraints() if (simplifiedConstraints == null) {
simplifiedConstraints = simplifyConstraints()
}
return simplifiedConstraints!!
} }
return simplifiedConstraints!!
}
private val mutableConstraints = ArrayList(constraints) private val mutableConstraints = ArrayList(constraints)
private var simplifiedConstraints: List<Constraint>? = null private var simplifiedConstraints: List<Constraint>? = null
@@ -49,8 +50,7 @@ class MutableVariableWithConstraints(
val actualConstraint = if (previousConstraintWithSameType.isNotEmpty()) { val actualConstraint = if (previousConstraintWithSameType.isNotEmpty()) {
// i.e. previous is LOWER and new is UPPER or opposite situation // i.e. previous is LOWER and new is UPPER or opposite situation
Constraint(ConstraintKind.EQUALITY, constraint.type, constraint.position, constraint.typeHashCode) Constraint(ConstraintKind.EQUALITY, constraint.type, constraint.position, constraint.typeHashCode)
} } else {
else {
constraint constraint
} }
mutableConstraints.add(actualConstraint) mutableConstraints.add(actualConstraint)
@@ -72,16 +72,16 @@ class MutableVariableWithConstraints(
} }
private fun newConstraintIsUseless(oldKind: ConstraintKind, newKind: ConstraintKind) = private fun newConstraintIsUseless(oldKind: ConstraintKind, newKind: ConstraintKind) =
when (oldKind) { when (oldKind) {
ConstraintKind.EQUALITY -> true ConstraintKind.EQUALITY -> true
ConstraintKind.LOWER -> newKind == ConstraintKind.LOWER ConstraintKind.LOWER -> newKind == ConstraintKind.LOWER
ConstraintKind.UPPER -> newKind == ConstraintKind.UPPER ConstraintKind.UPPER -> newKind == ConstraintKind.UPPER
} }
private fun simplifyConstraints(): List<Constraint> { private fun simplifyConstraints(): List<Constraint> {
val equalityConstraints = mutableConstraints val equalityConstraints = mutableConstraints
.filter { it.kind == ConstraintKind.EQUALITY } .filter { it.kind == ConstraintKind.EQUALITY }
.groupBy { it.typeHashCode } .groupBy { it.typeHashCode }
return mutableConstraints.filter { isUsefulConstraint(it, equalityConstraints) } return mutableConstraints.filter { isUsefulConstraint(it, equalityConstraints) }
} }
@@ -31,16 +31,15 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
class NewConstraintSystemImpl( class NewConstraintSystemImpl(
private val constraintInjector: ConstraintInjector, private val constraintInjector: ConstraintInjector,
override val builtIns: KotlinBuiltIns override val builtIns: KotlinBuiltIns
): ) :
NewConstraintSystem, NewConstraintSystem,
ConstraintSystemBuilder, ConstraintSystemBuilder,
ConstraintInjector.Context, ConstraintInjector.Context,
ResultTypeResolver.Context, ResultTypeResolver.Context,
KotlinConstraintSystemCompleter.Context, KotlinConstraintSystemCompleter.Context,
PostponedArgumentsAnalyzer.Context PostponedArgumentsAnalyzer.Context {
{
private val storage = MutableConstraintStorage() private val storage = MutableConstraintStorage()
private var state = State.BUILDING private var state = State.BUILDING
private val typeVariablesTransaction: MutableList<NewTypeVariable> = SmartList() private val typeVariablesTransaction: MutableList<NewTypeVariable> = SmartList()
@@ -83,10 +82,20 @@ class NewConstraintSystemImpl(
} }
override fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) = override fun addSubtypeConstraint(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
constraintInjector.addInitialSubtypeConstraint(apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }, lowerType, upperType, position) constraintInjector.addInitialSubtypeConstraint(
apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
lowerType,
upperType,
position
)
override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) = override fun addEqualityConstraint(a: UnwrappedType, b: UnwrappedType, position: ConstraintPosition) =
constraintInjector.addInitialEqualityConstraint(apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) }, a, b, position) constraintInjector.addInitialEqualityConstraint(
apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) },
a,
b,
position
)
override fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor> { override fun getProperSuperTypeConstructors(type: UnwrappedType): List<TypeConstructor> {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
@@ -146,7 +155,14 @@ class NewConstraintSystemImpl(
// ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context // ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context
override val hasContradiction: Boolean override val hasContradiction: Boolean
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.FREEZED, State.BUILDING, State.COMPLETION, State.TRANSACTION) } get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply {
checkState(
State.FREEZED,
State.BUILDING,
State.COMPLETION,
State.TRANSACTION
)
}
override fun addOtherSystem(otherSystem: ConstraintStorage) { override fun addOtherSystem(otherSystem: ConstraintStorage) {
storage.allTypeVariables.putAll(otherSystem.allTypeVariables) storage.allTypeVariables.putAll(otherSystem.allTypeVariables)
@@ -154,7 +170,8 @@ class NewConstraintSystemImpl(
notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints) notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints)
} }
storage.initialConstraints.addAll(otherSystem.initialConstraints) storage.initialConstraints.addAll(otherSystem.initialConstraints)
storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints) storage.maxTypeDepthFromInitialConstraints =
Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
storage.errors.addAll(otherSystem.errors) storage.errors.addAll(otherSystem.errors)
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables) storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
} }
@@ -173,10 +190,11 @@ class NewConstraintSystemImpl(
} }
// ConstraintInjector.Context // ConstraintInjector.Context
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() { override val allTypeVariables: Map<TypeConstructor, NewTypeVariable>
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) get() {
return storage.allTypeVariables checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
} return storage.allTypeVariables
}
override var maxTypeDepthFromInitialConstraints: Int override var maxTypeDepthFromInitialConstraints: Int
get() = storage.maxTypeDepthFromInitialConstraints get() = storage.maxTypeDepthFromInitialConstraints
@@ -191,10 +209,11 @@ class NewConstraintSystemImpl(
} }
// ConstraintInjector.Context, FixationOrderCalculator.Context // ConstraintInjector.Context, FixationOrderCalculator.Context
override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints> get() { override val notFixedTypeVariables: MutableMap<TypeConstructor, MutableVariableWithConstraints>
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) get() {
return storage.notFixedTypeVariables checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
} return storage.notFixedTypeVariables
}
// ConstraintInjector.Context, KotlinConstraintSystemCompleter.Context // ConstraintInjector.Context, KotlinConstraintSystemCompleter.Context
override fun addError(error: KotlinCallDiagnostic) { override fun addError(error: KotlinCallDiagnostic) {
@@ -29,7 +29,8 @@ import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debugName: String): TypeConstructor, NewTypeVariableConstructor { class TypeVariableTypeConstructor(private val builtIns: KotlinBuiltIns, val debugName: String) : TypeConstructor,
NewTypeVariableConstructor {
override fun getParameters(): List<TypeParameterDescriptor> = emptyList() override fun getParameters(): List<TypeParameterDescriptor> = emptyList()
override fun getSupertypes(): Collection<KotlinType> = emptyList() override fun getSupertypes(): Collection<KotlinType> = emptyList()
override fun isFinal(): Boolean = false override fun isFinal(): Boolean = false
@@ -47,18 +48,19 @@ sealed class NewTypeVariable(builtIns: KotlinBuiltIns, name: String) {
// member scope is used if we have receiver with type TypeVariable(T) // member scope is used if we have receiver with type TypeVariable(T)
// todo add to member scope methods from supertypes for type variable // todo add to member scope methods from supertypes for type variable
val defaultType: SimpleType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope( val defaultType: SimpleType = KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
Annotations.EMPTY, freshTypeConstructor, arguments = emptyList(), Annotations.EMPTY, freshTypeConstructor, arguments = emptyList(),
nullable = false, memberScope = builtIns.any.unsubstitutedMemberScope) nullable = false, memberScope = builtIns.any.unsubstitutedMemberScope
)
override fun toString() = freshTypeConstructor.toString() override fun toString() = freshTypeConstructor.toString()
} }
class TypeVariableFromCallableDescriptor( class TypeVariableFromCallableDescriptor(
val originalTypeParameter: TypeParameterDescriptor val originalTypeParameter: TypeParameterDescriptor
) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier) ) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier)
class TypeVariableForLambdaReturnType( class TypeVariableForLambdaReturnType(
val lambdaArgument: LambdaKotlinCallArgument, val lambdaArgument: LambdaKotlinCallArgument,
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
name: String name: String
) : NewTypeVariable(builtIns, name) ) : NewTypeVariable(builtIns, name)
@@ -24,27 +24,27 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.prepareReceiverRegardingCap
class FakeKotlinCallArgumentForCallableReference( class FakeKotlinCallArgumentForCallableReference(
val index: Int val index: Int
) : KotlinCallArgument { ) : KotlinCallArgument {
override val isSpread: Boolean get() = false override val isSpread: Boolean get() = false
override val argumentName: Name? get() = null override val argumentName: Name? get() = null
} }
class ReceiverExpressionKotlinCallArgument private constructor( class ReceiverExpressionKotlinCallArgument private constructor(
override val receiver: ReceiverValueWithSmartCastInfo, override val receiver: ReceiverValueWithSmartCastInfo,
override val isSafeCall: Boolean = false, override val isSafeCall: Boolean = false,
val isVariableReceiverForInvoke: Boolean = false val isVariableReceiverForInvoke: Boolean = false
) : ExpressionKotlinCallArgument { ) : ExpressionKotlinCallArgument {
override val isSpread: Boolean get() = false override val isSpread: Boolean get() = false
override val argumentName: Name? get() = null override val argumentName: Name? get() = null
override fun toString() = "$receiver" + if(isSafeCall) "?" else "" override fun toString() = "$receiver" + if (isSafeCall) "?" else ""
companion object { companion object {
// we create ReceiverArgument and fix capture types // we create ReceiverArgument and fix capture types
operator fun invoke( operator fun invoke(
receiver: ReceiverValueWithSmartCastInfo, receiver: ReceiverValueWithSmartCastInfo,
isSafeCall: Boolean = false, isSafeCall: Boolean = false,
isVariableReceiverForInvoke: Boolean = false isVariableReceiverForInvoke: Boolean = false
) = ReceiverExpressionKotlinCallArgument(receiver.prepareReceiverRegardingCaptureTypes(), isSafeCall, isVariableReceiverForInvoke) ) = ReceiverExpressionKotlinCallArgument(receiver.prepareReceiverRegardingCaptureTypes(), isSafeCall, isVariableReceiverForInvoke)
} }
} }
@@ -78,8 +78,7 @@ fun KotlinCall.checkCallInvariants() {
assert(dispatchReceiverForInvokeExtension == null) { assert(dispatchReceiverForInvokeExtension == null) {
"Dispatch receiver for invoke should be null for not function call: $dispatchReceiverForInvokeExtension" "Dispatch receiver for invoke should be null for not function call: $dispatchReceiverForInvokeExtension"
} }
} } else {
else {
assert(externalArgument == null || !externalArgument!!.isSpread) { assert(externalArgument == null || !externalArgument!!.isSpread) {
"External argument cannot nave spread element: $externalArgument" "External argument cannot nave spread element: $externalArgument"
} }
@@ -88,7 +88,7 @@ interface FunctionExpression : LambdaKotlinCallArgument {
* D.E::foo <-> Expression * D.E::foo <-> Expression
*/ */
sealed class LHSResult { sealed class LHSResult {
class Type(val qualifier: QualifierReceiver, resolvedType: UnwrappedType): LHSResult() { class Type(val qualifier: QualifierReceiver, resolvedType: UnwrappedType) : LHSResult() {
val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo val unboundDetailedReceiver: ReceiverValueWithSmartCastInfo
init { init {
@@ -101,7 +101,7 @@ sealed class LHSResult {
} }
} }
class Object(val qualifier: QualifierReceiver): LHSResult() { class Object(val qualifier: QualifierReceiver) : LHSResult() {
val objectValueReceiver: ReceiverValueWithSmartCastInfo val objectValueReceiver: ReceiverValueWithSmartCastInfo
init { init {
@@ -111,12 +111,13 @@ sealed class LHSResult {
objectValueReceiver = qualifier.classValueReceiverWithSmartCastInfo ?: error("class value should be not null for $qualifier") objectValueReceiver = qualifier.classValueReceiverWithSmartCastInfo ?: error("class value should be not null for $qualifier")
} }
} }
class Expression(val lshCallArgument: SimpleKotlinCallArgument): LHSResult()
class Expression(val lshCallArgument: SimpleKotlinCallArgument) : LHSResult()
// todo this case is forbid for now // todo this case is forbid for now
object Empty: LHSResult() object Empty : LHSResult()
object Error: LHSResult() object Error : LHSResult()
} }
interface CallableReferenceKotlinCallArgument : PostponableKotlinCallArgument { interface CallableReferenceKotlinCallArgument : PostponableKotlinCallArgument {
@@ -135,6 +136,6 @@ interface TypeArgument
// todo allow '_' in frontend // todo allow '_' in frontend
object TypeArgumentPlaceholder : TypeArgument object TypeArgumentPlaceholder : TypeArgument
interface SimpleTypeArgument: TypeArgument { interface SimpleTypeArgument : TypeArgument {
val type: UnwrappedType val type: UnwrappedType
} }
@@ -31,7 +31,8 @@ abstract class InapplicableArgumentDiagnostic : KotlinCallDiagnostic(INAPPLICABL
} }
// ArgumentsToParameterMapper // ArgumentsToParameterMapper
class TooManyArguments(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) : KotlinCallDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) { class TooManyArguments(val argument: KotlinCallArgument, val descriptor: CallableDescriptor) :
KotlinCallDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
} }
@@ -50,54 +51,54 @@ class NameNotFound(val argument: KotlinCallArgument, val descriptor: CallableDes
} }
class NoValueForParameter( class NoValueForParameter(
val parameterDescriptor: ValueParameterDescriptor, val parameterDescriptor: ValueParameterDescriptor,
val descriptor: CallableDescriptor val descriptor: CallableDescriptor
) : KotlinCallDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) { ) : KotlinCallDiagnostic(INAPPLICABLE_ARGUMENTS_MAPPING_ERROR) {
override fun report(reporter: DiagnosticReporter) = reporter.onCall(this) override fun report(reporter: DiagnosticReporter) = reporter.onCall(this)
} }
class ArgumentPassedTwice( class ArgumentPassedTwice(
val argument: KotlinCallArgument, val argument: KotlinCallArgument,
val parameterDescriptor: ValueParameterDescriptor, val parameterDescriptor: ValueParameterDescriptor,
val firstOccurrence: ResolvedCallArgument val firstOccurrence: ResolvedCallArgument
) : KotlinCallDiagnostic(INAPPLICABLE) { ) : KotlinCallDiagnostic(INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
} }
class VarargArgumentOutsideParentheses( class VarargArgumentOutsideParentheses(
override val argument: KotlinCallArgument, override val argument: KotlinCallArgument,
val parameterDescriptor: ValueParameterDescriptor val parameterDescriptor: ValueParameterDescriptor
) : InapplicableArgumentDiagnostic() ) : InapplicableArgumentDiagnostic()
class NameForAmbiguousParameter( class NameForAmbiguousParameter(
val argument: KotlinCallArgument, val argument: KotlinCallArgument,
val parameterDescriptor: ValueParameterDescriptor, val parameterDescriptor: ValueParameterDescriptor,
val overriddenParameterWithOtherName: ValueParameterDescriptor val overriddenParameterWithOtherName: ValueParameterDescriptor
) : KotlinCallDiagnostic(CONVENTION_ERROR) { ) : KotlinCallDiagnostic(CONVENTION_ERROR) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
} }
class NamedArgumentReference( class NamedArgumentReference(
val argument: KotlinCallArgument, val argument: KotlinCallArgument,
val parameterDescriptor: ValueParameterDescriptor val parameterDescriptor: ValueParameterDescriptor
) : KotlinCallDiagnostic(RESOLVED) { ) : KotlinCallDiagnostic(RESOLVED) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgumentName(argument, this)
} }
// TypeArgumentsToParameterMapper // TypeArgumentsToParameterMapper
class WrongCountOfTypeArguments( class WrongCountOfTypeArguments(
val descriptor: CallableDescriptor, val descriptor: CallableDescriptor,
val currentCount: Int val currentCount: Int
) : KotlinCallDiagnostic(INAPPLICABLE) { ) : KotlinCallDiagnostic(INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) = reporter.onTypeArguments(this) override fun report(reporter: DiagnosticReporter) = reporter.onTypeArguments(this)
} }
// Callable reference resolution // Callable reference resolution
class CallableReferenceNotCompatible( class CallableReferenceNotCompatible(
override val argument: CallableReferenceKotlinCallArgument, override val argument: CallableReferenceKotlinCallArgument,
val candidate: CallableMemberDescriptor, val candidate: CallableMemberDescriptor,
val expectedType: UnwrappedType?, val expectedType: UnwrappedType?,
val callableReverenceType: UnwrappedType val callableReverenceType: UnwrappedType
) : InapplicableArgumentDiagnostic() ) : InapplicableArgumentDiagnostic()
// supported by FE but not supported by BE now // supported by FE but not supported by BE now
@@ -110,35 +111,35 @@ class CallableReferencesDefaultArgumentUsed(
} }
class NotCallableMemberReference( class NotCallableMemberReference(
override val argument: CallableReferenceKotlinCallArgument, override val argument: CallableReferenceKotlinCallArgument,
val candidate: CallableDescriptor val candidate: CallableDescriptor
) : InapplicableArgumentDiagnostic() ) : InapplicableArgumentDiagnostic()
class NoneCallableReferenceCandidates(override val argument: CallableReferenceKotlinCallArgument) : InapplicableArgumentDiagnostic() class NoneCallableReferenceCandidates(override val argument: CallableReferenceKotlinCallArgument) : InapplicableArgumentDiagnostic()
class CallableReferenceCandidatesAmbiguity( class CallableReferenceCandidatesAmbiguity(
override val argument: CallableReferenceKotlinCallArgument, override val argument: CallableReferenceKotlinCallArgument,
val candidates: Collection<CallableReferenceCandidate> val candidates: Collection<CallableReferenceCandidate>
) : InapplicableArgumentDiagnostic() ) : InapplicableArgumentDiagnostic()
class NotCallableExpectedType( class NotCallableExpectedType(
override val argument: CallableReferenceKotlinCallArgument, override val argument: CallableReferenceKotlinCallArgument,
val expectedType: UnwrappedType, val expectedType: UnwrappedType,
val notCallableTypeConstructor: TypeConstructor val notCallableTypeConstructor: TypeConstructor
) : InapplicableArgumentDiagnostic() ) : InapplicableArgumentDiagnostic()
// SmartCasts // SmartCasts
class SmartCastDiagnostic( class SmartCastDiagnostic(
val argument: ExpressionKotlinCallArgument, val argument: ExpressionKotlinCallArgument,
val smartCastType: UnwrappedType, val smartCastType: UnwrappedType,
val kotlinCall: KotlinCall? val kotlinCall: KotlinCall?
): KotlinCallDiagnostic(RESOLVED) { ) : KotlinCallDiagnostic(RESOLVED) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
} }
class UnstableSmartCast( class UnstableSmartCast(
val argument: ExpressionKotlinCallArgument, val argument: ExpressionKotlinCallArgument,
val targetType: UnwrappedType val targetType: UnwrappedType
) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) { ) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this) override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
} }
@@ -172,8 +173,8 @@ class NoneCandidatesCallDiagnostic(val kotlinCall: KotlinCall) : KotlinCallDiagn
} }
class ManyCandidatesCallDiagnostic( class ManyCandidatesCallDiagnostic(
val kotlinCall: KotlinCall, val kotlinCall: KotlinCall,
val candidates: Collection<KotlinResolutionCandidate> val candidates: Collection<KotlinResolutionCandidate>
) : KotlinCallDiagnostic(INAPPLICABLE) { ) : KotlinCallDiagnostic(INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) { override fun report(reporter: DiagnosticReporter) {
reporter.onCall(this) reporter.onCall(this)
@@ -36,20 +36,20 @@ import org.jetbrains.kotlin.types.isDynamic
class KotlinCallComponents( class KotlinCallComponents(
val statelessCallbacks: KotlinResolutionStatelessCallbacks, val statelessCallbacks: KotlinResolutionStatelessCallbacks,
val argumentsToParametersMapper: ArgumentsToParametersMapper, val argumentsToParametersMapper: ArgumentsToParametersMapper,
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper, val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
val constraintInjector: ConstraintInjector, val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes, val reflectionTypes: ReflectionTypes,
val builtIns: KotlinBuiltIns, val builtIns: KotlinBuiltIns,
val languageVersionSettings: LanguageVersionSettings val languageVersionSettings: LanguageVersionSettings
) )
class SimpleCandidateFactory( class SimpleCandidateFactory(
val callComponents: KotlinCallComponents, val callComponents: KotlinCallComponents,
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val kotlinCall: KotlinCall val kotlinCall: KotlinCall
): CandidateFactory<KotlinResolutionCandidate> { ) : CandidateFactory<KotlinResolutionCandidate> {
val baseSystem: ConstraintStorage val baseSystem: ConstraintStorage
init { init {
@@ -66,11 +66,11 @@ class SimpleCandidateFactory(
// todo: try something else, because current method is ugly and unstable // todo: try something else, because current method is ugly and unstable
private fun createReceiverArgument( private fun createReceiverArgument(
explicitReceiver: ReceiverKotlinCallArgument?, explicitReceiver: ReceiverKotlinCallArgument?,
fromResolution: ReceiverValueWithSmartCastInfo? fromResolution: ReceiverValueWithSmartCastInfo?
): SimpleKotlinCallArgument? = ): SimpleKotlinCallArgument? =
explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe
fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this
private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) { private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver
@@ -86,38 +86,55 @@ class SimpleCandidateFactory(
fun createCandidate(givenCandidate: GivenCandidate): KotlinResolutionCandidate { fun createCandidate(givenCandidate: GivenCandidate): KotlinResolutionCandidate {
val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false
val explicitReceiverKind = if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER val explicitReceiverKind =
if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) } val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) }
return createCandidate(givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null, return createCandidate(
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor) givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null,
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor
)
} }
override fun createCandidate( override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver, towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): KotlinResolutionCandidate { ): KotlinResolutionCandidate {
val dispatchArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind), val dispatchArgumentReceiver = createReceiverArgument(
towerCandidate.dispatchReceiver) kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind),
val extensionArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver) towerCandidate.dispatchReceiver
)
val extensionArgumentReceiver =
createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver)
return createCandidate(towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, return createCandidate(
extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null) towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver,
extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null
)
} }
private fun createCandidate( private fun createCandidate(
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
dispatchArgumentReceiver: SimpleKotlinCallArgument?, dispatchArgumentReceiver: SimpleKotlinCallArgument?,
extensionArgumentReceiver: SimpleKotlinCallArgument?, extensionArgumentReceiver: SimpleKotlinCallArgument?,
initialDiagnostics: Collection<KotlinCallDiagnostic>, initialDiagnostics: Collection<KotlinCallDiagnostic>,
knownSubstitutor: TypeSubstitutor? knownSubstitutor: TypeSubstitutor?
): KotlinResolutionCandidate { ): KotlinResolutionCandidate {
val resolvedKtCall = MutableResolvedCallAtom(kotlinCall, descriptor, explicitReceiverKind, val resolvedKtCall = MutableResolvedCallAtom(
dispatchArgumentReceiver, extensionArgumentReceiver) kotlinCall, descriptor, explicitReceiverKind,
dispatchArgumentReceiver, extensionArgumentReceiver
)
if (ErrorUtils.isError(descriptor)) { if (ErrorUtils.isError(descriptor)) {
return KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor, listOf(ErrorDescriptorResolutionPart)) return KotlinResolutionCandidate(
callComponents,
scopeTower,
baseSystem,
resolvedKtCall,
knownSubstitutor,
listOf(ErrorDescriptorResolutionPart)
)
} }
val candidate = KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor) val candidate = KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor)
@@ -145,45 +162,47 @@ class SimpleCandidateFactory(
val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall") val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall")
val errorDescriptor = if (kotlinCall.callKind == KotlinCallKind.VARIABLE) { val errorDescriptor = if (kotlinCall.callKind == KotlinCallKind.VARIABLE) {
errorScope.getContributedVariables(kotlinCall.name, scopeTower.location) errorScope.getContributedVariables(kotlinCall.name, scopeTower.location)
} } else {
else {
errorScope.getContributedFunctions(kotlinCall.name, scopeTower.location) errorScope.getContributedFunctions(kotlinCall.name, scopeTower.location)
}.first() }.first()
val dispatchReceiver = createReceiverArgument(kotlinCall.explicitReceiver, fromResolution = null) val dispatchReceiver = createReceiverArgument(kotlinCall.explicitReceiver, fromResolution = null)
val explicitReceiverKind = if (dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER val explicitReceiverKind =
if (dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
return createCandidate(errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null, return createCandidate(
initialDiagnostics = listOf(), knownSubstitutor = null) errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null,
initialDiagnostics = listOf(), knownSubstitutor = null
)
} }
} }
enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
VARIABLE( VARIABLE(
CheckVisibility, CheckVisibility,
CheckInfixResolutionPart, CheckInfixResolutionPart,
CheckOperatorResolutionPart, CheckOperatorResolutionPart,
CheckSuperExpressionCallPart, CheckSuperExpressionCallPart,
NoTypeArguments, NoTypeArguments,
NoArguments, NoArguments,
CreateFreshVariablesSubstitutor, CreateFreshVariablesSubstitutor,
CheckExplicitReceiverKindConsistency, CheckExplicitReceiverKindConsistency,
CheckReceivers CheckReceivers
), ),
FUNCTION( FUNCTION(
CheckInstantiationOfAbstractClass, CheckInstantiationOfAbstractClass,
CheckVisibility, CheckVisibility,
CheckInfixResolutionPart, CheckInfixResolutionPart,
CheckSuperExpressionCallPart, CheckSuperExpressionCallPart,
MapTypeArguments, MapTypeArguments,
MapArguments, MapArguments,
ArgumentsToCandidateParameterDescriptor, ArgumentsToCandidateParameterDescriptor,
CreateFreshVariablesSubstitutor, CreateFreshVariablesSubstitutor,
CheckExplicitReceiverKindConsistency, CheckExplicitReceiverKindConsistency,
CheckReceivers, CheckReceivers,
CheckArguments, CheckArguments,
CheckExternalArgument CheckExternalArgument
), ),
UNSUPPORTED(); UNSUPPORTED();
@@ -191,8 +210,8 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
} }
class GivenCandidate( class GivenCandidate(
val descriptor: FunctionDescriptor, val descriptor: FunctionDescriptor,
val dispatchReceiver: ReceiverValueWithSmartCastInfo?, val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
val knownTypeParametersResultingSubstitutor: TypeSubstitutor? val knownTypeParametersResultingSubstitutor: TypeSubstitutor?
) )
@@ -74,14 +74,15 @@ class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) :
setAnalyzedResults(listOf()) setAnalyzedResults(listOf())
} }
} }
sealed class PostponedResolvedAtom : ResolvedAtom() { sealed class PostponedResolvedAtom : ResolvedAtom() {
abstract val inputTypes: Collection<UnwrappedType> abstract val inputTypes: Collection<UnwrappedType>
abstract val outputType: UnwrappedType? abstract val outputType: UnwrappedType?
} }
class LambdaWithTypeVariableAsExpectedTypeAtom( class LambdaWithTypeVariableAsExpectedTypeAtom(
override val atom: LambdaKotlinCallArgument, override val atom: LambdaKotlinCallArgument,
val expectedType: UnwrappedType val expectedType: UnwrappedType
) : PostponedResolvedAtom() { ) : PostponedResolvedAtom() {
override val inputTypes: Collection<UnwrappedType> get() = listOf(expectedType) override val inputTypes: Collection<UnwrappedType> get() = listOf(expectedType)
override val outputType: UnwrappedType? get() = null override val outputType: UnwrappedType? get() = null
@@ -92,19 +93,19 @@ class LambdaWithTypeVariableAsExpectedTypeAtom(
} }
class ResolvedLambdaAtom( class ResolvedLambdaAtom(
override val atom: LambdaKotlinCallArgument, override val atom: LambdaKotlinCallArgument,
val isSuspend: Boolean, val isSuspend: Boolean,
val receiver: UnwrappedType?, val receiver: UnwrappedType?,
val parameters: List<UnwrappedType>, val parameters: List<UnwrappedType>,
val returnType: UnwrappedType, val returnType: UnwrappedType,
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType? val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?
) : PostponedResolvedAtom() { ) : PostponedResolvedAtom() {
lateinit var resultArguments: List<KotlinCallArgument> lateinit var resultArguments: List<KotlinCallArgument>
private set private set
fun setAnalyzedResults( fun setAnalyzedResults(
resultArguments: List<KotlinCallArgument>, resultArguments: List<KotlinCallArgument>,
subResolvedAtoms: List<ResolvedAtom> subResolvedAtoms: List<ResolvedAtom>
) { ) {
this.resultArguments = resultArguments this.resultArguments = resultArguments
setAnalyzedResults(subResolvedAtoms) setAnalyzedResults(subResolvedAtoms)
@@ -115,15 +116,15 @@ class ResolvedLambdaAtom(
} }
class ResolvedCallableReferenceAtom( class ResolvedCallableReferenceAtom(
override val atom: CallableReferenceKotlinCallArgument, override val atom: CallableReferenceKotlinCallArgument,
val expectedType: UnwrappedType? val expectedType: UnwrappedType?
) : PostponedResolvedAtom() { ) : PostponedResolvedAtom() {
var candidate: CallableReferenceCandidate? = null var candidate: CallableReferenceCandidate? = null
private set private set
fun setAnalyzedResults( fun setAnalyzedResults(
candidate: CallableReferenceCandidate?, candidate: CallableReferenceCandidate?,
subResolvedAtoms: List<ResolvedAtom> subResolvedAtoms: List<ResolvedAtom>
) { ) {
this.candidate = candidate this.candidate = candidate
setAnalyzedResults(subResolvedAtoms) setAnalyzedResults(subResolvedAtoms)
@@ -145,8 +146,8 @@ class ResolvedCallableReferenceAtom(
} }
class ResolvedCollectionLiteralAtom( class ResolvedCollectionLiteralAtom(
override val atom: CollectionLiteralKotlinCallArgument, override val atom: CollectionLiteralKotlinCallArgument,
val expectedType: UnwrappedType? val expectedType: UnwrappedType?
) : ResolvedAtom() { ) : ResolvedAtom() {
init { init {
setAnalyzedResults(listOf()) setAnalyzedResults(listOf())
@@ -154,11 +155,11 @@ class ResolvedCollectionLiteralAtom(
} }
class CallResolutionResult( class CallResolutionResult(
val type: Type, val type: Type,
val resultCallAtom: ResolvedCallAtom?, val resultCallAtom: ResolvedCallAtom?,
val diagnostics: List<KotlinCallDiagnostic>, val diagnostics: List<KotlinCallDiagnostic>,
val constraintSystem: ConstraintStorage, val constraintSystem: ConstraintStorage,
val allCandidates: Collection<KotlinResolutionCandidate>? = null val allCandidates: Collection<KotlinResolutionCandidate>? = null
) : ResolvedAtom() { ) : ResolvedAtom() {
override val atom: ResolutionAtom? get() = null override val atom: ResolutionAtom? get() = null
@@ -176,7 +177,8 @@ class CallResolutionResult(
override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})" override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})"
} }
val ResolvedCallAtom.freshReturnType: UnwrappedType? get() { val ResolvedCallAtom.freshReturnType: UnwrappedType?
val returnType = candidateDescriptor.returnType ?: return null get() {
return substitutor.safeSubstitute(returnType.unwrap()) val returnType = candidateDescriptor.returnType ?: return null
} return substitutor.safeSubstitute(returnType.unwrap())
}
@@ -56,17 +56,18 @@ interface KotlinDiagnosticsHolder {
fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) { fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) {
diagnostic?.let { addDiagnostic(it) } diagnostic?.let { addDiagnostic(it) }
} }
/** /**
* baseSystem contains all information from arguments, i.e. it is union of all system of arguments * baseSystem contains all information from arguments, i.e. it is union of all system of arguments
* Also by convention we suppose that baseSystem has no contradiction * Also by convention we suppose that baseSystem has no contradiction
*/ */
class KotlinResolutionCandidate( class KotlinResolutionCandidate(
val callComponents: KotlinCallComponents, val callComponents: KotlinCallComponents,
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
private val baseSystem: ConstraintStorage, private val baseSystem: ConstraintStorage,
val resolvedCall: MutableResolvedCallAtom, val resolvedCall: MutableResolvedCallAtom,
val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null, val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null,
private val resolutionSequence: List<ResolutionPart> = resolvedCall.atom.callKind.resolutionSequence private val resolutionSequence: List<ResolutionPart> = resolvedCall.atom.callKind.resolutionSequence
) : Candidate, KotlinDiagnosticsHolder { ) : Candidate, KotlinDiagnosticsHolder {
val diagnosticsFromResolutionParts = arrayListOf<KotlinCallDiagnostic>() // TODO: this is mutable list, take diagnostics only once! val diagnosticsFromResolutionParts = arrayListOf<KotlinCallDiagnostic>() // TODO: this is mutable list, take diagnostics only once!
private var newSystem: NewConstraintSystemImpl? = null private var newSystem: NewConstraintSystemImpl? = null
@@ -106,8 +107,7 @@ class KotlinResolutionCandidate(
if (workStep >= workCount) { if (workStep >= workCount) {
partIndex++ partIndex++
workStep -= workCount workStep -= workCount
} } else {
else {
break break
} }
} }
@@ -165,11 +165,11 @@ class KotlinResolutionCandidate(
} }
class MutableResolvedCallAtom( class MutableResolvedCallAtom(
override val atom: KotlinCall, override val atom: KotlinCall,
override val candidateDescriptor: CallableDescriptor, // original candidate descriptor override val candidateDescriptor: CallableDescriptor, // original candidate descriptor
override val explicitReceiverKind: ExplicitReceiverKind, override val explicitReceiverKind: ExplicitReceiverKind,
override val dispatchReceiverArgument: SimpleKotlinCallArgument?, override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
override val extensionReceiverArgument: SimpleKotlinCallArgument? override val extensionReceiverArgument: SimpleKotlinCallArgument?
) : ResolvedCallAtom() { ) : ResolvedCallAtom() {
override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument> override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
@@ -26,11 +26,11 @@ sealed class ResolvedCallArgument {
} }
class SimpleArgument(val callArgument: KotlinCallArgument): ResolvedCallArgument() { class SimpleArgument(val callArgument: KotlinCallArgument) : ResolvedCallArgument() {
override val arguments: List<KotlinCallArgument> override val arguments: List<KotlinCallArgument>
get() = listOf(callArgument) get() = listOf(callArgument)
} }
class VarargArgument(override val arguments: List<KotlinCallArgument>): ResolvedCallArgument() class VarargArgument(override val arguments: List<KotlinCallArgument>) : ResolvedCallArgument()
} }
@@ -33,76 +33,79 @@ interface SpecificityComparisonCallbacks {
interface TypeSpecificityComparator { interface TypeSpecificityComparator {
fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType): Boolean fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType): Boolean
object NONE: TypeSpecificityComparator { object NONE : TypeSpecificityComparator {
override fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType) = false override fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType) = false
} }
} }
class FlatSignature<out T> private constructor( class FlatSignature<out T> private constructor(
val origin: T, val origin: T,
val typeParameters: Collection<TypeParameterDescriptor>, val typeParameters: Collection<TypeParameterDescriptor>,
val valueParameterTypes: List<KotlinType?>, val valueParameterTypes: List<KotlinType?>,
val hasExtensionReceiver: Boolean, val hasExtensionReceiver: Boolean,
val hasVarargs: Boolean, val hasVarargs: Boolean,
val numDefaults: Int, val numDefaults: Int,
val isExpect: Boolean, val isExpect: Boolean,
val isSyntheticMember: Boolean val isSyntheticMember: Boolean
) { ) {
val isGeneric = typeParameters.isNotEmpty() val isGeneric = typeParameters.isNotEmpty()
companion object { companion object {
fun <T> createFromReflectionType( fun <T> createFromReflectionType(
origin: T, origin: T,
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
numDefaults: Int, numDefaults: Int,
reflectionType: UnwrappedType reflectionType: UnwrappedType
): FlatSignature<T> { ): FlatSignature<T> {
return FlatSignature(origin, return FlatSignature(
descriptor.typeParameters, origin,
reflectionType.arguments.map { it.type }, // should we drop return type? descriptor.typeParameters,
hasExtensionReceiver = false, reflectionType.arguments.map { it.type }, // should we drop return type?
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null }, hasExtensionReceiver = false,
numDefaults = numDefaults, hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
isExpect = descriptor is MemberDescriptor && descriptor.isExpect, numDefaults = numDefaults,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*> isExpect = descriptor is MemberDescriptor && descriptor.isExpect,
) isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
)
} }
fun <T> create( fun <T> create(
origin: T, origin: T,
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
numDefaults: Int, numDefaults: Int,
parameterTypes: List<KotlinType?> parameterTypes: List<KotlinType?>
): FlatSignature<T> { ): FlatSignature<T> {
val extensionReceiverType = descriptor.extensionReceiverParameter?.type val extensionReceiverType = descriptor.extensionReceiverParameter?.type
return FlatSignature(origin, return FlatSignature(
descriptor.typeParameters, origin,
valueParameterTypes = descriptor.typeParameters,
listOfNotNull(extensionReceiverType) + parameterTypes, valueParameterTypes =
hasExtensionReceiver = extensionReceiverType != null, listOfNotNull(extensionReceiverType) + parameterTypes,
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null }, hasExtensionReceiver = extensionReceiverType != null,
numDefaults = numDefaults, hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
isExpect = descriptor is MemberDescriptor && descriptor.isExpect, numDefaults = numDefaults,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*> isExpect = descriptor is MemberDescriptor && descriptor.isExpect,
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
) )
} }
fun <D : CallableDescriptor> createFromCallableDescriptor( fun <D : CallableDescriptor> createFromCallableDescriptor(
descriptor: D descriptor: D
): FlatSignature<D> = ): FlatSignature<D> =
create(descriptor, descriptor, numDefaults = 0, parameterTypes = descriptor.valueParameters.map { it.argumentValueType }) create(descriptor, descriptor, numDefaults = 0, parameterTypes = descriptor.valueParameters.map { it.argumentValueType })
fun <D : CallableDescriptor> createForPossiblyShadowedExtension(descriptor: D): FlatSignature<D> = fun <D : CallableDescriptor> createForPossiblyShadowedExtension(descriptor: D): FlatSignature<D> =
FlatSignature(descriptor, FlatSignature(
descriptor.typeParameters, descriptor,
valueParameterTypes = descriptor.valueParameters.map { it.argumentValueType }, descriptor.typeParameters,
hasExtensionReceiver = false, valueParameterTypes = descriptor.valueParameters.map { it.argumentValueType },
hasVarargs = descriptor.valueParameters.any { it.varargElementType != null }, hasExtensionReceiver = false,
numDefaults = descriptor.valueParameters.count { it.hasDefaultValue() }, hasVarargs = descriptor.valueParameters.any { it.varargElementType != null },
isExpect = descriptor is MemberDescriptor && descriptor.isExpect, numDefaults = descriptor.valueParameters.count { it.hasDefaultValue() },
isSyntheticMember = descriptor is SyntheticMemberDescriptor<*> isExpect = descriptor is MemberDescriptor && descriptor.isExpect,
) isSyntheticMember = descriptor is SyntheticMemberDescriptor<*>
)
val ValueParameterDescriptor.argumentValueType get() = varargElementType ?: type val ValueParameterDescriptor.argumentValueType get() = varargElementType ?: type
} }
@@ -119,10 +122,10 @@ interface SimpleConstraintSystem {
} }
fun <T> SimpleConstraintSystem.isSignatureNotLessSpecific( fun <T> SimpleConstraintSystem.isSignatureNotLessSpecific(
specific: FlatSignature<T>, specific: FlatSignature<T>,
general: FlatSignature<T>, general: FlatSignature<T>,
callbacks: SpecificityComparisonCallbacks, callbacks: SpecificityComparisonCallbacks,
specificityComparator: TypeSpecificityComparator specificityComparator: TypeSpecificityComparator
): Boolean { ): Boolean {
if (specific.hasExtensionReceiver != general.hasExtensionReceiver) return false if (specific.hasExtensionReceiver != general.hasExtensionReceiver) return false
if (specific.valueParameterTypes.size != general.valueParameterTypes.size) return false if (specific.valueParameterTypes.size != general.valueParameterTypes.size) return false
@@ -143,8 +146,7 @@ fun <T> SimpleConstraintSystem.isSignatureNotLessSpecific(
return false return false
} }
} }
} } else {
else {
val substitutedGeneralType = typeSubstitutor.safeSubstitute(generalType, Variance.INVARIANT) val substitutedGeneralType = typeSubstitutor.safeSubstitute(generalType, Variance.INVARIANT)
/** /**
@@ -33,41 +33,40 @@ import org.jetbrains.kotlin.types.TypeUtils
import java.util.* import java.util.*
open class OverloadingConflictResolver<C : Any>( open class OverloadingConflictResolver<C : Any>(
private val builtIns: KotlinBuiltIns, private val builtIns: KotlinBuiltIns,
private val specificityComparator: TypeSpecificityComparator, private val specificityComparator: TypeSpecificityComparator,
private val getResultingDescriptor: (C) -> CallableDescriptor, private val getResultingDescriptor: (C) -> CallableDescriptor,
private val createEmptyConstraintSystem: () -> SimpleConstraintSystem, private val createEmptyConstraintSystem: () -> SimpleConstraintSystem,
private val createFlatSignature: (C) -> FlatSignature<C>, private val createFlatSignature: (C) -> FlatSignature<C>,
private val getVariableCandidates: (C) -> C?, // for variable WithInvoke private val getVariableCandidates: (C) -> C?, // for variable WithInvoke
private val isFromSources: (CallableDescriptor) -> Boolean private val isFromSources: (CallableDescriptor) -> Boolean
) { ) {
private val resolvedCallHashingStrategy = object : TObjectHashingStrategy<C> { private val resolvedCallHashingStrategy = object : TObjectHashingStrategy<C> {
override fun equals(call1: C?, call2: C?): Boolean = override fun equals(call1: C?, call2: C?): Boolean =
if (call1 != null && call2 != null) if (call1 != null && call2 != null)
call1.resultingDescriptor == call2.resultingDescriptor call1.resultingDescriptor == call2.resultingDescriptor
else else
call1 == call2 call1 == call2
override fun computeHashCode(call: C?): Int = override fun computeHashCode(call: C?): Int =
call?.resultingDescriptor?.hashCode() ?: 0 call?.resultingDescriptor?.hashCode() ?: 0
} }
private val C.resultingDescriptor: CallableDescriptor get() = getResultingDescriptor(this) private val C.resultingDescriptor: CallableDescriptor get() = getResultingDescriptor(this)
// if result contains only one element -- it is maximally specific; otherwise we have ambiguity // if result contains only one element -- it is maximally specific; otherwise we have ambiguity
fun chooseMaximallySpecificCandidates( fun chooseMaximallySpecificCandidates(
candidates: Collection<C>, candidates: Collection<C>,
checkArgumentsMode: CheckArgumentTypesMode, checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean, discriminateGenerics: Boolean,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): Set<C> { ): Set<C> {
candidates.setIfOneOrEmpty()?.let { return it } candidates.setIfOneOrEmpty()?.let { return it }
val fixedCandidates = if (getVariableCandidates(candidates.first()) != null) { val fixedCandidates = if (getVariableCandidates(candidates.first()) != null) {
findMaximallySpecificVariableAsFunctionCalls(candidates, isDebuggerContext) ?: return LinkedHashSet(candidates) findMaximallySpecificVariableAsFunctionCalls(candidates, isDebuggerContext) ?: return LinkedHashSet(candidates)
} } else {
else {
candidates candidates
} }
@@ -131,35 +130,35 @@ open class OverloadingConflictResolver<C : Any>(
return result return result
} }
private fun Collection<C>.setIfOneOrEmpty() = when(size) { private fun Collection<C>.setIfOneOrEmpty() = when (size) {
0 -> emptySet() 0 -> emptySet()
1 -> setOf(single()) 1 -> setOf(single())
else -> null else -> null
} }
private fun findMaximallySpecific( private fun findMaximallySpecific(
candidates: Set<C>, candidates: Set<C>,
checkArgumentsMode: CheckArgumentTypesMode, checkArgumentsMode: CheckArgumentTypesMode,
discriminateGenerics: Boolean, discriminateGenerics: Boolean,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): C? = ): C? =
if (candidates.size <= 1) if (candidates.size <= 1)
candidates.firstOrNull() candidates.firstOrNull()
else when (checkArgumentsMode) { else when (checkArgumentsMode) {
CheckArgumentTypesMode.CHECK_CALLABLE_TYPE -> CheckArgumentTypesMode.CHECK_CALLABLE_TYPE ->
uniquifyCandidatesSet(candidates).singleOrNull { uniquifyCandidatesSet(candidates).singleOrNull {
isDefinitelyMostSpecific(it, candidates) { call1, call2 -> isDefinitelyMostSpecific(it, candidates) { call1, call2 ->
isNotLessSpecificCallableReference(call1.resultingDescriptor, call2.resultingDescriptor) isNotLessSpecificCallableReference(call1.resultingDescriptor, call2.resultingDescriptor)
}
} }
}
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS -> CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext) findMaximallySpecificCall(candidates, discriminateGenerics, isDebuggerContext)
?: findMaximallySpecificCall( ?: findMaximallySpecificCall(
candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember }, candidates.filterNotTo(mutableSetOf()) { createFlatSignature(it).isSyntheticMember },
discriminateGenerics, isDebuggerContext discriminateGenerics, isDebuggerContext
) )
} }
// null means ambiguity between variables // null means ambiguity between variables
private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Collection<C>, isDebuggerContext: Boolean): Set<C>? { private fun findMaximallySpecificVariableAsFunctionCalls(candidates: Collection<C>, isDebuggerContext: Boolean): Set<C>? {
@@ -167,8 +166,10 @@ open class OverloadingConflictResolver<C : Any>(
getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it") getVariableCandidates(it) ?: throw AssertionError("Regular call among variable-as-function calls: $it")
} }
val maxSpecificVariableCalls = chooseMaximallySpecificCandidates(variableCalls, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, val maxSpecificVariableCalls = chooseMaximallySpecificCandidates(
isDebuggerContext = isDebuggerContext, discriminateGenerics = false) variableCalls, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
isDebuggerContext = isDebuggerContext, discriminateGenerics = false
)
val maxSpecificVariableCall = maxSpecificVariableCalls.singleOrNull() ?: return null val maxSpecificVariableCall = maxSpecificVariableCalls.singleOrNull() ?: return null
return candidates.filterTo(newResolvedCallSet(2)) { return candidates.filterTo(newResolvedCallSet(2)) {
@@ -177,29 +178,25 @@ open class OverloadingConflictResolver<C : Any>(
} }
private fun findMaximallySpecificCall( private fun findMaximallySpecificCall(
candidates: Set<C>, candidates: Set<C>,
discriminateGenerics: Boolean, discriminateGenerics: Boolean,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): C? { ): C? {
val filteredCandidates = uniquifyCandidatesSet(candidates) val filteredCandidates = uniquifyCandidatesSet(candidates)
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull() if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
val conflictingCandidates = filteredCandidates.map { val conflictingCandidates = filteredCandidates.map { candidateCall ->
candidateCall ->
createFlatSignature(candidateCall) createFlatSignature(candidateCall)
} }
val bestCandidatesByParameterTypes = conflictingCandidates.filter { val bestCandidatesByParameterTypes = conflictingCandidates.filter { candidate ->
candidate -> isMostSpecific(candidate, conflictingCandidates) { call1, call2 ->
isMostSpecific(candidate, conflictingCandidates) {
call1, call2 ->
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics) isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenerics)
} }
} }
return bestCandidatesByParameterTypes.exactMaxWith { return bestCandidatesByParameterTypes.exactMaxWith { call1, call2 ->
call1, call2 ->
isOfNotLessSpecificShape(call1, call2) && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext) isOfNotLessSpecificShape(call1, call2) && isOfNotLessSpecificVisibilityForDebugger(call1, call2, isDebuggerContext)
}?.origin }?.origin
} }
@@ -219,29 +216,34 @@ open class OverloadingConflictResolver<C : Any>(
} }
private inline fun <C> isMostSpecific(candidate: C, candidates: Collection<C>, isNotLessSpecific: (C, C) -> Boolean): Boolean = private inline fun <C> isMostSpecific(candidate: C, candidates: Collection<C>, isNotLessSpecific: (C, C) -> Boolean): Boolean =
candidates.all { candidates.all { other ->
other -> candidate === other ||
candidate === other || isNotLessSpecific(candidate, other)
isNotLessSpecific(candidate, other) }
}
private inline fun <C> isDefinitelyMostSpecific(candidate: C, candidates: Collection<C>, isNotLessSpecific: (C, C) -> Boolean): Boolean = private inline fun <C> isDefinitelyMostSpecific(
candidates.all { candidate: C,
other -> candidates: Collection<C>,
candidate === other || isNotLessSpecific: (C, C) -> Boolean
isNotLessSpecific(candidate, other) && !isNotLessSpecific(other, candidate) ): Boolean =
} candidates.all { other ->
candidate === other ||
isNotLessSpecific(candidate, other) && !isNotLessSpecific(other, candidate)
}
/** /**
* `call1` is not less specific than `call2` * `call1` is not less specific than `call2`
*/ */
private fun isNotLessSpecificCallWithArgumentMapping( private fun isNotLessSpecificCallWithArgumentMapping(
call1: FlatSignature<C>, call1: FlatSignature<C>,
call2: FlatSignature<C>, call2: FlatSignature<C>,
discriminateGenerics: Boolean discriminateGenerics: Boolean
): Boolean { ): Boolean {
return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?: return tryCompareDescriptorsFromScripts(call1.candidateDescriptor(), call2.candidateDescriptor()) ?: compareCallsByUsedArguments(
compareCallsByUsedArguments(call1, call2, discriminateGenerics) call1,
call2,
discriminateGenerics
)
} }
/** /**
@@ -249,9 +251,9 @@ open class OverloadingConflictResolver<C : Any>(
* `false` otherwise. * `false` otherwise.
*/ */
private fun compareCallsByUsedArguments( private fun compareCallsByUsedArguments(
call1: FlatSignature<C>, call1: FlatSignature<C>,
call2: FlatSignature<C>, call2: FlatSignature<C>,
discriminateGenerics: Boolean discriminateGenerics: Boolean
): Boolean { ): Boolean {
if (discriminateGenerics) { if (discriminateGenerics) {
val isGeneric1 = call1.isGeneric val isGeneric1 = call1.isGeneric
@@ -266,7 +268,12 @@ open class OverloadingConflictResolver<C : Any>(
if (!call1.isExpect && call2.isExpect) return true if (!call1.isExpect && call2.isExpect) return true
if (call1.isExpect && !call2.isExpect) return false if (call1.isExpect && !call2.isExpect) return false
return createEmptyConstraintSystem().isSignatureNotLessSpecific(call1, call2, SpecificityComparisonWithNumerics, specificityComparator) return createEmptyConstraintSystem().isSignatureNotLessSpecific(
call1,
call2,
SpecificityComparisonWithNumerics,
specificityComparator
)
} }
private val SpecificityComparisonWithNumerics = object : SpecificityComparisonCallbacks { private val SpecificityComparisonWithNumerics = object : SpecificityComparisonCallbacks {
@@ -295,8 +302,8 @@ open class OverloadingConflictResolver<C : Any>(
} }
private fun isOfNotLessSpecificShape( private fun isOfNotLessSpecificShape(
call1: FlatSignature<C>, call1: FlatSignature<C>,
call2: FlatSignature<C> call2: FlatSignature<C>
): Boolean { ): Boolean {
val hasVarargs1 = call1.hasVarargs val hasVarargs1 = call1.hasVarargs
val hasVarargs2 = call2.hasVarargs val hasVarargs2 = call2.hasVarargs
@@ -311,9 +318,9 @@ open class OverloadingConflictResolver<C : Any>(
} }
private fun isOfNotLessSpecificVisibilityForDebugger( private fun isOfNotLessSpecificVisibilityForDebugger(
call1: FlatSignature<C>, call1: FlatSignature<C>,
call2: FlatSignature<C>, call2: FlatSignature<C>,
isDebuggerContext: Boolean isDebuggerContext: Boolean
): Boolean { ): Boolean {
if (isDebuggerContext) { if (isDebuggerContext) {
val isMoreVisible1 = Visibilities.compare(call1.descriptorVisibility(), call2.descriptorVisibility()) val isMoreVisible1 = Visibilities.compare(call1.descriptorVisibility(), call2.descriptorVisibility())
@@ -352,7 +359,12 @@ open class OverloadingConflictResolver<C : Any>(
val fSignature = FlatSignature.createFromCallableDescriptor(f) val fSignature = FlatSignature.createFromCallableDescriptor(f)
val gSignature = FlatSignature.createFromCallableDescriptor(g) val gSignature = FlatSignature.createFromCallableDescriptor(g)
if (!createEmptyConstraintSystem().isSignatureNotLessSpecific(fSignature, gSignature, SpecificityComparisonWithNumerics, specificityComparator)) { if (!createEmptyConstraintSystem().isSignatureNotLessSpecific(
fSignature,
gSignature,
SpecificityComparisonWithNumerics,
specificityComparator
)) {
return false return false
} }
@@ -365,20 +377,19 @@ open class OverloadingConflictResolver<C : Any>(
} }
private fun isNotLessSpecificCallableReference(f: CallableDescriptor, g: CallableDescriptor): Boolean = private fun isNotLessSpecificCallableReference(f: CallableDescriptor, g: CallableDescriptor): Boolean =
// TODO should we "discriminate generic descriptors" for callable references? // TODO should we "discriminate generic descriptors" for callable references?
tryCompareDescriptorsFromScripts(f, g) ?: tryCompareDescriptorsFromScripts(f, g) ?: isNotLessSpecificCallableReferenceDescriptor(f, g)
isNotLessSpecificCallableReferenceDescriptor(f, g)
// Different smart casts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects // Different smart casts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
private fun uniquifyCandidatesSet(candidates: Collection<C>): Set<C> = private fun uniquifyCandidatesSet(candidates: Collection<C>): Set<C> =
THashSet(candidates.size, resolvedCallHashingStrategy).apply { addAll(candidates) } THashSet(candidates.size, resolvedCallHashingStrategy).apply { addAll(candidates) }
private fun newResolvedCallSet(expectedSize: Int): MutableSet<C> = private fun newResolvedCallSet(expectedSize: Int): MutableSet<C> =
THashSet(expectedSize, resolvedCallHashingStrategy) THashSet(expectedSize, resolvedCallHashingStrategy)
private fun FlatSignature<C>.candidateDescriptor() = private fun FlatSignature<C>.candidateDescriptor() =
origin.resultingDescriptor.original origin.resultingDescriptor.original
private fun FlatSignature<C>.descriptorVisibility() = private fun FlatSignature<C>.descriptorVisibility() =
candidateDescriptor().visibility candidateDescriptor().visibility
} }
@@ -20,8 +20,8 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
fun getReceiverValueWithSmartCast( fun getReceiverValueWithSmartCast(
receiverArgument: ReceiverValue?, receiverArgument: ReceiverValue?,
smartCastType: KotlinType? smartCastType: KotlinType?
) = smartCastType?.let(::SmartCastReceiverValue) ?: receiverArgument ) = smartCastType?.let(::SmartCastReceiverValue) ?: receiverArgument
private class SmartCastReceiverValue(private val type: KotlinType) : ReceiverValue { private class SmartCastReceiverValue(private val type: KotlinType) : ReceiverValue {
@@ -43,17 +43,16 @@ fun createSynthesizedInvokes(functions: Collection<FunctionDescriptor>): Collect
val containerClassId = (invoke.containingDeclaration as ClassDescriptor).classId val containerClassId = (invoke.containingDeclaration as ClassDescriptor).classId
val synthesized = if (containerClassId != null && isBuiltinFunctionClass(containerClassId)) { val synthesized = if (containerClassId != null && isBuiltinFunctionClass(containerClassId)) {
createSynthesizedFunctionWithFirstParameterAsReceiver(invoke) createSynthesizedFunctionWithFirstParameterAsReceiver(invoke)
} } else {
else {
val invokeDeclaration = invoke.overriddenDescriptors.singleOrNull() val invokeDeclaration = invoke.overriddenDescriptors.singleOrNull()
?: error("No single overridden invoke for $invoke: ${invoke.overriddenDescriptors}") ?: error("No single overridden invoke for $invoke: ${invoke.overriddenDescriptors}")
val synthesizedSuperFun = createSynthesizedFunctionWithFirstParameterAsReceiver(invokeDeclaration) val synthesizedSuperFun = createSynthesizedFunctionWithFirstParameterAsReceiver(invokeDeclaration)
val fakeOverride = synthesizedSuperFun.copy( val fakeOverride = synthesizedSuperFun.copy(
invoke.containingDeclaration, invoke.containingDeclaration,
synthesizedSuperFun.modality, synthesizedSuperFun.modality,
synthesizedSuperFun.visibility, synthesizedSuperFun.visibility,
CallableMemberDescriptor.Kind.FAKE_OVERRIDE, CallableMemberDescriptor.Kind.FAKE_OVERRIDE,
/* copyOverrides = */ false /* copyOverrides = */ false
) )
fakeOverride.setSingleOverridden(synthesizedSuperFun) fakeOverride.setSingleOverridden(synthesizedSuperFun)
fakeOverride fakeOverride
@@ -69,9 +68,9 @@ private fun createSynthesizedFunctionWithFirstParameterAsReceiver(descriptor: Fu
descriptor.original.newCopyBuilder().apply { descriptor.original.newCopyBuilder().apply {
setExtensionReceiverType(descriptor.original.valueParameters.first().type) setExtensionReceiverType(descriptor.original.valueParameters.first().type)
setValueParameters( setValueParameters(
descriptor.original.valueParameters descriptor.original.valueParameters
.drop(1) .drop(1)
.map { p -> p.copy(descriptor.original, Name.identifier("p${p.index + 1}"), p.index - 1) } .map { p -> p.copy(descriptor.original, Name.identifier("p${p.index + 1}"), p.index - 1) }
) )
}.build()!! }.build()!!
@@ -85,5 +84,5 @@ fun isSynthesizedInvoke(descriptor: DeclarationDescriptor): Boolean {
} }
return real.kind == CallableMemberDescriptor.Kind.SYNTHESIZED && return real.kind == CallableMemberDescriptor.Kind.SYNTHESIZED &&
real.containingDeclaration.getFunctionalClassKind() != null real.containingDeclaration.getFunctionalClassKind() != null
} }
@@ -36,19 +36,19 @@ enum class WrongResolutionToClassifier(val message: (Name) -> String) {
OBJECT_AS_FUNCTION({ "Function 'invoke()' is not found in object $it" }) OBJECT_AS_FUNCTION({ "Function 'invoke()' is not found in object $it" })
} }
sealed class ErrorCandidate<out D: DeclarationDescriptor>(val descriptor: D) { sealed class ErrorCandidate<out D : DeclarationDescriptor>(val descriptor: D) {
class Classifier( class Classifier(
classifierDescriptor: ClassifierDescriptor, classifierDescriptor: ClassifierDescriptor,
val kind: WrongResolutionToClassifier val kind: WrongResolutionToClassifier
) : ErrorCandidate<ClassifierDescriptor>(classifierDescriptor) { ) : ErrorCandidate<ClassifierDescriptor>(classifierDescriptor) {
val errorMessage = kind.message(descriptor.name) val errorMessage = kind.message(descriptor.name)
} }
} }
fun collectErrorCandidatesForFunction( fun collectErrorCandidatesForFunction(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
name: Name, name: Name,
explicitReceiver: DetailedReceiver? explicitReceiver: DetailedReceiver?
): Collection<ErrorCandidate<*>> { ): Collection<ErrorCandidate<*>> {
val context = ErrorCandidateContext(scopeTower, name, explicitReceiver) val context = ErrorCandidateContext(scopeTower, name, explicitReceiver)
context.asClassifierCall(asFunction = true) context.asClassifierCall(asFunction = true)
@@ -56,9 +56,9 @@ fun collectErrorCandidatesForFunction(
} }
fun collectErrorCandidatesForVariable( fun collectErrorCandidatesForVariable(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
name: Name, name: Name,
explicitReceiver: DetailedReceiver? explicitReceiver: DetailedReceiver?
): Collection<ErrorCandidate<*>> { ): Collection<ErrorCandidate<*>> {
val context = ErrorCandidateContext(scopeTower, name, explicitReceiver) val context = ErrorCandidateContext(scopeTower, name, explicitReceiver)
context.asClassifierCall(asFunction = false) context.asClassifierCall(asFunction = false)
@@ -66,54 +66,59 @@ fun collectErrorCandidatesForVariable(
} }
private class ErrorCandidateContext( private class ErrorCandidateContext(
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val name: Name, val name: Name,
val explicitReceiver: DetailedReceiver? val explicitReceiver: DetailedReceiver?
) { ) {
val result = SmartList<ErrorCandidate<*>>() val result = SmartList<ErrorCandidate<*>>()
fun add(errorCandidate: ErrorCandidate<*>) { result.add(errorCandidate) } fun add(errorCandidate: ErrorCandidate<*>) {
result.add(errorCandidate)
}
} }
private fun ErrorCandidateContext.asClassifierCall(asFunction: Boolean) { private fun ErrorCandidateContext.asClassifierCall(asFunction: Boolean) {
val classifier = val classifier =
when (explicitReceiver) { when (explicitReceiver) {
is ReceiverValueWithSmartCastInfo -> { is ReceiverValueWithSmartCastInfo -> {
explicitReceiver.receiverValue.type.memberScope.getContributedClassifier(name, scopeTower.location) explicitReceiver.receiverValue.type.memberScope.getContributedClassifier(name, scopeTower.location)
} }
is QualifierReceiver -> { is QualifierReceiver -> {
explicitReceiver.staticScope.getContributedClassifier(name, scopeTower.location) explicitReceiver.staticScope.getContributedClassifier(name, scopeTower.location)
} }
else -> scopeTower.lexicalScope.findClassifier(name, scopeTower.location) else -> scopeTower.lexicalScope.findClassifier(name, scopeTower.location)
} ?: return } ?: return
val kind = getWrongResolutionToClassifier(classifier, asFunction) ?: return val kind = getWrongResolutionToClassifier(classifier, asFunction) ?: return
add(ErrorCandidate.Classifier(classifier, kind)) add(ErrorCandidate.Classifier(classifier, kind))
} }
private fun ErrorCandidateContext.getWrongResolutionToClassifier(classifier: ClassifierDescriptor, asFunction: Boolean): WrongResolutionToClassifier? = private fun ErrorCandidateContext.getWrongResolutionToClassifier(
when (classifier) { classifier: ClassifierDescriptor,
is TypeAliasDescriptor -> classifier.classDescriptor?.let { getWrongResolutionToClassifier(it, asFunction) } asFunction: Boolean
): WrongResolutionToClassifier? =
when (classifier) {
is TypeAliasDescriptor -> classifier.classDescriptor?.let { getWrongResolutionToClassifier(it, asFunction) }
is TypeParameterDescriptor -> if (asFunction) TYPE_PARAMETER_AS_FUNCTION else TYPE_PARAMETER_AS_VALUE is TypeParameterDescriptor -> if (asFunction) TYPE_PARAMETER_AS_FUNCTION else TYPE_PARAMETER_AS_VALUE
is ClassDescriptor -> { is ClassDescriptor -> {
when (classifier.kind) { when (classifier.kind) {
ClassKind.INTERFACE -> if (asFunction) INTERFACE_AS_FUNCTION else INTERFACE_AS_VALUE ClassKind.INTERFACE -> if (asFunction) INTERFACE_AS_FUNCTION else INTERFACE_AS_VALUE
ClassKind.OBJECT -> if (asFunction) OBJECT_AS_FUNCTION else null ClassKind.OBJECT -> if (asFunction) OBJECT_AS_FUNCTION else null
ClassKind.CLASS -> when {
asFunction && explicitReceiver is QualifierReceiver? && classifier.isInner -> INNER_CLASS_CONSTRUCTOR_NO_RECEIVER
asFunction && classifier.isExpect -> EXPECT_CLASS_AS_FUNCTION
!asFunction -> CLASS_AS_VALUE
else -> null
}
ClassKind.CLASS -> when {
asFunction && explicitReceiver is QualifierReceiver? && classifier.isInner -> INNER_CLASS_CONSTRUCTOR_NO_RECEIVER
asFunction && classifier.isExpect -> EXPECT_CLASS_AS_FUNCTION
!asFunction -> CLASS_AS_VALUE
else -> null else -> null
} }
}
else -> null else -> null
}
} }
else -> null
}
@@ -64,8 +64,9 @@ interface CandidateWithBoundDispatchReceiver {
val dispatchReceiver: ReceiverValueWithSmartCastInfo? val dispatchReceiver: ReceiverValueWithSmartCastInfo?
} }
fun getResultApplicability(diagnostics: Collection<KotlinCallDiagnostic>) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability fun getResultApplicability(diagnostics: Collection<KotlinCallDiagnostic>) =
?: RESOLVED diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability
?: RESOLVED
enum class ResolutionCandidateApplicability { enum class ResolutionCandidateApplicability {
RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate RESOLVED, // call success or has uncompleted inference or in other words possible successful candidate
@@ -80,30 +81,31 @@ enum class ResolutionCandidateApplicability {
HIDDEN, // removed from resolve HIDDEN, // removed from resolve
} }
abstract class ResolutionDiagnostic(candidateApplicability: ResolutionCandidateApplicability): KotlinCallDiagnostic(candidateApplicability) { abstract class ResolutionDiagnostic(candidateApplicability: ResolutionCandidateApplicability) :
KotlinCallDiagnostic(candidateApplicability) {
override fun report(reporter: DiagnosticReporter) { override fun report(reporter: DiagnosticReporter) {
// do nothing // do nothing
} }
} }
// todo error for this access from nested class // todo error for this access from nested class
class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility): ResolutionDiagnostic(RUNTIME_ERROR) { class VisibilityError(val invisibleMember: DeclarationDescriptorWithVisibility) : ResolutionDiagnostic(RUNTIME_ERROR) {
override fun report(reporter: DiagnosticReporter) { override fun report(reporter: DiagnosticReporter) {
reporter.onCall(this) reporter.onCall(this)
} }
} }
class NestedClassViaInstanceReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE) class NestedClassViaInstanceReference(val classDescriptor: ClassDescriptor) : ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
class InnerClassViaStaticReference(val classDescriptor: ClassDescriptor): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE) class InnerClassViaStaticReference(val classDescriptor: ClassDescriptor) : ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
class UnsupportedInnerClassCall(val message: String): ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE) class UnsupportedInnerClassCall(val message: String) : ResolutionDiagnostic(IMPOSSIBLE_TO_GENERATE)
class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType): ResolutionDiagnostic(RESOLVED) class UsedSmartCastForDispatchReceiver(val smartCastType: KotlinType) : ResolutionDiagnostic(RESOLVED)
object ErrorDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED) // todo discuss and change to INAPPLICABLE object ErrorDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED) // todo discuss and change to INAPPLICABLE
object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) object LowPriorityDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY)
object DynamicDescriptorDiagnostic: ResolutionDiagnostic(RESOLVED_LOW_PRIORITY) object DynamicDescriptorDiagnostic : ResolutionDiagnostic(RESOLVED_LOW_PRIORITY)
object UnstableSmartCastDiagnostic: ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR) object UnstableSmartCastDiagnostic : ResolutionDiagnostic(MAY_THROW_RUNTIME_ERROR)
object HiddenExtensionRelatedToDynamicTypes: ResolutionDiagnostic(HIDDEN) object HiddenExtensionRelatedToDynamicTypes : ResolutionDiagnostic(HIDDEN)
object HiddenDescriptor: ResolutionDiagnostic(HIDDEN) object HiddenDescriptor : ResolutionDiagnostic(HIDDEN)
object InvokeConventionCallNoOperatorModifier : ResolutionDiagnostic(CONVENTION_ERROR) object InvokeConventionCallNoOperatorModifier : ResolutionDiagnostic(CONVENTION_ERROR)
object InfixCallNoInfixModifier : ResolutionDiagnostic(CONVENTION_ERROR) object InfixCallNoInfixModifier : ResolutionDiagnostic(CONVENTION_ERROR)
@@ -26,8 +26,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.* import java.util.*
abstract class AbstractInvokeTowerProcessor<C : Candidate>( abstract class AbstractInvokeTowerProcessor<C : Candidate>(
protected val factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>, protected val factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>,
protected val variableProcessor: ScopeTowerProcessor<C> protected val variableProcessor: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
// todo optimize it // todo optimize it
private val previousData = ArrayList<TowerData>() private val previousData = ArrayList<TowerData>()
@@ -36,14 +36,13 @@ abstract class AbstractInvokeTowerProcessor<C : Candidate>(
protected fun hasInvokeProcessors() = invokeProcessors.isNotEmpty() protected fun hasInvokeProcessors() = invokeProcessors.isNotEmpty()
private inner class VariableInvokeProcessor( private inner class VariableInvokeProcessor(
var variableCandidate: C, var variableCandidate: C,
val invokeProcessor: ScopeTowerProcessor<C> val invokeProcessor: ScopeTowerProcessor<C>
): ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
override fun process(data: TowerData) override fun process(data: TowerData) = invokeProcessor.process(data).map { candidateGroup ->
= invokeProcessor.process(data).map { candidateGroup -> candidateGroup.map { factoryProviderForInvoke.transformCandidate(variableCandidate, it) }
candidateGroup.map { factoryProviderForInvoke.transformCandidate(variableCandidate, it) } }
}
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) { override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
invokeProcessor.recordLookups(skippedData, name) invokeProcessor.recordLookups(skippedData, name)
@@ -51,7 +50,7 @@ abstract class AbstractInvokeTowerProcessor<C : Candidate>(
} }
private fun createVariableInvokeProcessor(variableCandidate: C): VariableInvokeProcessor? = private fun createVariableInvokeProcessor(variableCandidate: C): VariableInvokeProcessor? =
createInvokeProcessor(variableCandidate)?.let { VariableInvokeProcessor(variableCandidate, it) } createInvokeProcessor(variableCandidate)?.let { VariableInvokeProcessor(variableCandidate, it) }
protected abstract fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>? protected abstract fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>?
@@ -98,24 +97,33 @@ abstract class AbstractInvokeTowerProcessor<C : Candidate>(
// todo KT-9522 Allow invoke convention for synthetic property // todo KT-9522 Allow invoke convention for synthetic property
class InvokeTowerProcessor<C : Candidate>( class InvokeTowerProcessor<C : Candidate>(
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val name: Name, val name: Name,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>, factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>,
explicitReceiver: DetailedReceiver? explicitReceiver: DetailedReceiver?
) : AbstractInvokeTowerProcessor<C>( ) : AbstractInvokeTowerProcessor<C>(
factoryProviderForInvoke, factoryProviderForInvoke,
createVariableAndObjectProcessor(scopeTower, name, factoryProviderForInvoke.factoryForVariable(stripExplicitReceiver = false), explicitReceiver) createVariableAndObjectProcessor(
scopeTower,
name,
factoryProviderForInvoke.factoryForVariable(stripExplicitReceiver = false),
explicitReceiver
)
) { ) {
// todo filter by operator // todo filter by operator
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>? { override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>? {
val (variableReceiver, invokeContext) = factoryProviderForInvoke.factoryForInvoke(variableCandidate, useExplicitReceiver = false) val (variableReceiver, invokeContext) = factoryProviderForInvoke.factoryForInvoke(variableCandidate, useExplicitReceiver = false)
?: return null ?: return null
return ExplicitReceiverScopeTowerProcessor(scopeTower, invokeContext, variableReceiver) { getFunctions(OperatorNameConventions.INVOKE, it) } return ExplicitReceiverScopeTowerProcessor(
scopeTower,
invokeContext,
variableReceiver
) { getFunctions(OperatorNameConventions.INVOKE, it) }
} }
override fun mayDataBeApplicable(data: TowerData) = override fun mayDataBeApplicable(data: TowerData) =
data == TowerData.Empty || data is TowerData.TowerLevel data == TowerData.Empty || data is TowerData.TowerLevel
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) { override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
variableProcessor.recordLookups(skippedData, name) variableProcessor.recordLookups(skippedData, name)
@@ -130,20 +138,25 @@ class InvokeTowerProcessor<C : Candidate>(
} }
class InvokeExtensionTowerProcessor<C : Candidate>( class InvokeExtensionTowerProcessor<C : Candidate>(
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val name: Name, val name: Name,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>, factoryProviderForInvoke: CandidateFactoryProviderForInvoke<C>,
private val explicitReceiver: ReceiverValueWithSmartCastInfo? private val explicitReceiver: ReceiverValueWithSmartCastInfo?
) : AbstractInvokeTowerProcessor<C>( ) : AbstractInvokeTowerProcessor<C>(
factoryProviderForInvoke, factoryProviderForInvoke,
createVariableAndObjectProcessor(scopeTower, name, factoryProviderForInvoke.factoryForVariable(stripExplicitReceiver = true), explicitReceiver = null) createVariableAndObjectProcessor(
scopeTower,
name,
factoryProviderForInvoke.factoryForVariable(stripExplicitReceiver = true),
explicitReceiver = null
)
) { ) {
override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>? { override fun createInvokeProcessor(variableCandidate: C): ScopeTowerProcessor<C>? {
val (variableReceiver, invokeContext) = factoryProviderForInvoke.factoryForInvoke(variableCandidate, useExplicitReceiver = true) val (variableReceiver, invokeContext) = factoryProviderForInvoke.factoryForInvoke(variableCandidate, useExplicitReceiver = true)
?: return null ?: return null
val invokeDescriptor = scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver) val invokeDescriptor = scopeTower.getExtensionInvokeCandidateDescriptor(variableReceiver)
?: return null ?: return null
return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver) return InvokeExtensionScopeTowerProcessor(invokeContext, invokeDescriptor, explicitReceiver)
} }
@@ -155,18 +168,30 @@ class InvokeExtensionTowerProcessor<C : Candidate>(
} }
private class InvokeExtensionScopeTowerProcessor<C : Candidate>( private class InvokeExtensionScopeTowerProcessor<C : Candidate>(
context: CandidateFactory<C>, context: CandidateFactory<C>,
private val invokeCandidateDescriptor: CandidateWithBoundDispatchReceiver, private val invokeCandidateDescriptor: CandidateWithBoundDispatchReceiver,
private val explicitReceiver: ReceiverValueWithSmartCastInfo? private val explicitReceiver: ReceiverValueWithSmartCastInfo?
) : AbstractSimpleScopeTowerProcessor<C>(context) { ) : AbstractSimpleScopeTowerProcessor<C>(context) {
override fun simpleProcess(data: TowerData): Collection<C> { override fun simpleProcess(data: TowerData): Collection<C> {
if (explicitReceiver != null && data == TowerData.Empty) { if (explicitReceiver != null && data == TowerData.Empty) {
return listOf(candidateFactory.createCandidate(invokeCandidateDescriptor, ExplicitReceiverKind.BOTH_RECEIVERS, explicitReceiver)) return listOf(
candidateFactory.createCandidate(
invokeCandidateDescriptor,
ExplicitReceiverKind.BOTH_RECEIVERS,
explicitReceiver
)
)
} }
if (explicitReceiver == null && data is TowerData.OnlyImplicitReceiver) { if (explicitReceiver == null && data is TowerData.OnlyImplicitReceiver) {
return listOf(candidateFactory.createCandidate(invokeCandidateDescriptor, ExplicitReceiverKind.DISPATCH_RECEIVER, data.implicitReceiver)) return listOf(
candidateFactory.createCandidate(
invokeCandidateDescriptor,
ExplicitReceiverKind.DISPATCH_RECEIVER,
data.implicitReceiver
)
)
} }
return emptyList() return emptyList()
@@ -178,7 +203,7 @@ private class InvokeExtensionScopeTowerProcessor<C : Candidate>(
// todo debug info // todo debug info
private fun ImplicitScopeTower.getExtensionInvokeCandidateDescriptor( private fun ImplicitScopeTower.getExtensionInvokeCandidateDescriptor(
extensionFunctionReceiver: ReceiverValueWithSmartCastInfo extensionFunctionReceiver: ReceiverValueWithSmartCastInfo
): CandidateWithBoundDispatchReceiver? { ): CandidateWithBoundDispatchReceiver? {
val type = extensionFunctionReceiver.receiverValue.type val type = extensionFunctionReceiver.receiverValue.type
if (!type.isBuiltinExtensionFunctionalType) return null // todo: missing smart cast? if (!type.isBuiltinExtensionFunctionalType) return null // todo: missing smart cast?
@@ -186,7 +211,7 @@ private fun ImplicitScopeTower.getExtensionInvokeCandidateDescriptor(
val invokeDescriptor = type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, location).single() val invokeDescriptor = type.memberScope.getContributedFunctions(OperatorNameConventions.INVOKE, location).single()
val synthesizedInvokes = createSynthesizedInvokes(listOf(invokeDescriptor)) val synthesizedInvokes = createSynthesizedInvokes(listOf(invokeDescriptor))
val synthesizedInvoke = synthesizedInvokes.singleOrNull() val synthesizedInvoke = synthesizedInvokes.singleOrNull()
?: error("No single synthesized invoke for $invokeDescriptor: $synthesizedInvokes") ?: error("No single synthesized invoke for $invokeDescriptor: $synthesizedInvokes")
// here we don't add SynthesizedDescriptor diagnostic because it should has priority as member // here we don't add SynthesizedDescriptor diagnostic because it should has priority as member
return CandidateWithBoundDispatchReceiverImpl(extensionFunctionReceiver, synthesizedInvoke, listOf()) return CandidateWithBoundDispatchReceiverImpl(extensionFunctionReceiver, synthesizedInvoke, listOf())
@@ -194,31 +219,32 @@ private fun ImplicitScopeTower.getExtensionInvokeCandidateDescriptor(
// case 1.(foo())() or (foo())() // case 1.(foo())() or (foo())()
fun <C : Candidate> createCallTowerProcessorForExplicitInvoke( fun <C : Candidate> createCallTowerProcessorForExplicitInvoke(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
functionContext: CandidateFactory<C>, functionContext: CandidateFactory<C>,
expressionForInvoke: ReceiverValueWithSmartCastInfo, expressionForInvoke: ReceiverValueWithSmartCastInfo,
explicitReceiver: ReceiverValueWithSmartCastInfo? explicitReceiver: ReceiverValueWithSmartCastInfo?
): ScopeTowerProcessor<C> { ): ScopeTowerProcessor<C> {
val invokeExtensionDescriptor = scopeTower.getExtensionInvokeCandidateDescriptor(expressionForInvoke) val invokeExtensionDescriptor = scopeTower.getExtensionInvokeCandidateDescriptor(expressionForInvoke)
if (explicitReceiver != null) { if (explicitReceiver != null) {
return if (invokeExtensionDescriptor == null) { return if (invokeExtensionDescriptor == null) {
// case 1.(foo())(), where foo() isn't extension function // case 1.(foo())(), where foo() isn't extension function
KnownResultProcessor(emptyList()) KnownResultProcessor(emptyList())
} } else {
else {
InvokeExtensionScopeTowerProcessor(functionContext, invokeExtensionDescriptor, explicitReceiver = explicitReceiver) InvokeExtensionScopeTowerProcessor(functionContext, invokeExtensionDescriptor, explicitReceiver = explicitReceiver)
} }
} } else {
else { val usualInvoke = ExplicitReceiverScopeTowerProcessor(
val usualInvoke = ExplicitReceiverScopeTowerProcessor(scopeTower, functionContext, expressionForInvoke) { getFunctions(OperatorNameConventions.INVOKE, it) } // todo operator scopeTower,
functionContext,
expressionForInvoke
) { getFunctions(OperatorNameConventions.INVOKE, it) } // todo operator
return if (invokeExtensionDescriptor == null) { return if (invokeExtensionDescriptor == null) {
usualInvoke usualInvoke
} } else {
else {
PrioritizedCompositeScopeTowerProcessor( PrioritizedCompositeScopeTowerProcessor(
usualInvoke, usualInvoke,
InvokeExtensionScopeTowerProcessor(functionContext, invokeExtensionDescriptor, explicitReceiver = null) InvokeExtensionScopeTowerProcessor(functionContext, invokeExtensionDescriptor, explicitReceiver = null)
) )
} }
} }
@@ -24,17 +24,16 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastI
class KnownResultProcessor<out C>( class KnownResultProcessor<out C>(
val result: Collection<C> val result: Collection<C>
): ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
override fun process(data: TowerData) override fun process(data: TowerData) = if (data == TowerData.Empty) listOfNotNull(result.takeIf { it.isNotEmpty() }) else emptyList()
= if (data == TowerData.Empty) listOfNotNull(result.takeIf { it.isNotEmpty() }) else emptyList()
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {} override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {}
} }
// use this if processors priority is important // use this if processors priority is important
class PrioritizedCompositeScopeTowerProcessor<out C>( class PrioritizedCompositeScopeTowerProcessor<out C>(
vararg val processors: ScopeTowerProcessor<C> vararg val processors: ScopeTowerProcessor<C>
) : ScopeTowerProcessor<C> { ) : ScopeTowerProcessor<C> {
override fun process(data: TowerData): List<Collection<C>> = processors.flatMap { it.process(data) } override fun process(data: TowerData): List<Collection<C>> = processors.flatMap { it.process(data) }
@@ -46,8 +45,8 @@ class PrioritizedCompositeScopeTowerProcessor<out C>(
// use this if all processors has same priority // use this if all processors has same priority
class SamePriorityCompositeScopeTowerProcessor<out C>( class SamePriorityCompositeScopeTowerProcessor<out C>(
private vararg val processors: SimpleScopeTowerProcessor<C> private vararg val processors: SimpleScopeTowerProcessor<C>
): SimpleScopeTowerProcessor<C> { ) : SimpleScopeTowerProcessor<C> {
override fun simpleProcess(data: TowerData): Collection<C> = processors.flatMap { it.simpleProcess(data) } override fun simpleProcess(data: TowerData): Collection<C> = processors.flatMap { it.simpleProcess(data) }
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) { override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
processors.forEach { it.recordLookups(skippedData, name) } processors.forEach { it.recordLookups(skippedData, name) }
@@ -55,19 +54,19 @@ class SamePriorityCompositeScopeTowerProcessor<out C>(
} }
internal abstract class AbstractSimpleScopeTowerProcessor<C: Candidate>( internal abstract class AbstractSimpleScopeTowerProcessor<C : Candidate>(
val candidateFactory: CandidateFactory<C> val candidateFactory: CandidateFactory<C>
) : SimpleScopeTowerProcessor<C> ) : SimpleScopeTowerProcessor<C>
private typealias CandidatesCollector = private typealias CandidatesCollector =
ScopeTowerLevel.(extensionReceiver: ReceiverValueWithSmartCastInfo?) -> Collection<CandidateWithBoundDispatchReceiver> ScopeTowerLevel.(extensionReceiver: ReceiverValueWithSmartCastInfo?) -> Collection<CandidateWithBoundDispatchReceiver>
internal class ExplicitReceiverScopeTowerProcessor<C: Candidate>( internal class ExplicitReceiverScopeTowerProcessor<C : Candidate>(
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
context: CandidateFactory<C>, context: CandidateFactory<C>,
val explicitReceiver: ReceiverValueWithSmartCastInfo, val explicitReceiver: ReceiverValueWithSmartCastInfo,
val collectCandidates: CandidatesCollector val collectCandidates: CandidatesCollector
): AbstractSimpleScopeTowerProcessor<C>(context) { ) : AbstractSimpleScopeTowerProcessor<C>(context) {
override fun simpleProcess(data: TowerData): Collection<C> { override fun simpleProcess(data: TowerData): Collection<C> {
return when (data) { return when (data) {
TowerData.Empty -> resolveAsMember() TowerData.Empty -> resolveAsMember()
@@ -80,7 +79,13 @@ internal class ExplicitReceiverScopeTowerProcessor<C: Candidate>(
val members = mutableListOf<C>() val members = mutableListOf<C>()
for (memberCandidate in MemberScopeTowerLevel(scopeTower, explicitReceiver).collectCandidates(null)) { for (memberCandidate in MemberScopeTowerLevel(scopeTower, explicitReceiver).collectCandidates(null)) {
if (!memberCandidate.requiresExtensionReceiver) { if (!memberCandidate.requiresExtensionReceiver) {
members.add(candidateFactory.createCandidate(memberCandidate, ExplicitReceiverKind.DISPATCH_RECEIVER, extensionReceiver = null)) members.add(
candidateFactory.createCandidate(
memberCandidate,
ExplicitReceiverKind.DISPATCH_RECEIVER,
extensionReceiver = null
)
)
} }
} }
return members return members
@@ -90,7 +95,13 @@ internal class ExplicitReceiverScopeTowerProcessor<C: Candidate>(
val extensions = mutableListOf<C>() val extensions = mutableListOf<C>()
for (extensionCandidate in level.collectCandidates(explicitReceiver)) { for (extensionCandidate in level.collectCandidates(explicitReceiver)) {
if (extensionCandidate.requiresExtensionReceiver) { if (extensionCandidate.requiresExtensionReceiver) {
extensions.add(candidateFactory.createCandidate(extensionCandidate, ExplicitReceiverKind.EXTENSION_RECEIVER, extensionReceiver = explicitReceiver)) extensions.add(
candidateFactory.createCandidate(
extensionCandidate,
ExplicitReceiverKind.EXTENSION_RECEIVER,
extensionReceiver = explicitReceiver
)
)
} }
} }
return extensions return extensions
@@ -105,19 +116,25 @@ internal class ExplicitReceiverScopeTowerProcessor<C: Candidate>(
} }
} }
private class QualifierScopeTowerProcessor<C: Candidate>( private class QualifierScopeTowerProcessor<C : Candidate>(
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
context: CandidateFactory<C>, context: CandidateFactory<C>,
val qualifier: QualifierReceiver, val qualifier: QualifierReceiver,
val collectCandidates: CandidatesCollector val collectCandidates: CandidatesCollector
): AbstractSimpleScopeTowerProcessor<C>(context) { ) : AbstractSimpleScopeTowerProcessor<C>(context) {
override fun simpleProcess(data: TowerData): Collection<C> { override fun simpleProcess(data: TowerData): Collection<C> {
if (data != TowerData.Empty) return emptyList() if (data != TowerData.Empty) return emptyList()
val staticMembers = mutableListOf<C>() val staticMembers = mutableListOf<C>()
for (towerCandidate in QualifierScopeTowerLevel(scopeTower, qualifier).collectCandidates(null)) { for (towerCandidate in QualifierScopeTowerLevel(scopeTower, qualifier).collectCandidates(null)) {
if (!towerCandidate.requiresExtensionReceiver) { if (!towerCandidate.requiresExtensionReceiver) {
staticMembers.add(candidateFactory.createCandidate(towerCandidate, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = null)) staticMembers.add(
candidateFactory.createCandidate(
towerCandidate,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
extensionReceiver = null
)
)
} }
} }
return staticMembers return staticMembers
@@ -127,32 +144,43 @@ private class QualifierScopeTowerProcessor<C: Candidate>(
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {} override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {}
} }
private class NoExplicitReceiverScopeTowerProcessor<C: Candidate>( private class NoExplicitReceiverScopeTowerProcessor<C : Candidate>(
context: CandidateFactory<C>, context: CandidateFactory<C>,
val collectCandidates: CandidatesCollector val collectCandidates: CandidatesCollector
) : AbstractSimpleScopeTowerProcessor<C>(context) { ) : AbstractSimpleScopeTowerProcessor<C>(context) {
override fun simpleProcess(data: TowerData): Collection<C> override fun simpleProcess(data: TowerData): Collection<C> = when (data) {
= when(data) { is TowerData.TowerLevel -> {
is TowerData.TowerLevel -> { val result = mutableListOf<C>()
val result = mutableListOf<C>() for (towerCandidate in data.level.collectCandidates(null)) {
for (towerCandidate in data.level.collectCandidates(null)) { if (!towerCandidate.requiresExtensionReceiver) {
if (!towerCandidate.requiresExtensionReceiver) { result.add(
result.add(candidateFactory.createCandidate(towerCandidate, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = null)) candidateFactory.createCandidate(
} towerCandidate,
} ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
result extensionReceiver = null
)
)
} }
is TowerData.BothTowerLevelAndImplicitReceiver -> {
val result = mutableListOf<C>()
for (towerCandidate in data.level.collectCandidates(data.implicitReceiver)) {
if (towerCandidate.requiresExtensionReceiver) {
result.add(candidateFactory.createCandidate(towerCandidate, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, extensionReceiver = data.implicitReceiver))
}
}
result
}
else -> emptyList()
} }
result
}
is TowerData.BothTowerLevelAndImplicitReceiver -> {
val result = mutableListOf<C>()
for (towerCandidate in data.level.collectCandidates(data.implicitReceiver)) {
if (towerCandidate.requiresExtensionReceiver) {
result.add(
candidateFactory.createCandidate(
towerCandidate,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
extensionReceiver = data.implicitReceiver
)
)
}
}
result
}
else -> emptyList()
}
override fun recordLookups(skippedData: Collection<TowerData>, name: Name) { override fun recordLookups(skippedData: Collection<TowerData>, name: Name) {
for (data in skippedData) { for (data in skippedData) {
@@ -166,73 +194,77 @@ private class NoExplicitReceiverScopeTowerProcessor<C: Candidate>(
} }
private fun <C : Candidate> createSimpleProcessorWithoutClassValueReceiver( private fun <C : Candidate> createSimpleProcessorWithoutClassValueReceiver(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
context: CandidateFactory<C>, context: CandidateFactory<C>,
explicitReceiver: DetailedReceiver?, explicitReceiver: DetailedReceiver?,
collectCandidates: CandidatesCollector collectCandidates: CandidatesCollector
): SimpleScopeTowerProcessor<C> = ): SimpleScopeTowerProcessor<C> =
when (explicitReceiver) { when (explicitReceiver) {
is ReceiverValueWithSmartCastInfo -> ExplicitReceiverScopeTowerProcessor(scopeTower, context, explicitReceiver, collectCandidates) is ReceiverValueWithSmartCastInfo -> ExplicitReceiverScopeTowerProcessor(scopeTower, context, explicitReceiver, collectCandidates)
is QualifierReceiver -> QualifierScopeTowerProcessor(scopeTower, context, explicitReceiver, collectCandidates) is QualifierReceiver -> QualifierScopeTowerProcessor(scopeTower, context, explicitReceiver, collectCandidates)
else -> { else -> {
assert(explicitReceiver == null) { assert(explicitReceiver == null) {
"Illegal explicit receiver: $explicitReceiver(${explicitReceiver!!::class.java.simpleName})" "Illegal explicit receiver: $explicitReceiver(${explicitReceiver!!::class.java.simpleName})"
}
NoExplicitReceiverScopeTowerProcessor(context, collectCandidates)
} }
NoExplicitReceiverScopeTowerProcessor(context, collectCandidates)
} }
}
private fun <C : Candidate> createSimpleProcessor( private fun <C : Candidate> createSimpleProcessor(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
context: CandidateFactory<C>, context: CandidateFactory<C>,
explicitReceiver: DetailedReceiver?, explicitReceiver: DetailedReceiver?,
classValueReceiver: Boolean, classValueReceiver: Boolean,
collectCandidates: CandidatesCollector collectCandidates: CandidatesCollector
) : ScopeTowerProcessor<C> { ): ScopeTowerProcessor<C> {
val withoutClassValueProcessor = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver, collectCandidates) val withoutClassValueProcessor =
createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver, collectCandidates)
if (classValueReceiver && explicitReceiver is QualifierReceiver) { if (classValueReceiver && explicitReceiver is QualifierReceiver) {
val classValue = explicitReceiver.classValueReceiverWithSmartCastInfo ?: return withoutClassValueProcessor val classValue = explicitReceiver.classValueReceiverWithSmartCastInfo ?: return withoutClassValueProcessor
return PrioritizedCompositeScopeTowerProcessor( return PrioritizedCompositeScopeTowerProcessor(
withoutClassValueProcessor, withoutClassValueProcessor,
ExplicitReceiverScopeTowerProcessor(scopeTower, context, classValue, collectCandidates) ExplicitReceiverScopeTowerProcessor(scopeTower, context, classValue, collectCandidates)
) )
} }
return withoutClassValueProcessor return withoutClassValueProcessor
} }
fun <C : Candidate> createCallableReferenceProcessor( fun <C : Candidate> createCallableReferenceProcessor(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
name: Name, context: CandidateFactory<C>, name: Name, context: CandidateFactory<C>,
explicitReceiver: DetailedReceiver? explicitReceiver: DetailedReceiver?
): SimpleScopeTowerProcessor<C> { ): SimpleScopeTowerProcessor<C> {
val variable = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getVariables(name, it) } val variable = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getVariables(name, it) }
val function = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getFunctions(name, it) } val function = createSimpleProcessorWithoutClassValueReceiver(scopeTower, context, explicitReceiver) { getFunctions(name, it) }
return SamePriorityCompositeScopeTowerProcessor(variable, function) return SamePriorityCompositeScopeTowerProcessor(variable, function)
} }
fun <C : Candidate> createVariableProcessor(scopeTower: ImplicitScopeTower, name: Name, fun <C : Candidate> createVariableProcessor(
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true scopeTower: ImplicitScopeTower, name: Name,
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true
) = createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getVariables(name, it) } ) = createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getVariables(name, it) }
fun <C : Candidate> createVariableAndObjectProcessor(scopeTower: ImplicitScopeTower, name: Name, fun <C : Candidate> createVariableAndObjectProcessor(
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true scopeTower: ImplicitScopeTower, name: Name,
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true
) = PrioritizedCompositeScopeTowerProcessor( ) = PrioritizedCompositeScopeTowerProcessor(
createVariableProcessor(scopeTower, name, context, explicitReceiver), createVariableProcessor(scopeTower, name, context, explicitReceiver),
createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getObjects(name, it) } createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getObjects(name, it) }
) )
fun <C : Candidate> createSimpleFunctionProcessor(scopeTower: ImplicitScopeTower, name: Name, fun <C : Candidate> createSimpleFunctionProcessor(
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true scopeTower: ImplicitScopeTower, name: Name,
context: CandidateFactory<C>, explicitReceiver: DetailedReceiver?, classValueReceiver: Boolean = true
) = createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getFunctions(name, it) } ) = createSimpleProcessor(scopeTower, context, explicitReceiver, classValueReceiver) { getFunctions(name, it) }
fun <С: Candidate> createFunctionProcessor( fun <С : Candidate> createFunctionProcessor(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
name: Name, name: Name,
simpleContext: CandidateFactory<С>, simpleContext: CandidateFactory<С>,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<С>, factoryProviderForInvoke: CandidateFactoryProviderForInvoke<С>,
explicitReceiver: DetailedReceiver? explicitReceiver: DetailedReceiver?
): PrioritizedCompositeScopeTowerProcessor<С> { ): PrioritizedCompositeScopeTowerProcessor<С> {
// a.foo() -- simple function call // a.foo() -- simple function call
@@ -250,15 +282,14 @@ fun <С: Candidate> createFunctionProcessor(
} }
fun <C: Candidate> createProcessorWithReceiverValueOrEmpty( fun <C : Candidate> createProcessorWithReceiverValueOrEmpty(
explicitReceiver: DetailedReceiver?, explicitReceiver: DetailedReceiver?,
create: (ReceiverValueWithSmartCastInfo?) -> ScopeTowerProcessor<C> create: (ReceiverValueWithSmartCastInfo?) -> ScopeTowerProcessor<C>
): ScopeTowerProcessor<C> { ): ScopeTowerProcessor<C> {
return if (explicitReceiver is QualifierReceiver) { return if (explicitReceiver is QualifierReceiver) {
explicitReceiver.classValueReceiverWithSmartCastInfo?.let(create) explicitReceiver.classValueReceiverWithSmartCastInfo?.let(create)
?: KnownResultProcessor<C>(listOf()) ?: KnownResultProcessor<C>(listOf())
} } else {
else {
create(explicitReceiver as ReceiverValueWithSmartCastInfo?) create(explicitReceiver as ReceiverValueWithSmartCastInfo?)
} }
} }
@@ -42,23 +42,22 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.* import java.util.*
internal abstract class AbstractScopeTowerLevel( internal abstract class AbstractScopeTowerLevel(
protected val scopeTower: ImplicitScopeTower protected val scopeTower: ImplicitScopeTower
): ScopeTowerLevel { ) : ScopeTowerLevel {
protected val location: LookupLocation get() = scopeTower.location protected val location: LookupLocation get() = scopeTower.location
protected fun createCandidateDescriptor( protected fun createCandidateDescriptor(
descriptor: CallableDescriptor, descriptor: CallableDescriptor,
dispatchReceiver: ReceiverValueWithSmartCastInfo?, dispatchReceiver: ReceiverValueWithSmartCastInfo?,
specialError: ResolutionDiagnostic? = null, specialError: ResolutionDiagnostic? = null,
dispatchReceiverSmartCastType: KotlinType? = null dispatchReceiverSmartCastType: KotlinType? = null
): CandidateWithBoundDispatchReceiver { ): CandidateWithBoundDispatchReceiver {
val diagnostics = SmartList<ResolutionDiagnostic>() val diagnostics = SmartList<ResolutionDiagnostic>()
diagnostics.addIfNotNull(specialError) diagnostics.addIfNotNull(specialError)
if (ErrorUtils.isError(descriptor)) { if (ErrorUtils.isError(descriptor)) {
diagnostics.add(ErrorDescriptorDiagnostic) diagnostics.add(ErrorDescriptorDiagnostic)
} } else {
else {
if (descriptor.hasLowPriorityInOverloadResolution() || descriptor.isLowPriorityFromStdlibJre7Or8()) { if (descriptor.hasLowPriorityInOverloadResolution() || descriptor.isLowPriorityFromStdlibJre7Or8()) {
diagnostics.add(LowPriorityDescriptorDiagnostic) diagnostics.add(LowPriorityDescriptorDiagnostic)
} }
@@ -67,9 +66,9 @@ internal abstract class AbstractScopeTowerLevel(
val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext || scopeTower.isNewInferenceEnabled val shouldSkipVisibilityCheck = scopeTower.isDebuggerContext || scopeTower.isNewInferenceEnabled
if (!shouldSkipVisibilityCheck) { if (!shouldSkipVisibilityCheck) {
Visibilities.findInvisibleMember( Visibilities.findInvisibleMember(
getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType), getReceiverValueWithSmartCast(dispatchReceiver?.receiverValue, dispatchReceiverSmartCastType),
descriptor, descriptor,
scopeTower.lexicalScope.ownerDescriptor scopeTower.lexicalScope.ownerDescriptor
)?.let { diagnostics.add(VisibilityError(it)) } )?.let { diagnostics.add(VisibilityError(it)) }
} }
} }
@@ -81,15 +80,15 @@ internal abstract class AbstractScopeTowerLevel(
// todo KT-9538 Unresolved inner class via subclass reference // todo KT-9538 Unresolved inner class via subclass reference
// todo add static methods & fields with error // todo add static methods & fields with error
internal class MemberScopeTowerLevel( internal class MemberScopeTowerLevel(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
val dispatchReceiver: ReceiverValueWithSmartCastInfo val dispatchReceiver: ReceiverValueWithSmartCastInfo
): AbstractScopeTowerLevel(scopeTower) { ) : AbstractScopeTowerLevel(scopeTower) {
private val syntheticScopes = scopeTower.syntheticScopes private val syntheticScopes = scopeTower.syntheticScopes
private val isNewInferenceEnabled = scopeTower.isNewInferenceEnabled private val isNewInferenceEnabled = scopeTower.isNewInferenceEnabled
private fun collectMembers( private fun collectMembers(
getMembers: ResolutionScope.(KotlinType?) -> Collection<CallableDescriptor> getMembers: ResolutionScope.(KotlinType?) -> Collection<CallableDescriptor>
): Collection<CandidateWithBoundDispatchReceiver> { ): Collection<CandidateWithBoundDispatchReceiver> {
val result = ArrayList<CandidateWithBoundDispatchReceiver>(0) val result = ArrayList<CandidateWithBoundDispatchReceiver>(0)
val receiverValue = dispatchReceiver.receiverValue val receiverValue = dispatchReceiver.receiverValue
@@ -103,9 +102,9 @@ internal class MemberScopeTowerLevel(
for (possibleType in dispatchReceiver.possibleTypes) { for (possibleType in dispatchReceiver.possibleTypes) {
possibleType.memberScope.getMembers(possibleType).mapTo(unstableCandidates ?: result) { possibleType.memberScope.getMembers(possibleType).mapTo(unstableCandidates ?: result) {
createCandidateDescriptor( createCandidateDescriptor(
it, it,
dispatchReceiver.smartCastReceiver(possibleType), dispatchReceiver.smartCastReceiver(possibleType),
unstableError, dispatchReceiverSmartCastType = possibleType unstableError, dispatchReceiverSmartCastType = possibleType
) )
} }
} }
@@ -113,8 +112,7 @@ internal class MemberScopeTowerLevel(
if (dispatchReceiver.possibleTypes.isNotEmpty()) { if (dispatchReceiver.possibleTypes.isNotEmpty()) {
if (unstableCandidates == null) { if (unstableCandidates == null) {
result.retainAll(result.selectMostSpecificInEachOverridableGroup { descriptor.approximateCapturedTypes() }) result.retainAll(result.selectMostSpecificInEachOverridableGroup { descriptor.approximateCapturedTypes() })
} } else {
else {
result.addAll(unstableCandidates.selectMostSpecificInEachOverridableGroup { descriptor.approximateCapturedTypes() }) result.addAll(unstableCandidates.selectMostSpecificInEachOverridableGroup { descriptor.approximateCapturedTypes() })
} }
} }
@@ -142,8 +140,14 @@ internal class MemberScopeTowerLevel(
override fun get(key: KotlinType): TypeProjection? = null override fun get(key: KotlinType): TypeProjection? = null
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = when (position) { override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) = when (position) {
Variance.INVARIANT -> null Variance.INVARIANT -> null
Variance.OUT_VARIANCE -> approximator.approximateToSuperType(topLevelType.unwrap(), TypeApproximatorConfiguration.CapturedTypesApproximation) Variance.OUT_VARIANCE -> approximator.approximateToSuperType(
Variance.IN_VARIANCE -> approximator.approximateToSubType(topLevelType.unwrap(), TypeApproximatorConfiguration.CapturedTypesApproximation) topLevelType.unwrap(),
TypeApproximatorConfiguration.CapturedTypesApproximation
)
Variance.IN_VARIANCE -> approximator.approximateToSubType(
topLevelType.unwrap(),
TypeApproximatorConfiguration.CapturedTypesApproximation
)
} ?: topLevelType } ?: topLevelType
} }
return substitute(TypeSubstitutor.create(wrappedSubstitution)) return substitute(TypeSubstitutor.create(wrappedSubstitution))
@@ -156,18 +160,27 @@ internal class MemberScopeTowerLevel(
return ReceiverValueWithSmartCastInfo(newReceiverValue, possibleTypes, isStable) return ReceiverValueWithSmartCastInfo(newReceiverValue, possibleTypes, isStable)
} }
override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> { override fun getVariables(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> {
return collectMembers { getContributedVariables(name, location) } return collectMembers { getContributedVariables(name, location) }
} }
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> { override fun getObjects(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> {
return emptyList() return emptyList()
} }
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> { override fun getFunctions(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> {
return collectMembers { return collectMembers {
getContributedFunctions(name, location) + it.getInnerConstructors(name, location) + getContributedFunctions(name, location) + it.getInnerConstructors(name, location) +
syntheticScopes.collectSyntheticMemberFunctions(listOfNotNull(it), name, location) syntheticScopes.collectSyntheticMemberFunctions(listOfNotNull(it), name, location)
} }
} }
@@ -179,71 +192,86 @@ internal class MemberScopeTowerLevel(
} }
} }
internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qualifier: QualifierReceiver) : AbstractScopeTowerLevel(scopeTower) { internal class QualifierScopeTowerLevel(scopeTower: ImplicitScopeTower, val qualifier: QualifierReceiver) :
AbstractScopeTowerLevel(scopeTower) {
override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope
.getContributedVariables(name, location).map { .getContributedVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope
.getContributedObjectVariables(name, location).map { .getContributedObjectVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) = qualifier.staticScope
.getContributedFunctionsAndConstructors(name, .getContributedFunctionsAndConstructors(
location, name,
scopeTower.syntheticScopes, location,
qualifier.staticScope).map { scopeTower.syntheticScopes,
createCandidateDescriptor(it, dispatchReceiver = null) qualifier.staticScope
} ).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
override fun recordLookup(name: Name) {} override fun recordLookup(name: Name) {}
} }
// KT-3335 Creating imported super class' inner class fails in codegen // KT-3335 Creating imported super class' inner class fails in codegen
internal open class ScopeBasedTowerLevel protected constructor( internal open class ScopeBasedTowerLevel protected constructor(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
private val resolutionScope: ResolutionScope private val resolutionScope: ResolutionScope
) : AbstractScopeTowerLevel(scopeTower) { ) : AbstractScopeTowerLevel(scopeTower) {
internal constructor(scopeTower: ImplicitScopeTower, lexicalScope: LexicalScope) : this(scopeTower, lexicalScope as ResolutionScope) internal constructor(scopeTower: ImplicitScopeTower, lexicalScope: LexicalScope) : this(scopeTower, lexicalScope as ResolutionScope)
override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> override fun getVariables(
= resolutionScope.getContributedVariables(name, location).map { name: Name,
createCandidateDescriptor(it, dispatchReceiver = null) extensionReceiver: ReceiverValueWithSmartCastInfo?
} ): Collection<CandidateWithBoundDispatchReceiver> = resolutionScope.getContributedVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> override fun getObjects(
= resolutionScope.getContributedObjectVariables(name, location).map { name: Name,
createCandidateDescriptor(it, dispatchReceiver = null) extensionReceiver: ReceiverValueWithSmartCastInfo?
} ): Collection<CandidateWithBoundDispatchReceiver> = resolutionScope.getContributedObjectVariables(name, location).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> override fun getFunctions(
= resolutionScope.getContributedFunctionsAndConstructors(name, name: Name,
location, extensionReceiver: ReceiverValueWithSmartCastInfo?
scopeTower.syntheticScopes, ): Collection<CandidateWithBoundDispatchReceiver> = resolutionScope.getContributedFunctionsAndConstructors(
resolutionScope).map { name,
createCandidateDescriptor(it, dispatchReceiver = null) location,
} scopeTower.syntheticScopes,
resolutionScope
).map {
createCandidateDescriptor(it, dispatchReceiver = null)
}
override fun recordLookup(name: Name) { override fun recordLookup(name: Name) {
resolutionScope.recordLookup(name, location) resolutionScope.recordLookup(name, location)
} }
} }
internal class ImportingScopeBasedTowerLevel( internal class ImportingScopeBasedTowerLevel(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
importingScope: ImportingScope importingScope: ImportingScope
): ScopeBasedTowerLevel(scopeTower, importingScope) ) : ScopeBasedTowerLevel(scopeTower, importingScope)
internal class SyntheticScopeBasedTowerLevel( internal class SyntheticScopeBasedTowerLevel(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
private val syntheticScopes: SyntheticScopes private val syntheticScopes: SyntheticScopes
): AbstractScopeTowerLevel(scopeTower) { ) : AbstractScopeTowerLevel(scopeTower) {
private val ReceiverValueWithSmartCastInfo.allTypes: Set<KotlinType> private val ReceiverValueWithSmartCastInfo.allTypes: Set<KotlinType>
get() = possibleTypes + receiverValue.type get() = possibleTypes + receiverValue.type
override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?): Collection<CandidateWithBoundDispatchReceiver> { override fun getVariables(
name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> {
if (extensionReceiver == null) return emptyList() if (extensionReceiver == null) return emptyList()
return syntheticScopes.collectSyntheticExtensionProperties(extensionReceiver.allTypes, name, location).map { return syntheticScopes.collectSyntheticExtensionProperties(extensionReceiver.allTypes, name, location).map {
@@ -252,43 +280,43 @@ internal class SyntheticScopeBasedTowerLevel(
} }
override fun getObjects( override fun getObjects(
name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo? name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> = ): Collection<CandidateWithBoundDispatchReceiver> =
emptyList() emptyList()
override fun getFunctions( override fun getFunctions(
name: Name, name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): Collection<CandidateWithBoundDispatchReceiver> = ): Collection<CandidateWithBoundDispatchReceiver> =
emptyList() emptyList()
override fun recordLookup(name: Name) { override fun recordLookup(name: Name) {
} }
} }
internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower): AbstractScopeTowerLevel(scopeTower) { internal class HidesMembersTowerLevel(scopeTower: ImplicitScopeTower) : AbstractScopeTowerLevel(scopeTower) {
override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) override fun getVariables(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) =
= getCandidates(name, extensionReceiver, LexicalScope::collectVariables) getCandidates(name, extensionReceiver, LexicalScope::collectVariables)
override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) override fun getObjects(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) =
= emptyList<CandidateWithBoundDispatchReceiver>() emptyList<CandidateWithBoundDispatchReceiver>()
override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) override fun getFunctions(name: Name, extensionReceiver: ReceiverValueWithSmartCastInfo?) =
= getCandidates(name, extensionReceiver, LexicalScope::collectFunctions) getCandidates(name, extensionReceiver, LexicalScope::collectFunctions)
private fun getCandidates( private fun getCandidates(
name: Name, name: Name,
extensionReceiver: ReceiverValueWithSmartCastInfo?, extensionReceiver: ReceiverValueWithSmartCastInfo?,
collectCandidates: LexicalScope.(Name, LookupLocation) -> Collection<CallableDescriptor> collectCandidates: LexicalScope.(Name, LookupLocation) -> Collection<CallableDescriptor>
): Collection<CandidateWithBoundDispatchReceiver> { ): Collection<CandidateWithBoundDispatchReceiver> {
if (extensionReceiver == null || name !in HIDES_MEMBERS_NAME_LIST) return emptyList() if (extensionReceiver == null || name !in HIDES_MEMBERS_NAME_LIST) return emptyList()
return scopeTower.lexicalScope.collectCandidates(name, location).filter { return scopeTower.lexicalScope.collectCandidates(name, location).filter {
it.extensionReceiverParameter != null && it.hasHidesMembersAnnotation() it.extensionReceiverParameter != null && it.hasHidesMembersAnnotation()
}.map { }.map {
createCandidateDescriptor(it, dispatchReceiver = null) createCandidateDescriptor(it, dispatchReceiver = null)
} }
} }
override fun recordLookup(name: Name) {} override fun recordLookup(name: Name) {}
@@ -309,10 +337,10 @@ private fun KotlinType?.getInnerConstructors(name: Name, location: LookupLocatio
} }
private fun ResolutionScope.getContributedFunctionsAndConstructors( private fun ResolutionScope.getContributedFunctionsAndConstructors(
name: Name, name: Name,
location: LookupLocation, location: LookupLocation,
syntheticScopes: SyntheticScopes, syntheticScopes: SyntheticScopes,
scope: ResolutionScope scope: ResolutionScope
): Collection<FunctionDescriptor> { ): Collection<FunctionDescriptor> {
val result = ArrayList<FunctionDescriptor>(getContributedFunctions(name, location)) val result = ArrayList<FunctionDescriptor>(getContributedFunctions(name, location))
@@ -338,27 +366,27 @@ private fun ResolutionScope.getContributedObjectVariables(name: Name, location:
} }
fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? = fun getFakeDescriptorForObject(classifier: ClassifierDescriptor?): FakeCallableDescriptorForObject? =
when (classifier) { when (classifier) {
is TypeAliasDescriptor -> is TypeAliasDescriptor ->
classifier.classDescriptor?.let { classDescriptor -> classifier.classDescriptor?.let { classDescriptor ->
if (classDescriptor.hasClassValueDescriptor) if (classDescriptor.hasClassValueDescriptor)
FakeCallableDescriptorForTypeAliasObject(classifier) FakeCallableDescriptorForTypeAliasObject(classifier)
else
null
}
is ClassDescriptor ->
if (classifier.hasClassValueDescriptor)
FakeCallableDescriptorForObject(classifier)
else else
null null
else -> null }
} is ClassDescriptor ->
if (classifier.hasClassValueDescriptor)
FakeCallableDescriptorForObject(classifier)
else
null
else -> null
}
private fun getClassWithConstructors(classifier: ClassifierDescriptor?): ClassDescriptor? = private fun getClassWithConstructors(classifier: ClassifierDescriptor?): ClassDescriptor? =
if (classifier !is ClassDescriptor || !classifier.canHaveCallableConstructors) if (classifier !is ClassDescriptor || !classifier.canHaveCallableConstructors)
null null
else else
classifier classifier
private val ClassDescriptor.canHaveCallableConstructors: Boolean private val ClassDescriptor.canHaveCallableConstructors: Boolean
get() = !ErrorUtils.isError(this) && !kind.isSingleton get() = !ErrorUtils.isError(this) && !kind.isSingleton
@@ -37,11 +37,11 @@ interface Candidate {
val resultingApplicability: ResolutionCandidateApplicability val resultingApplicability: ResolutionCandidateApplicability
} }
interface CandidateFactory<out C: Candidate> { interface CandidateFactory<out C : Candidate> {
fun createCandidate( fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver, towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): C ): C
} }
@@ -59,7 +59,7 @@ interface CandidateFactoryProviderForInvoke<C : Candidate> {
sealed class TowerData { sealed class TowerData {
object Empty : TowerData() object Empty : TowerData()
class OnlyImplicitReceiver(val implicitReceiver: ReceiverValueWithSmartCastInfo): TowerData() class OnlyImplicitReceiver(val implicitReceiver: ReceiverValueWithSmartCastInfo) : TowerData()
class TowerLevel(val level: ScopeTowerLevel) : TowerData() class TowerLevel(val level: ScopeTowerLevel) : TowerData()
class BothTowerLevelAndImplicitReceiver(val level: ScopeTowerLevel, val implicitReceiver: ReceiverValueWithSmartCastInfo) : TowerData() class BothTowerLevelAndImplicitReceiver(val level: ScopeTowerLevel, val implicitReceiver: ReceiverValueWithSmartCastInfo) : TowerData()
// Has the same meaning as BothTowerLevelAndImplicitReceiver, but it's only used for names lookup, so it doesn't need implicit receiver // Has the same meaning as BothTowerLevelAndImplicitReceiver, but it's only used for names lookup, so it doesn't need implicit receiver
@@ -81,41 +81,40 @@ interface SimpleScopeTowerProcessor<out C> : ScopeTowerProcessor<C> {
} }
class TowerResolver { class TowerResolver {
fun <C: Candidate> runResolve( fun <C : Candidate> runResolve(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
useOrder: Boolean, useOrder: Boolean,
name: Name name: Name
): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder, name) ): Collection<C> = scopeTower.run(processor, SuccessfulResultCollector(), useOrder, name)
fun <C: Candidate> collectAllCandidates( fun <C : Candidate> collectAllCandidates(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
name: Name name: Name
): Collection<C> ): Collection<C> = scopeTower.run(processor, AllCandidatesCollector(), false, name)
= scopeTower.run(processor, AllCandidatesCollector(), false, name)
fun <C : Candidate> ImplicitScopeTower.run( fun <C : Candidate> ImplicitScopeTower.run(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean, useOrder: Boolean,
name: Name name: Name
): Collection<C> = Task(this, processor, resultCollector, useOrder, name).run() ): Collection<C> = Task(this, processor, resultCollector, useOrder, name).run()
private inner class Task<out C : Candidate>( private inner class Task<out C : Candidate>(
private val implicitScopeTower: ImplicitScopeTower, private val implicitScopeTower: ImplicitScopeTower,
private val processor: ScopeTowerProcessor<C>, private val processor: ScopeTowerProcessor<C>,
private val resultCollector: ResultCollector<C>, private val resultCollector: ResultCollector<C>,
private val useOrder: Boolean, private val useOrder: Boolean,
private val name: Name private val name: Name
) { ) {
private val isNameForHidesMember = name in HIDES_MEMBERS_NAME_LIST private val isNameForHidesMember = name in HIDES_MEMBERS_NAME_LIST
private val skippedDataForLookup = mutableListOf<TowerData>() private val skippedDataForLookup = mutableListOf<TowerData>()
private val localLevels: Collection<ScopeTowerLevel> by lazy(LazyThreadSafetyMode.NONE) { private val localLevels: Collection<ScopeTowerLevel> by lazy(LazyThreadSafetyMode.NONE) {
implicitScopeTower.lexicalScope.parentsWithSelf. implicitScopeTower.lexicalScope.parentsWithSelf.filterIsInstance<LexicalScope>()
filterIsInstance<LexicalScope>().filter { it.kind.withLocalDescriptors && it.mayFitForName(name) }. .filter { it.kind.withLocalDescriptors && it.mayFitForName(name) }.map { ScopeBasedTowerLevel(implicitScopeTower, it) }
map { ScopeBasedTowerLevel(implicitScopeTower, it) }.toList() .toList()
} }
private val nonLocalLevels: Collection<ScopeTowerLevel> by lazy(LazyThreadSafetyMode.NONE) { private val nonLocalLevels: Collection<ScopeTowerLevel> by lazy(LazyThreadSafetyMode.NONE) {
@@ -131,8 +130,7 @@ class TowerResolver {
fun addLevel(scopeTowerLevel: ScopeTowerLevel, mayFitForName: Boolean) { fun addLevel(scopeTowerLevel: ScopeTowerLevel, mayFitForName: Boolean) {
if (mayFitForName) { if (mayFitForName) {
mainResult.add(scopeTowerLevel) mainResult.add(scopeTowerLevel)
} } else {
else {
skippedDataForLookup.add(TowerData.ForLookupForNoExplicitReceiver(scopeTowerLevel)) skippedDataForLookup.add(TowerData.ForLookupForNoExplicitReceiver(scopeTowerLevel))
} }
} }
@@ -141,22 +139,21 @@ class TowerResolver {
if (scope is LexicalScope) { if (scope is LexicalScope) {
if (!scope.kind.withLocalDescriptors) { if (!scope.kind.withLocalDescriptors) {
addLevel( addLevel(
ScopeBasedTowerLevel(this@createNonLocalLevels, scope), ScopeBasedTowerLevel(this@createNonLocalLevels, scope),
scope.mayFitForName(name) scope.mayFitForName(name)
) )
} }
getImplicitReceiver(scope)?.let { getImplicitReceiver(scope)?.let {
addLevel( addLevel(
MemberScopeTowerLevel(this@createNonLocalLevels, it), MemberScopeTowerLevel(this@createNonLocalLevels, it),
it.mayFitForName(name) it.mayFitForName(name)
) )
} }
} } else {
else {
addLevel( addLevel(
ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope), ImportingScopeBasedTowerLevel(this@createNonLocalLevels, scope as ImportingScope),
scope.mayFitForName(name) scope.mayFitForName(name)
) )
} }
} }
@@ -197,16 +194,15 @@ class TowerResolver {
// statics // statics
if (!scope.kind.withLocalDescriptors) { if (!scope.kind.withLocalDescriptors) {
TowerData.TowerLevel(ScopeBasedTowerLevel(implicitScopeTower, scope)) TowerData.TowerLevel(ScopeBasedTowerLevel(implicitScopeTower, scope))
.process(scope.mayFitForName(name))?.let { return it } .process(scope.mayFitForName(name))?.let { return it }
} }
implicitScopeTower.getImplicitReceiver(scope) implicitScopeTower.getImplicitReceiver(scope)
?.let(this::processImplicitReceiver) ?.let(this::processImplicitReceiver)
?.let { return it } ?.let { return it }
} } else {
else {
TowerData.TowerLevel(ImportingScopeBasedTowerLevel(implicitScopeTower, scope as ImportingScope)) TowerData.TowerLevel(ImportingScopeBasedTowerLevel(implicitScopeTower, scope as ImportingScope))
.process(scope.mayFitForName(name))?.let { return it } .process(scope.mayFitForName(name))?.let { return it }
} }
} }
@@ -223,7 +219,7 @@ class TowerResolver {
// members of implicit receiver or member extension for explicit receiver // members of implicit receiver or member extension for explicit receiver
TowerData.TowerLevel(MemberScopeTowerLevel(implicitScopeTower, implicitReceiver)) TowerData.TowerLevel(MemberScopeTowerLevel(implicitScopeTower, implicitReceiver))
.process(implicitReceiver.mayFitForName(name))?.let { return it } .process(implicitReceiver.mayFitForName(name))?.let { return it }
// synthetic properties // synthetic properties
TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it } TowerData.BothTowerLevelAndImplicitReceiver(syntheticLevel, implicitReceiver).process()?.let { return it }
@@ -255,32 +251,31 @@ class TowerResolver {
} }
private fun KotlinType.mayFitForName(name: Name) = private fun KotlinType.mayFitForName(name: Name) =
isDynamic() || isDynamic() ||
!memberScope.definitelyDoesNotContainName(name) || !memberScope.definitelyDoesNotContainName(name) ||
!memberScope.definitelyDoesNotContainName(OperatorNameConventions.INVOKE) !memberScope.definitelyDoesNotContainName(OperatorNameConventions.INVOKE)
private fun ResolutionScope.mayFitForName(name: Name) = private fun ResolutionScope.mayFitForName(name: Name) =
!definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE) !definitelyDoesNotContainName(name) || !definitelyDoesNotContainName(OperatorNameConventions.INVOKE)
} }
fun <C : Candidate> runWithEmptyTowerData( fun <C : Candidate> runWithEmptyTowerData(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean useOrder: Boolean
): Collection<C> = processTowerData(processor, resultCollector, useOrder, TowerData.Empty) ?: resultCollector.getFinalCandidates() ): Collection<C> = processTowerData(processor, resultCollector, useOrder, TowerData.Empty) ?: resultCollector.getFinalCandidates()
private fun <C : Candidate> processTowerData( private fun <C : Candidate> processTowerData(
processor: ScopeTowerProcessor<C>, processor: ScopeTowerProcessor<C>,
resultCollector: ResultCollector<C>, resultCollector: ResultCollector<C>,
useOrder: Boolean, useOrder: Boolean,
towerData: TowerData towerData: TowerData
): Collection<C>? { ): Collection<C>? {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
val candidatesGroups = if (useOrder) { val candidatesGroups = if (useOrder) {
processor.process(towerData) processor.process(towerData)
} } else {
else {
listOf(processor.process(towerData).flatMap { it }) listOf(processor.process(towerData).flatMap { it })
} }
@@ -301,7 +296,7 @@ class TowerResolver {
abstract fun pushCandidates(candidates: Collection<C>) abstract fun pushCandidates(candidates: Collection<C>)
} }
class AllCandidatesCollector<C : Candidate>: ResultCollector<C>() { class AllCandidatesCollector<C : Candidate> : ResultCollector<C>() {
private val allCandidates = ArrayList<C>() private val allCandidates = ArrayList<C>()
override fun getSuccessfulCandidates(): Collection<C>? = null override fun getSuccessfulCandidates(): Collection<C>? = null
@@ -352,7 +347,8 @@ class TowerResolver {
return moreSuitableGroup.filter { it.resultingApplicability == groupApplicability } return moreSuitableGroup.filter { it.resultingApplicability == groupApplicability }
} }
private val Collection<C>.groupApplicability get() = private val Collection<C>.groupApplicability
minBy { it.resultingApplicability }?.resultingApplicability ?: ResolutionCandidateApplicability.HIDDEN get() =
minBy { it.resultingApplicability }?.resultingApplicability ?: ResolutionCandidateApplicability.HIDDEN
} }
} }
@@ -21,9 +21,10 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
private val INAPPLICABLE_STATUSES = setOf( private val INAPPLICABLE_STATUSES = setOf(
ResolutionCandidateApplicability.INAPPLICABLE, ResolutionCandidateApplicability.INAPPLICABLE,
ResolutionCandidateApplicability.INAPPLICABLE_ARGUMENTS_MAPPING_ERROR, ResolutionCandidateApplicability.INAPPLICABLE_ARGUMENTS_MAPPING_ERROR,
ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER) ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
)
val ResolutionCandidateApplicability.isSuccess: Boolean val ResolutionCandidateApplicability.isSuccess: Boolean
get() = this <= ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY get() = this <= ResolutionCandidateApplicability.RESOLVED_LOW_PRIORITY
@@ -38,9 +39,9 @@ val ResolutionCandidateApplicability.isInapplicable: Boolean
get() = this in INAPPLICABLE_STATUSES get() = this in INAPPLICABLE_STATUSES
internal class CandidateWithBoundDispatchReceiverImpl( internal class CandidateWithBoundDispatchReceiverImpl(
override val dispatchReceiver: ReceiverValueWithSmartCastInfo?, override val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
override val descriptor: CallableDescriptor, override val descriptor: CallableDescriptor,
override val diagnostics: List<ResolutionDiagnostic> override val diagnostics: List<ResolutionDiagnostic>
) : CandidateWithBoundDispatchReceiver ) : CandidateWithBoundDispatchReceiver
fun <C : Candidate> C.forceResolution(): C { fun <C : Candidate> C.forceResolution(): C {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
import java.util.* import java.util.*
open class FakeCallableDescriptorForObject( open class FakeCallableDescriptorForObject(
val classDescriptor: ClassDescriptor val classDescriptor: ClassDescriptor
) : DeclarationDescriptorWithVisibility by classDescriptor.getClassObjectReferenceTarget(), VariableDescriptor { ) : DeclarationDescriptorWithVisibility by classDescriptor.getClassObjectReferenceTarget(), VariableDescriptor {
init { init {
@@ -20,16 +20,15 @@ import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.impl.DescriptorDerivedFromTypeAlias import org.jetbrains.kotlin.descriptors.impl.DescriptorDerivedFromTypeAlias
class FakeCallableDescriptorForTypeAliasObject(override val typeAliasDescriptor: TypeAliasDescriptor) : class FakeCallableDescriptorForTypeAliasObject(override val typeAliasDescriptor: TypeAliasDescriptor) :
FakeCallableDescriptorForObject(typeAliasDescriptor.classDescriptor!!), FakeCallableDescriptorForObject(typeAliasDescriptor.classDescriptor!!),
DescriptorDerivedFromTypeAlias DescriptorDerivedFromTypeAlias {
{
override fun getReferencedDescriptor() = override fun getReferencedDescriptor() =
typeAliasDescriptor typeAliasDescriptor
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean =
other is FakeCallableDescriptorForTypeAliasObject && other is FakeCallableDescriptorForTypeAliasObject &&
typeAliasDescriptor == other.typeAliasDescriptor typeAliasDescriptor == other.typeAliasDescriptor
override fun hashCode(): Int = override fun hashCode(): Int =
typeAliasDescriptor.hashCode() typeAliasDescriptor.hashCode()
} }
@@ -28,16 +28,16 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjection
fun createValueParametersForInvokeInFunctionType( fun createValueParametersForInvokeInFunctionType(
functionDescriptor: FunctionDescriptor, parameterTypes: List<TypeProjection> functionDescriptor: FunctionDescriptor, parameterTypes: List<TypeProjection>
): List<ValueParameterDescriptor> { ): List<ValueParameterDescriptor> {
return parameterTypes.mapIndexed { i, typeProjection -> return parameterTypes.mapIndexed { i, typeProjection ->
ValueParameterDescriptorImpl( ValueParameterDescriptorImpl(
functionDescriptor, null, i, Annotations.EMPTY, functionDescriptor, null, i, Annotations.EMPTY,
Name.identifier("p${i + 1}"), typeProjection.type, Name.identifier("p${i + 1}"), typeProjection.type,
/* declaresDefaultValue = */ false, /* declaresDefaultValue = */ false,
/* isCrossinline = */ false, /* isCrossinline = */ false,
/* isNoinline = */ false, /* isNoinline = */ false,
null, SourceElement.NO_SOURCE null, SourceElement.NO_SOURCE
) )
} }
} }
@@ -46,10 +46,10 @@ fun CallableDescriptor.isLowPriorityFromStdlibJre7Or8(): Boolean {
if (!packageFqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return false if (!packageFqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return false
val isFromStdlibJre7Or8 = val isFromStdlibJre7Or8 =
packageFqName == kotlin && name == use || packageFqName == kotlin && name == use ||
packageFqName == kotlinText && name == get || packageFqName == kotlinText && name == get ||
packageFqName == kotlinCollections && (name == getOrDefault || name == remove) || packageFqName == kotlinCollections && (name == getOrDefault || name == remove) ||
packageFqName == kotlinStreams packageFqName == kotlinStreams
if (!isFromStdlibJre7Or8) return false if (!isFromStdlibJre7Or8) return false
@@ -26,31 +26,36 @@ import org.jetbrains.kotlin.util.collectionUtils.getFromAllScopes
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
class LexicalChainedScope @JvmOverloads constructor( class LexicalChainedScope @JvmOverloads constructor(
parent: LexicalScope, parent: LexicalScope,
override val ownerDescriptor: DeclarationDescriptor, override val ownerDescriptor: DeclarationDescriptor,
override val isOwnerDescriptorAccessibleByLabel: Boolean, override val isOwnerDescriptorAccessibleByLabel: Boolean,
override val implicitReceiver: ReceiverParameterDescriptor?, override val implicitReceiver: ReceiverParameterDescriptor?,
override val kind: LexicalScopeKind, override val kind: LexicalScopeKind,
private val memberScopes: List<MemberScope>, private val memberScopes: List<MemberScope>,
@Deprecated("This value is temporary hack for resolve -- don't use it!") @Deprecated("This value is temporary hack for resolve -- don't use it!")
val isStaticScope: Boolean = false val isStaticScope: Boolean = false
): LexicalScope { ) : LexicalScope {
override val parent = parent.takeSnapshot() override val parent = parent.takeSnapshot()
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) =
= getFromAllScopes(memberScopes) { it.getContributedDescriptors() } getFromAllScopes(memberScopes) { it.getContributedDescriptors() }
override fun getContributedClassifier(name: Name, location: LookupLocation) = getFirstClassifierDiscriminateHeaders(memberScopes) { it.getContributedClassifier(name, location) } override fun getContributedClassifier(name: Name, location: LookupLocation) =
getFirstClassifierDiscriminateHeaders(memberScopes) { it.getContributedClassifier(name, location) }
override fun getContributedVariables(name: Name, location: LookupLocation) = getFromAllScopes(memberScopes) { it.getContributedVariables(name, location) } override fun getContributedVariables(name: Name, location: LookupLocation) =
getFromAllScopes(memberScopes) { it.getContributedVariables(name, location) }
override fun getContributedFunctions(name: Name, location: LookupLocation) = getFromAllScopes(memberScopes) { it.getContributedFunctions(name, location) } override fun getContributedFunctions(name: Name, location: LookupLocation) =
getFromAllScopes(memberScopes) { it.getContributedFunctions(name, location) }
override fun toString(): String = kind.toString() override fun toString(): String = kind.toString()
override fun printStructure(p: Printer) { override fun printStructure(p: Printer) {
p.println(this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name, p.println(
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {") this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name,
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {"
)
p.pushIndent() p.pushIndent()
for (scope in memberScopes) { for (scope in memberScopes) {
@@ -20,14 +20,14 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
class LexicalScopeImpl @JvmOverloads constructor( class LexicalScopeImpl @JvmOverloads constructor(
parent: HierarchicalScope, parent: HierarchicalScope,
override val ownerDescriptor: DeclarationDescriptor, override val ownerDescriptor: DeclarationDescriptor,
override val isOwnerDescriptorAccessibleByLabel: Boolean, override val isOwnerDescriptorAccessibleByLabel: Boolean,
override val implicitReceiver: ReceiverParameterDescriptor?, override val implicitReceiver: ReceiverParameterDescriptor?,
override val kind: LexicalScopeKind, override val kind: LexicalScopeKind,
redeclarationChecker: LocalRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING, redeclarationChecker: LocalRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING,
initialize: LexicalScopeImpl.InitializeHandler.() -> Unit = {} initialize: LexicalScopeImpl.InitializeHandler.() -> Unit = {}
): LexicalScope, LexicalScopeStorage(parent, redeclarationChecker) { ) : LexicalScope, LexicalScopeStorage(parent, redeclarationChecker) {
init { init {
InitializeHandler().initialize() InitializeHandler().initialize()
@@ -36,8 +36,10 @@ class LexicalScopeImpl @JvmOverloads constructor(
override fun toString(): String = kind.toString() override fun toString(): String = kind.toString()
override fun printStructure(p: Printer) { override fun printStructure(p: Printer) {
p.println(this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name, p.println(
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {") this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name,
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {"
)
p.pushIndent() p.pushIndent()
p.print("parent = ") p.print("parent = ")
@@ -49,14 +51,14 @@ class LexicalScopeImpl @JvmOverloads constructor(
inner class InitializeHandler() { inner class InitializeHandler() {
fun addVariableDescriptor(variableDescriptor: VariableDescriptor): Unit fun addVariableDescriptor(variableDescriptor: VariableDescriptor): Unit =
= this@LexicalScopeImpl.addVariableOrClassDescriptor(variableDescriptor) this@LexicalScopeImpl.addVariableOrClassDescriptor(variableDescriptor)
fun addFunctionDescriptor(functionDescriptor: FunctionDescriptor): Unit fun addFunctionDescriptor(functionDescriptor: FunctionDescriptor): Unit =
= this@LexicalScopeImpl.addFunctionDescriptorInternal(functionDescriptor) this@LexicalScopeImpl.addFunctionDescriptorInternal(functionDescriptor)
fun addClassifierDescriptor(classifierDescriptor: ClassifierDescriptor): Unit fun addClassifierDescriptor(classifierDescriptor: ClassifierDescriptor): Unit =
= this@LexicalScopeImpl.addVariableOrClassDescriptor(classifierDescriptor) this@LexicalScopeImpl.addVariableOrClassDescriptor(classifierDescriptor)
} }
} }
@@ -35,9 +35,9 @@ interface LocalRedeclarationChecker {
} }
abstract class LexicalScopeStorage( abstract class LexicalScopeStorage(
parent: HierarchicalScope, parent: HierarchicalScope,
val redeclarationChecker: LocalRedeclarationChecker val redeclarationChecker: LocalRedeclarationChecker
): LexicalScope { ) : LexicalScope {
override val parent = parent.takeSnapshot() override val parent = parent.takeSnapshot()
protected val addedDescriptors: MutableList<DeclarationDescriptor> = SmartList() protected val addedDescriptors: MutableList<DeclarationDescriptor> = SmartList()
@@ -45,13 +45,15 @@ abstract class LexicalScopeStorage(
private var functionsByName: MutableMap<Name, IntList>? = null private var functionsByName: MutableMap<Name, IntList>? = null
private var variablesAndClassifiersByName: MutableMap<Name, IntList>? = null private var variablesAndClassifiersByName: MutableMap<Name, IntList>? = null
override fun getContributedClassifier(name: Name, location: LookupLocation) = variableOrClassDescriptorByName(name) as? ClassifierDescriptor override fun getContributedClassifier(name: Name, location: LookupLocation) =
override fun getContributedVariables(name: Name, location: LookupLocation) = listOfNotNull(variableOrClassDescriptorByName(name) as? VariableDescriptor) variableOrClassDescriptorByName(name) as? ClassifierDescriptor
override fun getContributedVariables(name: Name, location: LookupLocation) =
listOfNotNull(variableOrClassDescriptorByName(name) as? VariableDescriptor)
override fun getContributedFunctions(name: Name, location: LookupLocation) = functionsByName(name) override fun getContributedFunctions(name: Name, location: LookupLocation) = functionsByName(name)
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = addedDescriptors
= addedDescriptors
protected fun addVariableOrClassDescriptor(descriptor: DeclarationDescriptor) { protected fun addVariableOrClassDescriptor(descriptor: DeclarationDescriptor) {
val name = descriptor.name val name = descriptor.name
@@ -115,7 +117,7 @@ abstract class LexicalScopeStorage(
private operator fun IntList?.plus(value: Int) = IntList(value, this) private operator fun IntList?.plus(value: Int) = IntList(value, this)
private fun <TDescriptor: DeclarationDescriptor> IntList.toDescriptors(): List<TDescriptor> { private fun <TDescriptor : DeclarationDescriptor> IntList.toDescriptors(): List<TDescriptor> {
val result = ArrayList<TDescriptor>(1) val result = ArrayList<TDescriptor>(1)
var rest: IntList? = this var rest: IntList? = this
do { do {
@@ -126,5 +128,5 @@ abstract class LexicalScopeStorage(
} }
override fun definitelyDoesNotContainName(name: Name) = override fun definitelyDoesNotContainName(name: Name) =
functionsByName?.get(name) == null && variablesAndClassifiersByName?.get(name) == null functionsByName?.get(name) == null && variablesAndClassifiersByName?.get(name) == null
} }
@@ -22,11 +22,11 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
class LexicalWritableScope( class LexicalWritableScope(
parent: LexicalScope, parent: LexicalScope,
override val ownerDescriptor: DeclarationDescriptor, override val ownerDescriptor: DeclarationDescriptor,
override val isOwnerDescriptorAccessibleByLabel: Boolean, override val isOwnerDescriptorAccessibleByLabel: Boolean,
redeclarationChecker: LocalRedeclarationChecker, redeclarationChecker: LocalRedeclarationChecker,
override val kind: LexicalScopeKind override val kind: LexicalScopeKind
) : LexicalScopeStorage(parent, redeclarationChecker) { ) : LexicalScopeStorage(parent, redeclarationChecker) {
override val implicitReceiver: ReceiverParameterDescriptor? override val implicitReceiver: ReceiverParameterDescriptor?
@@ -68,11 +68,14 @@ class LexicalWritableScope(
} }
private inner class Snapshot(val descriptorLimit: Int) : LexicalScope by this { private inner class Snapshot(val descriptorLimit: Int) : LexicalScope by this {
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) =
= addedDescriptors.subList(0, descriptorLimit) addedDescriptors.subList(0, descriptorLimit)
override fun getContributedClassifier(name: Name, location: LookupLocation) = variableOrClassDescriptorByName(name, descriptorLimit) as? ClassifierDescriptor override fun getContributedClassifier(name: Name, location: LookupLocation) =
override fun getContributedVariables(name: Name, location: LookupLocation) = listOfNotNull(variableOrClassDescriptorByName(name, descriptorLimit) as? VariableDescriptor) variableOrClassDescriptorByName(name, descriptorLimit) as? ClassifierDescriptor
override fun getContributedVariables(name: Name, location: LookupLocation) =
listOfNotNull(variableOrClassDescriptorByName(name, descriptorLimit) as? VariableDescriptor)
override fun getContributedFunctions(name: Name, location: LookupLocation) = functionsByName(name, descriptorLimit) override fun getContributedFunctions(name: Name, location: LookupLocation) = functionsByName(name, descriptorLimit)
@@ -88,8 +91,10 @@ class LexicalWritableScope(
override fun toString(): String = kind.toString() override fun toString(): String = kind.toString()
override fun printStructure(p: Printer) { override fun printStructure(p: Printer) {
p.println(this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name, p.println(
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {") this::class.java.simpleName, ": ", kind, "; for descriptor: ", ownerDescriptor.name,
" with implicitReceiver: ", implicitReceiver?.value ?: "NONE", " {"
)
p.pushIndent() p.pushIndent()
p.print("parent = ") p.print("parent = ")
@@ -40,8 +40,8 @@ interface LexicalScope : HierarchicalScope {
val kind: LexicalScopeKind val kind: LexicalScopeKind
class Base( class Base(
parent: HierarchicalScope, parent: HierarchicalScope,
override val ownerDescriptor: DeclarationDescriptor override val ownerDescriptor: DeclarationDescriptor
) : BaseHierarchicalScope(parent), LexicalScope { ) : BaseHierarchicalScope(parent), LexicalScope {
override val parent: HierarchicalScope override val parent: HierarchicalScope
get() = super.parent!! get() = super.parent!!
@@ -112,12 +112,15 @@ interface ImportingScope : HierarchicalScope {
fun getContributedPackage(name: Name): PackageViewDescriptor? fun getContributedPackage(name: Name): PackageViewDescriptor?
fun getContributedDescriptors( fun getContributedDescriptors(
kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL, kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL,
nameFilter: (Name) -> Boolean = MemberScope.ALL_NAME_FILTER, nameFilter: (Name) -> Boolean = MemberScope.ALL_NAME_FILTER,
changeNamesForAliased: Boolean changeNamesForAliased: Boolean
): Collection<DeclarationDescriptor> ): Collection<DeclarationDescriptor>
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> { override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
return getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased = false) return getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased = false)
} }
@@ -135,7 +138,10 @@ interface ImportingScope : HierarchicalScope {
} }
abstract class BaseHierarchicalScope(override val parent: HierarchicalScope?) : HierarchicalScope { abstract class BaseHierarchicalScope(override val parent: HierarchicalScope?) : HierarchicalScope {
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = emptyList() override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> = emptyList()
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
@@ -150,10 +156,16 @@ abstract class BaseImportingScope(parent: ImportingScope?) : BaseHierarchicalSco
override fun getContributedPackage(name: Name): PackageViewDescriptor? = null override fun getContributedPackage(name: Name): PackageViewDescriptor? = null
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> { override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
return getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased = false) return getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased = false)
} }
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, changeNamesForAliased: Boolean): Collection<DeclarationDescriptor> override fun getContributedDescriptors(
= emptyList() kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
): Collection<DeclarationDescriptor> = emptyList()
} }
@@ -27,9 +27,9 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
class SubpackagesImportingScope( class SubpackagesImportingScope(
override val parent: ImportingScope?, override val parent: ImportingScope?,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
fqName: FqName fqName: FqName
) : SubpackagesScope(moduleDescriptor, fqName), ImportingScope by ImportingScope.Empty { ) : SubpackagesScope(moduleDescriptor, fqName), ImportingScope by ImportingScope.Empty {
override fun getContributedPackage(name: Name): PackageViewDescriptor? = getPackage(name) override fun getContributedPackage(name: Name): PackageViewDescriptor? = getPackage(name)
@@ -42,11 +42,18 @@ class SubpackagesImportingScope(
//TODO: kept old behavior, but it seems very strange (super call seems more applicable) //TODO: kept old behavior, but it seems very strange (super call seems more applicable)
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = override fun getContributedDescriptors(
emptyList() kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> =
emptyList()
//TODO: kept old behavior, but it seems very strange (super call seems more applicable) //TODO: kept old behavior, but it seems very strange (super call seems more applicable)
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, changeNamesForAliased: Boolean): Collection<DeclarationDescriptor> override fun getContributedDescriptors(
= emptyList() kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
): Collection<DeclarationDescriptor> = emptyList()
override fun computeImportedNames() = emptySet<Name>() override fun computeImportedNames() = emptySet<Name>()
} }
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTyp
interface DetailedReceiver interface DetailedReceiver
class ReceiverValueWithSmartCastInfo( class ReceiverValueWithSmartCastInfo(
val receiverValue: ReceiverValue, val receiverValue: ReceiverValue,
val possibleTypes: Set<KotlinType>, // doesn't include receiver.type val possibleTypes: Set<KotlinType>, // doesn't include receiver.type
val isStable: Boolean val isStable: Boolean
): DetailedReceiver { ) : DetailedReceiver {
override fun toString() = receiverValue.toString() override fun toString() = receiverValue.toString()
} }
@@ -42,17 +42,16 @@ fun LexicalScope.getImplicitReceiversHierarchy(): List<ReceiverParameterDescript
fun LexicalScope.getDeclarationsByLabel(labelName: Name): Collection<DeclarationDescriptor> = collectAllFromMeAndParent { fun LexicalScope.getDeclarationsByLabel(labelName: Name): Collection<DeclarationDescriptor> = collectAllFromMeAndParent {
if (it is LexicalScope && it.isOwnerDescriptorAccessibleByLabel && it.ownerDescriptor.name == labelName) { if (it is LexicalScope && it.isOwnerDescriptorAccessibleByLabel && it.ownerDescriptor.name == labelName) {
listOf(it.ownerDescriptor) listOf(it.ownerDescriptor)
} } else {
else {
listOf() listOf()
} }
} }
// Result is guaranteed to be filtered by kind and name. // Result is guaranteed to be filtered by kind and name.
fun HierarchicalScope.collectDescriptorsFiltered( fun HierarchicalScope.collectDescriptorsFiltered(
kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL, kindFilter: DescriptorKindFilter = DescriptorKindFilter.ALL,
nameFilter: (Name) -> Boolean = { true }, nameFilter: (Name) -> Boolean = { true },
changeNamesForAliased: Boolean = false changeNamesForAliased: Boolean = false
): Collection<DeclarationDescriptor> { ): Collection<DeclarationDescriptor> {
if (kindFilter.kindMask == 0) return listOf() if (kindFilter.kindMask == 0) return listOf()
return collectAllFromMeAndParent { return collectAllFromMeAndParent {
@@ -63,38 +62,49 @@ fun HierarchicalScope.collectDescriptorsFiltered(
}.filter { kindFilter.accepts(it) && nameFilter(it.name) } }.filter { kindFilter.accepts(it) && nameFilter(it.name) }
} }
@Deprecated("Use getContributedProperties instead") fun LexicalScope.findLocalVariable(name: Name): VariableDescriptor? { @Deprecated("Use getContributedProperties instead")
fun LexicalScope.findLocalVariable(name: Name): VariableDescriptor? {
return findFirstFromMeAndParent { return findFirstFromMeAndParent {
when { when {
it is LexicalScopeWrapper -> it.delegate.findLocalVariable(name) it is LexicalScopeWrapper -> it.delegate.findLocalVariable(name)
it !is ImportingScope && it !is LexicalChainedScope -> it.getContributedVariables(name, NoLookupLocation.WHEN_GET_LOCAL_VARIABLE).singleOrNull() /* todo check this*/ it !is ImportingScope && it !is LexicalChainedScope -> it.getContributedVariables(
name,
NoLookupLocation.WHEN_GET_LOCAL_VARIABLE
).singleOrNull() /* todo check this*/
else -> null else -> null
} }
} }
} }
fun HierarchicalScope.findClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? fun HierarchicalScope.findClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? =
= findFirstFromMeAndParent { it.getContributedClassifier(name, location) } findFirstFromMeAndParent { it.getContributedClassifier(name, location) }
fun HierarchicalScope.findPackage(name: Name): PackageViewDescriptor? fun HierarchicalScope.findPackage(name: Name): PackageViewDescriptor? = findFirstFromImportingScopes { it.getContributedPackage(name) }
= findFirstFromImportingScopes { it.getContributedPackage(name) }
fun HierarchicalScope.collectVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> fun HierarchicalScope.collectVariables(name: Name, location: LookupLocation): Collection<VariableDescriptor> =
= collectAllFromMeAndParent { it.getContributedVariables(name, location) } collectAllFromMeAndParent { it.getContributedVariables(name, location) }
fun HierarchicalScope.collectFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> fun HierarchicalScope.collectFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> =
= collectAllFromMeAndParent { it.getContributedFunctions(name, location) } collectAllFromMeAndParent { it.getContributedFunctions(name, location) }
fun HierarchicalScope.findVariable(name: Name, location: LookupLocation, predicate: (VariableDescriptor) -> Boolean = { true }): VariableDescriptor? { fun HierarchicalScope.findVariable(
name: Name,
location: LookupLocation,
predicate: (VariableDescriptor) -> Boolean = { true }
): VariableDescriptor? {
processForMeAndParent { processForMeAndParent {
it.getContributedVariables(name, location).firstOrNull(predicate)?.let { return it } it.getContributedVariables(name, location).firstOrNull(predicate)?.let { return it }
} }
return null return null
} }
fun HierarchicalScope.findFunction(name: Name, location: LookupLocation, predicate: (FunctionDescriptor) -> Boolean = { true }): FunctionDescriptor? { fun HierarchicalScope.findFunction(
name: Name,
location: LookupLocation,
predicate: (FunctionDescriptor) -> Boolean = { true }
): FunctionDescriptor? {
processForMeAndParent { processForMeAndParent {
it.getContributedFunctions(name, location).firstOrNull(predicate)?.let { return it } it.getContributedFunctions(name, location).firstOrNull(predicate)?.let { return it }
} }
@@ -103,13 +113,18 @@ fun HierarchicalScope.findFunction(name: Name, location: LookupLocation, predica
fun HierarchicalScope.takeSnapshot(): HierarchicalScope = if (this is LexicalWritableScope) takeSnapshot() else this fun HierarchicalScope.takeSnapshot(): HierarchicalScope = if (this is LexicalWritableScope) takeSnapshot() else this
@JvmOverloads fun MemberScope.memberScopeAsImportingScope(parentScope: ImportingScope? = null): ImportingScope = MemberScopeToImportingScopeAdapter(parentScope, this) @JvmOverloads
fun MemberScope.memberScopeAsImportingScope(parentScope: ImportingScope? = null): ImportingScope =
MemberScopeToImportingScopeAdapter(parentScope, this)
private class MemberScopeToImportingScopeAdapter(override val parent: ImportingScope?, val memberScope: MemberScope) : ImportingScope { private class MemberScopeToImportingScopeAdapter(override val parent: ImportingScope?, val memberScope: MemberScope) : ImportingScope {
override fun getContributedPackage(name: Name): PackageViewDescriptor? = null override fun getContributedPackage(name: Name): PackageViewDescriptor? = null
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, changeNamesForAliased: Boolean) override fun getContributedDescriptors(
= memberScope.getContributedDescriptors(kindFilter, nameFilter) kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
) = memberScope.getContributedDescriptors(kindFilter, nameFilter)
override fun getContributedClassifier(name: Name, location: LookupLocation) = memberScope.getContributedClassifier(name, location) override fun getContributedClassifier(name: Name, location: LookupLocation) = memberScope.getContributedClassifier(name, location)
@@ -144,8 +159,8 @@ inline fun HierarchicalScope.processForMeAndParent(process: (HierarchicalScope)
} }
} }
private inline fun <T: Any> HierarchicalScope.collectFromMeAndParent( private inline fun <T : Any> HierarchicalScope.collectFromMeAndParent(
collect: (HierarchicalScope) -> T? collect: (HierarchicalScope) -> T?
): List<T> { ): List<T> {
var result: MutableList<T>? = null var result: MutableList<T>? = null
processForMeAndParent { processForMeAndParent {
@@ -160,26 +175,26 @@ private inline fun <T: Any> HierarchicalScope.collectFromMeAndParent(
return result ?: emptyList() return result ?: emptyList()
} }
inline fun <T: Any> HierarchicalScope.collectAllFromMeAndParent( inline fun <T : Any> HierarchicalScope.collectAllFromMeAndParent(
collect: (HierarchicalScope) -> Collection<T> collect: (HierarchicalScope) -> Collection<T>
): Collection<T> { ): Collection<T> {
var result: Collection<T>? = null var result: Collection<T>? = null
processForMeAndParent { result = result.concat(collect(it)) } processForMeAndParent { result = result.concat(collect(it)) }
return result ?: emptySet() return result ?: emptySet()
} }
inline fun <T: Any> HierarchicalScope.findFirstFromMeAndParent(fetch: (HierarchicalScope) -> T?): T? { inline fun <T : Any> HierarchicalScope.findFirstFromMeAndParent(fetch: (HierarchicalScope) -> T?): T? {
processForMeAndParent { fetch(it)?.let { return it } } processForMeAndParent { fetch(it)?.let { return it } }
return null return null
} }
inline fun <T: Any> HierarchicalScope.collectAllFromImportingScopes( inline fun <T : Any> HierarchicalScope.collectAllFromImportingScopes(
collect: (ImportingScope) -> Collection<T> collect: (ImportingScope) -> Collection<T>
): Collection<T> { ): Collection<T> {
return collectAllFromMeAndParent { if (it is ImportingScope) collect(it) else emptyList() } return collectAllFromMeAndParent { if (it is ImportingScope) collect(it) else emptyList() }
} }
inline fun <T: Any> HierarchicalScope.findFirstFromImportingScopes(fetch: (ImportingScope) -> T?): T? { inline fun <T : Any> HierarchicalScope.findFirstFromImportingScopes(fetch: (ImportingScope) -> T?): T? {
return findFirstFromMeAndParent { if (it is ImportingScope) fetch(it) else null } return findFirstFromMeAndParent { if (it is ImportingScope) fetch(it) else null }
} }
@@ -190,11 +205,10 @@ fun LexicalScope.addImportingScopes(importScopes: List<ImportingScope>): Lexical
return replaceImportingScopes(newFirstImporting) return replaceImportingScopes(newFirstImporting)
} }
fun LexicalScope.addImportingScope(importScope: ImportingScope): LexicalScope fun LexicalScope.addImportingScope(importScope: ImportingScope): LexicalScope = addImportingScopes(listOf(importScope))
= addImportingScopes(listOf(importScope))
fun ImportingScope.withParent(newParent: ImportingScope?): ImportingScope { fun ImportingScope.withParent(newParent: ImportingScope?): ImportingScope {
return object: ImportingScope by this { return object : ImportingScope by this {
override val parent: ImportingScope? override val parent: ImportingScope?
get() = newParent get() = newParent
} }
@@ -210,13 +224,13 @@ fun LexicalScope.replaceImportingScopes(importingScopeChain: ImportingScope?): L
fun LexicalScope.createScopeForDestructuring(newReceiver: ReceiverParameterDescriptor?): LexicalScope { fun LexicalScope.createScopeForDestructuring(newReceiver: ReceiverParameterDescriptor?): LexicalScope {
return LexicalScopeImpl( return LexicalScopeImpl(
parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel, parent, ownerDescriptor, isOwnerDescriptorAccessibleByLabel,
newReceiver, newReceiver,
LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING
) )
} }
private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingScopeChain: ImportingScope): LexicalScope by delegate { private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingScopeChain: ImportingScope) : LexicalScope by delegate {
init { init {
assert(delegate !is LexicalScopeWrapper) { assert(delegate !is LexicalScopeWrapper) {
"Do not wrap again to avoid performance issues" "Do not wrap again to avoid performance issues"
@@ -229,8 +243,7 @@ private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingSc
val parent = delegate.parent val parent = delegate.parent
if (parent is LexicalScope) { if (parent is LexicalScope) {
parent.replaceImportingScopes(newImportingScopeChain) parent.replaceImportingScopes(newImportingScopeChain)
} } else {
else {
newImportingScopeChain newImportingScopeChain
} }
} }
@@ -240,10 +253,10 @@ private class LexicalScopeWrapper(val delegate: LexicalScope, val newImportingSc
fun chainImportingScopes(scopes: List<ImportingScope>, tail: ImportingScope? = null): ImportingScope? { fun chainImportingScopes(scopes: List<ImportingScope>, tail: ImportingScope? = null): ImportingScope? {
return scopes.asReversed() return scopes.asReversed()
.fold(tail) { current, scope -> .fold(tail) { current, scope ->
assert(scope.parent == null) assert(scope.parent == null)
scope.withParent(current) scope.withParent(current)
} }
} }
class ErrorLexicalScope : LexicalScope { class ErrorLexicalScope : LexicalScope {
@@ -260,7 +273,10 @@ class ErrorLexicalScope : LexicalScope {
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet() override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet()
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = emptySet() override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> = emptySet()
} }
override fun printStructure(p: Printer) { override fun printStructure(p: Printer) {
@@ -278,5 +294,8 @@ class ErrorLexicalScope : LexicalScope {
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet() override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<FunctionDescriptor> = emptySet()
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> = emptySet() override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> = emptySet()
} }
@@ -30,12 +30,12 @@ val SINCE_KOTLIN_FQ_NAME = FqName("kotlin.SinceKotlin")
* callback is called with the version specified in the [SinceKotlin] annotation if the descriptor is inaccessible. * callback is called with the version specified in the [SinceKotlin] annotation if the descriptor is inaccessible.
*/ */
fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility( fun DeclarationDescriptor.checkSinceKotlinVersionAccessibility(
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
actionIfInaccessible: ((ApiVersion) -> Unit)? = null actionIfInaccessible: ((ApiVersion) -> Unit)? = null
): Boolean { ): Boolean {
val version = val version =
if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this) if (this is CallableMemberDescriptor && !kind.isReal) getSinceKotlinVersionByOverridden(this)
else getOwnSinceKotlinVersion() else getOwnSinceKotlinVersion()
// Allow access in the following cases: // Allow access in the following cases:
// 1) There's no @SinceKotlin annotation for this descriptor // 1) There's no @SinceKotlin annotation for this descriptor
@@ -59,16 +59,15 @@ private fun getSinceKotlinVersionByOverridden(descriptor: CallableMemberDescript
private fun DeclarationDescriptor.getOwnSinceKotlinVersion(): ApiVersion? { private fun DeclarationDescriptor.getOwnSinceKotlinVersion(): ApiVersion? {
// TODO: use-site targeted annotations // TODO: use-site targeted annotations
fun DeclarationDescriptor.loadAnnotationValue(): ApiVersion? = fun DeclarationDescriptor.loadAnnotationValue(): ApiVersion? =
(annotations.findAnnotation(SINCE_KOTLIN_FQ_NAME)?.allValueArguments?.values?.singleOrNull()?.value as? String) (annotations.findAnnotation(SINCE_KOTLIN_FQ_NAME)?.allValueArguments?.values?.singleOrNull()?.value as? String)
?.let(ApiVersion.Companion::parse) ?.let(ApiVersion.Companion::parse)
val ownVersion = loadAnnotationValue() val ownVersion = loadAnnotationValue()
val ctorClass = (this as? ConstructorDescriptor)?.containingDeclaration?.loadAnnotationValue() val ctorClass = (this as? ConstructorDescriptor)?.containingDeclaration?.loadAnnotationValue()
val property = (this as? PropertyAccessorDescriptor)?.correspondingProperty?.loadAnnotationValue() val property = (this as? PropertyAccessorDescriptor)?.correspondingProperty?.loadAnnotationValue()
val typeAliasDescriptor = (this as? TypeAliasDescriptor) ?: val typeAliasDescriptor = (this as? TypeAliasDescriptor) ?: (this as? TypeAliasConstructorDescriptor)?.typeAliasDescriptor
(this as? TypeAliasConstructorDescriptor)?.typeAliasDescriptor ?: ?: (this as? FakeCallableDescriptorForTypeAliasObject)?.typeAliasDescriptor
(this as? FakeCallableDescriptorForTypeAliasObject)?.typeAliasDescriptor
val typeAlias = typeAliasDescriptor?.loadAnnotationValue() val typeAlias = typeAliasDescriptor?.loadAnnotationValue()
@@ -35,6 +35,7 @@ open class TypeApproximatorConfiguration {
TO_FIRST, TO_FIRST,
TO_COMMON_SUPERTYPE TO_COMMON_SUPERTYPE
} }
open val flexible get() = false // simple flexible types (FlexibleTypeImpl) open val flexible get() = false // simple flexible types (FlexibleTypeImpl)
open val dynamic get() = false // DynamicType open val dynamic get() = false // DynamicType
open val rawType get() = false // RawTypeImpl open val rawType get() = false // RawTypeImpl
@@ -65,7 +66,8 @@ open class TypeApproximatorConfiguration {
override val definitelyNotNullType get() = false override val definitelyNotNullType get() = false
} }
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() { abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus) :
TypeApproximatorConfiguration.AllFlexibleSameValue() {
override val allFlexible get() = true override val allFlexible get() = true
override val errorType get() = true override val errorType get() = true
@@ -94,39 +96,42 @@ class TypeApproximator {
// null means that this input type is the result, i.e. input type not contains not-allowed kind of types // null means that this input type is the result, i.e. input type not contains not-allowed kind of types
// type <: resultType // type <: resultType
fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? = fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? =
approximateToSuperType(type, conf, - type.typeDepth()) approximateToSuperType(type, conf, -type.typeDepth())
// resultType <: type // resultType <: type
fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? = fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration): UnwrappedType? =
approximateToSubType(type, conf, - type.typeDepth()) approximateToSubType(type, conf, -type.typeDepth())
private fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? { private fun approximateToSuperType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? {
if (type is TypeUtils.SpecialType) return null if (type is TypeUtils.SpecialType) return null
return approximateTo(NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::upperBound, return approximateTo(
referenceApproximateToSuperType, depth) NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::upperBound,
referenceApproximateToSuperType, depth
)
} }
private fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? { private fun approximateToSubType(type: UnwrappedType, conf: TypeApproximatorConfiguration, depth: Int): UnwrappedType? {
if (type is TypeUtils.SpecialType) return null if (type is TypeUtils.SpecialType) return null
return approximateTo(NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::lowerBound, return approximateTo(
referenceApproximateToSubType, depth) NewKotlinTypeChecker.transformToNewType(type), conf, FlexibleType::lowerBound,
referenceApproximateToSubType, depth
)
} }
// comments for case bound = upperBound, approximateTo = toSuperType // comments for case bound = upperBound, approximateTo = toSuperType
private fun approximateTo( private fun approximateTo(
type: UnwrappedType, type: UnwrappedType,
conf: TypeApproximatorConfiguration, conf: TypeApproximatorConfiguration,
bound: FlexibleType.() -> SimpleType, bound: FlexibleType.() -> SimpleType,
approximateTo: (SimpleType, TypeApproximatorConfiguration, depth: Int) -> UnwrappedType?, approximateTo: (SimpleType, TypeApproximatorConfiguration, depth: Int) -> UnwrappedType?,
depth: Int depth: Int
): UnwrappedType? { ): UnwrappedType? {
when (type) { when (type) {
is SimpleType -> return approximateTo(type, conf, depth) is SimpleType -> return approximateTo(type, conf, depth)
is FlexibleType -> { is FlexibleType -> {
if (type is DynamicType) { if (type is DynamicType) {
return if (conf.dynamic) null else type.bound() return if (conf.dynamic) null else type.bound()
} } else if (type is RawType) {
else if (type is RawType) {
return if (conf.rawType) null else type.bound() return if (conf.rawType) null else type.bound()
} }
@@ -157,17 +162,23 @@ class TypeApproximator {
* *
* If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper. * If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper.
*/ */
return KotlinTypeFactory.flexibleType(lowerResult?.lowerIfFlexible() ?: type.lowerBound, return KotlinTypeFactory.flexibleType(
upperResult?.upperIfFlexible() ?: type.upperBound) lowerResult?.lowerIfFlexible() ?: type.lowerBound,
} upperResult?.upperIfFlexible() ?: type.upperBound
else { )
} else {
return type.bound().let { approximateTo(it, conf, depth) ?: it } return type.bound().let { approximateTo(it, conf, depth) ?: it }
} }
} }
} }
} }
private fun approximateIntersectionType(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): UnwrappedType? { private fun approximateIntersectionType(
type: SimpleType,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): UnwrappedType? {
val typeConstructor = type.constructor val typeConstructor = type.constructor
assert(typeConstructor is IntersectionTypeConstructor) { assert(typeConstructor is IntersectionTypeConstructor) {
"Should be intersection type: $type, typeConstructor class: ${typeConstructor::class.java.canonicalName}" "Should be intersection type: $type, typeConstructor class: ${typeConstructor::class.java.canonicalName}"
@@ -194,35 +205,42 @@ class TypeApproximator {
val baseResult = when (conf.intersection) { val baseResult = when (conf.intersection) {
ALLOWED -> if (!thereIsApproximation) return null else intersectTypes(newTypes) ALLOWED -> if (!thereIsApproximation) return null else intersectTypes(newTypes)
TO_FIRST -> if (toSuper) newTypes.first() else return type.defaultResult(toSuper = false) TO_FIRST -> if (toSuper) newTypes.first() else return type.defaultResult(toSuper = false)
// commonSupertypeCalculator should handle flexible types correctly // commonSupertypeCalculator should handle flexible types correctly
TO_COMMON_SUPERTYPE -> if (toSuper) NewCommonSuperTypeCalculator.commonSuperType(newTypes) else return type.defaultResult(toSuper = false) TO_COMMON_SUPERTYPE -> if (toSuper) NewCommonSuperTypeCalculator.commonSuperType(newTypes) else return type.defaultResult(
toSuper = false
)
} }
return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult return if (type.isMarkedNullable) baseResult.makeNullableAsSpecified(true) else baseResult
} }
private fun approximateCapturedType(type: NewCapturedType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): UnwrappedType? { private fun approximateCapturedType(
type: NewCapturedType,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): UnwrappedType? {
val supertypes = type.constructor.supertypes val supertypes = type.constructor.supertypes
val baseSuperType = when (supertypes.size) { val baseSuperType = when (supertypes.size) {
0 -> type.builtIns.nullableAnyType // Let C = in Int, then superType for C and C? is Any? 0 -> type.builtIns.nullableAnyType // Let C = in Int, then superType for C and C? is Any?
1 -> supertypes.single() 1 -> supertypes.single()
// Consider the following example: // Consider the following example:
// A.getA()::class.java, where `getA()` returns some class from Java // A.getA()::class.java, where `getA()` returns some class from Java
// From `::class` we are getting type KClass<Cap<out A!>>, where Cap<out A!> have two supertypes: // From `::class` we are getting type KClass<Cap<out A!>>, where Cap<out A!> have two supertypes:
// - Any (from declared upper bound of type parameter for KClass) // - Any (from declared upper bound of type parameter for KClass)
// - (A..A?) -- from A!, projection type of captured type // - (A..A?) -- from A!, projection type of captured type
// Now, after approximation we were getting type `KClass<out A>`, because { Any & (A..A?) } = A, // Now, after approximation we were getting type `KClass<out A>`, because { Any & (A..A?) } = A,
// but in old inference type was equal to `KClass<out A!>`. // but in old inference type was equal to `KClass<out A!>`.
// Important note that from the point of type system first type is more specific: // Important note that from the point of type system first type is more specific:
// Here, approximation of KClass<Cap<out A!>> is a type KClass<T> such that KClass<Cap<out A!>> <: KClass<out T> => // Here, approximation of KClass<Cap<out A!>> is a type KClass<T> such that KClass<Cap<out A!>> <: KClass<out T> =>
// So, the the more specific type for T would be "some non-null (because of declared upper bound type) subtype of A", which is `out A` // So, the the more specific type for T would be "some non-null (because of declared upper bound type) subtype of A", which is `out A`
// But for now, to reduce differences in behaviour of old and new inference, we'll approximate such types to `KClass<out A!>` // But for now, to reduce differences in behaviour of old and new inference, we'll approximate such types to `KClass<out A!>`
// Once NI will be more stabilized, we'll use more specific type // Once NI will be more stabilized, we'll use more specific type
else -> type.constructor.projection.type.unwrap() else -> type.constructor.projection.type.unwrap()
} }
@@ -241,7 +259,11 @@ class TypeApproximator {
return null return null
} }
} }
val baseResult = if (toSuper) approximateToSuperType(baseSuperType, conf, depth) ?: baseSuperType else approximateToSubType(baseSubType, conf, depth) ?: baseSubType val baseResult = if (toSuper) approximateToSuperType(baseSuperType, conf, depth) ?: baseSuperType else approximateToSubType(
baseSubType,
conf,
depth
) ?: baseSubType
// C = in Int, Int <: C => Int? <: C? // C = in Int, Int <: C => Int? <: C?
// C = out Number, C <: Number => C? <: Number? // C = out Number, C <: Number => C? <: Number?
@@ -249,9 +271,10 @@ class TypeApproximator {
} }
private fun approximateSimpleToSuperType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) = private fun approximateSimpleToSuperType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) =
approximateTo(type, conf, toSuper = true, depth = depth) approximateTo(type, conf, toSuper = true, depth = depth)
private fun approximateSimpleToSubType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) = private fun approximateSimpleToSubType(type: SimpleType, conf: TypeApproximatorConfiguration, depth: Int) =
approximateTo(type, conf, toSuper = false, depth = depth) approximateTo(type, conf, toSuper = false, depth = depth)
private fun approximateTo(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): UnwrappedType? { private fun approximateTo(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): UnwrappedType? {
if (type.isError) { if (type.isError) {
@@ -272,9 +295,10 @@ class TypeApproximator {
val typeConstructor = type.constructor val typeConstructor = type.constructor
if (typeConstructor is NewCapturedTypeConstructor) { if (typeConstructor is NewCapturedTypeConstructor) {
assert(type is NewCapturedType) { // KT-16147 assert(type is NewCapturedType) {
// KT-16147
"Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " + "Type is inconsistent -- somewhere we create type with typeConstructor = $typeConstructor " +
"and class: ${type::class.java.canonicalName}. type.toString() = $type" "and class: ${type::class.java.canonicalName}. type.toString() = $type"
} }
return approximateCapturedType(type as NewCapturedType, conf, toSuper, depth) return approximateCapturedType(type as NewCapturedType, conf, toSuper, depth)
} }
@@ -291,16 +315,15 @@ class TypeApproximator {
} }
private fun approximateDefinitelyNotNullType( private fun approximateDefinitelyNotNullType(
type: DefinitelyNotNullType, type: DefinitelyNotNullType,
conf: TypeApproximatorConfiguration, conf: TypeApproximatorConfiguration,
toSuper: Boolean, toSuper: Boolean,
depth: Int depth: Int
): UnwrappedType? { ): UnwrappedType? {
val approximatedOriginalType = approximateTo(type.original, conf, toSuper, depth) val approximatedOriginalType = approximateTo(type.original, conf, toSuper, depth)
return if (conf.definitelyNotNullType) { return if (conf.definitelyNotNullType) {
approximatedOriginalType?.makeDefinitelyNotNullOrNotNull() approximatedOriginalType?.makeDefinitelyNotNullOrNotNull()
} } else {
else {
if (toSuper) if (toSuper)
(approximatedOriginalType ?: type.original).makeNullableAsSpecified(false) (approximatedOriginalType ?: type.original).makeNullableAsSpecified(false)
else else
@@ -309,20 +332,24 @@ class TypeApproximator {
} }
private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) = private fun isApproximateDirectionToSuper(effectiveVariance: Variance, toSuper: Boolean) =
when (effectiveVariance) { when (effectiveVariance) {
Variance.OUT_VARIANCE -> toSuper Variance.OUT_VARIANCE -> toSuper
Variance.IN_VARIANCE -> !toSuper Variance.IN_VARIANCE -> !toSuper
Variance.INVARIANT -> throw AssertionError("Incorrect variance $effectiveVariance") Variance.INVARIANT -> throw AssertionError("Incorrect variance $effectiveVariance")
} }
private fun approximateParametrizedType(type: SimpleType, conf: TypeApproximatorConfiguration, toSuper: Boolean, depth: Int): SimpleType? { private fun approximateParametrizedType(
type: SimpleType,
conf: TypeApproximatorConfiguration,
toSuper: Boolean,
depth: Int
): SimpleType? {
val parameters = type.constructor.parameters val parameters = type.constructor.parameters
val arguments = type.arguments val arguments = type.arguments
if (parameters.size != arguments.size) { if (parameters.size != arguments.size) {
return if (conf.errorType) { return if (conf.errorType) {
ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${parameters.size}, arguments.size = ${arguments.size})") ErrorUtils.createErrorType("Inconsistent type: $type (parameters.size = ${parameters.size}, arguments.size = ${arguments.size})")
} } else type.defaultResult(toSuper)
else type.defaultResult(toSuper)
} }
val newArguments = arrayOfNulls<TypeProjection?>(arguments.size) val newArguments = arrayOfNulls<TypeProjection?>(arguments.size)
@@ -338,8 +365,10 @@ class TypeApproximator {
when (effectiveVariance) { when (effectiveVariance) {
null -> { null -> {
return if (conf.errorType) { return if (conf.errorType) {
ErrorUtils.createErrorType("Inconsistent type: $type ($index parameter has declared variance: ${parameter.variance}, " + ErrorUtils.createErrorType(
"but argument variance is ${argument.projectionKind})") "Inconsistent type: $type ($index parameter has declared variance: ${parameter.variance}, " +
"but argument variance is ${argument.projectionKind})"
)
} else type.defaultResult(toSuper) } else type.defaultResult(toSuper)
} }
Variance.OUT_VARIANCE, Variance.IN_VARIANCE -> { Variance.OUT_VARIANCE, Variance.IN_VARIANCE -> {
@@ -353,8 +382,7 @@ class TypeApproximator {
val approximatedArgument = argumentType.let { val approximatedArgument = argumentType.let {
if (isApproximateDirectionToSuper(effectiveVariance, toSuper)) { if (isApproximateDirectionToSuper(effectiveVariance, toSuper)) {
approximateToSuperType(it, conf, depth) approximateToSuperType(it, conf, depth)
} } else {
else {
approximateToSubType(it, conf, depth) approximateToSubType(it, conf, depth)
} }
} ?: continue@loop } ?: continue@loop
@@ -397,9 +425,11 @@ class TypeApproximator {
} }
} }
val approximatedSuperType = approximateToSuperType(argumentType, conf, depth) ?: continue@loop // null means that this type we can leave as is val approximatedSuperType =
approximateToSuperType(argumentType, conf, depth) ?: continue@loop // null means that this type we can leave as is
if (approximatedSuperType.isTrivialSuper()) { if (approximatedSuperType.isTrivialSuper()) {
val approximatedSubType = approximateToSubType(argumentType, conf, depth) ?: continue@loop // seems like this is never null val approximatedSubType =
approximateToSubType(argumentType, conf, depth) ?: continue@loop // seems like this is never null
if (!approximatedSubType.isTrivialSub()) { if (!approximatedSubType.isTrivialSub()) {
newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, approximatedSubType) newArguments[index] = TypeProjectionImpl(Variance.IN_VARIANCE, approximatedSubType)
continue@loop continue@loop
@@ -408,8 +438,7 @@ class TypeApproximator {
if (NewKotlinTypeChecker.equalTypes(argumentType, approximatedSuperType)) { if (NewKotlinTypeChecker.equalTypes(argumentType, approximatedSuperType)) {
newArguments[index] = approximatedSuperType.asTypeProjection() newArguments[index] = approximatedSuperType.asTypeProjection()
} } else {
else {
newArguments[index] = TypeProjectionImpl(Variance.OUT_VARIANCE, approximatedSuperType) newArguments[index] = TypeProjectionImpl(Variance.OUT_VARIANCE, approximatedSuperType)
} }
} }
@@ -434,10 +463,10 @@ class TypeApproximator {
} }
internal fun UnwrappedType.typeDepth() = internal fun UnwrappedType.typeDepth() =
when (this) { when (this) {
is SimpleType -> typeDepth() is SimpleType -> typeDepth()
is FlexibleType -> Math.max(lowerBound.typeDepth(), upperBound.typeDepth()) is FlexibleType -> Math.max(lowerBound.typeDepth(), upperBound.typeDepth())
} }
internal fun SimpleType.typeDepth(): Int { internal fun SimpleType.typeDepth(): Int {
if (this is TypeUtils.SpecialType) return 0 if (this is TypeUtils.SpecialType) return 0