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.descriptors.impl.EnumClassObjectDescriptor;
035    import org.jetbrains.jet.lang.psi.*;
036    import org.jetbrains.jet.lang.resolve.BindingContext;
037    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
038    import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver;
039    import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
040    import org.jetbrains.jet.lang.resolve.lazy.LazyEntity;
041    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
042    import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
043    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
044    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
045    import org.jetbrains.jet.lang.resolve.lazy.data.SyntheticClassObjectInfo;
046    import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
047    import org.jetbrains.jet.lang.resolve.name.Name;
048    import org.jetbrains.jet.lang.resolve.scopes.*;
049    import org.jetbrains.jet.lang.types.AbstractClassTypeConstructor;
050    import org.jetbrains.jet.lang.types.JetType;
051    import org.jetbrains.jet.lang.types.TypeConstructor;
052    import org.jetbrains.jet.lang.types.TypeUtils;
053    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
054    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
055    import org.jetbrains.jet.storage.NotNullLazyValue;
056    import org.jetbrains.jet.storage.NullableLazyValue;
057    import org.jetbrains.jet.storage.StorageManager;
058    
059    import java.util.*;
060    
061    import static org.jetbrains.jet.lang.diagnostics.Errors.CLASS_OBJECT_NOT_ALLOWED;
062    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isSyntheticClassObject;
063    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*;
064    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
065    import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
066    
067    public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDescriptorWithResolutionScopes, LazyEntity {
068        private static final Predicate<JetType> VALID_SUPERTYPE = new Predicate<JetType>() {
069            @Override
070            public boolean apply(JetType type) {
071                assert !type.isError() : "Error types must be filtered out in DescriptorResolver";
072                return TypeUtils.getClassDescriptor(type) != null;
073            }
074        };
075        private final ResolveSession resolveSession;
076    
077        private final JetClassLikeInfo originalClassInfo;
078        private final ClassMemberDeclarationProvider declarationProvider;
079    
080        private final LazyClassTypeConstructor typeConstructor;
081        private final Modality modality;
082        private final Visibility visibility;
083        private final ClassKind kind;
084        private final boolean isInner;
085    
086        private final Annotations annotations;
087        private final NullableLazyValue<ClassDescriptor> classObjectDescriptor;
088        private final MemoizedFunctionToNotNull<JetClassObject, ClassDescriptor> extraClassObjectDescriptors;
089    
090        private final LazyClassMemberScope unsubstitutedMemberScope;
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<ClassDescriptor>() {
162                @Override
163                public ClassDescriptor 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.changeLockLevel(WritableScope.LockLevel.READING);
247    
248            ClassDescriptor classObject = getClassObjectDescriptor();
249            JetScope classObjectAdapterScope = (classObject != null) ? new ClassObjectMixinScope(classObject) : JetScope.EMPTY;
250    
251            return new ChainedScope(
252                    this,
253                    "ScopeForMemberDeclarationResolution: " + getName(),
254                    thisScope,
255                    getScopeForMemberLookup(),
256                    getScopeForClassHeaderResolution(),
257                    classObjectAdapterScope);
258        }
259    
260        @Override
261        @NotNull
262        public JetScope getScopeForInitializerResolution() {
263            return scopeForPropertyInitializerResolution.invoke();
264        }
265    
266        @NotNull
267        @Override
268        public Collection<CallableMemberDescriptor> getDeclaredCallableMembers() {
269            //noinspection unchecked
270            return (Collection) KotlinPackage.filter(
271                    unsubstitutedMemberScope.getAllDescriptors(),
272                    new Function1<DeclarationDescriptor, Boolean>() {
273                        @Override
274                        public Boolean invoke(DeclarationDescriptor descriptor) {
275                            return descriptor instanceof CallableMemberDescriptor
276                                   && ((CallableMemberDescriptor) descriptor).getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
277                        }
278                    }
279            );
280        }
281    
282        @NotNull
283        private JetScope computeScopeForPropertyInitializerResolution() {
284            ConstructorDescriptor primaryConstructor = getUnsubstitutedPrimaryConstructor();
285            if (primaryConstructor == null) return getScopeForMemberDeclarationResolution();
286    
287            WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, primaryConstructor, RedeclarationHandler.DO_NOTHING, "Scope with constructor parameters in " + getName());
288            for (int i = 0; i < originalClassInfo.getPrimaryConstructorParameters().size(); i++) {
289                JetParameter jetParameter = originalClassInfo.getPrimaryConstructorParameters().get(i);
290                if (!jetParameter.hasValOrVarNode()) {
291                    scope.addVariableDescriptor(primaryConstructor.getValueParameters().get(i));
292                }
293            }
294            scope.changeLockLevel(WritableScope.LockLevel.READING);
295    
296            return new ChainedScope(
297                    primaryConstructor,
298                    "ScopeForPropertyInitializerResolution: " + getName(),
299                    scope, getScopeForMemberDeclarationResolution());
300        }
301    
302        @NotNull
303        @Override
304        public Collection<ConstructorDescriptor> getConstructors() {
305            return unsubstitutedMemberScope.getConstructors();
306        }
307    
308        @Override
309        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
310            return unsubstitutedMemberScope.getPrimaryConstructor();
311        }
312    
313        @NotNull
314        @Override
315        public TypeConstructor getTypeConstructor() {
316            return typeConstructor;
317        }
318    
319        @Override
320        public ClassDescriptor getClassObjectDescriptor() {
321            return classObjectDescriptor.invoke();
322        }
323    
324        @NotNull
325        @ReadOnly
326        public List<ClassDescriptor> getDescriptorsForExtraClassObjects() {
327            return KotlinPackage.map(
328                    KotlinPackage.filter(
329                            declarationProvider.getOwnerInfo().getClassObjects(),
330                            new Function1<JetClassObject, Boolean>() {
331                                @Override
332                                public Boolean invoke(JetClassObject classObject) {
333                                    return classObject != declarationProvider.getOwnerInfo().getClassObject();
334                                }
335                            }
336                    ),
337                    new Function1<JetClassObject, ClassDescriptor>() {
338                        @Override
339                        public ClassDescriptor invoke(JetClassObject classObject) {
340                            return extraClassObjectDescriptors.invoke(classObject);
341                        }
342                    }
343            );
344        }
345    
346        @Nullable
347        private ClassDescriptor computeClassObjectDescriptor(@Nullable JetClassObject classObject) {
348            if (getKind() == ClassKind.ENUM_CLASS) {
349                return new EnumClassObjectDescriptor(resolveSession.getStorageManager(), this);
350            }
351            JetClassLikeInfo classObjectInfo = getClassObjectInfo(classObject);
352            if (classObjectInfo != null) {
353                return new LazyClassDescriptor(resolveSession, this, getClassObjectName(getName()), classObjectInfo);
354            }
355            return null;
356        }
357    
358        @Nullable
359        private JetClassLikeInfo getClassObjectInfo(@Nullable JetClassObject classObject) {
360            if (classObject != null) {
361                if (getKind() != ClassKind.CLASS && getKind() != ClassKind.TRAIT && getKind() != ClassKind.ANNOTATION_CLASS || isInner()) {
362                    resolveSession.getTrace().report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
363                }
364    
365                JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
366                return JetClassInfoUtil.createClassLikeInfo(objectDeclaration);
367            }
368            else if (getKind() == ClassKind.OBJECT || getKind() == ClassKind.ENUM_ENTRY) {
369                return new SyntheticClassObjectInfo(originalClassInfo, this);
370            }
371    
372            return null;
373        }
374    
375        @NotNull
376        @Override
377        public ClassKind getKind() {
378            return kind;
379        }
380    
381        @NotNull
382        @Override
383        public Modality getModality() {
384            return modality;
385        }
386    
387        @NotNull
388        @Override
389        public Visibility getVisibility() {
390            return visibility;
391        }
392    
393        @Override
394        public boolean isInner() {
395            return isInner;
396        }
397    
398        @NotNull
399        @Override
400        public Annotations getAnnotations() {
401            return annotations;
402        }
403    
404        @Override
405        public String toString() {
406            // not using descriptor render to preserve laziness
407            return "lazy class " + getName().toString();
408        }
409    
410        @Override
411        public void forceResolveAllContents() {
412            forceResolveAllContents.invoke();
413        }
414    
415        private void doForceResolveAllContents() {
416            resolveMemberHeaders();
417            ClassDescriptor classObjectDescriptor = getClassObjectDescriptor();
418            if (classObjectDescriptor != null) {
419                ForceResolveUtil.forceResolveAllContents(classObjectDescriptor);
420            }
421    
422            ForceResolveUtil.forceResolveAllContents(getConstructors());
423            ForceResolveUtil.forceResolveAllContents(getDescriptorsForExtraClassObjects());
424            ForceResolveUtil.forceResolveAllContents(getScopeForMemberLookup());
425            ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
426        }
427    
428        // Note: headers of member classes' members are not resolved
429        public void resolveMemberHeaders() {
430            ForceResolveUtil.forceResolveAllContents(getAnnotations());
431    
432            getClassObjectDescriptor();
433    
434            getDescriptorsForExtraClassObjects();
435    
436            getClassObjectType();
437            getConstructors();
438            getContainingDeclaration();
439            getThisAsReceiverParameter();
440            getKind();
441            getModality();
442            getName();
443            getOriginal();
444            getScopeForClassHeaderResolution();
445            getScopeForMemberDeclarationResolution();
446            getScopeForMemberLookup().getAllDescriptors();
447            getScopeForInitializerResolution();
448            getUnsubstitutedInnerClassesScope();
449            getTypeConstructor().getSupertypes();
450            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
451                typeParameterDescriptor.getUpperBounds();
452                typeParameterDescriptor.getLowerBounds();
453            }
454            getUnsubstitutedPrimaryConstructor();
455            getVisibility();
456        }
457    
458        private static class Supertypes {
459            @Mutable
460            public final Collection<JetType> trueSupertypes;
461            @Mutable
462            public final Collection<JetType> cyclicSupertypes;
463    
464            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes) {
465                this(trueSupertypes, new ArrayList<JetType>(0));
466            }
467    
468            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes, @Mutable @NotNull Collection<JetType> cyclicSupertypes) {
469                this.trueSupertypes = trueSupertypes;
470                this.cyclicSupertypes = cyclicSupertypes;
471            }
472    
473            @NotNull
474            public Collection<JetType> getAllSupertypes() {
475                return KotlinPackage.plus(trueSupertypes, cyclicSupertypes);
476            }
477        }
478    
479        private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
480            private final NotNullLazyValue<Supertypes> supertypes = resolveSession.getStorageManager().createLazyValueWithPostCompute(
481                    new Function0<Supertypes>() {
482                        @Override
483                        public Supertypes invoke() {
484                            if (KotlinBuiltIns.getInstance().isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
485                                return new Supertypes(Collections.<JetType>emptyList());
486                            }
487    
488                            JetClassLikeInfo info = declarationProvider.getOwnerInfo();
489                            if (info instanceof SyntheticClassObjectInfo) {
490                                LazyClassDescriptor descriptor = ((SyntheticClassObjectInfo) info).getClassDescriptor();
491                                if (descriptor.getKind().isSingleton()) {
492                                    return new Supertypes(Collections.singleton(descriptor.getDefaultType()));
493                                }
494                            }
495    
496                            JetClassOrObject classOrObject = info.getCorrespondingClassOrObject();
497                            if (classOrObject == null) {
498                                return new Supertypes(Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()));
499                            }
500    
501                            List<JetType> allSupertypes = resolveSession.getDescriptorResolver()
502                                    .resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
503                                                       resolveSession.getTrace());
504    
505                            return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
506                        }
507                    },
508                    new Function1<Boolean, Supertypes>() {
509                        @Override
510                        public Supertypes invoke(Boolean firstTime) {
511                            return new Supertypes(Collections.<JetType>emptyList());
512                        }
513                    },
514                    new Function1<Supertypes, Unit>() {
515                        @Override
516                        public Unit invoke(@NotNull Supertypes supertypes) {
517                            findAndDisconnectLoopsInTypeHierarchy(supertypes);
518                            return Unit.INSTANCE$;
519                        }
520                    }
521            );
522    
523            private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = resolveSession.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
524                @Override
525                public List<TypeParameterDescriptor> invoke() {
526                    JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
527                    List<JetTypeParameter> typeParameters = classInfo.getTypeParameters();
528    
529                    List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
530                    for (int i = 0; i < typeParameters.size(); i++) {
531                        parameters.add(new LazyTypeParameterDescriptor(resolveSession, LazyClassDescriptor.this, typeParameters.get(i), i));
532                    }
533    
534                    return parameters;
535                }
536            });
537    
538            private final NullableLazyValue<Void> forceResolveAllContents =
539                    resolveSession.getStorageManager().createRecursionTolerantNullableLazyValue(new Function0<Void>() {
540                        @Override
541                        public Void invoke() {
542                            doForceResolveAllContents();
543                            return null;
544                        }
545                    }, null);
546    
547            @NotNull
548            @Override
549            public List<TypeParameterDescriptor> getParameters() {
550                return parameters.invoke();
551            }
552    
553            @NotNull
554            @Override
555            public Collection<JetType> getSupertypes() {
556                return supertypes.invoke().trueSupertypes;
557            }
558    
559            private void findAndDisconnectLoopsInTypeHierarchy(Supertypes supertypes) {
560                for (Iterator<JetType> iterator = supertypes.trueSupertypes.iterator(); iterator.hasNext(); ) {
561                    JetType supertype = iterator.next();
562                    if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
563                        iterator.remove();
564                        supertypes.cyclicSupertypes.add(supertype);
565    
566                        ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
567                        if (supertypeDescriptor instanceof ClassDescriptor) {
568                            ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
569                            TypeHierarchyResolver.reportCyclicInheritanceHierarchyError(resolveSession.getTrace(), LazyClassDescriptor.this,
570                                                                                        superclass);
571                        }
572                    }
573                }
574            }
575    
576            private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
577                if (!visited.add(from)) return false;
578                for (JetType supertype : getNeighbors(from)) {
579                    TypeConstructor supertypeConstructor = supertype.getConstructor();
580                    if (supertypeConstructor == to) {
581                        return true;
582                    }
583                    if (isReachable(supertypeConstructor, to, visited)) {
584                        return true;
585                    }
586                }
587                return false;
588            }
589    
590            private Collection<JetType> getNeighbors(TypeConstructor from) {
591                // Supertypes + type for container
592                Collection<JetType> neighbours = new ArrayList<JetType>(
593                        from instanceof LazyClassTypeConstructor
594                                 ? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
595                                 : from.getSupertypes()
596                );
597    
598                ClassifierDescriptor fromDescriptor = from.getDeclarationDescriptor();
599                if (fromDescriptor != null) {
600                    DeclarationDescriptor container = fromDescriptor.getContainingDeclaration();
601                    if (container instanceof ClassDescriptor) {
602                        neighbours.add(((ClassDescriptor) container).getDefaultType());
603                    }
604                }
605                return neighbours;
606            }
607    
608            @Override
609            public boolean isFinal() {
610                return !getModality().isOverridable();
611            }
612    
613            @Override
614            public boolean isDenotable() {
615                return true;
616            }
617    
618            @Override
619            public ClassifierDescriptor getDeclarationDescriptor() {
620                return LazyClassDescriptor.this;
621            }
622    
623            @NotNull
624            @Override
625            public Annotations getAnnotations() {
626                return Annotations.EMPTY; // TODO
627            }
628    
629            @Override
630            public String toString() {
631                return LazyClassDescriptor.this.getName().toString();
632            }
633    
634            @Override
635            public void forceResolveAllContents() {
636                forceResolveAllContents.invoke();
637            }
638    
639            private void doForceResolveAllContents() {
640                ForceResolveUtil.forceResolveAllContents(getAnnotations());
641                ForceResolveUtil.forceResolveAllContents(getSupertypes());
642                ForceResolveUtil.forceResolveAllContents(getParameters());
643            }
644        }
645    
646        @NotNull
647        private ScopeProvider getScopeProvider() {
648            return resolveSession.getScopeProvider();
649        }
650    }