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