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