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.collections.CollectionsKt;
020    import kotlin.Unit;
021    import kotlin.jvm.functions.Function1;
022    import org.jetbrains.annotations.Mutable;
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.types.FlexibleTypesKt;
031    import org.jetbrains.kotlin.types.KotlinType;
032    import org.jetbrains.kotlin.types.TypeConstructor;
033    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
034    
035    import java.util.*;
036    
037    import static org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.*;
038    
039    public class OverridingUtil {
040    
041        private static final List<ExternalOverridabilityCondition> EXTERNAL_CONDITIONS =
042                CollectionsKt.toList(ServiceLoader.load(
043                        ExternalOverridabilityCondition.class,
044                        ExternalOverridabilityCondition.class.getClassLoader()
045                ));
046    
047        public static final OverridingUtil DEFAULT = new OverridingUtil(new KotlinTypeChecker.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 KotlinTypeChecker.TypeConstructorEquality equalityAxioms) {
056            return new OverridingUtil(equalityAxioms);
057        }
058    
059        private final KotlinTypeChecker.TypeConstructorEquality equalityAxioms;
060    
061        private OverridingUtil(KotlinTypeChecker.TypeConstructorEquality axioms) {
062            equalityAxioms = axioms;
063        }
064    
065        @NotNull
066        public OverrideCompatibilityInfo isOverridableBy(
067                @NotNull CallableDescriptor superDescriptor,
068                @NotNull CallableDescriptor subDescriptor,
069                @Nullable ClassDescriptor subClassDescriptor
070        ) {
071            return isOverridableBy(superDescriptor, subDescriptor, subClassDescriptor, false);
072        }
073    
074        @NotNull
075        public OverrideCompatibilityInfo isOverridableByIncludingReturnType(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
076            return isOverridableBy(superDescriptor, subDescriptor, null, true);
077        }
078    
079        @NotNull
080        private OverrideCompatibilityInfo isOverridableBy(
081                @NotNull CallableDescriptor superDescriptor,
082                @NotNull CallableDescriptor subDescriptor,
083                @Nullable ClassDescriptor subClassDescriptor,
084                boolean checkReturnType
085        ) {
086            boolean wasSuccessfulExternalCondition = false;
087            for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
088                ExternalOverridabilityCondition.Result result =
089                        externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor);
090                switch (result) {
091                    case OVERRIDABLE:
092                        wasSuccessfulExternalCondition = true;
093                        break;
094                    case CONFLICT:
095                        return OverrideCompatibilityInfo.conflict("External condition failed");
096                    case INCOMPATIBLE:
097                        return OverrideCompatibilityInfo.incompatible("External condition");
098                    case UNKNOWN:
099                        // do nothing
100                        // go to the next external condition or default override check
101                }
102            }
103    
104            if (wasSuccessfulExternalCondition) {
105                return OverrideCompatibilityInfo.success();
106            }
107    
108            return isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType);
109        }
110    
111        @NotNull
112        public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions(
113                @NotNull CallableDescriptor superDescriptor,
114                @NotNull CallableDescriptor subDescriptor,
115                boolean checkReturnType
116        ) {
117            if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) ||
118                superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) {
119                return OverrideCompatibilityInfo.incompatible("Member kind mismatch");
120            }
121    
122            if (!(superDescriptor instanceof FunctionDescriptor) && !(superDescriptor instanceof PropertyDescriptor)) {
123                throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
124            }
125    
126            // TODO: check outside of this method
127            if (!superDescriptor.getName().equals(subDescriptor.getName())) {
128                return OverrideCompatibilityInfo.incompatible("Name mismatch");
129            }
130    
131            OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor);
132            if (receiverAndParameterResult != null) {
133                return receiverAndParameterResult;
134            }
135    
136            List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor);
137            List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor);
138    
139            List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
140            List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
141    
142            if (superTypeParameters.size() != subTypeParameters.size()) {
143                for (int i = 0; i < superValueParameters.size(); ++i) {
144                    // TODO: compare erasure
145                    if (!KotlinTypeChecker.DEFAULT.equalTypes(superValueParameters.get(i), subValueParameters.get(i))) {
146                        return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch");
147                    }
148                }
149                return OverrideCompatibilityInfo.conflict("Type parameter number mismatch");
150            }
151    
152            KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters);
153    
154            for (int i = 0; i < superTypeParameters.size(); i++) {
155                if (!areTypeParametersEquivalent(superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) {
156                    return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch");
157                }
158            }
159    
160            for (int i = 0; i < superValueParameters.size(); i++) {
161                if (!areTypesEquivalent(superValueParameters.get(i), subValueParameters.get(i), typeChecker)) {
162                    return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch");
163                }
164            }
165    
166            if (checkReturnType) {
167                KotlinType superReturnType = superDescriptor.getReturnType();
168                KotlinType subReturnType = subDescriptor.getReturnType();
169    
170                if (superReturnType != null && subReturnType != null) {
171                    boolean bothErrors = subReturnType.isError() && superReturnType.isError();
172                    if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) {
173                        return OverrideCompatibilityInfo.conflict("Return type mismatch");
174                    }
175                }
176            }
177    
178            return OverrideCompatibilityInfo.success();
179        }
180    
181        @NotNull
182        private KotlinTypeChecker createTypeChecker(
183                @NotNull List<TypeParameterDescriptor> firstParameters,
184                @NotNull List<TypeParameterDescriptor> secondParameters
185        ) {
186            assert firstParameters.size() == secondParameters.size() :
187                    "Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters;
188            if (firstParameters.isEmpty()) return KotlinTypeChecker.withAxioms(equalityAxioms);
189    
190            final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
191            for (int i = 0; i < firstParameters.size(); i++) {
192                matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor());
193            }
194    
195            return KotlinTypeChecker.withAxioms(new KotlinTypeChecker.TypeConstructorEquality() {
196                @Override
197                public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
198                    if (equalityAxioms.equals(a, b)) return true;
199                    TypeConstructor img1 = matchingTypeConstructors.get(a);
200                    TypeConstructor img2 = matchingTypeConstructors.get(b);
201                    return (img1 != null && img1.equals(b)) || (img2 != null && img2.equals(a));
202                }
203            });
204        }
205    
206        @Nullable
207        static OverrideCompatibilityInfo checkReceiverAndParameterCount(
208                CallableDescriptor superDescriptor,
209                CallableDescriptor subDescriptor
210        ) {
211            if ((superDescriptor.getExtensionReceiverParameter() == null) != (subDescriptor.getExtensionReceiverParameter() == null)) {
212                return OverrideCompatibilityInfo.incompatible("Receiver presence mismatch");
213            }
214    
215            if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
216                return OverrideCompatibilityInfo.incompatible("Value parameter number mismatch");
217            }
218    
219            return null;
220        }
221    
222        private static boolean areTypesEquivalent(
223                @NotNull KotlinType typeInSuper,
224                @NotNull KotlinType typeInSub,
225                @NotNull KotlinTypeChecker typeChecker
226        ) {
227            boolean bothErrors = typeInSuper.isError() && typeInSub.isError();
228            return bothErrors || typeChecker.equalTypes(typeInSuper, typeInSub);
229        }
230    
231        // See JLS 8, 8.4.4 Generic Methods
232        // TODO: use TypeSubstitutor instead
233        private static boolean areTypeParametersEquivalent(
234                @NotNull TypeParameterDescriptor superTypeParameter,
235                @NotNull TypeParameterDescriptor subTypeParameter,
236                @NotNull KotlinTypeChecker typeChecker
237        ) {
238            List<KotlinType> superBounds = superTypeParameter.getUpperBounds();
239            List<KotlinType> subBounds = new ArrayList<KotlinType>(subTypeParameter.getUpperBounds());
240            if (superBounds.size() != subBounds.size()) return false;
241    
242            outer:
243            for (KotlinType superBound : superBounds) {
244                ListIterator<KotlinType> it = subBounds.listIterator();
245                while (it.hasNext()) {
246                    KotlinType subBound = it.next();
247                    if (areTypesEquivalent(superBound, subBound, typeChecker)) {
248                        it.remove();
249                        continue outer;
250                    }
251                }
252                return false;
253            }
254    
255            return true;
256        }
257    
258        static List<KotlinType> compiledValueParameters(CallableDescriptor callableDescriptor) {
259            ReceiverParameterDescriptor receiverParameter = callableDescriptor.getExtensionReceiverParameter();
260            List<KotlinType> parameters = new ArrayList<KotlinType>();
261            if (receiverParameter != null) {
262                parameters.add(receiverParameter.getType());
263            }
264            for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
265                parameters.add(valueParameterDescriptor.getType());
266            }
267            return parameters;
268        }
269    
270        public static void generateOverridesInFunctionGroup(
271                @SuppressWarnings("UnusedParameters")
272                @NotNull Name name, //DO NOT DELETE THIS PARAMETER: needed to make sure all descriptors have the same name
273                @NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes,
274                @NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent,
275                @NotNull ClassDescriptor current,
276                @NotNull DescriptorSink sink
277        ) {
278            Collection<CallableMemberDescriptor> notOverridden = new LinkedHashSet<CallableMemberDescriptor>(membersFromSupertypes);
279    
280            for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
281                Collection<CallableMemberDescriptor> bound =
282                        extractAndBindOverridesForMember(fromCurrent, membersFromSupertypes, current, sink);
283                notOverridden.removeAll(bound);
284            }
285    
286            createAndBindFakeOverrides(current, notOverridden, sink);
287        }
288    
289        private static Collection<CallableMemberDescriptor> extractAndBindOverridesForMember(
290                @NotNull CallableMemberDescriptor fromCurrent,
291                @NotNull Collection<? extends CallableMemberDescriptor> descriptorsFromSuper,
292                @NotNull ClassDescriptor current,
293                @NotNull DescriptorSink sink
294        ) {
295            Collection<CallableMemberDescriptor> bound = new ArrayList<CallableMemberDescriptor>(descriptorsFromSuper.size());
296            for (CallableMemberDescriptor fromSupertype : descriptorsFromSuper) {
297                OverrideCompatibilityInfo.Result result = DEFAULT.isOverridableBy(fromSupertype, fromCurrent, current).getResult();
298    
299                boolean isVisible = Visibilities.isVisibleWithIrrelevantReceiver(fromSupertype, current);
300                switch (result) {
301                    case OVERRIDABLE:
302                        if (isVisible) {
303                            fromCurrent.addOverriddenDescriptor(fromSupertype);
304                        }
305                        bound.add(fromSupertype);
306                        break;
307                    case CONFLICT:
308                        if (isVisible) {
309                            sink.conflict(fromSupertype, fromCurrent);
310                        }
311                        bound.add(fromSupertype);
312                        break;
313                    case INCOMPATIBLE:
314                        break;
315                }
316            }
317            return bound;
318        }
319    
320        private static void createAndBindFakeOverrides(
321                @NotNull ClassDescriptor current,
322                @NotNull Collection<CallableMemberDescriptor> notOverridden,
323                @NotNull DescriptorSink sink
324        ) {
325            Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
326            while (!fromSuperQueue.isEmpty()) {
327                CallableMemberDescriptor notOverriddenFromSuper = VisibilityUtilKt.findMemberWithMaxVisibility(fromSuperQueue);
328                Collection<CallableMemberDescriptor> overridables =
329                        extractMembersOverridableInBothWays(notOverriddenFromSuper, fromSuperQueue, sink);
330                createAndBindFakeOverride(overridables, current, sink);
331            }
332        }
333    
334        public static boolean isMoreSpecific(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) {
335            KotlinType aReturnType = a.getReturnType();
336            KotlinType bReturnType = b.getReturnType();
337    
338            assert aReturnType != null : "Return type of " + a + " is null";
339            assert bReturnType != null : "Return type of " + b + " is null";
340    
341            if (!isVisibilityMoreSpecific(a, b)) return false;
342    
343            if (a instanceof SimpleFunctionDescriptor) {
344                assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
345    
346                return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
347            }
348            if (a instanceof PropertyDescriptor) {
349                assert b instanceof PropertyDescriptor : "b is " + b.getClass();
350    
351                PropertyDescriptor pa = (PropertyDescriptor) a;
352                PropertyDescriptor pb = (PropertyDescriptor) b;
353    
354                if (!isAccessorMoreSpecific(pa.getSetter(), pb.getSetter())) return false;
355    
356                if (pa.isVar() && pb.isVar()) {
357                    return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType);
358                }
359                else {
360                    // both vals or var vs val: val can't be more specific then var
361                    return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
362                }
363            }
364            throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
365        }
366    
367        private static boolean isVisibilityMoreSpecific(
368                @NotNull DeclarationDescriptorWithVisibility a,
369                @NotNull DeclarationDescriptorWithVisibility b
370        ) {
371            Integer result = Visibilities.compare(a.getVisibility(), b.getVisibility());
372            return result == null || result >= 0;
373        }
374    
375        private static boolean isAccessorMoreSpecific(@Nullable PropertyAccessorDescriptor a, @Nullable PropertyAccessorDescriptor b) {
376            if (a == null || b == null) return true;
377            return isVisibilityMoreSpecific(a, b);
378        }
379    
380        private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection<CallableDescriptor> descriptors) {
381            // NB subtyping relation in Kotlin is not transitive in presence of flexible types:
382            //  String? <: String! <: String, but not String? <: String
383            for (CallableDescriptor descriptor : descriptors) {
384                if (!isMoreSpecific(candidate, descriptor)) {
385                    return false;
386                }
387            }
388            return true;
389        }
390    
391        private static boolean isReturnTypeMoreSpecific(
392                @NotNull CallableDescriptor a,
393                @NotNull KotlinType aReturnType,
394                @NotNull CallableDescriptor b,
395                @NotNull KotlinType bReturnType
396        ) {
397            KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
398            return typeChecker.isSubtypeOf(aReturnType, bReturnType);
399        }
400    
401        @NotNull
402        public static <H> H selectMostSpecificMember(
403                @NotNull Collection<H> overridables,
404                @NotNull Function1<H, CallableDescriptor> descriptorByHandle
405        ) {
406            assert !overridables.isEmpty() : "Should have at least one overridable descriptor";
407    
408            if (overridables.size() == 1) {
409                return CollectionsKt.first(overridables);
410            }
411    
412            Collection<H> candidates = new ArrayList<H>(2);
413            List<CallableDescriptor> callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle);
414    
415            H transitivelyMostSpecific = CollectionsKt.first(overridables);
416            CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific);
417    
418            for (H overridable : overridables) {
419                CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
420                if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
421                    candidates.add(overridable);
422                }
423                if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
424                    && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
425                    transitivelyMostSpecific = overridable;
426                }
427            }
428    
429            if (candidates.isEmpty()) {
430                return transitivelyMostSpecific;
431            }
432            else if (candidates.size() == 1) {
433                return CollectionsKt.first(candidates);
434            }
435    
436            H firstNonFlexible = null;
437            for (H candidate : candidates) {
438                if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
439                    firstNonFlexible = candidate;
440                    break;
441                }
442            }
443            if (firstNonFlexible != null) {
444                return firstNonFlexible;
445            }
446    
447            return CollectionsKt.first(candidates);
448        }
449    
450        private static void createAndBindFakeOverride(
451                @NotNull Collection<CallableMemberDescriptor> overridables,
452                @NotNull ClassDescriptor current,
453                @NotNull DescriptorSink sink
454        ) {
455            Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
456            boolean allInvisible = visibleOverridables.isEmpty();
457            Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
458    
459            // FIXME doesn't work as expected for flexible types: should create a refined signature.
460            // Current algorithm produces bad results in presence of annotated Java signatures such as:
461            //      J: foo(s: String!): String -- @NotNull String foo(String s);
462            //      K: foo(s: String): String?
463            //  --> 'foo(s: String!): String' as an inherited signature with most specific return type.
464            // This is bad because it can be overridden by 'foo(s: String?): String', which is not override-equivalent with K::foo above.
465            // Should be 'foo(s: String): String'.
466            Modality modality = getMinimalModality(effectiveOverridden);
467            Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
468            CallableMemberDescriptor mostSpecific =
469                    selectMostSpecificMember(effectiveOverridden,
470                                             new Function1<CallableMemberDescriptor, CallableDescriptor>() {
471                                                  @Override
472                                                  public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
473                                                      return descriptor;
474                                                  }
475                                             });
476            CallableMemberDescriptor fakeOverride =
477                    mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
478            for (CallableMemberDescriptor descriptor : effectiveOverridden) {
479                fakeOverride.addOverriddenDescriptor(descriptor);
480            }
481            sink.addFakeOverride(fakeOverride);
482        }
483    
484        @NotNull
485        private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
486            Modality modality = Modality.ABSTRACT;
487            for (CallableMemberDescriptor descriptor : descriptors) {
488                if (descriptor.getModality().compareTo(modality) < 0) {
489                    modality = descriptor.getModality();
490                }
491            }
492            return modality;
493        }
494    
495        @NotNull
496        private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
497                @NotNull final ClassDescriptor current,
498                @NotNull Collection<CallableMemberDescriptor> toFilter
499        ) {
500            return CollectionsKt.filter(toFilter, new Function1<CallableMemberDescriptor, Boolean>() {
501                @Override
502                public Boolean invoke(CallableMemberDescriptor descriptor) {
503                    //nested class could capture private member, so check for private visibility added
504                    return !Visibilities.isPrivate(descriptor.getVisibility()) &&
505                           Visibilities.isVisibleWithIrrelevantReceiver(descriptor, current);
506                }
507            });
508        }
509    
510        /**
511         * @param <H> is something that handles CallableDescriptor inside
512         * @return
513         */
514        @NotNull
515        public static <H> Collection<H> extractMembersOverridableInBothWays(
516                @NotNull H overrider,
517                @NotNull @Mutable Collection<H> extractFrom,
518                @NotNull Function1<H, CallableDescriptor> descriptorByHandle,
519                @NotNull Function1<H, Unit> onConflict
520        ) {
521            Collection<H> overridable = new ArrayList<H>();
522            overridable.add(overrider);
523            CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider);
524            for (Iterator<H> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
525                H candidate = iterator.next();
526                CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate);
527                if (overrider == candidate) {
528                    iterator.remove();
529                    continue;
530                }
531    
532                OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor);
533    
534                if (finalResult == OVERRIDABLE) {
535                    overridable.add(candidate);
536                    iterator.remove();
537                }
538                else if (finalResult == CONFLICT) {
539                    onConflict.invoke(candidate);
540                    iterator.remove();
541                }
542            }
543            return overridable;
544        }
545    
546        @Nullable
547        public static OverrideCompatibilityInfo.Result getBothWaysOverridability(
548                CallableDescriptor overriderDescriptor,
549                CallableDescriptor candidateDescriptor
550        ) {
551            OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult();
552            OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult();
553    
554            return result1 == OVERRIDABLE && result2 == OVERRIDABLE
555                   ? OVERRIDABLE
556                   : ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE);
557        }
558    
559        @NotNull
560        private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
561                @NotNull final CallableMemberDescriptor overrider,
562                @NotNull Queue<CallableMemberDescriptor> extractFrom,
563                @NotNull final DescriptorSink sink
564        ) {
565            return extractMembersOverridableInBothWays(overrider, extractFrom,
566                    // ID
567                    new Function1<CallableMemberDescriptor, CallableDescriptor>() {
568                        @Override
569                        public CallableDescriptor invoke(CallableMemberDescriptor descriptor) {
570                            return descriptor;
571                        }
572                    },
573                    new Function1<CallableMemberDescriptor, Unit>() {
574                        @Override
575                        public Unit invoke(CallableMemberDescriptor descriptor) {
576                            sink.conflict(overrider, descriptor);
577                            return Unit.INSTANCE;
578                        }
579                    });
580        }
581    
582    
583        public static void resolveUnknownVisibilityForMember(
584                @NotNull CallableMemberDescriptor memberDescriptor,
585                @Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
586        ) {
587            for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
588                if (descriptor.getVisibility() == Visibilities.INHERITED) {
589                    resolveUnknownVisibilityForMember(descriptor, cannotInferVisibility);
590                }
591            }
592    
593            if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
594                return;
595            }
596    
597            Visibility maxVisibility = computeVisibilityToInherit(memberDescriptor);
598            Visibility visibilityToInherit;
599            if (maxVisibility == null) {
600                if (cannotInferVisibility != null) {
601                    cannotInferVisibility.invoke(memberDescriptor);
602                }
603                visibilityToInherit = Visibilities.PUBLIC;
604            }
605            else {
606                visibilityToInherit = maxVisibility;
607            }
608    
609            if (memberDescriptor instanceof PropertyDescriptorImpl) {
610                ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
611                for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
612                    // If we couldn't infer visibility for property, the diagnostic is already reported, no need to report it again on accessors
613                    resolveUnknownVisibilityForMember(accessor, maxVisibility == null ? null : cannotInferVisibility);
614                }
615            }
616            else if (memberDescriptor instanceof FunctionDescriptorImpl) {
617                ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
618            }
619            else {
620                assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
621                ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
622            }
623        }
624    
625        @Nullable
626        private static Visibility computeVisibilityToInherit(@NotNull CallableMemberDescriptor memberDescriptor) {
627            Collection<? extends CallableMemberDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
628            Visibility maxVisibility = findMaxVisibility(overriddenDescriptors);
629            if (maxVisibility == null) {
630                return null;
631            }
632            if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
633                for (CallableMemberDescriptor overridden : overriddenDescriptors) {
634                    // An implementation (a non-abstract overridden member) of a fake override should have the maximum possible visibility
635                    if (overridden.getModality() != Modality.ABSTRACT && !overridden.getVisibility().equals(maxVisibility)) {
636                        return null;
637                    }
638                }
639                return maxVisibility;
640            }
641            return maxVisibility.normalize();
642        }
643    
644        @Nullable
645        public static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
646            if (descriptors.isEmpty()) {
647                return Visibilities.DEFAULT_VISIBILITY;
648            }
649            Visibility maxVisibility = null;
650            for (CallableMemberDescriptor descriptor : descriptors) {
651                Visibility visibility = descriptor.getVisibility();
652                assert visibility != Visibilities.INHERITED : "Visibility should have been computed for " + descriptor;
653                if (maxVisibility == null) {
654                    maxVisibility = visibility;
655                    continue;
656                }
657                Integer compareResult = Visibilities.compare(visibility, maxVisibility);
658                if (compareResult == null) {
659                    maxVisibility = null;
660                }
661                else if (compareResult > 0) {
662                    maxVisibility = visibility;
663                }
664            }
665            if (maxVisibility == null) {
666                return null;
667            }
668            for (CallableMemberDescriptor descriptor : descriptors) {
669                Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
670                if (compareResult == null || compareResult < 0) {
671                    return null;
672                }
673            }
674            return maxVisibility;
675        }
676    
677        public interface DescriptorSink {
678            void addFakeOverride(@NotNull CallableMemberDescriptor fakeOverride);
679    
680            void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent);
681        }
682    
683        public static class OverrideCompatibilityInfo {
684            public enum Result {
685                OVERRIDABLE,
686                INCOMPATIBLE,
687                CONFLICT,
688            }
689    
690            private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(OVERRIDABLE, "SUCCESS");
691    
692            @NotNull
693            public static OverrideCompatibilityInfo success() {
694                return SUCCESS;
695            }
696    
697            @NotNull
698            public static OverrideCompatibilityInfo incompatible(@NotNull String debugMessage) {
699                return new OverrideCompatibilityInfo(INCOMPATIBLE, debugMessage);
700            }
701    
702            @NotNull
703            public static OverrideCompatibilityInfo conflict(@NotNull String debugMessage) {
704                return new OverrideCompatibilityInfo(CONFLICT, debugMessage);
705            }
706    
707            private final Result overridable;
708            private final String debugMessage;
709    
710            public OverrideCompatibilityInfo(@NotNull Result success, @NotNull String debugMessage) {
711                this.overridable = success;
712                this.debugMessage = debugMessage;
713            }
714    
715            @NotNull
716            public Result getResult() {
717                return overridable;
718            }
719    
720            @NotNull
721            public String getDebugMessage() {
722                return debugMessage;
723            }
724        }
725    }