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.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 (a instanceof SimpleFunctionDescriptor) {
342                assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
343    
344                return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
345            }
346            if (a instanceof PropertyDescriptor) {
347                assert b instanceof PropertyDescriptor : "b is " + b.getClass();
348    
349                PropertyDescriptor pa = (PropertyDescriptor) a;
350                PropertyDescriptor pb = (PropertyDescriptor) b;
351                if (pa.isVar() && pb.isVar()) {
352                    return DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters()).equalTypes(aReturnType, bReturnType);
353                }
354                else {
355                    // both vals or var vs val: val can't be more specific then var
356                    return !(!pa.isVar() && pb.isVar()) && isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType);
357                }
358            }
359            throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
360        }
361    
362        private static boolean isMoreSpecificThenAllOf(@NotNull CallableDescriptor candidate, @NotNull Collection<CallableDescriptor> descriptors) {
363            // NB subtyping relation in Kotlin is not transitive in presence of flexible types:
364            //  String? <: String! <: String, but not String? <: String
365            for (CallableDescriptor descriptor : descriptors) {
366                if (!isMoreSpecific(candidate, descriptor)) {
367                    return false;
368                }
369            }
370            return true;
371        }
372    
373        private static boolean isReturnTypeMoreSpecific(
374                @NotNull CallableDescriptor a,
375                @NotNull KotlinType aReturnType,
376                @NotNull CallableDescriptor b,
377                @NotNull KotlinType bReturnType
378        ) {
379            KotlinTypeChecker typeChecker = DEFAULT.createTypeChecker(a.getTypeParameters(), b.getTypeParameters());
380            return typeChecker.isSubtypeOf(aReturnType, bReturnType);
381        }
382    
383        @NotNull
384        public static <H> H selectMostSpecificMember(
385                @NotNull Collection<H> overridables,
386                @NotNull Function1<H, CallableDescriptor> descriptorByHandle
387        ) {
388            assert !overridables.isEmpty() : "Should have at least one overridable descriptor";
389    
390            if (overridables.size() == 1) {
391                return CollectionsKt.first(overridables);
392            }
393    
394            Collection<H> candidates = new ArrayList<H>(2);
395            List<CallableDescriptor> callableMemberDescriptors = CollectionsKt.map(overridables, descriptorByHandle);
396    
397            H transitivelyMostSpecific = CollectionsKt.first(overridables);
398            CallableDescriptor transitivelyMostSpecificDescriptor = descriptorByHandle.invoke(transitivelyMostSpecific);
399    
400            for (H overridable : overridables) {
401                CallableDescriptor descriptor = descriptorByHandle.invoke(overridable);
402                if (isMoreSpecificThenAllOf(descriptor, callableMemberDescriptors)) {
403                    candidates.add(overridable);
404                }
405                if (isMoreSpecific(descriptor, transitivelyMostSpecificDescriptor)
406                    && !isMoreSpecific(transitivelyMostSpecificDescriptor, descriptor)) {
407                    transitivelyMostSpecific = overridable;
408                }
409            }
410    
411            if (candidates.isEmpty()) {
412                return transitivelyMostSpecific;
413            }
414            else if (candidates.size() == 1) {
415                return CollectionsKt.first(candidates);
416            }
417    
418            H firstNonFlexible = null;
419            for (H candidate : candidates) {
420                if (!FlexibleTypesKt.isFlexible(descriptorByHandle.invoke(candidate).getReturnType())) {
421                    firstNonFlexible = candidate;
422                    break;
423                }
424            }
425            if (firstNonFlexible != null) {
426                return firstNonFlexible;
427            }
428    
429            return CollectionsKt.first(candidates);
430        }
431    
432        private static void createAndBindFakeOverride(
433                @NotNull Collection<CallableMemberDescriptor> overridables,
434                @NotNull ClassDescriptor current,
435                @NotNull DescriptorSink sink
436        ) {
437            Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
438            boolean allInvisible = visibleOverridables.isEmpty();
439            Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
440    
441            // FIXME doesn't work as expected for flexible types: should create a refined signature.
442            // Current algorithm produces bad results in presence of annotated Java signatures such as:
443            //      J: foo(s: String!): String -- @NotNull String foo(String s);
444            //      K: foo(s: String): String?
445            //  --> 'foo(s: String!): String' as an inherited signature with most specific return type.
446            // This is bad because it can be overridden by 'foo(s: String?): String', which is not override-equivalent with K::foo above.
447            // Should be 'foo(s: String): String'.
448            Modality modality = getMinimalModality(effectiveOverridden);
449            Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
450            CallableMemberDescriptor mostSpecific =
451                    selectMostSpecificMember(effectiveOverridden,
452                                             new Function1<CallableMemberDescriptor, CallableDescriptor>() {
453                                                  @Override
454                                                  public CallableMemberDescriptor invoke(CallableMemberDescriptor descriptor) {
455                                                      return descriptor;
456                                                  }
457                                             });
458            CallableMemberDescriptor fakeOverride =
459                    mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
460            for (CallableMemberDescriptor descriptor : effectiveOverridden) {
461                fakeOverride.addOverriddenDescriptor(descriptor);
462            }
463            sink.addFakeOverride(fakeOverride);
464        }
465    
466        @NotNull
467        private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
468            Modality modality = Modality.ABSTRACT;
469            for (CallableMemberDescriptor descriptor : descriptors) {
470                if (descriptor.getModality().compareTo(modality) < 0) {
471                    modality = descriptor.getModality();
472                }
473            }
474            return modality;
475        }
476    
477        @NotNull
478        private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
479                @NotNull final ClassDescriptor current,
480                @NotNull Collection<CallableMemberDescriptor> toFilter
481        ) {
482            return CollectionsKt.filter(toFilter, new Function1<CallableMemberDescriptor, Boolean>() {
483                @Override
484                public Boolean invoke(CallableMemberDescriptor descriptor) {
485                    //nested class could capture private member, so check for private visibility added
486                    return !Visibilities.isPrivate(descriptor.getVisibility()) &&
487                           Visibilities.isVisibleWithIrrelevantReceiver(descriptor, current);
488                }
489            });
490        }
491    
492        /**
493         * @param <H> is something that handles CallableDescriptor inside
494         * @return
495         */
496        @NotNull
497        public static <H> Collection<H> extractMembersOverridableInBothWays(
498                @NotNull H overrider,
499                @NotNull @Mutable Collection<H> extractFrom,
500                @NotNull Function1<H, CallableDescriptor> descriptorByHandle,
501                @NotNull Function1<H, Unit> onConflict
502        ) {
503            Collection<H> overridable = new ArrayList<H>();
504            overridable.add(overrider);
505            CallableDescriptor overriderDescriptor = descriptorByHandle.invoke(overrider);
506            for (Iterator<H> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
507                H candidate = iterator.next();
508                CallableDescriptor candidateDescriptor = descriptorByHandle.invoke(candidate);
509                if (overrider == candidate) {
510                    iterator.remove();
511                    continue;
512                }
513    
514                OverrideCompatibilityInfo.Result finalResult = getBothWaysOverridability(overriderDescriptor, candidateDescriptor);
515    
516                if (finalResult == OVERRIDABLE) {
517                    overridable.add(candidate);
518                    iterator.remove();
519                }
520                else if (finalResult == CONFLICT) {
521                    onConflict.invoke(candidate);
522                    iterator.remove();
523                }
524            }
525            return overridable;
526        }
527    
528        @Nullable
529        public static OverrideCompatibilityInfo.Result getBothWaysOverridability(
530                CallableDescriptor overriderDescriptor,
531                CallableDescriptor candidateDescriptor
532        ) {
533            OverrideCompatibilityInfo.Result result1 = DEFAULT.isOverridableBy(candidateDescriptor, overriderDescriptor, null).getResult();
534            OverrideCompatibilityInfo.Result result2 = DEFAULT.isOverridableBy(overriderDescriptor, candidateDescriptor, null).getResult();
535    
536            return result1 == OVERRIDABLE && result2 == OVERRIDABLE
537                   ? OVERRIDABLE
538                   : ((result1 == CONFLICT || result2 == CONFLICT) ? CONFLICT : INCOMPATIBLE);
539        }
540    
541        @NotNull
542        private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
543                @NotNull final CallableMemberDescriptor overrider,
544                @NotNull Queue<CallableMemberDescriptor> extractFrom,
545                @NotNull final DescriptorSink sink
546        ) {
547            return extractMembersOverridableInBothWays(overrider, extractFrom,
548                    // ID
549                    new Function1<CallableMemberDescriptor, CallableDescriptor>() {
550                        @Override
551                        public CallableDescriptor invoke(CallableMemberDescriptor descriptor) {
552                            return descriptor;
553                        }
554                    },
555                    new Function1<CallableMemberDescriptor, Unit>() {
556                        @Override
557                        public Unit invoke(CallableMemberDescriptor descriptor) {
558                            sink.conflict(overrider, descriptor);
559                            return Unit.INSTANCE;
560                        }
561                    });
562        }
563    
564    
565        public static void resolveUnknownVisibilityForMember(
566                @NotNull CallableMemberDescriptor memberDescriptor,
567                @Nullable Function1<CallableMemberDescriptor, Unit> cannotInferVisibility
568        ) {
569            for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
570                if (descriptor.getVisibility() == Visibilities.INHERITED) {
571                    resolveUnknownVisibilityForMember(descriptor, cannotInferVisibility);
572                }
573            }
574    
575            if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
576                return;
577            }
578    
579            Visibility maxVisibility = computeVisibilityToInherit(memberDescriptor);
580            Visibility visibilityToInherit;
581            if (maxVisibility == null) {
582                if (cannotInferVisibility != null) {
583                    cannotInferVisibility.invoke(memberDescriptor);
584                }
585                visibilityToInherit = Visibilities.PUBLIC;
586            }
587            else {
588                visibilityToInherit = maxVisibility;
589            }
590    
591            if (memberDescriptor instanceof PropertyDescriptorImpl) {
592                ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
593                for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
594                    // If we couldn't infer visibility for property, the diagnostic is already reported, no need to report it again on accessors
595                    resolveUnknownVisibilityForMember(accessor, maxVisibility == null ? null : cannotInferVisibility);
596                }
597            }
598            else if (memberDescriptor instanceof FunctionDescriptorImpl) {
599                ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
600            }
601            else {
602                assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
603                ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
604            }
605        }
606    
607        @Nullable
608        private static Visibility computeVisibilityToInherit(@NotNull CallableMemberDescriptor memberDescriptor) {
609            Collection<? extends CallableMemberDescriptor> overriddenDescriptors = memberDescriptor.getOverriddenDescriptors();
610            Visibility maxVisibility = findMaxVisibility(overriddenDescriptors);
611            if (maxVisibility == null) {
612                return null;
613            }
614            if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
615                for (CallableMemberDescriptor overridden : overriddenDescriptors) {
616                    // An implementation (a non-abstract overridden member) of a fake override should have the maximum possible visibility
617                    if (overridden.getModality() != Modality.ABSTRACT && !overridden.getVisibility().equals(maxVisibility)) {
618                        return null;
619                    }
620                }
621                return maxVisibility;
622            }
623            return maxVisibility.normalize();
624        }
625    
626        @Nullable
627        public static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
628            if (descriptors.isEmpty()) {
629                return Visibilities.DEFAULT_VISIBILITY;
630            }
631            Visibility maxVisibility = null;
632            for (CallableMemberDescriptor descriptor : descriptors) {
633                Visibility visibility = descriptor.getVisibility();
634                assert visibility != Visibilities.INHERITED : "Visibility should have been computed for " + descriptor;
635                if (maxVisibility == null) {
636                    maxVisibility = visibility;
637                    continue;
638                }
639                Integer compareResult = Visibilities.compare(visibility, maxVisibility);
640                if (compareResult == null) {
641                    maxVisibility = null;
642                }
643                else if (compareResult > 0) {
644                    maxVisibility = visibility;
645                }
646            }
647            if (maxVisibility == null) {
648                return null;
649            }
650            for (CallableMemberDescriptor descriptor : descriptors) {
651                Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
652                if (compareResult == null || compareResult < 0) {
653                    return null;
654                }
655            }
656            return maxVisibility;
657        }
658    
659        public interface DescriptorSink {
660            void addFakeOverride(@NotNull CallableMemberDescriptor fakeOverride);
661    
662            void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent);
663        }
664    
665        public static class OverrideCompatibilityInfo {
666            public enum Result {
667                OVERRIDABLE,
668                INCOMPATIBLE,
669                CONFLICT,
670            }
671    
672            private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(OVERRIDABLE, "SUCCESS");
673    
674            @NotNull
675            public static OverrideCompatibilityInfo success() {
676                return SUCCESS;
677            }
678    
679            @NotNull
680            public static OverrideCompatibilityInfo incompatible(@NotNull String debugMessage) {
681                return new OverrideCompatibilityInfo(INCOMPATIBLE, debugMessage);
682            }
683    
684            @NotNull
685            public static OverrideCompatibilityInfo conflict(@NotNull String debugMessage) {
686                return new OverrideCompatibilityInfo(CONFLICT, debugMessage);
687            }
688    
689            private final Result overridable;
690            private final String debugMessage;
691    
692            public OverrideCompatibilityInfo(@NotNull Result success, @NotNull String debugMessage) {
693                this.overridable = success;
694                this.debugMessage = debugMessage;
695            }
696    
697            @NotNull
698            public Result getResult() {
699                return overridable;
700            }
701    
702            @NotNull
703            public String getDebugMessage() {
704                return debugMessage;
705            }
706        }
707    }