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