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