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