J2K: OverloadingConflictResolver.kt - convert to Kotlin

This commit is contained in:
Dmitry Petrov
2015-12-11 14:41:43 +03:00
parent ca6153e8f1
commit 52f0e0bc93
@@ -14,102 +14,82 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.resolve.calls.results; package org.jetbrains.kotlin.resolve.calls.results
import gnu.trove.THashSet; import gnu.trove.THashSet
import gnu.trove.TObjectHashingStrategy; import gnu.trove.TObjectHashingStrategy
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.OverrideResolver; import org.jetbrains.kotlin.resolve.OverrideResolver
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode; import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import java.util.List; class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
import java.util.Set;
public class OverloadingConflictResolver { fun <D : CallableDescriptor> findMaximallySpecific(
candidates: Set<MutableResolvedCall<D>>,
private final KotlinBuiltIns builtIns; discriminateGenericDescriptors: Boolean,
checkArgumentsMode: CheckArgumentTypesMode
public OverloadingConflictResolver(@NotNull KotlinBuiltIns builtIns) { ): MutableResolvedCall<D>? {
this.builtIns = builtIns;
}
@Nullable
public <D extends CallableDescriptor> MutableResolvedCall<D> findMaximallySpecific(
@NotNull Set<MutableResolvedCall<D>> candidates,
boolean discriminateGenericDescriptors,
@NotNull CheckArgumentTypesMode checkArgumentsMode
) {
// Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects // Different smartcasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
Set<MutableResolvedCall<D>> maximallySpecific = new THashSet<MutableResolvedCall<D>>(new TObjectHashingStrategy<MutableResolvedCall<D>>() {
@Override val maximallySpecific = THashSet(object : TObjectHashingStrategy<MutableResolvedCall<D>> {
public boolean equals(MutableResolvedCall<D> o1, MutableResolvedCall<D> o2) { override fun equals(call1: MutableResolvedCall<D>?, call2: MutableResolvedCall<D>?): Boolean =
return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor()); if (call1 == null) call2 == null
} else call1.resultingDescriptor == call2!!.resultingDescriptor
@Override override fun computeHashCode(call: MutableResolvedCall<D>?): Int =
public int computeHashCode(MutableResolvedCall<D> object) { call?.resultingDescriptor?.hashCode() ?: 0
return object == null ? 0 : object.getResultingDescriptor().hashCode(); })
}
}); candidates.filterTo(maximallySpecific) {
for (MutableResolvedCall<D> candidateCall : candidates) { isMaximallySpecific(it, candidates, discriminateGenericDescriptors, checkArgumentsMode)
if (isMaximallySpecific(candidateCall, candidates, discriminateGenericDescriptors, checkArgumentsMode)) {
maximallySpecific.add(candidateCall);
}
} }
return maximallySpecific.size() == 1 ? maximallySpecific.iterator().next() : null;
return if (maximallySpecific.size == 1) maximallySpecific.first() else null
} }
private <D extends CallableDescriptor> boolean isMaximallySpecific( private fun <D : CallableDescriptor> isMaximallySpecific(
@NotNull MutableResolvedCall<D> candidateCall, candidateCall: MutableResolvedCall<D>,
@NotNull Set<MutableResolvedCall<D>> candidates, candidates: Set<MutableResolvedCall<D>>,
boolean discriminateGenericDescriptors, discriminateGenericDescriptors: Boolean,
@NotNull CheckArgumentTypesMode checkArgumentsMode checkArgumentsMode: CheckArgumentTypesMode): Boolean {
) { val me = candidateCall.resultingDescriptor
D me = candidateCall.getResultingDescriptor();
boolean isInvoke = candidateCall instanceof VariableAsFunctionResolvedCall; val isInvoke = candidateCall is VariableAsFunctionResolvedCall
VariableDescriptor variable; val variable = (candidateCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
if (isInvoke) {
variable = ((VariableAsFunctionResolvedCall) candidateCall).getVariableCall().getResultingDescriptor();
}
else {
variable = null;
}
for (MutableResolvedCall<D> otherCall : candidates) { for (otherCall in candidates) {
D other = otherCall.getResultingDescriptor(); val other = otherCall.resultingDescriptor
if (other == me) continue; if (other === me) continue
if (definitelyNotMaximallySpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode)) { if (definitelyNotMaximallySpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode)) {
if (!isInvoke) return false
if (!isInvoke) return false; assert(otherCall is VariableAsFunctionResolvedCall) { "'invoke' candidate goes with usual one: " + candidateCall + otherCall }
assert otherCall instanceof VariableAsFunctionResolvedCall : "'invoke' candidate goes with usual one: " + candidateCall + otherCall; val otherVariableCall = (otherCall as VariableAsFunctionResolvedCall).variableCall
ResolvedCall<VariableDescriptor> otherVariableCall = ((VariableAsFunctionResolvedCall) otherCall).getVariableCall(); if (definitelyNotMaximallySpecific(variable!!, otherVariableCall.resultingDescriptor, discriminateGenericDescriptors, checkArgumentsMode)) {
if (definitelyNotMaximallySpecific(variable, otherVariableCall.getResultingDescriptor(), discriminateGenericDescriptors, checkArgumentsMode)) { return false
return false;
} }
} }
} }
return true;
return true
} }
private <D extends CallableDescriptor> boolean definitelyNotMaximallySpecific( private fun <D : CallableDescriptor> definitelyNotMaximallySpecific(
D me, me: D,
D other, other: D,
boolean discriminateGenericDescriptors, discriminateGenericDescriptors: Boolean,
@NotNull CheckArgumentTypesMode checkArgumentsMode checkArgumentsMode: CheckArgumentTypesMode): Boolean {
) {
return !moreSpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode) || return !moreSpecific(me, other, discriminateGenericDescriptors, checkArgumentsMode) ||
moreSpecific(other, me, discriminateGenericDescriptors, checkArgumentsMode); moreSpecific(other, me, discriminateGenericDescriptors, checkArgumentsMode)
} }
/** /**
@@ -119,85 +99,86 @@ public class OverloadingConflictResolver {
* Int < Long * Int < Long
* Int < Short < Byte * Int < Short < Byte
*/ */
private <Descriptor extends CallableDescriptor> boolean moreSpecific( private fun <Descriptor : CallableDescriptor> moreSpecific(
Descriptor f, f: Descriptor,
Descriptor g, g: Descriptor,
boolean discriminateGenericDescriptors, discriminateGenericDescriptors: Boolean,
@NotNull CheckArgumentTypesMode checkArgumentsMode checkArgumentsMode: CheckArgumentTypesMode): Boolean {
) { val resolvingCallableReference = checkArgumentsMode == CheckArgumentTypesMode.CHECK_CALLABLE_TYPE
boolean resolvingCallableReference = checkArgumentsMode == CheckArgumentTypesMode.CHECK_CALLABLE_TYPE;
if (f.getContainingDeclaration() instanceof ScriptDescriptor && g.getContainingDeclaration() instanceof ScriptDescriptor) { if (f.containingDeclaration is ScriptDescriptor && g.containingDeclaration is ScriptDescriptor) {
ScriptDescriptor fs = (ScriptDescriptor) f.getContainingDeclaration(); val fs = f.containingDeclaration as ScriptDescriptor
ScriptDescriptor gs = (ScriptDescriptor) g.getContainingDeclaration(); val gs = g.containingDeclaration as ScriptDescriptor
if (fs.getPriority() != gs.getPriority()) { if (fs.priority != gs.priority) {
return fs.getPriority() > gs.getPriority(); return fs.priority > gs.priority
} }
} }
boolean isGenericF = isGeneric(f); val isGenericF = isGeneric(f)
boolean isGenericG = isGeneric(g); val isGenericG = isGeneric(g)
if (discriminateGenericDescriptors) { if (discriminateGenericDescriptors) {
if (!isGenericF && isGenericG) return true; if (!isGenericF && isGenericG) return true
if (isGenericF && !isGenericG) return false; if (isGenericF && !isGenericG) return false
if (isGenericF && isGenericG) { if (isGenericF && isGenericG) {
return moreSpecific(BoundsSubstitutor.substituteBounds(f), BoundsSubstitutor.substituteBounds(g), false, checkArgumentsMode); return moreSpecific(BoundsSubstitutor.substituteBounds(f),
BoundsSubstitutor.substituteBounds(g),
false, checkArgumentsMode)
} }
} }
if (OverrideResolver.overrides(f, g)) return true; if (OverrideResolver.overrides(f, g)) return true
if (OverrideResolver.overrides(g, f)) return false; if (OverrideResolver.overrides(g, f)) return false
ReceiverParameterDescriptor receiverOfF = f.getExtensionReceiverParameter(); val receiverOfF = f.extensionReceiverParameter
ReceiverParameterDescriptor receiverOfG = g.getExtensionReceiverParameter(); val receiverOfG = g.extensionReceiverParameter
if (receiverOfF != null && receiverOfG != null) { if (receiverOfF != null && receiverOfG != null) {
if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false; if (!typeMoreSpecific(receiverOfF.type, receiverOfG.type)) return false
} }
List<ValueParameterDescriptor> fParams = f.getValueParameters(); val fParams = f.valueParameters
List<ValueParameterDescriptor> gParams = g.getValueParameters(); val gParams = g.valueParameters
int fSize = fParams.size(); val fSize = fParams.size
int gSize = gParams.size(); val gSize = gParams.size
boolean fIsVararg = isVariableArity(fParams); val fIsVararg = isVariableArity(fParams)
boolean gIsVararg = isVariableArity(gParams); val gIsVararg = isVariableArity(gParams)
if (resolvingCallableReference && fIsVararg != gIsVararg) return false; if (resolvingCallableReference && fIsVararg != gIsVararg) return false
if (!fIsVararg && gIsVararg) return true; if (!fIsVararg && gIsVararg) return true
if (fIsVararg && !gIsVararg) return false; if (fIsVararg && !gIsVararg) return false
if (!fIsVararg && !gIsVararg) { if (!fIsVararg && !gIsVararg) {
if (resolvingCallableReference && fSize != gSize) return false; if (resolvingCallableReference && fSize != gSize) return false
if (!resolvingCallableReference && fSize > gSize) return false; if (!resolvingCallableReference && fSize > gSize) return false
for (int i = 0; i < fSize; i++) { for (i in 0..fSize - 1) {
ValueParameterDescriptor fParam = fParams.get(i); val fParam = fParams[i]
ValueParameterDescriptor gParam = gParams.get(i); val gParam = gParams[i]
KotlinType fParamType = fParam.getType(); val fParamType = fParam.type
KotlinType gParamType = gParam.getType(); val gParamType = gParam.type
if (!typeMoreSpecific(fParamType, gParamType)) { if (!typeMoreSpecific(fParamType, gParamType)) {
return false; return false
} }
} }
} }
if (fIsVararg && gIsVararg) { if (fIsVararg && gIsVararg) {
// Check matching parameters // Check matching parameters
int minSize = Math.min(fSize, gSize); val minSize = Math.min(fSize, gSize)
for (int i = 0; i < minSize - 1; i++) { for (i in 0..minSize - 1 - 1) {
ValueParameterDescriptor fParam = fParams.get(i); val fParam = fParams[i]
ValueParameterDescriptor gParam = gParams.get(i); val gParam = gParams[i]
KotlinType fParamType = fParam.getType(); val fParamType = fParam.type
KotlinType gParamType = gParam.getType(); val gParamType = gParam.type
if (!typeMoreSpecific(fParamType, gParamType)) { if (!typeMoreSpecific(fParamType, gParamType)) {
return false; return false
} }
} }
@@ -207,81 +188,77 @@ public class OverloadingConflictResolver {
// g(a : A, vararg vg : T) // g(a : A, vararg vg : T)
// here we check that typeOf(a) < elementTypeOf(vf) and elementTypeOf(vg) < elementTypeOf(vf) // here we check that typeOf(a) < elementTypeOf(vf) and elementTypeOf(vg) < elementTypeOf(vf)
if (fSize < gSize) { if (fSize < gSize) {
ValueParameterDescriptor fParam = fParams.get(fSize - 1); val fParam = fParams[fSize - 1]
KotlinType fParamType = fParam.getVarargElementType(); val fParamType = fParam.varargElementType
assert fParamType != null : "fIsVararg guarantees this"; assert(fParamType != null) { "fIsVararg guarantees this" }
for (int i = fSize - 1; i < gSize; i++) { for (i in fSize - 1..gSize - 1) {
ValueParameterDescriptor gParam = gParams.get(i); val gParam = gParams[i]
if (!typeMoreSpecific(fParamType, getVarargElementTypeOrType(gParam))) { if (!typeMoreSpecific(fParamType!!, getVarargElementTypeOrType(gParam))) {
return false; return false
} }
} }
} }
else { else {
ValueParameterDescriptor gParam = gParams.get(gSize - 1); val gParam = gParams[gSize - 1]
KotlinType gParamType = gParam.getVarargElementType(); val gParamType = gParam.varargElementType
assert gParamType != null : "gIsVararg guarantees this"; assert(gParamType != null) { "gIsVararg guarantees this" }
for (int i = gSize - 1; i < fSize; i++) { for (i in gSize - 1..fSize - 1) {
ValueParameterDescriptor fParam = fParams.get(i); val fParam = fParams[i]
if (!typeMoreSpecific(getVarargElementTypeOrType(fParam), gParamType)) { if (!typeMoreSpecific(getVarargElementTypeOrType(fParam), gParamType!!)) {
return false; return false
} }
} }
} }
} }
return true; return true
} }
@NotNull private fun getVarargElementTypeOrType(parameterDescriptor: ValueParameterDescriptor): KotlinType =
private static KotlinType getVarargElementTypeOrType(@NotNull ValueParameterDescriptor parameterDescriptor) { parameterDescriptor.varargElementType ?: parameterDescriptor.type
KotlinType varargElementType = parameterDescriptor.getVarargElementType();
if (varargElementType != null) {
return varargElementType;
}
return parameterDescriptor.getType();
}
private static boolean isVariableArity(List<ValueParameterDescriptor> fParams) { private fun isVariableArity(fParams: List<ValueParameterDescriptor>): Boolean =
int fSize = fParams.size(); fParams.lastOrNull()?.varargElementType != null
return fSize > 0 && fParams.get(fSize - 1).getVarargElementType() != null;
}
private static boolean isGeneric(CallableDescriptor f) { private fun isGeneric(f: CallableDescriptor): Boolean =
return !f.getOriginal().getTypeParameters().isEmpty(); f.original.typeParameters.isNotEmpty()
}
private boolean typeMoreSpecific(@NotNull KotlinType specific, @NotNull KotlinType general) { private fun typeMoreSpecific(specific: KotlinType, general: KotlinType): Boolean {
boolean isSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(specific, general) || val isSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(specific, general) || numericTypeMoreSpecific(specific, general)
numericTypeMoreSpecific(specific, general);
if (!isSubtype) return false; if (!isSubtype) return false
Specificity.Relation sThanG = TypeCapabilitiesKt.getSpecificityRelationTo(specific, general); val sThanG = specific.getSpecificityRelationTo(general)
Specificity.Relation gThanS = TypeCapabilitiesKt.getSpecificityRelationTo(general, specific); val gThanS = general.getSpecificityRelationTo(specific)
if (sThanG == Specificity.Relation.LESS_SPECIFIC && gThanS != Specificity.Relation.LESS_SPECIFIC) { if (sThanG === Specificity.Relation.LESS_SPECIFIC &&
return false; gThanS !== Specificity.Relation.LESS_SPECIFIC) {
return false
} }
return true; return true
} }
private boolean numericTypeMoreSpecific(@NotNull KotlinType specific, @NotNull KotlinType general) { private fun numericTypeMoreSpecific(specific: KotlinType, general: KotlinType): Boolean {
KotlinType _double = builtIns.getDoubleType(); val _double = builtIns.doubleType
KotlinType _float = builtIns.getFloatType(); val _float = builtIns.floatType
KotlinType _long = builtIns.getLongType(); val _long = builtIns.longType
KotlinType _int = builtIns.getIntType(); val _int = builtIns.intType
KotlinType _byte = builtIns.getByteType(); val _byte = builtIns.byteType
KotlinType _short = builtIns.getShortType(); val _short = builtIns.shortType
if (TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float)) return true; when {
if (TypeUtils.equalTypes(specific, _int)) { TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float) -> return true
if (TypeUtils.equalTypes(general, _long)) return true; TypeUtils.equalTypes(specific, _int) -> {
if (TypeUtils.equalTypes(general, _byte)) return true; when {
if (TypeUtils.equalTypes(general, _short)) return true; TypeUtils.equalTypes(general, _long) -> return true
TypeUtils.equalTypes(general, _byte) -> return true
TypeUtils.equalTypes(general, _short) -> return true
}
}
TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte) -> return true
} }
if (TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte)) return true;
return false; return false
} }
} }