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