Select most specific overloaded function/property by explicitly used arguments only.

Major rewrite of OverloadingConflictResolver.
This commit is contained in:
Dmitry Petrov
2015-12-15 16:20:09 +03:00
parent 52f0e0bc93
commit 09f53ea0bb
24 changed files with 689 additions and 172 deletions
@@ -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()
@@ -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)
}
}
}
@@ -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>
}
}
@@ -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>();
@@ -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)
@@ -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
}
@@ -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)
@@ -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>
}
@@ -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 = "")
@@ -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
}
@@ -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("")
@@ -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
}
@@ -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)
@@ -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
}
@@ -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 = "")
@@ -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) {
@@ -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() {
@@ -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"