001/* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.jetbrains.jet.lang.resolve.calls.results; 018 019import gnu.trove.THashSet; 020import gnu.trove.TObjectHashingStrategy; 021import org.jetbrains.annotations.NotNull; 022import org.jetbrains.annotations.Nullable; 023import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 024import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; 025import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; 026import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 027import org.jetbrains.jet.lang.resolve.DescriptorUtils; 028import org.jetbrains.jet.lang.resolve.OverridingUtil; 029import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; 030import org.jetbrains.jet.lang.types.JetType; 031import org.jetbrains.jet.lang.types.TypeUtils; 032import org.jetbrains.jet.lang.types.checker.JetTypeChecker; 033import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 034 035import java.util.List; 036import java.util.Set; 037 038public class OverloadingConflictResolver { 039 040 public static OverloadingConflictResolver INSTANCE = new OverloadingConflictResolver(); 041 042 private OverloadingConflictResolver() {} 043 044 @Nullable 045 public <D extends CallableDescriptor> ResolvedCallWithTrace<D> findMaximallySpecific( 046 @NotNull Set<ResolvedCallWithTrace<D>> candidates, 047 boolean discriminateGenericDescriptors 048 ) { 049 // Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects 050 Set<ResolvedCallWithTrace<D>> maximallySpecific = new THashSet<ResolvedCallWithTrace<D>>(new TObjectHashingStrategy<ResolvedCallWithTrace<D>>() { 051 @Override 052 public boolean equals(ResolvedCallWithTrace<D> o1, ResolvedCallWithTrace<D> o2) { 053 return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor()); 054 } 055 056 @Override 057 public int computeHashCode(ResolvedCallWithTrace<D> object) { 058 return object == null ? 0 : object.getResultingDescriptor().hashCode(); 059 } 060 }); 061 meLoop: 062 for (ResolvedCallWithTrace<D> candidateCall : candidates) { 063 D me = candidateCall.getResultingDescriptor(); 064 for (ResolvedCallWithTrace<D> otherCall : candidates) { 065 D other = otherCall.getResultingDescriptor(); 066 if (other == me) continue; 067 if (!moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors)) { 068 continue meLoop; 069 } 070 } 071 maximallySpecific.add(candidateCall); 072 } 073 return maximallySpecific.size() == 1 ? maximallySpecific.iterator().next() : null; 074 } 075 076 /** 077 * Let < mean "more specific" 078 * Subtype < supertype 079 * Double < Float 080 * Int < Long 081 * Int < Short < Byte 082 */ 083 private <Descriptor extends CallableDescriptor> boolean moreSpecific( 084 Descriptor f, 085 Descriptor g, 086 boolean discriminateGenericDescriptors 087 ) { 088 if (f.getContainingDeclaration() instanceof ScriptDescriptor && g.getContainingDeclaration() instanceof ScriptDescriptor) { 089 ScriptDescriptor fs = (ScriptDescriptor) f.getContainingDeclaration(); 090 ScriptDescriptor gs = (ScriptDescriptor) g.getContainingDeclaration(); 091 092 if (fs.getPriority() != gs.getPriority()) { 093 return fs.getPriority() > gs.getPriority(); 094 } 095 } 096 097 boolean isGenericF = isGeneric(f); 098 boolean isGenericG = isGeneric(g); 099 if (discriminateGenericDescriptors) { 100 if (!isGenericF && isGenericG) return true; 101 if (isGenericF && !isGenericG) return false; 102 103 if (isGenericF && isGenericG) { 104 return moreSpecific(DescriptorUtils.substituteBounds(f), DescriptorUtils.substituteBounds(g), false); 105 } 106 } 107 108 109 if (OverridingUtil.overrides(f, g)) return true; 110 if (OverridingUtil.overrides(g, f)) return false; 111 112 ReceiverParameterDescriptor receiverOfF = f.getReceiverParameter(); 113 ReceiverParameterDescriptor receiverOfG = g.getReceiverParameter(); 114 if (receiverOfF != null && receiverOfG != null) { 115 if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false; 116 } 117 118 List<ValueParameterDescriptor> fParams = f.getValueParameters(); 119 List<ValueParameterDescriptor> gParams = g.getValueParameters(); 120 121 int fSize = fParams.size(); 122 int gSize = gParams.size(); 123 124 boolean fIsVararg = isVariableArity(fParams); 125 boolean gIsVararg = isVariableArity(gParams); 126 127 if (!fIsVararg && gIsVararg) return true; 128 if (fIsVararg && !gIsVararg) return false; 129 130 if (!fIsVararg && !gIsVararg) { 131 if (fSize != gSize) return false; 132 133 for (int i = 0; i < fSize; i++) { 134 ValueParameterDescriptor fParam = fParams.get(i); 135 ValueParameterDescriptor gParam = gParams.get(i); 136 137 JetType fParamType = fParam.getType(); 138 JetType gParamType = gParam.getType(); 139 140 if (!typeMoreSpecific(fParamType, gParamType)) { 141 return false; 142 } 143 } 144 } 145 146 if (fIsVararg && gIsVararg) { 147 // Check matching parameters 148 int minSize = Math.min(fSize, gSize); 149 for (int i = 0; i < minSize - 1; i++) { 150 ValueParameterDescriptor fParam = fParams.get(i); 151 ValueParameterDescriptor gParam = gParams.get(i); 152 153 JetType fParamType = fParam.getType(); 154 JetType gParamType = gParam.getType(); 155 156 if (!typeMoreSpecific(fParamType, gParamType)) { 157 return false; 158 } 159 } 160 161 // Check the non-matching parameters of one function against the vararg parameter of the other function 162 // Example: 163 // f(vararg vf : T) 164 // g(a : A, vararg vg : T) 165 // here we check that typeOf(a) < elementTypeOf(vf) and elementTypeOf(vg) < elementTypeOf(vf) 166 if (fSize < gSize) { 167 ValueParameterDescriptor fParam = fParams.get(fSize - 1); 168 JetType fParamType = fParam.getVarargElementType(); 169 assert fParamType != null : "fIsVararg guarantees this"; 170 for (int i = fSize - 1; i < gSize; i++) { 171 ValueParameterDescriptor gParam = gParams.get(i); 172 if (!typeMoreSpecific(fParamType, getVarargElementTypeOrType(gParam))) { 173 return false; 174 } 175 } 176 } 177 else { 178 ValueParameterDescriptor gParam = gParams.get(gSize - 1); 179 JetType gParamType = gParam.getVarargElementType(); 180 assert gParamType != null : "gIsVararg guarantees this"; 181 for (int i = gSize - 1; i < fSize; i++) { 182 ValueParameterDescriptor fParam = fParams.get(i); 183 if (!typeMoreSpecific(getVarargElementTypeOrType(fParam), gParamType)) { 184 return false; 185 } 186 } 187 } 188 } 189 190 return true; 191 } 192 193 @NotNull 194 private static JetType getVarargElementTypeOrType(@NotNull ValueParameterDescriptor parameterDescriptor) { 195 JetType varargElementType = parameterDescriptor.getVarargElementType(); 196 if (varargElementType != null) { 197 return varargElementType; 198 } 199 return parameterDescriptor.getType(); 200 } 201 202 private boolean isVariableArity(List<ValueParameterDescriptor> fParams) { 203 int fSize = fParams.size(); 204 return fSize > 0 && fParams.get(fSize - 1).getVarargElementType() != null; 205 } 206 207 private boolean isGeneric(CallableDescriptor f) { 208 return !f.getOriginal().getTypeParameters().isEmpty(); 209 } 210 211 private boolean typeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { 212 return JetTypeChecker.INSTANCE.isSubtypeOf(specific, general) || 213 numericTypeMoreSpecific(specific, general); 214 } 215 216 private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) { 217 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); 218 JetType _double = builtIns.getDoubleType(); 219 JetType _float = builtIns.getFloatType(); 220 JetType _long = builtIns.getLongType(); 221 JetType _int = builtIns.getIntType(); 222 JetType _byte = builtIns.getByteType(); 223 JetType _short = builtIns.getShortType(); 224 225 if (TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float)) return true; 226 if (TypeUtils.equalTypes(specific, _int)) { 227 if (TypeUtils.equalTypes(general, _long)) return true; 228 if (TypeUtils.equalTypes(general, _byte)) return true; 229 if (TypeUtils.equalTypes(general, _short)) return true; 230 } 231 if (TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte)) return true; 232 return false; 233 } 234 235}