Select most specific overloaded function/property by explicitly used arguments only.
Major rewrite of OverloadingConflictResolver.
This commit is contained in:
+6
-1
@@ -27,10 +27,15 @@ public interface VariableAsFunctionResolvedCall {
|
||||
public val variableCall: ResolvedCall<VariableDescriptor>
|
||||
}
|
||||
|
||||
public interface VariableAsFunctionMutableResolvedCall : VariableAsFunctionResolvedCall {
|
||||
override val functionCall: MutableResolvedCall<FunctionDescriptor>
|
||||
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
||||
}
|
||||
|
||||
class VariableAsFunctionResolvedCallImpl(
|
||||
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
|
||||
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
||||
) : VariableAsFunctionResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
|
||||
) : VariableAsFunctionMutableResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
|
||||
|
||||
override fun markCallAsCompleted() {
|
||||
functionCall.markCallAsCompleted()
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.results
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.types.BoundsSubstitutor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
|
||||
class CandidateCallWithArgumentMapping<D : CallableDescriptor, K> private constructor(
|
||||
val resolvedCall: MutableResolvedCall<D>,
|
||||
private val argumentsToParameters: Map<K, ValueParameterDescriptor>,
|
||||
val parametersWithDefaultValuesCount: Int
|
||||
) {
|
||||
override fun toString(): String =
|
||||
"${resolvedCall.call}: $parametersWithDefaultValuesCount defaults in ${resolvedCall.candidateDescriptor}"
|
||||
|
||||
val resultingDescriptor: D
|
||||
get() = resolvedCall.resultingDescriptor
|
||||
|
||||
val argumentsCount: Int
|
||||
get() = argumentsToParameters.size
|
||||
|
||||
val argumentKeys: Collection<K>
|
||||
get() = argumentsToParameters.keys
|
||||
|
||||
val callElement: KtElement
|
||||
get() = resolvedCall.call.callElement
|
||||
|
||||
val isGeneric: Boolean = resolvedCall.resultingDescriptor.original.typeParameters.isNotEmpty()
|
||||
|
||||
private val upperBoundsSubstitutor =
|
||||
BoundsSubstitutor.createUpperBoundsSubstitutor(resolvedCall.resultingDescriptor)
|
||||
|
||||
fun getExtensionReceiverType(substituteUpperBounds: Boolean): KotlinType? =
|
||||
resultingDescriptor.extensionReceiverParameter?.type?.let {
|
||||
extensionReceiverType ->
|
||||
if (substituteUpperBounds)
|
||||
upperBoundsSubstitutor.substitute(extensionReceiverType, Variance.INVARIANT)
|
||||
else
|
||||
extensionReceiverType
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of a value that can be used in place of the corresponding parameter.
|
||||
*/
|
||||
fun getValueParameterType(argumentKey: K, substituteUpperBounds: Boolean): KotlinType? =
|
||||
argumentsToParameters[argumentKey]?.let {
|
||||
valueParameterDescriptor ->
|
||||
val valueParameterType = valueParameterDescriptor.varargElementType ?: valueParameterDescriptor.type
|
||||
if (substituteUpperBounds)
|
||||
upperBoundsSubstitutor.substitute(valueParameterType, Variance.INVARIANT)
|
||||
else
|
||||
valueParameterType
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <D : CallableDescriptor, K> create(
|
||||
call: MutableResolvedCall<D>,
|
||||
resolvedArgumentToKeys: (ResolvedValueArgument) -> Collection<K>
|
||||
): CandidateCallWithArgumentMapping<D, K> {
|
||||
val argumentsToParameters = hashMapOf<K, ValueParameterDescriptor>()
|
||||
var parametersWithDefaultValuesCount = 0
|
||||
|
||||
for ((valueParameterDescriptor, resolvedValueArgument) in call.valueArguments.entries) {
|
||||
if (resolvedValueArgument is DefaultValueArgument) {
|
||||
parametersWithDefaultValuesCount++
|
||||
}
|
||||
else {
|
||||
val keys = resolvedArgumentToKeys(resolvedValueArgument)
|
||||
for (argumentKey in keys) {
|
||||
argumentsToParameters[argumentKey] = valueParameterDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CandidateCallWithArgumentMapping(call, argumentsToParameters, parametersWithDefaultValuesCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+218
-149
@@ -22,12 +22,18 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionMutableResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Specificity
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.getSpecificityRelationTo
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
|
||||
class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
||||
|
||||
@@ -35,203 +41,233 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
||||
candidates: Set<MutableResolvedCall<D>>,
|
||||
discriminateGenericDescriptors: Boolean,
|
||||
checkArgumentsMode: CheckArgumentTypesMode
|
||||
): MutableResolvedCall<D>? {
|
||||
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
|
||||
|
||||
val maximallySpecific = THashSet(object : TObjectHashingStrategy<MutableResolvedCall<D>> {
|
||||
override fun equals(call1: MutableResolvedCall<D>?, call2: MutableResolvedCall<D>?): Boolean =
|
||||
if (call1 == null) call2 == null
|
||||
else call1.resultingDescriptor == call2!!.resultingDescriptor
|
||||
): MutableResolvedCall<D>? =
|
||||
if (candidates.size <= 1)
|
||||
candidates.firstOrNull()
|
||||
else when (checkArgumentsMode) {
|
||||
CheckArgumentTypesMode.CHECK_CALLABLE_TYPE ->
|
||||
uniquifyCandidatesSet(candidates).filter {
|
||||
isMaxSpecific(it, candidates) {
|
||||
call1, call2 ->
|
||||
isNotLessSpecificCallableReference(call1.resultingDescriptor, call2.resultingDescriptor)
|
||||
}
|
||||
}.singleOrNull()
|
||||
|
||||
override fun computeHashCode(call: MutableResolvedCall<D>?): Int =
|
||||
call?.resultingDescriptor?.hashCode() ?: 0
|
||||
})
|
||||
|
||||
candidates.filterTo(maximallySpecific) {
|
||||
isMaximallySpecific(it, candidates, discriminateGenericDescriptors, checkArgumentsMode)
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS ->
|
||||
findMaximallySpecificCall(candidates, discriminateGenericDescriptors)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> findMaximallySpecificVariableAsFunctionCalls(
|
||||
candidates: Set<MutableResolvedCall<D>>,
|
||||
discriminateGenericDescriptors: Boolean
|
||||
): Set<MutableResolvedCall<D>> {
|
||||
val variableCalls = candidates.mapTo(newResolvedCallSet<MutableResolvedCall<VariableDescriptor>>(candidates.size)) {
|
||||
if (it is VariableAsFunctionMutableResolvedCall)
|
||||
it.variableCall
|
||||
else
|
||||
throw AssertionError("Regular call among variable-as-function calls: $it")
|
||||
}
|
||||
|
||||
return if (maximallySpecific.size == 1) maximallySpecific.first() else null
|
||||
val maxSpecificVariableCall = findMaximallySpecificCall(variableCalls, discriminateGenericDescriptors) ?: return emptySet()
|
||||
|
||||
return candidates.filterTo(newResolvedCallSet<MutableResolvedCall<D>>(2)) {
|
||||
it.resultingVariableDescriptor == maxSpecificVariableCall.resultingDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> isMaximallySpecific(
|
||||
candidateCall: MutableResolvedCall<D>,
|
||||
private fun <D : CallableDescriptor> findMaximallySpecificCall(
|
||||
candidates: Set<MutableResolvedCall<D>>,
|
||||
discriminateGenericDescriptors: Boolean,
|
||||
checkArgumentsMode: CheckArgumentTypesMode): Boolean {
|
||||
val me = candidateCall.resultingDescriptor
|
||||
discriminateGenericDescriptors: Boolean
|
||||
): MutableResolvedCall<D>? {
|
||||
val filteredCandidates = uniquifyCandidatesSet(candidates)
|
||||
|
||||
val isInvoke = candidateCall is VariableAsFunctionResolvedCall
|
||||
val variable = (candidateCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
|
||||
if (filteredCandidates.size <= 1) return filteredCandidates.singleOrNull()
|
||||
|
||||
for (otherCall in candidates) {
|
||||
val other = otherCall.resultingDescriptor
|
||||
if (other === me) continue
|
||||
val conflictingCandidates = filteredCandidates.map {
|
||||
candidateCall ->
|
||||
CandidateCallWithArgumentMapping.create(candidateCall) { it.arguments.filter { it.getArgumentExpression() != null } }
|
||||
}
|
||||
|
||||
if (definitelyNotMaximallySpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode)) {
|
||||
if (!isInvoke) return false
|
||||
val (varargCandidates, regularCandidates) = conflictingCandidates.partition { it.resultingDescriptor.hasVarargs }
|
||||
val mostSpecificRegularCandidates = regularCandidates.selectMostSpecificCallsWithArgumentMapping(discriminateGenericDescriptors)
|
||||
|
||||
assert(otherCall is VariableAsFunctionResolvedCall) { "'invoke' candidate goes with usual one: " + candidateCall + otherCall }
|
||||
return when {
|
||||
mostSpecificRegularCandidates.size > 1 ->
|
||||
null
|
||||
mostSpecificRegularCandidates.size == 1 ->
|
||||
mostSpecificRegularCandidates.single()
|
||||
else ->
|
||||
varargCandidates.selectMostSpecificCallsWithArgumentMapping(discriminateGenericDescriptors).singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
val otherVariableCall = (otherCall as VariableAsFunctionResolvedCall).variableCall
|
||||
if (definitelyNotMaximallySpecific(variable!!, otherVariableCall.resultingDescriptor, discriminateGenericDescriptors, checkArgumentsMode)) {
|
||||
return false
|
||||
}
|
||||
private fun <D : CallableDescriptor, K> Collection<CandidateCallWithArgumentMapping<D, K>>.selectMostSpecificCallsWithArgumentMapping(
|
||||
discriminateGenericDescriptors: Boolean
|
||||
): Collection<MutableResolvedCall<D>> =
|
||||
this.mapNotNull {
|
||||
candidate ->
|
||||
candidate.check {
|
||||
isMaxSpecific(candidate, this) {
|
||||
call1, call2 ->
|
||||
isNotLessSpecificCallWithArgumentMapping(call1, call2, discriminateGenericDescriptors)
|
||||
}
|
||||
}?.resolvedCall
|
||||
}
|
||||
|
||||
private inline fun <C> isMaxSpecific(
|
||||
candidate: C,
|
||||
candidates: Collection<C>,
|
||||
isNotLessSpecific: (C, C) -> Boolean
|
||||
): Boolean =
|
||||
candidates.all {
|
||||
other ->
|
||||
candidate === other ||
|
||||
isNotLessSpecific(candidate, other) && !isNotLessSpecific(other, candidate)
|
||||
}
|
||||
|
||||
/**
|
||||
* `call1` is not less specific than `call2`
|
||||
*/
|
||||
private fun <D : CallableDescriptor, K> isNotLessSpecificCallWithArgumentMapping(
|
||||
call1: CandidateCallWithArgumentMapping<D, K>,
|
||||
call2: CandidateCallWithArgumentMapping<D, K>,
|
||||
discriminateGenericDescriptors: Boolean
|
||||
): Boolean {
|
||||
return tryCompareDescriptorsFromScripts(call1.resultingDescriptor, call2.resultingDescriptor) ?:
|
||||
compareCallsWithArgumentMapping(call1, call2, discriminateGenericDescriptors)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
||||
* `false` if `d1` is definitely less specific than `d2` or undecided.
|
||||
*/
|
||||
private fun <D : CallableDescriptor, K> compareCallsWithArgumentMapping(
|
||||
call1: CandidateCallWithArgumentMapping<D, K>,
|
||||
call2: CandidateCallWithArgumentMapping<D, K>,
|
||||
discriminateGenericDescriptors: Boolean
|
||||
): Boolean {
|
||||
val substituteParameterTypes =
|
||||
if (discriminateGenericDescriptors) {
|
||||
if (!call1.isGeneric && call2.isGeneric) return true
|
||||
if (call1.isGeneric && !call2.isGeneric) return false
|
||||
call1.isGeneric && call2.isGeneric
|
||||
}
|
||||
else false
|
||||
|
||||
val extensionReceiverType1 = call1.getExtensionReceiverType(substituteParameterTypes)
|
||||
val extensionReceiverType2 = call2.getExtensionReceiverType(substituteParameterTypes)
|
||||
tryCompareExtensionReceiverType(extensionReceiverType1, extensionReceiverType2)?.let {
|
||||
return it
|
||||
}
|
||||
|
||||
assert(call1.argumentsCount == call2.argumentsCount) {
|
||||
"$call1 and $call2 have different number of explicit arguments"
|
||||
}
|
||||
|
||||
for (argumentKey in call1.argumentKeys) {
|
||||
val type1 = call1.getValueParameterType(argumentKey, substituteParameterTypes) ?: continue
|
||||
val type2 = call2.getValueParameterType(argumentKey, substituteParameterTypes) ?: continue
|
||||
|
||||
if (!typeNotLessSpecific(type1, type2)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (call1.parametersWithDefaultValuesCount > call2.parametersWithDefaultValuesCount) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> definitelyNotMaximallySpecific(
|
||||
me: D,
|
||||
other: D,
|
||||
discriminateGenericDescriptors: Boolean,
|
||||
checkArgumentsMode: CheckArgumentTypesMode): Boolean {
|
||||
return !moreSpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode) ||
|
||||
moreSpecific(other, me, discriminateGenericDescriptors, checkArgumentsMode)
|
||||
/**
|
||||
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
||||
* `false` if `d1` is definitely less specific than `d2`,
|
||||
* `null` if undecided.
|
||||
*/
|
||||
private fun tryCompareDescriptorsFromScripts(d1: CallableDescriptor, d2: CallableDescriptor): Boolean? {
|
||||
val containingDeclaration1 = d1.containingDeclaration
|
||||
val containingDeclaration2 = d2.containingDeclaration
|
||||
|
||||
if (containingDeclaration1 is ScriptDescriptor && containingDeclaration2 is ScriptDescriptor) {
|
||||
when {
|
||||
containingDeclaration1.priority > containingDeclaration2.priority -> return true
|
||||
containingDeclaration1.priority < containingDeclaration2.priority -> return false
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Let < mean "more specific"
|
||||
* Subtype < supertype
|
||||
* Double < Float
|
||||
* Int < Long
|
||||
* Int < Short < Byte
|
||||
* Returns `false` if `d1` is definitely less specific than `d2`,
|
||||
* `null` if undecided.
|
||||
*/
|
||||
private fun <Descriptor : CallableDescriptor> moreSpecific(
|
||||
f: Descriptor,
|
||||
g: Descriptor,
|
||||
discriminateGenericDescriptors: Boolean,
|
||||
checkArgumentsMode: CheckArgumentTypesMode): Boolean {
|
||||
val resolvingCallableReference = checkArgumentsMode == CheckArgumentTypesMode.CHECK_CALLABLE_TYPE
|
||||
|
||||
if (f.containingDeclaration is ScriptDescriptor && g.containingDeclaration is ScriptDescriptor) {
|
||||
val fs = f.containingDeclaration as ScriptDescriptor
|
||||
val gs = g.containingDeclaration as ScriptDescriptor
|
||||
|
||||
if (fs.priority != gs.priority) {
|
||||
return fs.priority > gs.priority
|
||||
}
|
||||
}
|
||||
|
||||
val isGenericF = isGeneric(f)
|
||||
val isGenericG = isGeneric(g)
|
||||
if (discriminateGenericDescriptors) {
|
||||
if (!isGenericF && isGenericG) return true
|
||||
if (isGenericF && !isGenericG) return false
|
||||
|
||||
if (isGenericF && isGenericG) {
|
||||
return moreSpecific(BoundsSubstitutor.substituteBounds(f),
|
||||
BoundsSubstitutor.substituteBounds(g),
|
||||
false, checkArgumentsMode)
|
||||
}
|
||||
}
|
||||
|
||||
if (OverrideResolver.overrides(f, g)) return true
|
||||
if (OverrideResolver.overrides(g, f)) return false
|
||||
|
||||
val receiverOfF = f.extensionReceiverParameter
|
||||
val receiverOfG = g.extensionReceiverParameter
|
||||
if (receiverOfF != null && receiverOfG != null) {
|
||||
if (!typeMoreSpecific(receiverOfF.type, receiverOfG.type)) return false
|
||||
private fun tryCompareExtensionReceiverType(type1: KotlinType?, type2: KotlinType?): Boolean? {
|
||||
if (type1 != null && type2 != null) {
|
||||
if (!typeNotLessSpecific(type1, type2))
|
||||
return false
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if `d1` is definitely not less specific than `d2`,
|
||||
* `false` if `d1` is definitely less specific than `d2`,
|
||||
* `null` if undecided.
|
||||
*/
|
||||
private fun compareFunctionParameterTypes(f: CallableDescriptor, g: CallableDescriptor): Boolean {
|
||||
val fParams = f.valueParameters
|
||||
val gParams = g.valueParameters
|
||||
|
||||
val fSize = fParams.size
|
||||
val gSize = gParams.size
|
||||
|
||||
val fIsVararg = isVariableArity(fParams)
|
||||
val gIsVararg = isVariableArity(gParams)
|
||||
if (fSize != gSize) return false
|
||||
|
||||
if (resolvingCallableReference && fIsVararg != gIsVararg) return false
|
||||
if (!fIsVararg && gIsVararg) return true
|
||||
if (fIsVararg && !gIsVararg) return false
|
||||
for (i in 0..fSize - 1) {
|
||||
val fParam = fParams[i]
|
||||
val gParam = gParams[i]
|
||||
|
||||
if (!fIsVararg && !gIsVararg) {
|
||||
if (resolvingCallableReference && fSize != gSize) return false
|
||||
if (!resolvingCallableReference && fSize > gSize) return false
|
||||
val fParamIsVararg = fParam.varargElementType != null
|
||||
val gParamIsVararg = gParam.varargElementType != null
|
||||
|
||||
for (i in 0..fSize - 1) {
|
||||
val fParam = fParams[i]
|
||||
val gParam = gParams[i]
|
||||
|
||||
val fParamType = fParam.type
|
||||
val gParamType = gParam.type
|
||||
|
||||
if (!typeMoreSpecific(fParamType, gParamType)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fIsVararg && gIsVararg) {
|
||||
// Check matching parameters
|
||||
val minSize = Math.min(fSize, gSize)
|
||||
for (i in 0..minSize - 1 - 1) {
|
||||
val fParam = fParams[i]
|
||||
val gParam = gParams[i]
|
||||
|
||||
val fParamType = fParam.type
|
||||
val gParamType = gParam.type
|
||||
|
||||
if (!typeMoreSpecific(fParamType, gParamType)) {
|
||||
return false
|
||||
}
|
||||
if (fParamIsVararg != gParamIsVararg) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check the non-matching parameters of one function against the vararg parameter of the other function
|
||||
// Example:
|
||||
// f(vararg vf : T)
|
||||
// g(a : A, vararg vg : T)
|
||||
// here we check that typeOf(a) < elementTypeOf(vf) and elementTypeOf(vg) < elementTypeOf(vf)
|
||||
if (fSize < gSize) {
|
||||
val fParam = fParams[fSize - 1]
|
||||
val fParamType = fParam.varargElementType
|
||||
assert(fParamType != null) { "fIsVararg guarantees this" }
|
||||
for (i in fSize - 1..gSize - 1) {
|
||||
val gParam = gParams[i]
|
||||
if (!typeMoreSpecific(fParamType!!, getVarargElementTypeOrType(gParam))) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val gParam = gParams[gSize - 1]
|
||||
val gParamType = gParam.varargElementType
|
||||
assert(gParamType != null) { "gIsVararg guarantees this" }
|
||||
for (i in gSize - 1..fSize - 1) {
|
||||
val fParam = fParams[i]
|
||||
if (!typeMoreSpecific(getVarargElementTypeOrType(fParam), gParamType!!)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
val fParamType = getVarargElementTypeOrType(fParam)
|
||||
val gParamType = getVarargElementTypeOrType(gParam)
|
||||
|
||||
if (!typeNotLessSpecific(fParamType, gParamType)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isNotLessSpecificCallableReference(f: CallableDescriptor, g: CallableDescriptor): Boolean =
|
||||
// TODO should we "discriminate generic descriptors" for callable references?
|
||||
tryCompareDescriptorsFromScripts(f, g) ?:
|
||||
// TODO compare functional types for 'f' and 'g'
|
||||
tryCompareExtensionReceiverType(f.extensionReceiverType, g.extensionReceiverType) ?:
|
||||
compareFunctionParameterTypes(f, g)
|
||||
|
||||
private fun getVarargElementTypeOrType(parameterDescriptor: ValueParameterDescriptor): KotlinType =
|
||||
parameterDescriptor.varargElementType ?: parameterDescriptor.type
|
||||
|
||||
private fun isVariableArity(fParams: List<ValueParameterDescriptor>): Boolean =
|
||||
fParams.lastOrNull()?.varargElementType != null
|
||||
private val CallableDescriptor.hasVarargs: Boolean get() =
|
||||
this.valueParameters.any { it.varargElementType != null }
|
||||
|
||||
private fun isGeneric(f: CallableDescriptor): Boolean =
|
||||
f.original.typeParameters.isNotEmpty()
|
||||
|
||||
private fun typeMoreSpecific(specific: KotlinType, general: KotlinType): Boolean {
|
||||
private fun typeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean {
|
||||
val isSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(specific, general) || numericTypeMoreSpecific(specific, general)
|
||||
|
||||
if (!isSubtype) return false
|
||||
|
||||
val sThanG = specific.getSpecificityRelationTo(general)
|
||||
val gThanS = general.getSpecificityRelationTo(specific)
|
||||
if (sThanG === Specificity.Relation.LESS_SPECIFIC &&
|
||||
gThanS !== Specificity.Relation.LESS_SPECIFIC) {
|
||||
if (sThanG == Specificity.Relation.LESS_SPECIFIC &&
|
||||
gThanS != Specificity.Relation.LESS_SPECIFIC) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -261,4 +297,37 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
|
||||
return false
|
||||
}
|
||||
|
||||
private val CallableDescriptor.extensionReceiverType: KotlinType?
|
||||
get() = extensionReceiverParameter?.type
|
||||
|
||||
companion object {
|
||||
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
|
||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||
private fun <D : CallableDescriptor> uniquifyCandidatesSet(candidates: Collection<MutableResolvedCall<D>>): Set<MutableResolvedCall<D>> =
|
||||
THashSet<MutableResolvedCall<D>>(candidates.size, getCallHashingStrategy<MutableResolvedCall<D>>()).apply { addAll(candidates) }
|
||||
|
||||
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||
private fun <C> newResolvedCallSet(expectedSize: Int): MutableSet<C> =
|
||||
THashSet<C>(expectedSize, getCallHashingStrategy<C>())
|
||||
|
||||
private object ResolvedCallHashingStrategy : TObjectHashingStrategy<ResolvedCall<*>> {
|
||||
override fun equals(call1: ResolvedCall<*>?, call2: ResolvedCall<*>?): Boolean =
|
||||
if (call1 != null && call2 != null)
|
||||
call1.resultingDescriptor == call2.resultingDescriptor
|
||||
else
|
||||
call1 == call2
|
||||
|
||||
override fun computeHashCode(call: ResolvedCall<*>?): Int =
|
||||
call?.resultingDescriptor?.hashCode() ?: 0
|
||||
}
|
||||
|
||||
private val MutableResolvedCall<*>.resultingVariableDescriptor: VariableDescriptor
|
||||
get() = (this as VariableAsFunctionResolvedCall).variableCall.resultingDescriptor
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "CAST_NEVER_SUCCEEDS")
|
||||
private fun <C> getCallHashingStrategy() =
|
||||
ResolvedCallHashingStrategy as TObjectHashingStrategy<C>
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -193,6 +194,10 @@ public class ResolutionResultsHandler {
|
||||
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
|
||||
}
|
||||
|
||||
if (candidates.iterator().next() instanceof VariableAsFunctionResolvedCall) {
|
||||
candidates = overloadingConflictResolver.findMaximallySpecificVariableAsFunctionCalls(candidates, discriminateGenerics);
|
||||
}
|
||||
|
||||
Set<MutableResolvedCall<D>> noOverrides = OverrideResolver.filterOutOverridden(candidates, MAP_TO_RESULT);
|
||||
if (noOverrides.size() == 1) {
|
||||
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.types;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
@@ -53,6 +54,11 @@ public class BoundsSubstitutor {
|
||||
return substitutedFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <D extends CallableDescriptor> TypeSubstitutor createUpperBoundsSubstitutor(@NotNull D callableDescriptor) {
|
||||
return createUpperBoundsSubstitutor(callableDescriptor.getTypeParameters());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TypeSubstitutor createUpperBoundsSubstitutor(@NotNull List<TypeParameterDescriptor> typeParameters) {
|
||||
Map<TypeConstructor, TypeProjection> mutableSubstitution = new HashMap<TypeConstructor, TypeProjection>();
|
||||
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object Right
|
||||
object Wrong
|
||||
|
||||
interface IA
|
||||
interface IB : IA
|
||||
fun IA.foo(vararg x: Int) = Wrong
|
||||
fun IB.foo(vararg x: Int) = Right
|
||||
class CC : IB
|
||||
|
||||
val test7 = CC().foo(1, 2, 3)
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
package
|
||||
|
||||
public val test7: Right
|
||||
public fun IA.foo(/*0*/ vararg x: kotlin.Int /*kotlin.IntArray*/): Wrong
|
||||
public fun IB.foo(/*0*/ vararg x: kotlin.Int /*kotlin.IntArray*/): Right
|
||||
|
||||
public final class CC : IB {
|
||||
public constructor CC()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IA {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public interface IB : IA {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Right {
|
||||
private constructor Right()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Wrong {
|
||||
private constructor Wrong()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// FILE: J.java
|
||||
import java.util.*
|
||||
|
||||
public class J {
|
||||
public static <E extends Enum<E>> String foo(E e) { return ""; }
|
||||
public static <E extends Enum<E>> String foo(E e1, E e2) { return ""; }
|
||||
public static <E extends Enum<E>> String foo(E s1, E s2, E s3) { return ""; }
|
||||
public static <E extends Enum<E>> int foo(E... ss) { return 0; }
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
enum class X { A }
|
||||
val a = X.A
|
||||
|
||||
val test0: Int = J.foo<X>()
|
||||
val test1: String = J.foo(a)
|
||||
val test2: String = J.foo(a, a)
|
||||
val test3: String = J.foo(a, a, a)
|
||||
val test4: Int = J.foo(a, a, a, a)
|
||||
val test5: Int = J.foo(a, a, a, a, a)
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package
|
||||
|
||||
public val a: X
|
||||
public val test0: kotlin.Int
|
||||
public val test1: kotlin.String
|
||||
public val test2: kotlin.String
|
||||
public val test3: kotlin.String
|
||||
public val test4: kotlin.Int
|
||||
public val test5: kotlin.Int
|
||||
|
||||
public open class J {
|
||||
public constructor J()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public open fun </*0*/ E : kotlin.Enum<E!>!> foo(/*0*/ e: E!): kotlin.String!
|
||||
public open fun </*0*/ E : kotlin.Enum<E!>!> foo(/*0*/ e1: E!, /*1*/ e2: E!): kotlin.String!
|
||||
public open fun </*0*/ E : kotlin.Enum<E!>!> foo(/*0*/ s1: E!, /*1*/ s2: E!, /*2*/ s3: E!): kotlin.String!
|
||||
public open fun </*0*/ E : kotlin.Enum<E!>!> foo(/*0*/ vararg ss: E! /*kotlin.Array<(out) E!>!*/): kotlin.Int
|
||||
}
|
||||
|
||||
public final enum class X : kotlin.Enum<X> {
|
||||
enum entry A
|
||||
|
||||
private constructor X()
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: X): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
@kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "Use 'values()' function instead", replaceWith = kotlin.ReplaceWith(expression = "this.values()", imports = {})) public final /*synthesized*/ val values: kotlin.Array<X>
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): X
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<X>
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object Right
|
||||
object Wrong
|
||||
|
||||
fun overloadedFun(c: Any = "", b: String = "", f: Any = "") = Right
|
||||
fun overloadedFun(b: Any = "", c: Any = "", e: String = "", x: String = "", y: String = "") = Wrong
|
||||
|
||||
val test: Right = overloadedFun(b = "")
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public val test: Right
|
||||
public fun overloadedFun(/*0*/ b: kotlin.Any = ..., /*1*/ c: kotlin.Any = ..., /*2*/ e: kotlin.String = ..., /*3*/ x: kotlin.String = ..., /*4*/ y: kotlin.String = ...): Wrong
|
||||
public fun overloadedFun(/*0*/ c: kotlin.Any = ..., /*1*/ b: kotlin.String = ..., /*2*/ f: kotlin.Any = ...): Right
|
||||
|
||||
public object Right {
|
||||
private constructor Right()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Wrong {
|
||||
private constructor Wrong()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object Right
|
||||
object Wrong
|
||||
|
||||
fun overloadedFun1(c: Any = "", b: String = "", f: Any = "") = Right
|
||||
fun overloadedFun1(b: Any = "", c: Any = "", e: String = "") = Wrong
|
||||
|
||||
val test1: Right = overloadedFun1(b = "")
|
||||
val test1a: Wrong = <!TYPE_MISMATCH!>overloadedFun1(b = "")<!>
|
||||
|
||||
fun overloadedFun2(a: String, b: Any = "") = Right
|
||||
fun overloadedFun2(a: Any, b: String = "") = Wrong
|
||||
|
||||
val test2: Right = overloadedFun2("")
|
||||
|
||||
fun overloadedFun2a(a: Any, b: String = "") = Wrong
|
||||
fun overloadedFun2a(a: String, b: Any = "") = Right
|
||||
|
||||
val test2a: Right = overloadedFun2a("")
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package
|
||||
|
||||
public val test1: Right
|
||||
public val test1a: Wrong
|
||||
public val test2: Right
|
||||
public val test2a: Right
|
||||
public fun overloadedFun1(/*0*/ b: kotlin.Any = ..., /*1*/ c: kotlin.Any = ..., /*2*/ e: kotlin.String = ...): Wrong
|
||||
public fun overloadedFun1(/*0*/ c: kotlin.Any = ..., /*1*/ b: kotlin.String = ..., /*2*/ f: kotlin.Any = ...): Right
|
||||
public fun overloadedFun2(/*0*/ a: kotlin.Any, /*1*/ b: kotlin.String = ...): Wrong
|
||||
public fun overloadedFun2(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Any = ...): Right
|
||||
public fun overloadedFun2a(/*0*/ a: kotlin.Any, /*1*/ b: kotlin.String = ...): Wrong
|
||||
public fun overloadedFun2a(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Any = ...): Right
|
||||
|
||||
public object Right {
|
||||
private constructor Right()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Wrong {
|
||||
private constructor Wrong()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object Right
|
||||
object Wrong
|
||||
|
||||
fun overloadedFun6(s1: String) = Right
|
||||
fun overloadedFun6(s1: String, s2: String) = Wrong
|
||||
fun overloadedFun6(s1: String, s2: String, s3: String) = Wrong
|
||||
fun overloadedFun6(s: String, vararg ss: String) = Wrong
|
||||
|
||||
val test6: Right = overloadedFun6("")
|
||||
@@ -0,0 +1,21 @@
|
||||
package
|
||||
|
||||
public val test6: Right
|
||||
public fun overloadedFun6(/*0*/ s1: kotlin.String): Right
|
||||
public fun overloadedFun6(/*0*/ s: kotlin.String, /*1*/ vararg ss: kotlin.String /*kotlin.Array<out kotlin.String>*/): Wrong
|
||||
public fun overloadedFun6(/*0*/ s1: kotlin.String, /*1*/ s2: kotlin.String): Wrong
|
||||
public fun overloadedFun6(/*0*/ s1: kotlin.String, /*1*/ s2: kotlin.String, /*2*/ s3: kotlin.String): Wrong
|
||||
|
||||
public object Right {
|
||||
private constructor Right()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Wrong {
|
||||
private constructor Wrong()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object X1
|
||||
object X2
|
||||
|
||||
fun overloadedFun(arg: String, vararg args: String) = X1
|
||||
fun overloadedFun(arg: String, vararg args: String, flag: Boolean = true) = X2
|
||||
|
||||
val test1a: X1 = overloadedFun("", "")
|
||||
val test1b: X1 = overloadedFun("", args = "")
|
||||
val test1c: X2 = overloadedFun("", "", "", flag = true)
|
||||
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
package
|
||||
|
||||
public val test1a: X1
|
||||
public val test1b: X1
|
||||
public val test1c: X2
|
||||
public fun overloadedFun(/*0*/ arg: kotlin.String, /*1*/ vararg args: kotlin.String /*kotlin.Array<out kotlin.String>*/): X1
|
||||
public fun overloadedFun(/*0*/ arg: kotlin.String, /*1*/ vararg args: kotlin.String /*kotlin.Array<out kotlin.String>*/, /*2*/ flag: kotlin.Boolean = ...): X2
|
||||
|
||||
public object X1 {
|
||||
private constructor X1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object X2 {
|
||||
private constructor X2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
object X1
|
||||
object X2
|
||||
|
||||
fun overloadedFun5(vararg ss: String) = X1
|
||||
fun overloadedFun5(s: String, vararg ss: String) = X2
|
||||
|
||||
val test1: X1 = <!OVERLOAD_RESOLUTION_AMBIGUITY!>overloadedFun5<!>("")
|
||||
val test2 = <!OVERLOAD_RESOLUTION_AMBIGUITY!>overloadedFun5<!>("", "")
|
||||
val test3: X2 = overloadedFun5(s = "", ss = "")
|
||||
val test4: X1 = overloadedFun5(ss = "")
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package
|
||||
|
||||
public val test1: X1
|
||||
public val test2: [ERROR : Type for overloadedFun5("", "")]
|
||||
public val test3: X2
|
||||
public val test4: X1
|
||||
public fun overloadedFun5(/*0*/ vararg ss: kotlin.String /*kotlin.Array<out kotlin.String>*/): X1
|
||||
public fun overloadedFun5(/*0*/ s: kotlin.String, /*1*/ vararg ss: kotlin.String /*kotlin.Array<out kotlin.String>*/): X2
|
||||
|
||||
public object X1 {
|
||||
private constructor X1()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object X2 {
|
||||
private constructor X2()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -13731,6 +13731,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class OverloadConflicts extends AbstractDiagnosticsTest {
|
||||
public void testAllFilesPresentInOverloadConflicts() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/overloadConflicts"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionReceiverAndVarargs.kt")
|
||||
public void testExtensionReceiverAndVarargs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/extensionReceiverAndVarargs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("javaOverloadedVarargs.kt")
|
||||
public void testJavaOverloadedVarargs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/javaOverloadedVarargs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("numberOfDefaults.kt")
|
||||
public void testNumberOfDefaults() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/numberOfDefaults.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("originalExamples.kt")
|
||||
public void testOriginalExamples() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/originalExamples.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("varargs.kt")
|
||||
public void testVarargs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("varargsInDifferentPositions.kt")
|
||||
public void testVarargsInDifferentPositions() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargsInDifferentPositions.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("varargsMixed.kt")
|
||||
public void testVarargsMixed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/overloadConflicts/varargsMixed.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/resolve/specialConstructions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -16,23 +16,23 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.util
|
||||
|
||||
import com.intellij.codeInspection.SmartHashMap
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
|
||||
import com.intellij.util.SmartFMap
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
public fun String.trimTrailingWhitespacesAndAddNewlineAtEOF(): String =
|
||||
this.split('\n').map { it.trimEnd() }.joinToString(separator = "\n").let {
|
||||
result -> if (result.endsWith("\n")) result else result + "\n"
|
||||
}
|
||||
|
||||
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String) {
|
||||
configureWithExtraFile(path, *extraNameParts)
|
||||
public fun CodeInsightTestFixture.configureWithExtraFileAbs(path: String, vararg extraNameParts: String) {
|
||||
configureWithExtraFile(path, *extraNameParts, relativePaths = false)
|
||||
}
|
||||
|
||||
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String = arrayOf(".Data"), relativePaths: Boolean = false) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import java.util.List;
|
||||
|
||||
public abstract class AbstractQuickDocProviderTest extends KotlinLightCodeInsightFixtureTestCase {
|
||||
public void doTest(@NotNull String path) throws Exception {
|
||||
JetTestUtilsKt.configureWithExtraFile(myFixture, path, "_Data");
|
||||
JetTestUtilsKt.configureWithExtraFileAbs(myFixture, path, "_Data");
|
||||
|
||||
PsiElement element = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
|
||||
assertNotNull("Can't find element at caret in file: " + path, element);
|
||||
|
||||
@@ -17,22 +17,18 @@
|
||||
package org.jetbrains.kotlin.idea.resolve
|
||||
|
||||
import com.google.common.collect.Lists
|
||||
import com.google.common.collect.Ordering
|
||||
import com.intellij.psi.PsiPolyVariantReference
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightPlatformCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.ReferenceUtils
|
||||
import org.jetbrains.kotlin.test.util.configureWithExtraFile
|
||||
import org.junit.Assert
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
public abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixtureTestCase() {
|
||||
|
||||
+9
-10
@@ -16,21 +16,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.structureView
|
||||
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import com.intellij.util.ui.tree.TreeUtil
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import java.io.File
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure
|
||||
import com.intellij.ide.util.FileStructurePopup
|
||||
import com.intellij.ide.actions.ViewStructureAction
|
||||
import com.intellij.ide.util.FileStructurePopup
|
||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import com.intellij.openapi.ui.Queryable.PrintInfo
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.ui.treeStructure.filtered.FilteringTreeStructure
|
||||
import com.intellij.util.ui.tree.TreeUtil
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.util.configureWithExtraFile
|
||||
import java.io.File
|
||||
|
||||
public abstract class AbstractKotlinFileStructureTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + "/structureView/fileStructure"
|
||||
|
||||
Reference in New Issue
Block a user