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