001    /*
002     * Copyright 2010-2014 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.lazy.descriptors;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Collections2;
021    import com.google.common.collect.Lists;
022    import com.intellij.psi.PsiElement;
023    import kotlin.Function0;
024    import kotlin.Function1;
025    import kotlin.KotlinPackage;
026    import kotlin.Unit;
027    import org.jetbrains.annotations.Mutable;
028    import org.jetbrains.annotations.NotNull;
029    import org.jetbrains.annotations.Nullable;
030    import org.jetbrains.annotations.ReadOnly;
031    import org.jetbrains.jet.lang.descriptors.*;
032    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
033    import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
034    import org.jetbrains.jet.lang.psi.*;
035    import org.jetbrains.jet.lang.resolve.BindingContext;
036    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
037    import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver;
038    import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
039    import org.jetbrains.jet.lang.resolve.lazy.LazyEntity;
040    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
041    import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
042    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
043    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
044    import org.jetbrains.jet.lang.resolve.lazy.data.SyntheticClassObjectInfo;
045    import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
046    import org.jetbrains.jet.lang.resolve.name.Name;
047    import org.jetbrains.jet.lang.resolve.scopes.*;
048    import org.jetbrains.jet.lang.types.AbstractClassTypeConstructor;
049    import org.jetbrains.jet.lang.types.JetType;
050    import org.jetbrains.jet.lang.types.TypeConstructor;
051    import org.jetbrains.jet.lang.types.TypeUtils;
052    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
053    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
054    import org.jetbrains.jet.storage.NotNullLazyValue;
055    import org.jetbrains.jet.storage.NullableLazyValue;
056    import org.jetbrains.jet.storage.StorageManager;
057    
058    import java.util.*;
059    
060    import static org.jetbrains.jet.lang.diagnostics.Errors.CLASS_OBJECT_NOT_ALLOWED;
061    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isSyntheticClassObject;
062    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*;
063    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
064    import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
065    
066    public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDescriptorWithResolutionScopes, LazyEntity {
067        private static final Predicate<JetType> VALID_SUPERTYPE = new Predicate<JetType>() {
068            @Override
069            public boolean apply(JetType type) {
070                assert !type.isError() : "Error types must be filtered out in DescriptorResolver";
071                return TypeUtils.getClassDescriptor(type) != null;
072            }
073        };
074        private final ResolveSession resolveSession;
075    
076        private final JetClassLikeInfo originalClassInfo;
077        private final ClassMemberDeclarationProvider declarationProvider;
078    
079        private final LazyClassTypeConstructor typeConstructor;
080        private final Modality modality;
081        private final Visibility visibility;
082        private final ClassKind kind;
083        private final boolean isInner;
084    
085        private final Annotations annotations;
086        private final NullableLazyValue<LazyClassDescriptor> classObjectDescriptor;
087        private final MemoizedFunctionToNotNull<JetClassObject, ClassDescriptor> extraClassObjectDescriptors;
088    
089        private final LazyClassMemberScope unsubstitutedMemberScope;
090        private final JetScope staticScope = new StaticScopeForKotlinClass(this);
091    
092        private final NotNullLazyValue<JetScope> scopeForClassHeaderResolution;
093        private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution;
094        private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution;
095    
096        private final NullableLazyValue<Void> forceResolveAllContents;
097    
098        public LazyClassDescriptor(
099                @NotNull final ResolveSession resolveSession,
100                @NotNull DeclarationDescriptor containingDeclaration,
101                @NotNull Name name,
102                @NotNull JetClassLikeInfo classLikeInfo
103        ) {
104            super(resolveSession.getStorageManager(), containingDeclaration, name,
105                  toSourceElement(classLikeInfo.getCorrespondingClassOrObject())
106            );
107            this.resolveSession = resolveSession;
108    
109            if (classLikeInfo.getCorrespondingClassOrObject() != null) {
110                this.resolveSession.getTrace().record(BindingContext.CLASS, classLikeInfo.getCorrespondingClassOrObject(), this);
111            }
112            this.resolveSession.getTrace().record(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFqName(this), this);
113    
114            this.originalClassInfo = classLikeInfo;
115            this.declarationProvider = resolveSession.getDeclarationProviderFactory().getClassMemberDeclarationProvider(classLikeInfo);
116    
117            this.unsubstitutedMemberScope = createMemberScope(resolveSession, this.declarationProvider);
118    
119            this.typeConstructor = new LazyClassTypeConstructor();
120    
121            this.kind = classLikeInfo.getClassKind();
122    
123            JetModifierList modifierList = classLikeInfo.getModifierList();
124            if (kind.isSingleton()) {
125                this.modality = Modality.FINAL;
126            }
127            else {
128                Modality defaultModality = kind == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
129                this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
130            }
131            this.visibility = isSyntheticClassObject(this)
132                              ? DescriptorUtils.getSyntheticClassObjectVisibility()
133                              : resolveVisibilityFromModifiers(modifierList, getDefaultClassVisibility(this));
134            this.isInner = isInnerClass(modifierList);
135    
136            StorageManager storageManager = resolveSession.getStorageManager();
137    
138    
139            if (modifierList != null) {
140                this.annotations = new LazyAnnotations(
141                        new LazyAnnotationsContext(
142                                resolveSession.getAnnotationResolver(),
143                                resolveSession.getStorageManager(),
144                                resolveSession.getTrace()
145                        ) {
146                            @NotNull
147                            @Override
148                            public JetScope getScope() {
149                                JetClassLikeInfo ownerInfo = declarationProvider.getOwnerInfo();
150                                return resolveSession.getScopeProvider().getResolutionScopeForDeclaration(ownerInfo.getScopeAnchor());
151                            }
152                        },
153                        modifierList.getAnnotationEntries()
154                    );
155    
156            }
157            else {
158                this.annotations = Annotations.EMPTY;
159            }
160    
161            this.classObjectDescriptor = storageManager.createNullableLazyValue(new Function0<LazyClassDescriptor>() {
162                @Override
163                public LazyClassDescriptor invoke() {
164                    return computeClassObjectDescriptor(declarationProvider.getOwnerInfo().getClassObject());
165                }
166            });
167            this.extraClassObjectDescriptors = storageManager.createMemoizedFunction(new Function1<JetClassObject, ClassDescriptor>() {
168                @Override
169                public ClassDescriptor invoke(JetClassObject classObject) {
170                    return computeClassObjectDescriptor(classObject);
171                }
172            });
173            this.scopeForClassHeaderResolution = storageManager.createLazyValue(new Function0<JetScope>() {
174                @Override
175                public JetScope invoke() {
176                    return computeScopeForClassHeaderResolution();
177                }
178            });
179            this.scopeForMemberDeclarationResolution = storageManager.createLazyValue(new Function0<JetScope>() {
180                @Override
181                public JetScope invoke() {
182                    return computeScopeForMemberDeclarationResolution();
183                }
184            });
185            this.scopeForPropertyInitializerResolution = storageManager.createLazyValue(new Function0<JetScope>() {
186                @Override
187                public JetScope invoke() {
188                    return computeScopeForPropertyInitializerResolution();
189                }
190            });
191            this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() {
192                @Override
193                public Void invoke() {
194                    doForceResolveAllContents();
195                    return null;
196                }
197            }, null);
198        }
199    
200        // NOTE: Called from constructor!
201        @NotNull
202        protected LazyClassMemberScope createMemberScope(
203                @NotNull ResolveSession resolveSession,
204                @NotNull ClassMemberDeclarationProvider declarationProvider
205        ) {
206            return new LazyClassMemberScope(resolveSession, declarationProvider, this, resolveSession.getTrace());
207        }
208    
209        @NotNull
210        @Override
211        public JetScope getScopeForMemberLookup() {
212            return unsubstitutedMemberScope;
213        }
214    
215        @Override
216        @NotNull
217        public JetScope getScopeForClassHeaderResolution() {
218            return scopeForClassHeaderResolution.invoke();
219        }
220    
221        @NotNull
222        private JetScope computeScopeForClassHeaderResolution() {
223            WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with type parameters for " + getName());
224            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
225                scope.addClassifierDescriptor(typeParameterDescriptor);
226            }
227            scope.changeLockLevel(WritableScope.LockLevel.READING);
228    
229            PsiElement scopeAnchor = declarationProvider.getOwnerInfo().getScopeAnchor();
230    
231            return new ChainedScope(this, "ScopeForClassHeaderResolution: " + getName(),
232                    scope,
233                    getScopeProvider().getResolutionScopeForDeclaration(scopeAnchor));
234        }
235    
236        @Override
237        @NotNull
238        public JetScope getScopeForMemberDeclarationResolution() {
239            return scopeForMemberDeclarationResolution.invoke();
240        }
241    
242        @NotNull
243        private JetScope computeScopeForMemberDeclarationResolution() {
244            WritableScopeImpl thisScope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with 'this' for " + getName());
245            thisScope.addLabeledDeclaration(this);
246            thisScope.setImplicitReceiver(this.getThisAsReceiverParameter());
247            thisScope.changeLockLevel(WritableScope.LockLevel.READING);
248    
249            ClassDescriptor classObject = getClassObjectDescriptor();
250            JetScope classObjectAdapterScope = (classObject != null) ? new ClassObjectMixinScope(classObject) : JetScope.EMPTY;
251    
252            return new ChainedScope(
253                    this,
254                    "ScopeForMemberDeclarationResolution: " + getName(),
255                    thisScope,
256                    getScopeForMemberLookup(),
257                    getScopeForClassHeaderResolution(),
258                    classObjectAdapterScope,
259                    getStaticScope()
260            );
261        }
262    
263        @Override
264        @NotNull
265        public JetScope getScopeForInitializerResolution() {
266            return scopeForPropertyInitializerResolution.invoke();
267        }
268    
269        @NotNull
270        @Override
271        public Collection<CallableMemberDescriptor> getDeclaredCallableMembers() {
272            //noinspection unchecked
273            return (Collection) KotlinPackage.filter(
274                    unsubstitutedMemberScope.getAllDescriptors(),
275                    new Function1<DeclarationDescriptor, Boolean>() {
276                        @Override
277                        public Boolean invoke(DeclarationDescriptor descriptor) {
278                            return descriptor instanceof CallableMemberDescriptor
279                                   && ((CallableMemberDescriptor) descriptor).getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
280                        }
281                    }
282            );
283        }
284    
285        @NotNull
286        private JetScope computeScopeForPropertyInitializerResolution() {
287            ConstructorDescriptor primaryConstructor = getUnsubstitutedPrimaryConstructor();
288            if (primaryConstructor == null) return getScopeForMemberDeclarationResolution();
289    
290            WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, primaryConstructor, RedeclarationHandler.DO_NOTHING, "Scope with constructor parameters in " + getName());
291            for (int i = 0; i < originalClassInfo.getPrimaryConstructorParameters().size(); i++) {
292                JetParameter jetParameter = originalClassInfo.getPrimaryConstructorParameters().get(i);
293                if (!jetParameter.hasValOrVarNode()) {
294                    scope.addVariableDescriptor(primaryConstructor.getValueParameters().get(i));
295                }
296            }
297            scope.changeLockLevel(WritableScope.LockLevel.READING);
298    
299            return new ChainedScope(
300                    primaryConstructor,
301                    "ScopeForPropertyInitializerResolution: " + getName(),
302                    scope, getScopeForMemberDeclarationResolution());
303        }
304    
305        @NotNull
306        @Override
307        public JetScope getStaticScope() {
308            return staticScope;
309        }
310    
311        @NotNull
312        @Override
313        public Collection<ConstructorDescriptor> getConstructors() {
314            return unsubstitutedMemberScope.getConstructors();
315        }
316    
317        @Override
318        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
319            return unsubstitutedMemberScope.getPrimaryConstructor();
320        }
321    
322        @NotNull
323        @Override
324        public TypeConstructor getTypeConstructor() {
325            return typeConstructor;
326        }
327    
328        @Override
329        public LazyClassDescriptor getClassObjectDescriptor() {
330            return classObjectDescriptor.invoke();
331        }
332    
333        @NotNull
334        @ReadOnly
335        public List<ClassDescriptor> getDescriptorsForExtraClassObjects() {
336            return KotlinPackage.map(
337                    KotlinPackage.filter(
338                            declarationProvider.getOwnerInfo().getClassObjects(),
339                            new Function1<JetClassObject, Boolean>() {
340                                @Override
341                                public Boolean invoke(JetClassObject classObject) {
342                                    return classObject != declarationProvider.getOwnerInfo().getClassObject();
343                                }
344                            }
345                    ),
346                    new Function1<JetClassObject, ClassDescriptor>() {
347                        @Override
348                        public ClassDescriptor invoke(JetClassObject classObject) {
349                            return extraClassObjectDescriptors.invoke(classObject);
350                        }
351                    }
352            );
353        }
354    
355        @Nullable
356        private LazyClassDescriptor computeClassObjectDescriptor(@Nullable JetClassObject classObject) {
357            JetClassLikeInfo classObjectInfo = getClassObjectInfo(classObject);
358            if (classObjectInfo != null) {
359                return new LazyClassDescriptor(resolveSession, this, getClassObjectName(getName()), classObjectInfo);
360            }
361            return null;
362        }
363    
364        @Nullable
365        private JetClassLikeInfo getClassObjectInfo(@Nullable JetClassObject classObject) {
366            if (classObject != null) {
367                if (getKind().isSingleton() || isInner()) {
368                    resolveSession.getTrace().report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
369                }
370    
371                return JetClassInfoUtil.createClassLikeInfo(classObject.getObjectDeclaration());
372            }
373            else if (getKind() == ClassKind.OBJECT || getKind() == ClassKind.ENUM_ENTRY) {
374                return new SyntheticClassObjectInfo(originalClassInfo, this);
375            }
376    
377            return null;
378        }
379    
380        @NotNull
381        @Override
382        public ClassKind getKind() {
383            return kind;
384        }
385    
386        @NotNull
387        @Override
388        public Modality getModality() {
389            return modality;
390        }
391    
392        @NotNull
393        @Override
394        public Visibility getVisibility() {
395            return visibility;
396        }
397    
398        @Override
399        public boolean isInner() {
400            return isInner;
401        }
402    
403        @NotNull
404        @Override
405        public Annotations getAnnotations() {
406            return annotations;
407        }
408    
409        @Override
410        public String toString() {
411            // not using descriptor render to preserve laziness
412            return "lazy class " + getName().toString();
413        }
414    
415        @Override
416        public void forceResolveAllContents() {
417            forceResolveAllContents.invoke();
418        }
419    
420        private void doForceResolveAllContents() {
421            resolveMemberHeaders();
422            ClassDescriptor classObjectDescriptor = getClassObjectDescriptor();
423            if (classObjectDescriptor != null) {
424                ForceResolveUtil.forceResolveAllContents(classObjectDescriptor);
425            }
426    
427            ForceResolveUtil.forceResolveAllContents(getConstructors());
428            ForceResolveUtil.forceResolveAllContents(getDescriptorsForExtraClassObjects());
429            ForceResolveUtil.forceResolveAllContents(getScopeForMemberLookup());
430            ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
431        }
432    
433        // Note: headers of member classes' members are not resolved
434        public void resolveMemberHeaders() {
435            ForceResolveUtil.forceResolveAllContents(getAnnotations());
436    
437            getClassObjectDescriptor();
438    
439            getDescriptorsForExtraClassObjects();
440    
441            getClassObjectType();
442            getConstructors();
443            getContainingDeclaration();
444            getThisAsReceiverParameter();
445            getKind();
446            getModality();
447            getName();
448            getOriginal();
449            getScopeForClassHeaderResolution();
450            getScopeForMemberDeclarationResolution();
451            getScopeForMemberLookup().getAllDescriptors();
452            getScopeForInitializerResolution();
453            getUnsubstitutedInnerClassesScope();
454            getTypeConstructor().getSupertypes();
455            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
456                typeParameterDescriptor.getUpperBounds();
457                typeParameterDescriptor.getLowerBounds();
458            }
459            getUnsubstitutedPrimaryConstructor();
460            getVisibility();
461        }
462    
463        private static class Supertypes {
464            @Mutable
465            public final Collection<JetType> trueSupertypes;
466            @Mutable
467            public final Collection<JetType> cyclicSupertypes;
468    
469            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes) {
470                this(trueSupertypes, new ArrayList<JetType>(0));
471            }
472    
473            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes, @Mutable @NotNull Collection<JetType> cyclicSupertypes) {
474                this.trueSupertypes = trueSupertypes;
475                this.cyclicSupertypes = cyclicSupertypes;
476            }
477    
478            @NotNull
479            public Collection<JetType> getAllSupertypes() {
480                return KotlinPackage.plus(trueSupertypes, cyclicSupertypes);
481            }
482        }
483    
484        private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
485            private final NotNullLazyValue<Supertypes> supertypes = resolveSession.getStorageManager().createLazyValueWithPostCompute(
486                    new Function0<Supertypes>() {
487                        @Override
488                        public Supertypes invoke() {
489                            if (KotlinBuiltIns.getInstance().isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
490                                return new Supertypes(Collections.<JetType>emptyList());
491                            }
492    
493                            JetClassLikeInfo info = declarationProvider.getOwnerInfo();
494                            if (info instanceof SyntheticClassObjectInfo) {
495                                LazyClassDescriptor descriptor = ((SyntheticClassObjectInfo) info).getClassDescriptor();
496                                if (descriptor.getKind().isSingleton()) {
497                                    return new Supertypes(Collections.singleton(descriptor.getDefaultType()));
498                                }
499                            }
500    
501                            JetClassOrObject classOrObject = info.getCorrespondingClassOrObject();
502                            if (classOrObject == null) {
503                                return new Supertypes(Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()));
504                            }
505    
506                            List<JetType> allSupertypes = resolveSession.getDescriptorResolver()
507                                    .resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
508                                                       resolveSession.getTrace());
509    
510                            return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
511                        }
512                    },
513                    new Function1<Boolean, Supertypes>() {
514                        @Override
515                        public Supertypes invoke(Boolean firstTime) {
516                            return new Supertypes(Collections.<JetType>emptyList());
517                        }
518                    },
519                    new Function1<Supertypes, Unit>() {
520                        @Override
521                        public Unit invoke(@NotNull Supertypes supertypes) {
522                            findAndDisconnectLoopsInTypeHierarchy(supertypes);
523                            return Unit.INSTANCE$;
524                        }
525                    }
526            );
527    
528            private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = resolveSession.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
529                @Override
530                public List<TypeParameterDescriptor> invoke() {
531                    JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
532                    List<JetTypeParameter> typeParameters = classInfo.getTypeParameters();
533    
534                    List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
535                    for (int i = 0; i < typeParameters.size(); i++) {
536                        parameters.add(new LazyTypeParameterDescriptor(resolveSession, LazyClassDescriptor.this, typeParameters.get(i), i));
537                    }
538    
539                    return parameters;
540                }
541            });
542    
543            private final NullableLazyValue<Void> forceResolveAllContents =
544                    resolveSession.getStorageManager().createRecursionTolerantNullableLazyValue(new Function0<Void>() {
545                        @Override
546                        public Void invoke() {
547                            doForceResolveAllContents();
548                            return null;
549                        }
550                    }, null);
551    
552            @NotNull
553            @Override
554            public List<TypeParameterDescriptor> getParameters() {
555                return parameters.invoke();
556            }
557    
558            @NotNull
559            @Override
560            public Collection<JetType> getSupertypes() {
561                return supertypes.invoke().trueSupertypes;
562            }
563    
564            private void findAndDisconnectLoopsInTypeHierarchy(Supertypes supertypes) {
565                for (Iterator<JetType> iterator = supertypes.trueSupertypes.iterator(); iterator.hasNext(); ) {
566                    JetType supertype = iterator.next();
567                    if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
568                        iterator.remove();
569                        supertypes.cyclicSupertypes.add(supertype);
570    
571                        ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
572                        if (supertypeDescriptor instanceof ClassDescriptor) {
573                            ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
574                            TypeHierarchyResolver.reportCyclicInheritanceHierarchyError(resolveSession.getTrace(), LazyClassDescriptor.this,
575                                                                                        superclass);
576                        }
577                    }
578                }
579            }
580    
581            private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
582                if (!visited.add(from)) return false;
583                for (JetType supertype : getNeighbors(from)) {
584                    TypeConstructor supertypeConstructor = supertype.getConstructor();
585                    if (supertypeConstructor == to) {
586                        return true;
587                    }
588                    if (isReachable(supertypeConstructor, to, visited)) {
589                        return true;
590                    }
591                }
592                return false;
593            }
594    
595            private Collection<JetType> getNeighbors(TypeConstructor from) {
596                // Supertypes + type for container
597                Collection<JetType> neighbours = new ArrayList<JetType>(
598                        from instanceof LazyClassTypeConstructor
599                                 ? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
600                                 : from.getSupertypes()
601                );
602    
603                ClassifierDescriptor fromDescriptor = from.getDeclarationDescriptor();
604                if (fromDescriptor != null) {
605                    DeclarationDescriptor container = fromDescriptor.getContainingDeclaration();
606                    if (container instanceof ClassDescriptor) {
607                        neighbours.add(((ClassDescriptor) container).getDefaultType());
608                    }
609                }
610                return neighbours;
611            }
612    
613            @Override
614            public boolean isFinal() {
615                return !getModality().isOverridable();
616            }
617    
618            @Override
619            public boolean isDenotable() {
620                return true;
621            }
622    
623            @Override
624            public ClassifierDescriptor getDeclarationDescriptor() {
625                return LazyClassDescriptor.this;
626            }
627    
628            @NotNull
629            @Override
630            public Annotations getAnnotations() {
631                return Annotations.EMPTY; // TODO
632            }
633    
634            @Override
635            public String toString() {
636                return LazyClassDescriptor.this.getName().toString();
637            }
638    
639            @Override
640            public void forceResolveAllContents() {
641                forceResolveAllContents.invoke();
642            }
643    
644            private void doForceResolveAllContents() {
645                ForceResolveUtil.forceResolveAllContents(getAnnotations());
646                ForceResolveUtil.forceResolveAllContents(getSupertypes());
647                ForceResolveUtil.forceResolveAllContents(getParameters());
648            }
649        }
650    
651        @NotNull
652        private ScopeProvider getScopeProvider() {
653            return resolveSession.getScopeProvider();
654        }
655    }