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