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
017package org.jetbrains.jet.lang.resolve;
018
019import com.google.common.collect.BiMap;
020import com.google.common.collect.HashBiMap;
021import com.google.common.collect.Maps;
022import com.google.common.collect.Sets;
023import com.intellij.util.Function;
024import org.jetbrains.annotations.NotNull;
025import org.jetbrains.annotations.Nullable;
026import org.jetbrains.jet.lang.descriptors.*;
027import org.jetbrains.jet.lang.types.*;
028import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
029
030import java.util.*;
031
032public class OverridingUtil {
033
034    private OverridingUtil() {
035    }
036
037    public static <D extends CallableDescriptor> Set<D> filterOverrides(Set<D> candidateSet) {
038        return filterOverrides(candidateSet, Function.ID);
039    }
040
041    public static <D> Set<D> filterOverrides(Set<D> candidateSet, Function<? super D, ? extends CallableDescriptor> transform) {
042        Set<D> candidates = Sets.newLinkedHashSet();
043        outerLoop:
044        for (D meD : candidateSet) {
045            CallableDescriptor me = transform.fun(meD);
046            for (D otherD : candidateSet) {
047                CallableDescriptor other = transform.fun(otherD);
048                if (me == other) continue;
049                if (overrides(other, me)) {
050                    continue outerLoop;
051                }
052            }
053            for (D otherD : candidates) {
054                CallableDescriptor other = transform.fun(otherD);
055                if (me.getOriginal() == other.getOriginal()
056                    && isOverridableBy(other, me).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE
057                    && isOverridableBy(me, other).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE) {
058                    continue outerLoop;
059                }
060            }
061//            System.out.println(me);
062            candidates.add(meD);
063        }
064//        Set<D> candidates = Sets.newLinkedHashSet(candidateSet);
065//        for (D descriptor : candidateSet) {
066//            Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
067//            getAllOverriddenDescriptors(descriptor.getOriginal(), overriddenDescriptors);
068//            candidates.removeAll(overriddenDescriptors);
069//        }
070        return candidates;
071    }
072
073    public static <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
074        Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
075        getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
076        CallableDescriptor originalG = g.getOriginal();
077        for (CallableDescriptor overriddenFunction : overriddenDescriptors) {
078            if (originalG.equals(overriddenFunction.getOriginal())) return true;
079        }
080        return false;
081    }
082
083    private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
084        if (overriddenDescriptors.contains(current)) return;
085        for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
086            getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
087            overriddenDescriptors.add(descriptor);
088        }
089    }
090
091    @NotNull
092    public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
093        if (superDescriptor instanceof FunctionDescriptor) {
094            if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
095        }
096        else if (superDescriptor instanceof PropertyDescriptor) {
097            if (!(subDescriptor instanceof PropertyDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
098        }
099        else {
100            throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
101        }
102
103        // TODO: check outside of this method
104        if (!superDescriptor.getName().equals(subDescriptor.getName())) {
105            return OverrideCompatibilityInfo.nameMismatch();
106        }
107
108        return isOverridableByImpl(superDescriptor, subDescriptor, true);
109    }
110    
111    private static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
112        ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
113        ArrayList<JetType> parameters = new ArrayList<JetType>();
114        if (receiverParameter != null) {
115            parameters.add(receiverParameter.getType());
116        }
117        for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
118            parameters.add(valueParameterDescriptor.getType());
119        }
120        return parameters;
121    }
122
123    /**
124     * @param forOverride true for override, false for overload
125     */
126    static OverrideCompatibilityInfo isOverridableByImpl(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean forOverride) {
127
128        // TODO : Visibility
129
130        if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
131            return OverrideCompatibilityInfo.receiverPresenseMismatch();
132        }
133
134        if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
135            return OverrideCompatibilityInfo.valueParameterNumberMismatch();
136        }
137
138        List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
139        List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
140
141        if (forOverride) {
142            if (superDescriptor.getTypeParameters().size() != subDescriptor.getTypeParameters().size()) {
143                for (int i = 0; i < superValueParameters.size(); ++i) {
144                    JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
145                    JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
146                    // TODO: compare erasure
147                    if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
148                        return OverrideCompatibilityInfo.typeParameterNumberMismatch();
149                    }
150                }
151                return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
152            }
153        }
154
155        if (forOverride) {
156
157            List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
158            List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
159
160            BiMap<TypeConstructor, TypeConstructor> axioms = HashBiMap.create();
161            for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
162                TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
163                TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
164                axioms.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
165            }
166
167            for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
168                TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
169                TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
170
171                if (!JetTypeChecker.INSTANCE.equalTypes(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), axioms)) {
172                    return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
173                }
174            }
175
176            for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
177                JetType superValueParameter = superValueParameters.get(i);
178                JetType subValueParameter = subValueParameters.get(i);
179
180                boolean bothErrors = ErrorUtils.isErrorType(superValueParameter) && ErrorUtils.isErrorType(subValueParameter);
181                if (!bothErrors && !JetTypeChecker.INSTANCE.equalTypes(superValueParameter, subValueParameter, axioms)) {
182                    return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
183                }
184            }
185
186        }
187        else {
188
189            for (int i = 0; i < superValueParameters.size(); ++i) {
190                JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
191                JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
192                // TODO: compare erasure
193                if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
194                    return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
195                }
196            }
197            
198            return OverrideCompatibilityInfo.success();
199
200        }
201
202        // TODO : Default values, varargs etc
203
204        return OverrideCompatibilityInfo.success();
205    }
206    
207    private static JetType getUpperBound(JetType type) {
208        if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
209            return type;
210        }
211        else if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
212            return ((TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor()).getUpperBoundsAsType();
213        }
214        else {
215            throw new IllegalStateException("unknown type constructor: " + type.getConstructor().getClass().getName());
216        }
217    }
218
219    public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
220        TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
221        if (typeSubstitutor == null) return false;
222
223        JetType superReturnType = superDescriptor.getReturnType();
224        assert superReturnType != null;
225
226        JetType subReturnType = subDescriptor.getReturnType();
227        assert subReturnType != null;
228
229        JetType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE);
230        assert substitutedSuperReturnType != null;
231
232        return typeChecker.isSubtypeOf(subReturnType, substitutedSuperReturnType);
233    }
234
235    @Nullable
236    private static TypeSubstitutor prepareTypeSubstitutor(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
237        List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
238        List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
239        if (subTypeParameters.size() != superTypeParameters.size()) return null;
240
241        Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
242        for (int i = 0; i < superTypeParameters.size(); i++) {
243            TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
244            TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
245            substitutionContext.put(
246                    superTypeParameter.getTypeConstructor(),
247                    new TypeProjection(subTypeParameter.getDefaultType()));
248        }
249        return TypeSubstitutor.create(substitutionContext);
250    }
251
252    public static boolean isPropertyTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull PropertyDescriptor superDescriptor, @NotNull PropertyDescriptor subDescriptor) {
253        TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
254        JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
255        assert substitutedSuperReturnType != null;
256        if (superDescriptor.isVar() && !typeChecker.equalTypes(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
257            return false;
258        }
259
260        return true;
261    }
262
263    /**
264     * Get overridden descriptors that are declarations or delegations.
265     *
266     * @see CallableMemberDescriptor.Kind#isReal()
267     */
268    public static Collection<CallableMemberDescriptor> getOverriddenDeclarations(CallableMemberDescriptor descriptor) {
269        Map<ClassDescriptor, CallableMemberDescriptor> result = Maps.newHashMap();
270        getOverriddenDeclarations(descriptor, result);
271        return result.values();
272    }
273
274    private static void getOverriddenDeclarations(CallableMemberDescriptor descriptor, Map<ClassDescriptor, CallableMemberDescriptor> r) {
275        if (descriptor.getKind().isReal()) {
276            r.put((ClassDescriptor) descriptor.getContainingDeclaration(), descriptor);
277        }
278        else {
279            if (descriptor.getOverriddenDescriptors().isEmpty()) {
280                throw new IllegalStateException();
281            }
282            for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
283                getOverriddenDeclarations(overridden, r);
284            }
285        }
286    }
287
288    public static void bindOverride(CallableMemberDescriptor fromCurrent, CallableMemberDescriptor fromSupertype) {
289        fromCurrent.addOverriddenDescriptor(fromSupertype);
290
291        for (ValueParameterDescriptor parameterFromCurrent : fromCurrent.getValueParameters()) {
292            assert parameterFromCurrent.getIndex() < fromSupertype.getValueParameters().size()
293                    : "An override relation between functions implies that they have the same number of value parameters";
294            ValueParameterDescriptor parameterFromSupertype = fromSupertype.getValueParameters().get(parameterFromCurrent.getIndex());
295            parameterFromCurrent.addOverriddenDescriptor(parameterFromSupertype);
296        }
297    }
298
299    public static class OverrideCompatibilityInfo {
300
301        public enum Result {
302            OVERRIDABLE,
303            INCOMPATIBLE,
304            CONFLICT,
305        }
306
307        private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(Result.OVERRIDABLE, "SUCCESS");
308
309        @NotNull
310        public static OverrideCompatibilityInfo success() {
311            return SUCCESS;
312        }
313
314        @NotNull
315        public static OverrideCompatibilityInfo nameMismatch() {
316            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "nameMismatch"); // TODO
317        }
318
319        @NotNull
320        public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
321            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "typeParameterNumberMismatch"); // TODO
322        }
323
324        @NotNull
325        public static OverrideCompatibilityInfo receiverPresenseMismatch() {
326            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "receiverPresenseMismatch"); // TODO
327        }
328
329        @NotNull
330        public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
331            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "valueParameterNumberMismatch"); // TODO
332        }
333
334        @NotNull
335        public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
336            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "boundsMismatch"); // TODO
337        }
338
339        @NotNull
340        public static OverrideCompatibilityInfo valueParameterTypeMismatch(JetType superValueParameter, JetType subValueParameter, Result result) {
341            return new OverrideCompatibilityInfo(result, "valueParameterTypeMismatch"); // TODO
342        }
343
344        @NotNull
345        public static OverrideCompatibilityInfo memberKindMismatch() {
346            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "memberKindMismatch"); // TODO
347        }
348
349        @NotNull
350        public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
351            return new OverrideCompatibilityInfo(Result.CONFLICT, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
352        }
353
354        @NotNull
355        public static OverrideCompatibilityInfo varOverriddenByVal() {
356            return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "varOverriddenByVal"); // TODO
357        }
358
359        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
360
361        private final Result overridable;
362        private final String message;
363
364        public OverrideCompatibilityInfo(Result success, String message) {
365            this.overridable = success;
366            this.message = message;
367        }
368
369        public Result getResult() {
370            return overridable;
371        }
372
373        public String getMessage() {
374            return message;
375        }
376    }
377}