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;
018    
019    import kotlin.Function1;
020    import kotlin.KotlinPackage;
021    import kotlin.Unit;
022    import kotlin.jvm.KotlinSignature;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.descriptors.*;
026    import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl;
027    import org.jetbrains.kotlin.descriptors.impl.PropertyAccessorDescriptorImpl;
028    import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl;
029    import org.jetbrains.kotlin.name.Name;
030    import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
031    import org.jetbrains.kotlin.types.JetType;
032    import org.jetbrains.kotlin.types.TypeConstructor;
033    import org.jetbrains.kotlin.types.checker.JetTypeChecker;
034    import org.jetbrains.kotlin.utils.DFS;
035    
036    import java.util.*;
037    
038    import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*;
039    
040    public class OverridingUtil {
041    
042        private static final List<ExternalOverridabilityCondition> EXTERNAL_CONDITIONS =
043                KotlinPackage.toList(ServiceLoader.load(
044                        ExternalOverridabilityCondition.class,
045                        ExternalOverridabilityCondition.class.getClassLoader()
046                ));
047    
048        public static final OverridingUtil DEFAULT = new OverridingUtil(new JetTypeChecker.TypeConstructorEquality() {
049            @Override
050            public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
051                return a.equals(b);
052            }
053        });
054    
055        @NotNull
056        public static OverridingUtil createWithEqualityAxioms(@NotNull JetTypeChecker.TypeConstructorEquality equalityAxioms) {
057            return new OverridingUtil(equalityAxioms);
058        }
059    
060        private final JetTypeChecker.TypeConstructorEquality equalityAxioms;
061    
062        private OverridingUtil(JetTypeChecker.TypeConstructorEquality axioms) {
063            equalityAxioms = axioms;
064        }
065    
066        @NotNull
067        public OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
068            return isOverridableBy(superDescriptor, subDescriptor, false);
069        }
070    
071        @NotNull
072        public OverrideCompatibilityInfo isOverridableByIncludingReturnType(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
073            return isOverridableBy(superDescriptor, subDescriptor, true);
074        }
075    
076        @NotNull
077        private OverrideCompatibilityInfo isOverridableBy(
078                @NotNull CallableDescriptor superDescriptor,
079                @NotNull CallableDescriptor subDescriptor,
080                boolean checkReturnType
081        ) {
082            if (superDescriptor instanceof FunctionDescriptor) {
083                if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
084            }
085            else if (superDescriptor instanceof PropertyDescriptor) {
086                if (!(subDescriptor instanceof PropertyDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
087            }
088            else {
089                throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
090            }
091    
092            // TODO: check outside of this method
093            if (!superDescriptor.getName().equals(subDescriptor.getName())) {
094                return OverrideCompatibilityInfo.nameMismatch();
095            }
096    
097            OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor);
098            if (receiverAndParameterResult != null) {
099                return receiverAndParameterResult;
100            }
101    
102            List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
103            List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
104    
105            List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
106            List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
107    
108            if (superTypeParameters.size() != subTypeParameters.size()) {
109                for (int i = 0; i < superValueParameters.size(); ++i) {
110                    JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
111                    JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
112                    // TODO: compare erasure
113                    if (!JetTypeChecker.DEFAULT.equalTypes(superValueParameterType, subValueParameterType)) {
114                        return OverrideCompatibilityInfo.typeParameterNumberMismatch();
115                    }
116                }
117                return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
118            }
119    
120            final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
121            for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
122                TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
123                TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
124                matchingTypeConstructors.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
125            }
126    
127            JetTypeChecker.TypeConstructorEquality localEqualityAxioms = new JetTypeChecker.TypeConstructorEquality() {
128                @Override
129                public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
130                    if (equalityAxioms.equals(a, b)) return true;
131                    TypeConstructor img1 = matchingTypeConstructors.get(a);
132                    TypeConstructor img2 = matchingTypeConstructors.get(b);
133                    if (!(img1 != null && img1.equals(b)) &&
134                        !(img2 != null && img2.equals(a))) {
135                        return false;
136                    }
137                    return true;
138                }
139            };
140    
141            for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
142                TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
143                TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
144    
145                if (!areTypesEquivalent(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), localEqualityAxioms)) {
146                    return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
147                }
148            }
149    
150            for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
151                JetType superValueParameter = superValueParameters.get(i);
152                JetType subValueParameter = subValueParameters.get(i);
153    
154                if (!areTypesEquivalent(superValueParameter, subValueParameter, localEqualityAxioms)) {
155                    return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, INCOMPATIBLE);
156                }
157            }
158    
159            if (checkReturnType) {
160                JetType superReturnType = superDescriptor.getReturnType();
161                JetType subReturnType = subDescriptor.getReturnType();
162    
163                if (superReturnType != null && subReturnType != null) {
164                    boolean bothErrors = subReturnType.isError() && superReturnType.isError();
165                    if (!bothErrors && !JetTypeChecker.withAxioms(localEqualityAxioms).isSubtypeOf(subReturnType, superReturnType)) {
166                        return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType);
167                    }
168                }
169            }
170    
171    
172            for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
173                if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
174                    return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
175                }
176            }
177    
178            return OverrideCompatibilityInfo.success();
179        }
180    
181        @Nullable
182        static OverrideCompatibilityInfo checkReceiverAndParameterCount(
183                CallableDescriptor superDescriptor,
184                CallableDescriptor subDescriptor
185        ) {
186            if ((superDescriptor.getExtensionReceiverParameter() == null) != (subDescriptor.getExtensionReceiverParameter() == null)) {
187                return OverrideCompatibilityInfo.receiverPresenceMismatch();
188            }
189    
190            if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
191                return OverrideCompatibilityInfo.valueParameterNumberMismatch();
192            }
193    
194            return null;
195        }
196    
197        private static boolean areTypesEquivalent(
198                @NotNull JetType typeInSuper,
199                @NotNull JetType typeInSub,
200                @NotNull JetTypeChecker.TypeConstructorEquality axioms
201        ) {
202            boolean bothErrors = typeInSuper.isError() && typeInSub.isError();
203            if (!bothErrors && !JetTypeChecker.withAxioms(axioms).equalTypes(typeInSuper, typeInSub)) {
204                return false;
205            }
206            return true;
207        }
208    
209        static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
210            ReceiverParameterDescriptor receiverParameter = callableDescriptor.getExtensionReceiverParameter();
211            ArrayList<JetType> parameters = new ArrayList<JetType>();
212            if (receiverParameter != null) {
213                parameters.add(receiverParameter.getType());
214            }
215            for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
216                parameters.add(valueParameterDescriptor.getType());
217            }
218            return parameters;
219        }
220    
221        static JetType getUpperBound(JetType type) {
222            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
223                return type;
224            }
225            else if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
226                return ((TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor()).getUpperBoundsAsType();
227            }
228            else {
229                throw new IllegalStateException("unknown type constructor: " + type.getConstructor().getClass().getName());
230            }
231        }
232    
233        public static void bindOverride(CallableMemberDescriptor fromCurrent, CallableMemberDescriptor fromSupertype) {
234            fromCurrent.addOverriddenDescriptor(fromSupertype);
235    
236            for (ValueParameterDescriptor parameterFromCurrent : fromCurrent.getValueParameters()) {
237                assert parameterFromCurrent.getIndex() < fromSupertype.getValueParameters().size()
238                        : "An override relation between functions implies that they have the same number of value parameters";
239                ValueParameterDescriptor parameterFromSupertype = fromSupertype.getValueParameters().get(parameterFromCurrent.getIndex());
240                parameterFromCurrent.addOverriddenDescriptor(parameterFromSupertype);
241            }
242        }
243    
244        public static void generateOverridesInFunctionGroup(
245                @SuppressWarnings("UnusedParameters")
246                @NotNull Name name, //DO NOT DELETE THIS PARAMETER: needed to make sure all descriptors have the same name
247                @NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes,
248                @NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent,
249                @NotNull ClassDescriptor current,
250                @NotNull DescriptorSink sink
251        ) {
252            Collection<CallableMemberDescriptor> notOverridden = new LinkedHashSet<CallableMemberDescriptor>(membersFromSupertypes);
253    
254            for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
255                Collection<CallableMemberDescriptor> bound =
256                        extractAndBindOverridesForMember(fromCurrent, membersFromSupertypes, current, sink);
257                notOverridden.removeAll(bound);
258            }
259    
260            createAndBindFakeOverrides(current, notOverridden, sink);
261        }
262    
263        private static Collection<CallableMemberDescriptor> extractAndBindOverridesForMember(
264                @NotNull CallableMemberDescriptor fromCurrent,
265                @NotNull Collection<? extends CallableMemberDescriptor> descriptorsFromSuper,
266                @NotNull ClassDescriptor current,
267                @NotNull DescriptorSink sink
268        ) {
269            Collection<CallableMemberDescriptor> bound = new ArrayList<CallableMemberDescriptor>(descriptorsFromSuper.size());
270            for (CallableMemberDescriptor fromSupertype : descriptorsFromSuper) {
271                OverrideCompatibilityInfo.Result result = DEFAULT.isOverridableBy(fromSupertype, fromCurrent).getResult();
272    
273                boolean isVisible = Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, fromSupertype, current);
274                switch (result) {
275                    case OVERRIDABLE:
276                        if (isVisible) {
277                            bindOverride(fromCurrent, fromSupertype);
278                        }
279                        bound.add(fromSupertype);
280                        break;
281                    case CONFLICT:
282                        if (isVisible) {
283                            sink.conflict(fromSupertype, fromCurrent);
284                        }
285                        bound.add(fromSupertype);
286                        break;
287                    case INCOMPATIBLE:
288                        break;
289                }
290            }
291            return bound;
292        }
293    
294        private static void createAndBindFakeOverrides(
295                @NotNull ClassDescriptor current,
296                @NotNull Collection<CallableMemberDescriptor> notOverridden,
297                @NotNull DescriptorSink sink
298        ) {
299            Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
300            while (!fromSuperQueue.isEmpty()) {
301                CallableMemberDescriptor notOverriddenFromSuper = VisibilityUtil.findMemberWithMaxVisibility(fromSuperQueue);
302                Collection<CallableMemberDescriptor> overridables =
303                        extractMembersOverridableInBothWays(notOverriddenFromSuper, fromSuperQueue, sink);
304                createAndBindFakeOverride(overridables, current, sink);
305            }
306        }
307    
308        private static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) {
309            if (a instanceof SimpleFunctionDescriptor) {
310                assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
311    
312                JetType aReturnType = a.getReturnType();
313                assert aReturnType != null;
314                JetType bReturnType = b.getReturnType();
315                assert bReturnType != null;
316    
317                return JetTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType);
318            }
319            if (a instanceof PropertyDescriptor) {
320                assert b instanceof PropertyDescriptor : "b is " + b.getClass();
321    
322                if (((PropertyDescriptor) a).isVar() || ((PropertyDescriptor) b).isVar()) {
323                    return ((PropertyDescriptor) a).isVar();
324                }
325    
326                // both vals
327                return JetTypeChecker.DEFAULT.isSubtypeOf(((PropertyDescriptor) a).getType(), ((PropertyDescriptor) b).getType());
328            }
329            throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
330        }
331    
332        private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection<CallableMemberDescriptor> overridables) {
333            CallableMemberDescriptor result = null;
334            for (CallableMemberDescriptor overridable : overridables) {
335                if (result == null || isMoreSpecific(overridable, result)) {
336                    result = overridable;
337                }
338            }
339            return result;
340        }
341    
342        private static void createAndBindFakeOverride(
343                @NotNull Collection<CallableMemberDescriptor> overridables,
344                @NotNull ClassDescriptor current,
345                @NotNull DescriptorSink sink
346        ) {
347            Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
348            boolean allInvisible = visibleOverridables.isEmpty();
349            Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
350    
351            Modality modality = getMinimalModality(effectiveOverridden);
352            Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
353            CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
354            CallableMemberDescriptor fakeOverride =
355                    mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
356            for (CallableMemberDescriptor descriptor : effectiveOverridden) {
357                bindOverride(fakeOverride, descriptor);
358            }
359            sink.addToScope(fakeOverride);
360        }
361    
362        @NotNull
363        private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
364            Modality modality = Modality.ABSTRACT;
365            for (CallableMemberDescriptor descriptor : descriptors) {
366                if (descriptor.getModality().compareTo(modality) < 0) {
367                    modality = descriptor.getModality();
368                }
369            }
370            return modality;
371        }
372    
373        @NotNull
374        private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
375                @NotNull final ClassDescriptor current,
376                @NotNull Collection<CallableMemberDescriptor> toFilter
377        ) {
378            return KotlinPackage.filter(toFilter, new Function1<CallableMemberDescriptor, Boolean>() {
379                @Override
380                public Boolean invoke(CallableMemberDescriptor descriptor) {
381                    //nested class could capture private member, so check for private visibility added
382                    return !Visibilities.isPrivate(descriptor.getVisibility()) &&
383                           Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, current);
384                }
385            });
386        }
387    
388        @NotNull
389        private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
390                @NotNull CallableMemberDescriptor overrider,
391                @NotNull Queue<CallableMemberDescriptor> extractFrom,
392                @NotNull DescriptorSink sink
393        ) {
394            Collection<CallableMemberDescriptor> overridable = new ArrayList<CallableMemberDescriptor>();
395            overridable.add(overrider);
396            for (Iterator<CallableMemberDescriptor> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
397                CallableMemberDescriptor candidate = iterator.next();
398                if (overrider == candidate) {
399                    iterator.remove();
400                    continue;
401                }
402    
403                OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidate, overrider).getResult();
404                OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overrider, candidate).getResult();
405                if (result1 == OVERRIDABLE && result2 == OVERRIDABLE) {
406                    overridable.add(candidate);
407                    iterator.remove();
408                }
409                else if (result1 == CONFLICT || result2 == CONFLICT) {
410                    sink.conflict(overrider, candidate);
411                    iterator.remove();
412                }
413            }
414            return overridable;
415        }
416    
417        public static void resolveUnknownVisibilityForMember(
418                @NotNull CallableMemberDescriptor memberDescriptor,
419                @Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
420        ) {
421            for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
422                if (descriptor.getVisibility() == Visibilities.INHERITED) {
423                    resolveUnknownVisibilityForMember(descriptor, cannotInferVisibility);
424                }
425            }
426    
427            if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
428                return;
429            }
430    
431            Visibility maxVisibility = computeVisibilityToInherit(memberDescriptor);
432            Visibility visibilityToInherit;
433            if (maxVisibility == null) {
434                if (cannotInferVisibility != null) {
435                    cannotInferVisibility.invoke(memberDescriptor);
436                }
437                visibilityToInherit = Visibilities.PUBLIC;
438            }
439            else {
440                visibilityToInherit = maxVisibility;
441            }
442    
443            if (memberDescriptor instanceof PropertyDescriptorImpl) {
444                ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
445                for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
446                    // If we couldn't infer visibility for property, the diagnostic is already reported, no need to report it again on accessors
447                    resolveUnknownVisibilityForMember(accessor, maxVisibility == null ? null : cannotInferVisibility);
448                }
449            }
450            else if (memberDescriptor instanceof FunctionDescriptorImpl) {
451                ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
452            }
453            else {
454                assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
455                ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
456            }
457        }
458    
459        @Nullable
460        private static Visibility computeVisibilityToInherit(@NotNull CallableMemberDescriptor memberDescriptor) {
461            Set<? extends CallableMemberDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
462            Visibility maxVisibility = findMaxVisibility(overriddenDescriptors);
463            if (maxVisibility == null) {
464                return null;
465            }
466            if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
467                for (CallableMemberDescriptor overridden : overriddenDescriptors) {
468                    // An implementation (a non-abstract overridden member) of a fake override should have the maximum possible visibility
469                    if (overridden.getModality() != Modality.ABSTRACT && !overridden.getVisibility().equals(maxVisibility)) {
470                        return null;
471                    }
472                }
473                return maxVisibility;
474            }
475            return maxVisibility.normalize();
476        }
477    
478        @Nullable
479        private static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
480            if (descriptors.isEmpty()) {
481                return Visibilities.INTERNAL;
482            }
483            Visibility maxVisibility = null;
484            for (CallableMemberDescriptor descriptor : descriptors) {
485                Visibility visibility = descriptor.getVisibility();
486                assert visibility != Visibilities.INHERITED : "Visibility should have been computed for " + descriptor;
487                if (maxVisibility == null) {
488                    maxVisibility = visibility;
489                    continue;
490                }
491                Integer compareResult = Visibilities.compare(visibility, maxVisibility);
492                if (compareResult == null) {
493                    maxVisibility = null;
494                }
495                else if (compareResult > 0) {
496                    maxVisibility = visibility;
497                }
498            }
499            // TODO: IDEA seems to issue an incorrect warning here
500            //noinspection ConstantConditions
501            if (maxVisibility == null) {
502                return null;
503            }
504            for (CallableMemberDescriptor descriptor : descriptors) {
505                Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
506                if (compareResult == null || compareResult < 0) {
507                    return null;
508                }
509            }
510            return maxVisibility;
511        }
512    
513    
514        @NotNull
515        @KotlinSignature("fun getTopmostOverridenDescriptors(originalDescriptor: CallableDescriptor): List<out CallableDescriptor>")
516        public static List<? extends CallableDescriptor> getTopmostOverridenDescriptors(@NotNull CallableDescriptor originalDescriptor) {
517            return DFS.dfs(
518                    Collections.singletonList(originalDescriptor),
519                    new DFS.Neighbors<CallableDescriptor>() {
520                        @NotNull
521                        @Override
522                        public Iterable<? extends CallableDescriptor> getNeighbors(CallableDescriptor current) {
523                            return current.getOverriddenDescriptors();
524                        }
525                    },
526                    new DFS.CollectingNodeHandler<CallableDescriptor, CallableDescriptor, ArrayList<CallableDescriptor>>(
527                            new ArrayList<CallableDescriptor>()
528                    ) {
529                        @Override
530                        public void afterChildren(CallableDescriptor current) {
531                            if (current.getOverriddenDescriptors().isEmpty()) {
532                                result.add(current);
533                            }
534                        }
535                    }
536            );
537        }
538    
539        public static boolean traverseOverridenDescriptors(
540                @NotNull CallableDescriptor originalDescriptor,
541                @NotNull final Function1<CallableDescriptor, Boolean> handler
542        ) {
543            return DFS.dfs(
544                    Collections.singletonList(originalDescriptor),
545                    new DFS.Neighbors<CallableDescriptor>() {
546                        @NotNull
547                        @Override
548                        public Iterable<? extends CallableDescriptor> getNeighbors(CallableDescriptor current) {
549                            return current.getOverriddenDescriptors();
550                        }
551                    },
552                    new DFS.AbstractNodeHandler<CallableDescriptor, Boolean>() {
553                        private boolean result = true;
554    
555                        @Override
556                        public boolean beforeChildren(CallableDescriptor current) {
557                            if (!handler.invoke(current)) {
558                                result = false;
559                            }
560                            return result;
561                        }
562    
563                        @Override
564                        public Boolean result() {
565                            return result;
566                        }
567                    }
568            );
569        }
570    
571        public interface DescriptorSink {
572            void addToScope(@NotNull CallableMemberDescriptor fakeOverride);
573    
574            void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent);
575        }
576    
577        public static class OverrideCompatibilityInfo {
578    
579            public enum Result {
580                OVERRIDABLE,
581                INCOMPATIBLE,
582                CONFLICT,
583            }
584    
585            private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(Result.OVERRIDABLE, "SUCCESS");
586    
587            @NotNull
588            public static OverrideCompatibilityInfo success() {
589                return SUCCESS;
590            }
591    
592            @NotNull
593            public static OverrideCompatibilityInfo nameMismatch() {
594                return new OverrideCompatibilityInfo(INCOMPATIBLE, "nameMismatch"); // TODO
595            }
596    
597            @NotNull
598            public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
599                return new OverrideCompatibilityInfo(INCOMPATIBLE, "typeParameterNumberMismatch"); // TODO
600            }
601    
602            @NotNull
603            public static OverrideCompatibilityInfo receiverPresenceMismatch() {
604                return new OverrideCompatibilityInfo(INCOMPATIBLE, "receiverPresenceMismatch"); // TODO
605            }
606    
607            @NotNull
608            public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
609                return new OverrideCompatibilityInfo(INCOMPATIBLE, "valueParameterNumberMismatch"); // TODO
610            }
611    
612            @NotNull
613            public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
614                return new OverrideCompatibilityInfo(INCOMPATIBLE, "boundsMismatch"); // TODO
615            }
616    
617            @NotNull
618            public static OverrideCompatibilityInfo valueParameterTypeMismatch(JetType superValueParameter, JetType subValueParameter, Result result) {
619                return new OverrideCompatibilityInfo(result, "valueParameterTypeMismatch"); // TODO
620            }
621    
622            @NotNull
623            public static OverrideCompatibilityInfo memberKindMismatch() {
624                return new OverrideCompatibilityInfo(INCOMPATIBLE, "memberKindMismatch"); // TODO
625            }
626    
627            @NotNull
628            public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
629                return new OverrideCompatibilityInfo(Result.CONFLICT, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
630            }
631    
632            @NotNull
633            public static OverrideCompatibilityInfo varOverriddenByVal() {
634                return new OverrideCompatibilityInfo(INCOMPATIBLE, "varOverriddenByVal"); // TODO
635            }
636    
637            @NotNull
638            public static OverrideCompatibilityInfo externalConditionFailed(Class<? extends ExternalOverridabilityCondition> conditionClass) {
639                return new OverrideCompatibilityInfo(INCOMPATIBLE, "externalConditionFailed: " + conditionClass.getName()); // TODO
640            }
641    
642            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
643    
644            private final Result overridable;
645            private final String message;
646    
647            public OverrideCompatibilityInfo(Result success, String message) {
648                this.overridable = success;
649                this.message = message;
650            }
651    
652            public Result getResult() {
653                return overridable;
654            }
655    
656            public String getMessage() {
657                return message;
658            }
659        }
660    }