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