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.CallableDescriptor;
024 import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
025 import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
026 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
027 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028 import org.jetbrains.jet.lang.resolve.OverridingUtil;
029 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
030 import org.jetbrains.jet.lang.types.JetType;
031 import org.jetbrains.jet.lang.types.TypeUtils;
032 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
033 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
034
035 import java.util.List;
036 import java.util.Set;
037
038 public 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 }