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 <D extends CallableDescriptor> boolean overrides(@NotNull D f, @NotNull D g) {
113            CallableDescriptor originalG = g.getOriginal();
114            for (CallableDescriptor overriddenFunction : getAllOverriddenDescriptors(f)) {
115                if (originalG.equals(overriddenFunction.getOriginal())) return true;
116            }
117            return false;
118        }
119    
120        public static Set<CallableDescriptor> getAllOverriddenDescriptors(CallableDescriptor f) {
121            Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
122            collectAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
123            return overriddenDescriptors;
124        }
125    
126        private static void collectAllOverriddenDescriptors(
127                @NotNull CallableDescriptor current,
128                @NotNull Set<CallableDescriptor> result
129        ) {
130            if (result.contains(current)) return;
131            for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
132                collectAllOverriddenDescriptors(descriptor, result);
133                result.add(descriptor);
134            }
135        }
136    
137        @NotNull
138        public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
139            if (superDescriptor instanceof FunctionDescriptor) {
140                if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
141            }
142            else if (superDescriptor instanceof PropertyDescriptor) {
143                if (!(subDescriptor instanceof PropertyDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
144            }
145            else {
146                throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
147            }
148    
149            // TODO: check outside of this method
150            if (!superDescriptor.getName().equals(subDescriptor.getName())) {
151                return OverrideCompatibilityInfo.nameMismatch();
152            }
153    
154            return isOverridableByImpl(superDescriptor, subDescriptor, true);
155        }
156        
157        private static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
158            ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
159            ArrayList<JetType> parameters = new ArrayList<JetType>();
160            if (receiverParameter != null) {
161                parameters.add(receiverParameter.getType());
162            }
163            for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
164                parameters.add(valueParameterDescriptor.getType());
165            }
166            return parameters;
167        }
168    
169        /**
170         * @param forOverride true for override, false for overload
171         */
172        static OverrideCompatibilityInfo isOverridableByImpl(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean forOverride) {
173    
174            // TODO : Visibility
175    
176            if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
177                return OverrideCompatibilityInfo.receiverPresenceMismatch();
178            }
179    
180            if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
181                return OverrideCompatibilityInfo.valueParameterNumberMismatch();
182            }
183    
184            List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
185            List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
186    
187            if (forOverride) {
188                if (superDescriptor.getTypeParameters().size() != subDescriptor.getTypeParameters().size()) {
189                    for (int i = 0; i < superValueParameters.size(); ++i) {
190                        JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
191                        JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
192                        // TODO: compare erasure
193                        if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
194                            return OverrideCompatibilityInfo.typeParameterNumberMismatch();
195                        }
196                    }
197                    return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
198                }
199            }
200    
201            if (forOverride) {
202    
203                List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
204                List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
205    
206                BiMap<TypeConstructor, TypeConstructor> axioms = HashBiMap.create();
207                for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
208                    TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
209                    TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
210                    axioms.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
211                }
212    
213                for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
214                    TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
215                    TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
216    
217                    if (!JetTypeChecker.INSTANCE.equalTypes(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), axioms)) {
218                        return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
219                    }
220                }
221    
222                for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
223                    JetType superValueParameter = superValueParameters.get(i);
224                    JetType subValueParameter = subValueParameters.get(i);
225    
226                    boolean bothErrors = superValueParameter.isError() && subValueParameter.isError();
227                    if (!bothErrors && !JetTypeChecker.INSTANCE.equalTypes(superValueParameter, subValueParameter, axioms)) {
228                        return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
229                    }
230                }
231    
232                for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
233                    if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
234                        return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
235                    }
236                }
237            }
238            else {
239    
240                for (int i = 0; i < superValueParameters.size(); ++i) {
241                    JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
242                    JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
243                    // TODO: compare erasure
244                    if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
245                        return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
246                    }
247                }
248                
249                return OverrideCompatibilityInfo.success();
250    
251            }
252    
253            // TODO : Default values, varargs etc
254    
255            return OverrideCompatibilityInfo.success();
256        }
257        
258        private static JetType getUpperBound(JetType type) {
259            if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
260                return type;
261            }
262            else if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
263                return ((TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor()).getUpperBoundsAsType();
264            }
265            else {
266                throw new IllegalStateException("unknown type constructor: " + type.getConstructor().getClass().getName());
267            }
268        }
269    
270        public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
271            TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
272            if (typeSubstitutor == null) return false;
273    
274            JetType superReturnType = superDescriptor.getReturnType();
275            assert superReturnType != null;
276    
277            JetType subReturnType = subDescriptor.getReturnType();
278            assert subReturnType != null;
279    
280            JetType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE);
281            assert substitutedSuperReturnType != null;
282    
283            return typeChecker.isSubtypeOf(subReturnType, substitutedSuperReturnType);
284        }
285    
286        @Nullable
287        private static TypeSubstitutor prepareTypeSubstitutor(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
288            List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
289            List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
290            if (subTypeParameters.size() != superTypeParameters.size()) return null;
291    
292            Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
293            for (int i = 0; i < superTypeParameters.size(); i++) {
294                TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
295                TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
296                substitutionContext.put(
297                        superTypeParameter.getTypeConstructor(),
298                        new TypeProjectionImpl(subTypeParameter.getDefaultType()));
299            }
300            return TypeSubstitutor.create(substitutionContext);
301        }
302    
303        public static boolean isPropertyTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull PropertyDescriptor superDescriptor, @NotNull PropertyDescriptor subDescriptor) {
304            TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
305            JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
306            assert substitutedSuperReturnType != null;
307            if (superDescriptor.isVar() && !typeChecker.equalTypes(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
308                return false;
309            }
310    
311            return true;
312        }
313    
314        /**
315         * Get overridden descriptors that are declarations or delegations.
316         *
317         * @see CallableMemberDescriptor.Kind#isReal()
318         */
319        public static Collection<CallableMemberDescriptor> getOverriddenDeclarations(CallableMemberDescriptor descriptor) {
320            Map<ClassDescriptor, CallableMemberDescriptor> result = Maps.newHashMap();
321            getOverriddenDeclarations(descriptor, result);
322            return result.values();
323        }
324    
325        private static void getOverriddenDeclarations(CallableMemberDescriptor descriptor, Map<ClassDescriptor, CallableMemberDescriptor> r) {
326            if (descriptor.getKind().isReal()) {
327                r.put((ClassDescriptor) descriptor.getContainingDeclaration(), descriptor);
328            }
329            else {
330                if (descriptor.getOverriddenDescriptors().isEmpty()) {
331                    throw new IllegalStateException("No overridden descriptors found for (fake override) " + descriptor);
332                }
333                for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
334                    getOverriddenDeclarations(overridden, r);
335                }
336            }
337        }
338    
339        public static void bindOverride(CallableMemberDescriptor fromCurrent, CallableMemberDescriptor fromSupertype) {
340            fromCurrent.addOverriddenDescriptor(fromSupertype);
341    
342            for (ValueParameterDescriptor parameterFromCurrent : fromCurrent.getValueParameters()) {
343                assert parameterFromCurrent.getIndex() < fromSupertype.getValueParameters().size()
344                        : "An override relation between functions implies that they have the same number of value parameters";
345                ValueParameterDescriptor parameterFromSupertype = fromSupertype.getValueParameters().get(parameterFromCurrent.getIndex());
346                parameterFromCurrent.addOverriddenDescriptor(parameterFromSupertype);
347            }
348        }
349    
350        public static void generateOverridesInFunctionGroup(
351                @SuppressWarnings("UnusedParameters")
352                @NotNull Name name, //DO NOT DELETE THIS PARAMETER: needed to make sure all descriptors have the same name
353                @NotNull Collection<? extends CallableMemberDescriptor> membersFromSupertypes,
354                @NotNull Collection<? extends CallableMemberDescriptor> membersFromCurrent,
355                @NotNull ClassDescriptor current,
356                @NotNull DescriptorSink sink
357        ) {
358            Collection<CallableMemberDescriptor> notOverridden = Sets.newLinkedHashSet(membersFromSupertypes);
359    
360            for (CallableMemberDescriptor fromCurrent : membersFromCurrent) {
361                Collection<CallableMemberDescriptor> bound =
362                        extractAndBindOverridesForMember(fromCurrent, membersFromSupertypes, current, sink);
363                notOverridden.removeAll(bound);
364            }
365    
366            createAndBindFakeOverrides(current, notOverridden, sink);
367        }
368    
369        private static Collection<CallableMemberDescriptor> extractAndBindOverridesForMember(
370                @NotNull CallableMemberDescriptor fromCurrent,
371                @NotNull Collection<? extends CallableMemberDescriptor> descriptorsFromSuper,
372                @NotNull ClassDescriptor current,
373                @NotNull DescriptorSink sink
374        ) {
375            Collection<CallableMemberDescriptor> bound = Lists.newArrayList();
376            for (CallableMemberDescriptor fromSupertype : descriptorsFromSuper) {
377                OverrideCompatibilityInfo.Result result = isOverridableBy(fromSupertype, fromCurrent).getResult();
378    
379                boolean isVisible = Visibilities.isVisible(fromSupertype, current);
380                switch (result) {
381                    case OVERRIDABLE:
382                        if (isVisible) {
383                            bindOverride(fromCurrent, fromSupertype);
384                        }
385                        bound.add(fromSupertype);
386                        break;
387                    case CONFLICT:
388                        if (isVisible) {
389                            sink.conflict(fromSupertype, fromCurrent);
390                        }
391                        bound.add(fromSupertype);
392                        break;
393                    case INCOMPATIBLE:
394                        break;
395                }
396            }
397            return bound;
398        }
399    
400        private static void createAndBindFakeOverrides(
401                @NotNull ClassDescriptor current,
402                @NotNull Collection<CallableMemberDescriptor> notOverridden,
403                @NotNull DescriptorSink sink
404        ) {
405            Queue<CallableMemberDescriptor> fromSuperQueue = new LinkedList<CallableMemberDescriptor>(notOverridden);
406            while (!fromSuperQueue.isEmpty()) {
407                CallableMemberDescriptor notOverriddenFromSuper = VisibilityUtil.findMemberWithMaxVisibility(fromSuperQueue);
408                Collection<CallableMemberDescriptor> overridables =
409                        extractMembersOverridableInBothWays(notOverriddenFromSuper, fromSuperQueue, sink);
410                createAndBindFakeOverride(overridables, current, sink);
411            }
412        }
413    
414        private static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) {
415            if (a instanceof SimpleFunctionDescriptor) {
416                assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass();
417    
418                JetType aReturnType = a.getReturnType();
419                assert aReturnType != null;
420                JetType bReturnType = b.getReturnType();
421                assert bReturnType != null;
422    
423                return JetTypeChecker.INSTANCE.isSubtypeOf(aReturnType, bReturnType);
424            }
425            if (a instanceof PropertyDescriptor) {
426                assert b instanceof PropertyDescriptor : "b is " + b.getClass();
427    
428                if (((PropertyDescriptor) a).isVar() || ((PropertyDescriptor) b).isVar()) {
429                    return ((PropertyDescriptor) a).isVar();
430                }
431    
432                // both vals
433                return JetTypeChecker.INSTANCE.isSubtypeOf(((PropertyDescriptor) a).getType(), ((PropertyDescriptor) b).getType());
434            }
435            throw new IllegalArgumentException("Unexpected callable: " + a.getClass());
436        }
437    
438        private static CallableMemberDescriptor selectMostSpecificMemberFromSuper(@NotNull Collection<CallableMemberDescriptor> overridables) {
439            CallableMemberDescriptor result = null;
440            for (CallableMemberDescriptor overridable : overridables) {
441                if (result == null || isMoreSpecific(overridable, result)) {
442                    result = overridable;
443                }
444            }
445            return result;
446        }
447    
448        private static void createAndBindFakeOverride(
449                @NotNull Collection<CallableMemberDescriptor> overridables,
450                @NotNull ClassDescriptor current,
451                @NotNull DescriptorSink sink
452        ) {
453            Collection<CallableMemberDescriptor> visibleOverridables = filterVisibleFakeOverrides(current, overridables);
454            Modality modality = getMinimalModality(visibleOverridables);
455            boolean allInvisible = visibleOverridables.isEmpty();
456            Collection<CallableMemberDescriptor> effectiveOverridden = allInvisible ? overridables : visibleOverridables;
457            Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED;
458            CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);
459            CallableMemberDescriptor fakeOverride =
460                    mostSpecific.copy(current, modality, visibility, CallableMemberDescriptor.Kind.FAKE_OVERRIDE, false);
461            for (CallableMemberDescriptor descriptor : effectiveOverridden) {
462                bindOverride(fakeOverride, descriptor);
463            }
464            sink.addToScope(fakeOverride);
465        }
466    
467        @NotNull
468        private static Modality getMinimalModality(@NotNull Collection<CallableMemberDescriptor> descriptors) {
469            Modality modality = Modality.ABSTRACT;
470            for (CallableMemberDescriptor descriptor : descriptors) {
471                if (descriptor.getModality().compareTo(modality) < 0) {
472                    modality = descriptor.getModality();
473                }
474            }
475            return modality;
476        }
477    
478        @NotNull
479        private static Collection<CallableMemberDescriptor> filterVisibleFakeOverrides(
480                @NotNull final ClassDescriptor current,
481                @NotNull Collection<CallableMemberDescriptor> toFilter
482        ) {
483            return Collections2.filter(toFilter, new Predicate<CallableMemberDescriptor>() {
484                @Override
485                public boolean apply(@Nullable CallableMemberDescriptor descriptor) {
486                    //nested class could capture private member, so check for private visibility added
487                    return descriptor != null &&
488                           descriptor.getVisibility() != Visibilities.PRIVATE &&
489                           Visibilities.isVisible(descriptor, current);
490                }
491            });
492        }
493    
494        @NotNull
495        private static Collection<CallableMemberDescriptor> extractMembersOverridableInBothWays(
496                @NotNull CallableMemberDescriptor overrider,
497                @NotNull Queue<CallableMemberDescriptor> extractFrom,
498                @NotNull DescriptorSink sink
499        ) {
500            Collection<CallableMemberDescriptor> overridable = Lists.newArrayList();
501            overridable.add(overrider);
502            for (Iterator<CallableMemberDescriptor> iterator = extractFrom.iterator(); iterator.hasNext(); ) {
503                CallableMemberDescriptor candidate = iterator.next();
504                if (overrider == candidate) {
505                    iterator.remove();
506                    continue;
507                }
508    
509                OverrideCompatibilityInfo.Result result1 = isOverridableBy(candidate, overrider).getResult();
510                OverrideCompatibilityInfo.Result result2 = isOverridableBy(overrider, candidate).getResult();
511                if (result1 == OVERRIDABLE && result2 == OVERRIDABLE) {
512                    overridable.add(candidate);
513                    iterator.remove();
514                }
515                else if (result1 == CONFLICT || result2 == CONFLICT) {
516                    sink.conflict(overrider, candidate);
517                    iterator.remove();
518                }
519            }
520            return overridable;
521        }
522    
523        public static void resolveUnknownVisibilityForMember(
524                @NotNull CallableMemberDescriptor memberDescriptor,
525                @NotNull NotInferredVisibilitySink sink
526        ) {
527            for (CallableMemberDescriptor descriptor : memberDescriptor.getOverriddenDescriptors()) {
528                if (descriptor.getVisibility() == Visibilities.INHERITED) {
529                    resolveUnknownVisibilityForMember(descriptor, sink);
530                }
531            }
532    
533            if (memberDescriptor.getVisibility() != Visibilities.INHERITED) {
534                return;
535            }
536    
537            Visibility visibilityToInherit = computeVisibilityToInherit(memberDescriptor, sink);
538            if (memberDescriptor instanceof PropertyDescriptorImpl) {
539                ((PropertyDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
540                for (PropertyAccessorDescriptor accessor : ((PropertyDescriptor) memberDescriptor).getAccessors()) {
541                    resolveUnknownVisibilityForMember(accessor, sink);
542                }
543            }
544            else if (memberDescriptor instanceof FunctionDescriptorImpl) {
545                ((FunctionDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
546            }
547            else {
548                assert memberDescriptor instanceof PropertyAccessorDescriptorImpl;
549                ((PropertyAccessorDescriptorImpl) memberDescriptor).setVisibility(visibilityToInherit);
550            }
551        }
552    
553        @NotNull
554        private static Visibility computeVisibilityToInherit(
555                @NotNull CallableMemberDescriptor memberDescriptor,
556                @NotNull NotInferredVisibilitySink sink
557        ) {
558            Visibility maxVisibility = findMaxVisibility(memberDescriptor.getOverriddenDescriptors());
559            if (maxVisibility == null) {
560                sink.cannotInferVisibility(memberDescriptor);
561                return Visibilities.PUBLIC;
562            }
563            if (memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
564                return maxVisibility;
565            }
566            return maxVisibility.normalize();
567        }
568    
569        @Nullable
570        private static Visibility findMaxVisibility(@NotNull Collection<? extends CallableMemberDescriptor> descriptors) {
571            if (descriptors.isEmpty()) {
572                return Visibilities.INTERNAL;
573            }
574            Visibility maxVisibility = null;
575            for (CallableMemberDescriptor descriptor : descriptors) {
576                Visibility visibility = descriptor.getVisibility();
577                assert visibility != Visibilities.INHERITED;
578                if (maxVisibility == null) {
579                    maxVisibility = visibility;
580                    continue;
581                }
582                Integer compareResult = Visibilities.compare(visibility, maxVisibility);
583                if (compareResult == null) {
584                    maxVisibility = null;
585                }
586                else if (compareResult > 0) {
587                    maxVisibility = visibility;
588                }
589            }
590            if (maxVisibility == null) {
591                return null;
592            }
593            for (CallableMemberDescriptor descriptor : descriptors) {
594                Integer compareResult = Visibilities.compare(maxVisibility, descriptor.getVisibility());
595                if (compareResult == null || compareResult < 0) {
596                    return null;
597                }
598            }
599            return maxVisibility;
600        }
601    
602        public interface DescriptorSink {
603            void addToScope(@NotNull CallableMemberDescriptor fakeOverride);
604    
605            void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent);
606        }
607    
608        public interface NotInferredVisibilitySink {
609            void cannotInferVisibility(@NotNull CallableMemberDescriptor descriptor);
610        }
611    
612        public static class OverrideCompatibilityInfo {
613    
614            public enum Result {
615                OVERRIDABLE,
616                INCOMPATIBLE,
617                CONFLICT,
618            }
619    
620            private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(Result.OVERRIDABLE, "SUCCESS");
621    
622            @NotNull
623            public static OverrideCompatibilityInfo success() {
624                return SUCCESS;
625            }
626    
627            @NotNull
628            public static OverrideCompatibilityInfo nameMismatch() {
629                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "nameMismatch"); // TODO
630            }
631    
632            @NotNull
633            public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
634                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "typeParameterNumberMismatch"); // TODO
635            }
636    
637            @NotNull
638            public static OverrideCompatibilityInfo receiverPresenceMismatch() {
639                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "receiverPresenceMismatch"); // TODO
640            }
641    
642            @NotNull
643            public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
644                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "valueParameterNumberMismatch"); // TODO
645            }
646    
647            @NotNull
648            public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
649                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "boundsMismatch"); // TODO
650            }
651    
652            @NotNull
653            public static OverrideCompatibilityInfo valueParameterTypeMismatch(JetType superValueParameter, JetType subValueParameter, Result result) {
654                return new OverrideCompatibilityInfo(result, "valueParameterTypeMismatch"); // TODO
655            }
656    
657            @NotNull
658            public static OverrideCompatibilityInfo memberKindMismatch() {
659                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "memberKindMismatch"); // TODO
660            }
661    
662            @NotNull
663            public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
664                return new OverrideCompatibilityInfo(Result.CONFLICT, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
665            }
666    
667            @NotNull
668            public static OverrideCompatibilityInfo varOverriddenByVal() {
669                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "varOverriddenByVal"); // TODO
670            }
671    
672            @NotNull
673            public static OverrideCompatibilityInfo externalConditionFailed(Class<? extends ExternalOverridabilityCondition> conditionClass) {
674                return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "externalConditionFailed: " + conditionClass.getName()); // TODO
675            }
676    
677            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
678    
679            private final Result overridable;
680            private final String message;
681    
682            public OverrideCompatibilityInfo(Result success, String message) {
683                this.overridable = success;
684                this.message = message;
685            }
686    
687            public Result getResult() {
688                return overridable;
689            }
690    
691            public String getMessage() {
692                return message;
693            }
694        }
695    }