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
017 package org.jetbrains.jet.lang.resolve.calls.results;
018
019 import gnu.trove.THashSet;
020 import gnu.trove.TObjectHashingStrategy;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
025 import org.jetbrains.jet.lang.resolve.OverridingUtil;
026 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
027 import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
028 import org.jetbrains.jet.lang.types.JetType;
029 import org.jetbrains.jet.lang.types.TypeUtils;
030 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
031 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032
033 import java.util.List;
034 import java.util.Set;
035
036 public class OverloadingConflictResolver {
037
038 public static OverloadingConflictResolver INSTANCE = new OverloadingConflictResolver();
039
040 private OverloadingConflictResolver() {}
041
042 @Nullable
043 public <D extends CallableDescriptor> ResolvedCallWithTrace<D> findMaximallySpecific(
044 @NotNull Set<ResolvedCallWithTrace<D>> candidates,
045 boolean discriminateGenericDescriptors
046 ) {
047 // Different autocasts may lead to the same candidate descriptor wrapped into different ResolvedCallImpl objects
048 Set<ResolvedCallWithTrace<D>> maximallySpecific = new THashSet<ResolvedCallWithTrace<D>>(new TObjectHashingStrategy<ResolvedCallWithTrace<D>>() {
049 @Override
050 public boolean equals(ResolvedCallWithTrace<D> o1, ResolvedCallWithTrace<D> o2) {
051 return o1 == null ? o2 == null : o1.getResultingDescriptor().equals(o2.getResultingDescriptor());
052 }
053
054 @Override
055 public int computeHashCode(ResolvedCallWithTrace<D> object) {
056 return object == null ? 0 : object.getResultingDescriptor().hashCode();
057 }
058 });
059 for (ResolvedCallWithTrace<D> candidateCall : candidates) {
060 if (isMaximallySpecific(candidateCall, candidates, discriminateGenericDescriptors)) {
061 maximallySpecific.add(candidateCall);
062 }
063 }
064 return maximallySpecific.size() == 1 ? maximallySpecific.iterator().next() : null;
065 }
066
067 private <D extends CallableDescriptor> boolean isMaximallySpecific(
068 @NotNull ResolvedCallWithTrace<D> candidateCall,
069 @NotNull Set<ResolvedCallWithTrace<D>> candidates,
070 boolean discriminateGenericDescriptors
071 ) {
072 D me = candidateCall.getResultingDescriptor();
073
074 boolean isInvoke = candidateCall instanceof VariableAsFunctionResolvedCall;
075 VariableDescriptor variable;
076 if (isInvoke) {
077 variable = ((VariableAsFunctionResolvedCall) candidateCall).getVariableCall().getResultingDescriptor();
078 }
079 else {
080 variable = null;
081 }
082
083 for (ResolvedCallWithTrace<D> otherCall : candidates) {
084 D other = otherCall.getResultingDescriptor();
085 if (other == me) continue;
086
087 if (definitelyNotMaximallySpecific(me, other, discriminateGenericDescriptors)) {
088
089 if (!isInvoke) return false;
090
091 assert otherCall instanceof VariableAsFunctionResolvedCall : "'invoke' candidate goes with usual one: " + candidateCall + otherCall;
092 ResolvedCallWithTrace<VariableDescriptor> otherVariableCall = ((VariableAsFunctionResolvedCall) otherCall).getVariableCall();
093 if (definitelyNotMaximallySpecific(variable, otherVariableCall.getResultingDescriptor(), discriminateGenericDescriptors)) {
094 return false;
095 }
096 }
097 }
098 return true;
099 }
100
101 private <D extends CallableDescriptor> boolean definitelyNotMaximallySpecific(D me, D other, boolean discriminateGenericDescriptors) {
102 return !moreSpecific(me, other, discriminateGenericDescriptors) || moreSpecific(other, me, discriminateGenericDescriptors);
103 }
104
105 /**
106 * Let < mean "more specific"
107 * Subtype < supertype
108 * Double < Float
109 * Int < Long
110 * Int < Short < Byte
111 */
112 private <Descriptor extends CallableDescriptor> boolean moreSpecific(
113 Descriptor f,
114 Descriptor g,
115 boolean discriminateGenericDescriptors
116 ) {
117 if (f.getContainingDeclaration() instanceof ScriptDescriptor && g.getContainingDeclaration() instanceof ScriptDescriptor) {
118 ScriptDescriptor fs = (ScriptDescriptor) f.getContainingDeclaration();
119 ScriptDescriptor gs = (ScriptDescriptor) g.getContainingDeclaration();
120
121 if (fs.getPriority() != gs.getPriority()) {
122 return fs.getPriority() > gs.getPriority();
123 }
124 }
125
126 boolean isGenericF = isGeneric(f);
127 boolean isGenericG = isGeneric(g);
128 if (discriminateGenericDescriptors) {
129 if (!isGenericF && isGenericG) return true;
130 if (isGenericF && !isGenericG) return false;
131
132 if (isGenericF && isGenericG) {
133 return moreSpecific(DescriptorUtils.substituteBounds(f), DescriptorUtils.substituteBounds(g), false);
134 }
135 }
136
137
138 if (OverridingUtil.overrides(f, g)) return true;
139 if (OverridingUtil.overrides(g, f)) return false;
140
141 ReceiverParameterDescriptor receiverOfF = f.getReceiverParameter();
142 ReceiverParameterDescriptor receiverOfG = g.getReceiverParameter();
143 if (receiverOfF != null && receiverOfG != null) {
144 if (!typeMoreSpecific(receiverOfF.getType(), receiverOfG.getType())) return false;
145 }
146
147 List<ValueParameterDescriptor> fParams = f.getValueParameters();
148 List<ValueParameterDescriptor> gParams = g.getValueParameters();
149
150 int fSize = fParams.size();
151 int gSize = gParams.size();
152
153 boolean fIsVararg = isVariableArity(fParams);
154 boolean gIsVararg = isVariableArity(gParams);
155
156 if (!fIsVararg && gIsVararg) return true;
157 if (fIsVararg && !gIsVararg) return false;
158
159 if (!fIsVararg && !gIsVararg) {
160 if (fSize != gSize) return false;
161
162 for (int i = 0; i < fSize; i++) {
163 ValueParameterDescriptor fParam = fParams.get(i);
164 ValueParameterDescriptor gParam = gParams.get(i);
165
166 JetType fParamType = fParam.getType();
167 JetType gParamType = gParam.getType();
168
169 if (!typeMoreSpecific(fParamType, gParamType)) {
170 return false;
171 }
172 }
173 }
174
175 if (fIsVararg && gIsVararg) {
176 // Check matching parameters
177 int minSize = Math.min(fSize, gSize);
178 for (int i = 0; i < minSize - 1; i++) {
179 ValueParameterDescriptor fParam = fParams.get(i);
180 ValueParameterDescriptor gParam = gParams.get(i);
181
182 JetType fParamType = fParam.getType();
183 JetType gParamType = gParam.getType();
184
185 if (!typeMoreSpecific(fParamType, gParamType)) {
186 return false;
187 }
188 }
189
190 // Check the non-matching parameters of one function against the vararg parameter of the other function
191 // Example:
192 // f(vararg vf : T)
193 // g(a : A, vararg vg : T)
194 // here we check that typeOf(a) < elementTypeOf(vf) and elementTypeOf(vg) < elementTypeOf(vf)
195 if (fSize < gSize) {
196 ValueParameterDescriptor fParam = fParams.get(fSize - 1);
197 JetType fParamType = fParam.getVarargElementType();
198 assert fParamType != null : "fIsVararg guarantees this";
199 for (int i = fSize - 1; i < gSize; i++) {
200 ValueParameterDescriptor gParam = gParams.get(i);
201 if (!typeMoreSpecific(fParamType, getVarargElementTypeOrType(gParam))) {
202 return false;
203 }
204 }
205 }
206 else {
207 ValueParameterDescriptor gParam = gParams.get(gSize - 1);
208 JetType gParamType = gParam.getVarargElementType();
209 assert gParamType != null : "gIsVararg guarantees this";
210 for (int i = gSize - 1; i < fSize; i++) {
211 ValueParameterDescriptor fParam = fParams.get(i);
212 if (!typeMoreSpecific(getVarargElementTypeOrType(fParam), gParamType)) {
213 return false;
214 }
215 }
216 }
217 }
218
219 return true;
220 }
221
222 @NotNull
223 private static JetType getVarargElementTypeOrType(@NotNull ValueParameterDescriptor parameterDescriptor) {
224 JetType varargElementType = parameterDescriptor.getVarargElementType();
225 if (varargElementType != null) {
226 return varargElementType;
227 }
228 return parameterDescriptor.getType();
229 }
230
231 private boolean isVariableArity(List<ValueParameterDescriptor> fParams) {
232 int fSize = fParams.size();
233 return fSize > 0 && fParams.get(fSize - 1).getVarargElementType() != null;
234 }
235
236 private boolean isGeneric(CallableDescriptor f) {
237 return !f.getOriginal().getTypeParameters().isEmpty();
238 }
239
240 private boolean typeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) {
241 return JetTypeChecker.INSTANCE.isSubtypeOf(specific, general) ||
242 numericTypeMoreSpecific(specific, general);
243 }
244
245 private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) {
246 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
247 JetType _double = builtIns.getDoubleType();
248 JetType _float = builtIns.getFloatType();
249 JetType _long = builtIns.getLongType();
250 JetType _int = builtIns.getIntType();
251 JetType _byte = builtIns.getByteType();
252 JetType _short = builtIns.getShortType();
253
254 if (TypeUtils.equalTypes(specific, _double) && TypeUtils.equalTypes(general, _float)) return true;
255 if (TypeUtils.equalTypes(specific, _int)) {
256 if (TypeUtils.equalTypes(general, _long)) return true;
257 if (TypeUtils.equalTypes(general, _byte)) return true;
258 if (TypeUtils.equalTypes(general, _short)) return true;
259 }
260 if (TypeUtils.equalTypes(specific, _short) && TypeUtils.equalTypes(general, _byte)) return true;
261 return false;
262 }
263
264 }