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