001    /*
002     * Copyright 2010-2015 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.kotlin.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 com.intellij.psi.PsiNameIdentifierOwner;
024    import kotlin.CollectionsKt;
025    import kotlin.Unit;
026    import kotlin.jvm.functions.Function0;
027    import kotlin.jvm.functions.Function1;
028    import org.jetbrains.annotations.Mutable;
029    import org.jetbrains.annotations.NotNull;
030    import org.jetbrains.annotations.Nullable;
031    import org.jetbrains.annotations.ReadOnly;
032    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
033    import org.jetbrains.kotlin.descriptors.*;
034    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
035    import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase;
036    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
037    import org.jetbrains.kotlin.lexer.KtTokens;
038    import org.jetbrains.kotlin.name.Name;
039    import org.jetbrains.kotlin.psi.*;
040    import org.jetbrains.kotlin.resolve.*;
041    import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
042    import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
043    import org.jetbrains.kotlin.resolve.lazy.LazyEntity;
044    import org.jetbrains.kotlin.resolve.lazy.data.KtClassInfoUtil;
045    import org.jetbrains.kotlin.resolve.lazy.data.KtClassLikeInfo;
046    import org.jetbrains.kotlin.resolve.lazy.data.KtClassOrObjectInfo;
047    import org.jetbrains.kotlin.resolve.lazy.data.KtObjectInfo;
048    import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider;
049    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
050    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
051    import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinClass;
052    import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
053    import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull;
054    import org.jetbrains.kotlin.storage.NotNullLazyValue;
055    import org.jetbrains.kotlin.storage.NullableLazyValue;
056    import org.jetbrains.kotlin.storage.StorageManager;
057    import org.jetbrains.kotlin.types.AbstractClassTypeConstructor;
058    import org.jetbrains.kotlin.types.KotlinType;
059    import org.jetbrains.kotlin.types.TypeConstructor;
060    import org.jetbrains.kotlin.types.TypeUtils;
061    
062    import java.util.ArrayList;
063    import java.util.Collection;
064    import java.util.Collections;
065    import java.util.List;
066    
067    import static kotlin.CollectionsKt.firstOrNull;
068    import static org.jetbrains.kotlin.diagnostics.Errors.CYCLIC_INHERITANCE_HIERARCHY;
069    import static org.jetbrains.kotlin.diagnostics.Errors.TYPE_PARAMETERS_IN_ENUM;
070    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
071    import static org.jetbrains.kotlin.resolve.ModifiersChecker.*;
072    
073    public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDescriptorWithResolutionScopes, LazyEntity {
074        private static final Predicate<KotlinType> VALID_SUPERTYPE = new Predicate<KotlinType>() {
075            @Override
076            public boolean apply(KotlinType type) {
077                assert !type.isError() : "Error types must be filtered out in DescriptorResolver";
078                return TypeUtils.getClassDescriptor(type) != null;
079            }
080        };
081        private final LazyClassContext c;
082    
083        private final ClassMemberDeclarationProvider declarationProvider;
084    
085        private final LazyClassTypeConstructor typeConstructor;
086        private final Modality modality;
087        private final Visibility visibility;
088        private final NotNullLazyValue<ClassKind> kind;
089        private final NotNullLazyValue<Boolean> isInner;
090        private final NotNullLazyValue<Boolean> isData;
091    
092        private final Annotations annotations;
093        private final Annotations danglingAnnotations;
094        private final NullableLazyValue<LazyClassDescriptor> companionObjectDescriptor;
095        private final MemoizedFunctionToNotNull<KtObjectDeclaration, ClassDescriptor> extraCompanionObjectDescriptors;
096    
097        private final LazyClassMemberScope unsubstitutedMemberScope;
098        private final MemberScope staticScope;
099    
100        private final NullableLazyValue<Void> forceResolveAllContents;
101        private final boolean isCompanionObject;
102    
103        private final ClassResolutionScopesSupport resolutionScopesSupport;
104        private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters;
105    
106        public LazyClassDescriptor(
107                @NotNull final LazyClassContext c,
108                @NotNull DeclarationDescriptor containingDeclaration,
109                @NotNull Name name,
110                @NotNull KtClassLikeInfo classLikeInfo
111        ) {
112            super(c.getStorageManager(), containingDeclaration, name,
113                  KotlinSourceElementKt.toSourceElement(classLikeInfo.getCorrespondingClassOrObject())
114            );
115            this.c = c;
116    
117            KtClassOrObject classOrObject = classLikeInfo.getCorrespondingClassOrObject();
118            if (classOrObject != null) {
119                this.c.getTrace().record(BindingContext.CLASS, classOrObject, this);
120            }
121            this.c.getTrace().record(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFqName(this), this);
122    
123            this.declarationProvider = c.getDeclarationProviderFactory().getClassMemberDeclarationProvider(classLikeInfo);
124    
125            this.unsubstitutedMemberScope = createMemberScope(c, this.declarationProvider);
126            this.staticScope = new StaticScopeForKotlinClass(this);
127    
128            this.typeConstructor = new LazyClassTypeConstructor();
129    
130            final ClassKind syntaxKind = classLikeInfo.getClassKind();
131            this.isCompanionObject = classLikeInfo instanceof KtObjectInfo && ((KtObjectInfo) classLikeInfo).isCompanionObject();
132    
133            final KtModifierList modifierList = classLikeInfo.getModifierList();
134            if (syntaxKind.isSingleton()) {
135                this.modality = Modality.FINAL;
136            }
137            else {
138                Modality defaultModality = syntaxKind == ClassKind.INTERFACE ? Modality.ABSTRACT : Modality.FINAL;
139                this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
140            }
141    
142            boolean isLocal = classOrObject != null && KtPsiUtil.isLocal(classOrObject);
143            Visibility defaultVisibility;
144            if (syntaxKind == ClassKind.ENUM_ENTRY || (syntaxKind == ClassKind.OBJECT && isCompanionObject)) {
145                defaultVisibility = Visibilities.PUBLIC;
146            }
147            else {
148                defaultVisibility = Visibilities.DEFAULT_VISIBILITY;
149            }
150            this.visibility = isLocal ? Visibilities.LOCAL : resolveVisibilityFromModifiers(modifierList, defaultVisibility);
151    
152            StorageManager storageManager = c.getStorageManager();
153            final ClassDescriptor descriptor = this;
154    
155            this.isInner = storageManager.createLazyValue(new Function0<Boolean>() {
156                @Override
157                public Boolean invoke() {
158                    return isInnerClass(modifierList) && !ModifiersChecker.isIllegalInner(descriptor);
159                }
160            });
161    
162            this.isData = storageManager.createLazyValue(new Function0<Boolean>() {
163                @Override
164                public Boolean invoke() {
165                    return modifierList != null && modifierList.hasModifier(KtTokens.DATA_KEYWORD);
166                }
167            });
168    
169            this.kind = storageManager.createLazyValue(new Function0<ClassKind>() {
170                @Override
171                public ClassKind invoke() {
172                    return (syntaxKind == ClassKind.CLASS && modifierList != null && modifierList.hasModifier(KtTokens.ANNOTATION_KEYWORD)) ? ClassKind.ANNOTATION_CLASS : syntaxKind;
173                }
174            });
175    
176            if (modifierList != null) {
177                this.annotations = new LazyAnnotations(
178                        new LazyAnnotationsContext(
179                                c.getAnnotationResolver(),
180                                storageManager,
181                                c.getTrace()
182                        ) {
183                            @NotNull
184                            @Override
185                            public LexicalScope getScope() {
186                                return getOuterScope();
187                            }
188                        },
189                        modifierList.getAnnotationEntries()
190                );
191            }
192            else {
193                this.annotations = Annotations.Companion.getEMPTY();
194            }
195    
196            List<KtAnnotationEntry> jetDanglingAnnotations = classLikeInfo.getDanglingAnnotations();
197            if (jetDanglingAnnotations.isEmpty()) {
198                this.danglingAnnotations = Annotations.Companion.getEMPTY();
199            }
200            else {
201                this.danglingAnnotations = new LazyAnnotations(
202                        new LazyAnnotationsContext(
203                                c.getAnnotationResolver(),
204                                storageManager,
205                                c.getTrace()
206                        ) {
207                            @NotNull
208                            @Override
209                            public LexicalScope getScope() {
210                                return getScopeForMemberDeclarationResolution();
211                            }
212                        },
213                        jetDanglingAnnotations
214                );
215            }
216    
217            this.companionObjectDescriptor = storageManager.createNullableLazyValue(new Function0<LazyClassDescriptor>() {
218                @Override
219                public LazyClassDescriptor invoke() {
220                    return computeCompanionObjectDescriptor(getCompanionObjectIfAllowed());
221                }
222            });
223            this.extraCompanionObjectDescriptors = storageManager.createMemoizedFunction(new Function1<KtObjectDeclaration, ClassDescriptor>() {
224                @Override
225                public ClassDescriptor invoke(KtObjectDeclaration companionObject) {
226                    return computeCompanionObjectDescriptor(companionObject);
227                }
228            });
229            this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() {
230                @Override
231                public Void invoke() {
232                    doForceResolveAllContents();
233                    return null;
234                }
235            }, null);
236    
237            this.resolutionScopesSupport = new ClassResolutionScopesSupport(this, storageManager, new Function0<LexicalScope>() {
238                @Override
239                public LexicalScope invoke() {
240                    return getOuterScope();
241                }
242            }, classLikeInfo.getPrimaryConstructorParameters());
243    
244            this.parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
245                @Override
246                public List<TypeParameterDescriptor> invoke() {
247                    KtClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
248                    KtTypeParameterList typeParameterList = classInfo.getTypeParameterList();
249                    if (typeParameterList == null) return Collections.emptyList();
250    
251                    if (classInfo.getClassKind() == ClassKind.ENUM_CLASS) {
252                        c.getTrace().report(TYPE_PARAMETERS_IN_ENUM.on(typeParameterList));
253                    }
254    
255                    List<KtTypeParameter> typeParameters = typeParameterList.getParameters();
256    
257                    List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
258    
259                    for (int i = 0; i < typeParameters.size(); i++) {
260                        parameters.add(new LazyTypeParameterDescriptor(c, LazyClassDescriptor.this, typeParameters.get(i), i));
261                    }
262    
263                    return parameters;
264                }
265            });
266    
267        }
268    
269        // NOTE: Called from constructor!
270        @NotNull
271        protected LazyClassMemberScope createMemberScope(
272                @NotNull LazyClassContext c,
273                @NotNull ClassMemberDeclarationProvider declarationProvider
274        ) {
275            return new LazyClassMemberScope(c, declarationProvider, this, c.getTrace());
276        }
277    
278        @NotNull
279        @Override
280        public MemberScope getUnsubstitutedMemberScope() {
281            return unsubstitutedMemberScope;
282        }
283    
284        @NotNull
285        protected LexicalScope getOuterScope() {
286            return c.getDeclarationScopeProvider().getResolutionScopeForDeclaration(declarationProvider.getOwnerInfo().getScopeAnchor());
287        }
288    
289        @Override
290        @NotNull
291        public LexicalScope getScopeForClassHeaderResolution() {
292            return resolutionScopesSupport.getScopeForClassHeaderResolution().invoke();
293        }
294    
295        @Override
296        @NotNull
297        public LexicalScope getScopeForConstructorHeaderResolution() {
298            return resolutionScopesSupport.getScopeForConstructorHeaderResolution().invoke();
299        }
300    
301        @Override
302        @NotNull
303        public LexicalScope getScopeForCompanionObjectHeaderResolution() {
304            return resolutionScopesSupport.getScopeForCompanionObjectHeaderResolution().invoke();
305        }
306    
307        @Override
308        @NotNull
309        public LexicalScope getScopeForMemberDeclarationResolution() {
310            return resolutionScopesSupport.getScopeForMemberDeclarationResolution().invoke();
311        }
312    
313        @Override
314        @NotNull
315        public LexicalScope getScopeForStaticMemberDeclarationResolution() {
316            return resolutionScopesSupport.getScopeForStaticMemberDeclarationResolution().invoke();
317        }
318    
319        @Override
320        @NotNull
321        public LexicalScope getScopeForInitializerResolution() {
322            return resolutionScopesSupport.getScopeForInitializerResolution().invoke();
323        }
324    
325        @NotNull
326        @Override
327        public Collection<CallableMemberDescriptor> getDeclaredCallableMembers() {
328            //noinspection unchecked
329            return (Collection) CollectionsKt.filter(
330                    DescriptorUtils.getAllDescriptors(unsubstitutedMemberScope),
331                    new Function1<DeclarationDescriptor, Boolean>() {
332                        @Override
333                        public Boolean invoke(DeclarationDescriptor descriptor) {
334                            return descriptor instanceof CallableMemberDescriptor
335                                   && ((CallableMemberDescriptor) descriptor).getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
336                        }
337                    }
338            );
339        }
340    
341        @NotNull
342        @Override
343        public MemberScope getStaticScope() {
344            return staticScope;
345        }
346    
347        @NotNull
348        @Override
349        public Collection<ConstructorDescriptor> getConstructors() {
350            return unsubstitutedMemberScope.getConstructors();
351        }
352    
353        @Override
354        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
355            return unsubstitutedMemberScope.getPrimaryConstructor();
356        }
357    
358        @NotNull
359        @Override
360        public TypeConstructor getTypeConstructor() {
361            return typeConstructor;
362        }
363    
364        @Override
365        public LazyClassDescriptor getCompanionObjectDescriptor() {
366            return companionObjectDescriptor.invoke();
367        }
368    
369        @NotNull
370        @ReadOnly
371        public List<ClassDescriptor> getDescriptorsForExtraCompanionObjects() {
372            final KtObjectDeclaration allowedCompanionObject = getCompanionObjectIfAllowed();
373    
374            return CollectionsKt.map(
375                    CollectionsKt.filter(
376                            declarationProvider.getOwnerInfo().getCompanionObjects(),
377                            new Function1<KtObjectDeclaration, Boolean>() {
378                                @Override
379                                public Boolean invoke(KtObjectDeclaration companionObject) {
380                                    return companionObject != allowedCompanionObject;
381                                }
382                            }
383                    ),
384                    new Function1<KtObjectDeclaration, ClassDescriptor>() {
385                        @Override
386                        public ClassDescriptor invoke(KtObjectDeclaration companionObject) {
387                            return extraCompanionObjectDescriptors.invoke(companionObject);
388                        }
389                    }
390            );
391        }
392    
393        @Nullable
394        private LazyClassDescriptor computeCompanionObjectDescriptor(@Nullable KtObjectDeclaration companionObject) {
395            KtClassLikeInfo companionObjectInfo = getCompanionObjectInfo(companionObject);
396            if (!(companionObjectInfo instanceof KtClassOrObjectInfo)) {
397                return null;
398            }
399            Name name = ((KtClassOrObjectInfo) companionObjectInfo).getName();
400            assert name != null;
401            getUnsubstitutedMemberScope().getContributedClassifier(name, NoLookupLocation.WHEN_GET_COMPANION_OBJECT);
402            ClassDescriptor companionObjectDescriptor = c.getTrace().get(BindingContext.CLASS, companionObject);
403            if (companionObjectDescriptor instanceof LazyClassDescriptor) {
404                assert DescriptorUtils.isCompanionObject(companionObjectDescriptor) : "Not a companion object: " + companionObjectDescriptor;
405                return (LazyClassDescriptor) companionObjectDescriptor;
406            }
407            else {
408                return null;
409            }
410        }
411    
412        @Nullable
413        private static KtClassLikeInfo getCompanionObjectInfo(@Nullable KtObjectDeclaration companionObject) {
414            if (companionObject != null) {
415                return KtClassInfoUtil.createClassLikeInfo(companionObject);
416            }
417    
418            return null;
419        }
420    
421        @Nullable
422        private KtObjectDeclaration getCompanionObjectIfAllowed() {
423            KtObjectDeclaration companionObject = firstOrNull(declarationProvider.getOwnerInfo().getCompanionObjects());
424            return (companionObject != null && isCompanionObjectAllowed()) ? companionObject : null;
425        }
426    
427        private boolean isCompanionObjectAllowed() {
428            return !(getKind().isSingleton() || isInner() || DescriptorUtils.isLocal(this));
429        }
430    
431        @NotNull
432        @Override
433        public ClassKind getKind() {
434            return kind.invoke();
435        }
436    
437        @NotNull
438        @Override
439        public Modality getModality() {
440            return modality;
441        }
442    
443        @NotNull
444        @Override
445        public Visibility getVisibility() {
446            return visibility;
447        }
448    
449        @Override
450        public boolean isInner() {
451            return isInner.invoke();
452        }
453    
454        @Override
455        public boolean isData() {
456            return isData.invoke();
457        }
458    
459        @Override
460        public boolean isCompanionObject() {
461            return isCompanionObject;
462        }
463    
464        @NotNull
465        @Override
466        public Annotations getAnnotations() {
467            return annotations;
468        }
469    
470        @NotNull
471        public Annotations getDanglingAnnotations() {
472            return danglingAnnotations;
473        }
474    
475        @Override
476        public String toString() {
477            // not using descriptor render to preserve laziness
478            return "lazy class " + getName().toString();
479        }
480    
481        @Override
482        public void forceResolveAllContents() {
483            forceResolveAllContents.invoke();
484        }
485    
486        private void doForceResolveAllContents() {
487            resolveMemberHeaders();
488            ClassDescriptor companionObjectDescriptor = getCompanionObjectDescriptor();
489            if (companionObjectDescriptor != null) {
490                ForceResolveUtil.forceResolveAllContents(companionObjectDescriptor);
491            }
492    
493            ForceResolveUtil.forceResolveAllContents(getConstructors());
494            ForceResolveUtil.forceResolveAllContents(getDescriptorsForExtraCompanionObjects());
495            ForceResolveUtil.forceResolveAllContents(getUnsubstitutedMemberScope());
496            ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
497        }
498    
499        // Note: headers of member classes' members are not resolved
500        public void resolveMemberHeaders() {
501            ForceResolveUtil.forceResolveAllContents(getAnnotations());
502            ForceResolveUtil.forceResolveAllContents(getDanglingAnnotations());
503    
504            getCompanionObjectDescriptor();
505    
506            getDescriptorsForExtraCompanionObjects();
507    
508            getConstructors();
509            getContainingDeclaration();
510            getThisAsReceiverParameter();
511            getKind();
512            getModality();
513            getName();
514            getOriginal();
515            getScopeForClassHeaderResolution();
516            getScopeForMemberDeclarationResolution();
517            DescriptorUtils.getAllDescriptors(getUnsubstitutedMemberScope());
518            getScopeForInitializerResolution();
519            getUnsubstitutedInnerClassesScope();
520            getTypeConstructor().getSupertypes();
521            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
522                typeParameterDescriptor.getUpperBounds();
523                typeParameterDescriptor.getLowerBounds();
524            }
525            getUnsubstitutedPrimaryConstructor();
526            getVisibility();
527        }
528    
529        @NotNull
530        @Override
531        public List<TypeParameterDescriptor> getDeclaredTypeParameters() {
532            return parameters.invoke();
533        }
534    
535        private static class Supertypes {
536            @Mutable
537            public final Collection<KotlinType> trueSupertypes;
538            @Mutable
539            public final Collection<KotlinType> allSuperTypes;
540    
541            private Supertypes(@Mutable @NotNull Collection<KotlinType> allSuperTypes) {
542                this.trueSupertypes = allSuperTypes;
543                this.allSuperTypes = new ArrayList<KotlinType>(allSuperTypes);
544            }
545    
546            @NotNull
547            public Collection<KotlinType> getAllSupertypes() {
548                return allSuperTypes;
549            }
550        }
551    
552        private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
553            private final NotNullLazyValue<Supertypes> supertypes = c.getStorageManager().createLazyValueWithPostCompute(
554                    new Function0<Supertypes>() {
555                        @Override
556                        public Supertypes invoke() {
557                            if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
558                                return new Supertypes(Collections.<KotlinType>emptyList());
559                            }
560    
561                            KtClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
562                            if (classOrObject == null) {
563                                return new Supertypes(Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType()));
564                            }
565    
566                            List<KotlinType> allSupertypes = c.getDescriptorResolver()
567                                    .resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
568                                                       c.getTrace());
569    
570                            return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
571                        }
572                    },
573                    new Function1<Boolean, Supertypes>() {
574                        @Override
575                        public Supertypes invoke(Boolean firstTime) {
576                            return new Supertypes(Collections.<KotlinType>emptyList());
577                        }
578                    },
579                    new Function1<Supertypes, Unit>() {
580                        @Override
581                        public Unit invoke(@NotNull Supertypes supertypes) {
582                            findAndDisconnectLoopsInTypeHierarchy(supertypes.trueSupertypes);
583                            return Unit.INSTANCE$;
584                        }
585                    }
586            );
587    
588            private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
589                @Override
590                public List<TypeParameterDescriptor> invoke() {
591                    return TypeParameterUtilsKt.computeConstructorTypeParameters(LazyClassDescriptor.this);
592                }
593            });
594    
595            private final NullableLazyValue<Void> forceResolveAllContents =
596                    c.getStorageManager().createRecursionTolerantNullableLazyValue(new Function0<Void>() {
597                        @Override
598                        public Void invoke() {
599                            doForceResolveAllContents();
600                            return null;
601                        }
602                    }, null);
603    
604            @NotNull
605            @Override
606            public List<TypeParameterDescriptor> getParameters() {
607                return parameters.invoke();
608            }
609    
610            @NotNull
611            @Override
612            public Collection<KotlinType> getSupertypes() {
613                return supertypes.invoke().trueSupertypes;
614            }
615    
616            private void findAndDisconnectLoopsInTypeHierarchy(@Mutable Collection<KotlinType> supertypes) {
617                c.getSupertypeLoopChecker().findLoopsInSupertypesAndDisconnect(
618                        typeConstructor, supertypes,
619                        new Function1<TypeConstructor, Iterable<? extends KotlinType>>() {
620                            @Override
621                            public Iterable<? extends KotlinType> invoke(TypeConstructor typeConstructor) {
622                                return getNeighbors(typeConstructor);
623                            }
624                        },
625                        new Function1<KotlinType, Unit>() {
626                            @Override
627                            public Unit invoke(KotlinType type) {
628                                ClassifierDescriptor supertypeDescriptor = type.getConstructor().getDeclarationDescriptor();
629                                if (supertypeDescriptor instanceof ClassDescriptor) {
630                                    ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
631                                    reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
632                                }
633    
634                                return Unit.INSTANCE;
635                            }
636                        }
637                );
638            }
639    
640            private void reportCyclicInheritanceHierarchyError(
641                    @NotNull BindingTrace trace,
642                    @NotNull ClassDescriptor classDescriptor,
643                    @NotNull ClassDescriptor superclass
644            ) {
645                PsiElement psiElement = DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor);
646    
647                PsiElement elementToMark = null;
648                if (psiElement instanceof KtClassOrObject) {
649                    KtClassOrObject classOrObject = (KtClassOrObject) psiElement;
650                    for (KtSuperTypeListEntry delegationSpecifier : classOrObject.getSuperTypeListEntries()) {
651                        KtTypeReference typeReference = delegationSpecifier.getTypeReference();
652                        if (typeReference == null) continue;
653                        KotlinType supertype = trace.get(TYPE, typeReference);
654                        if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
655                            elementToMark = typeReference;
656                        }
657                    }
658                }
659                if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
660                    PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
661                    PsiElement nameIdentifier = namedElement.getNameIdentifier();
662                    if (nameIdentifier != null) {
663                        elementToMark = nameIdentifier;
664                    }
665                }
666                if (elementToMark != null) {
667                    trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
668                }
669            }
670    
671            private Collection<KotlinType> getNeighbors(TypeConstructor from) {
672                // Supertypes + type for container
673                Collection<KotlinType> neighbours = new ArrayList<KotlinType>(
674                        from instanceof LazyClassTypeConstructor
675                                 ? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
676                                 : from.getSupertypes()
677                );
678    
679                ClassifierDescriptor fromDescriptor = from.getDeclarationDescriptor();
680                if (fromDescriptor != null) {
681                    DeclarationDescriptor container = fromDescriptor.getContainingDeclaration();
682                    if (container instanceof ClassDescriptor) {
683                        neighbours.add(((ClassDescriptor) container).getDefaultType());
684                    }
685                }
686                return neighbours;
687            }
688    
689            @Override
690            public boolean isFinal() {
691                return getModality() == Modality.FINAL;
692            }
693    
694            @Override
695            public boolean isDenotable() {
696                return true;
697            }
698    
699            @Override
700            @NotNull
701            public ClassifierDescriptor getDeclarationDescriptor() {
702                return LazyClassDescriptor.this;
703            }
704    
705            @NotNull
706            @Override
707            public Annotations getAnnotations() {
708                return Annotations.Companion.getEMPTY(); // TODO
709            }
710    
711            @Override
712            public String toString() {
713                return LazyClassDescriptor.this.getName().toString();
714            }
715    
716            @Override
717            public void forceResolveAllContents() {
718                forceResolveAllContents.invoke();
719            }
720    
721            private void doForceResolveAllContents() {
722                ForceResolveUtil.forceResolveAllContents(getAnnotations());
723                ForceResolveUtil.forceResolveAllContents(getSupertypes());
724                ForceResolveUtil.forceResolveAllContents(getParameters());
725            }
726        }
727    }