001/*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.jetbrains.jet.lang.resolve;
018
019import com.google.common.collect.Lists;
020import com.google.common.collect.Multimap;
021import com.google.common.collect.Sets;
022import com.intellij.psi.PsiElement;
023import com.intellij.psi.PsiNameIdentifierOwner;
024import com.intellij.util.containers.ContainerUtil;
025import org.jetbrains.annotations.NotNull;
026import org.jetbrains.annotations.Nullable;
027import org.jetbrains.jet.lang.descriptors.*;
028import org.jetbrains.jet.lang.descriptors.impl.*;
029import org.jetbrains.jet.lang.psi.*;
030import org.jetbrains.jet.lang.resolve.name.Name;
031import org.jetbrains.jet.lang.resolve.scopes.*;
032import org.jetbrains.jet.lang.types.JetType;
033import org.jetbrains.jet.lang.types.SubstitutionUtils;
034import org.jetbrains.jet.lang.types.TypeConstructor;
035import org.jetbrains.jet.lang.types.TypeProjection;
036import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
037import org.jetbrains.jet.utils.DFS;
038
039import javax.inject.Inject;
040import java.util.*;
041
042import static org.jetbrains.jet.lang.diagnostics.Errors.*;
043import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_CLASS_DESCRIPTOR;
044import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
045import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
046
047public class TypeHierarchyResolver {
048    @NotNull
049    private TopDownAnalysisContext context;
050    @NotNull
051    private ImportsResolver importsResolver;
052    @NotNull
053    private DescriptorResolver descriptorResolver;
054    @NotNull
055    private ScriptHeaderResolver scriptHeaderResolver;
056    @NotNull
057    private NamespaceFactoryImpl namespaceFactory;
058    @NotNull
059    private BindingTrace trace;
060
061    @Inject
062    public void setContext(@NotNull TopDownAnalysisContext context) {
063        this.context = context;
064    }
065
066    @Inject
067    public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
068        this.importsResolver = importsResolver;
069    }
070
071    @Inject
072    public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
073        this.descriptorResolver = descriptorResolver;
074    }
075
076    @Inject
077    public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
078        this.scriptHeaderResolver = scriptHeaderResolver;
079    }
080
081    @Inject
082    public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
083        this.namespaceFactory = namespaceFactory;
084    }
085
086    @Inject
087    public void setTrace(@NotNull BindingTrace trace) {
088        this.trace = trace;
089    }
090
091    public void process(
092            @NotNull JetScope outerScope, @NotNull NamespaceLikeBuilder owner,
093            @NotNull Collection<? extends PsiElement> declarations
094    ) {
095
096        {
097            // TODO: Very temp code - main goal is to remove recursion from collectNamespacesAndClassifiers
098            Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
099            forDeferredResolve.addAll(collectNamespacesAndClassifiers(outerScope, owner, declarations));
100
101            while (!forDeferredResolve.isEmpty()) {
102                JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
103                assert declarationContainer != null;
104
105                DeclarationDescriptor descriptorForDeferredResolve = context.forDeferredResolver.get(declarationContainer);
106                JetScope scope = context.normalScope.get(declarationContainer);
107
108                // Even more temp code
109                if (descriptorForDeferredResolve instanceof MutableClassDescriptorLite) {
110                    forDeferredResolve.addAll(
111                            collectNamespacesAndClassifiers(
112                                    scope,
113                                    ((MutableClassDescriptorLite) descriptorForDeferredResolve).getBuilder(),
114                                    declarationContainer.getDeclarations()));
115                }
116                else if (descriptorForDeferredResolve instanceof NamespaceDescriptorImpl) {
117                    forDeferredResolve.addAll(
118                            collectNamespacesAndClassifiers(
119                                    scope,
120                                    ((NamespaceDescriptorImpl) descriptorForDeferredResolve).getBuilder(),
121                                    declarationContainer.getDeclarations()));
122                }
123                else {
124                    assert false;
125                }
126            }
127        }
128
129        importsResolver.processTypeImports(outerScope);
130
131        createTypeConstructors(); // create type constructors for classes and generic parameters, supertypes are not filled in
132        resolveTypesInClassHeaders(); // Generic bounds and types in supertype lists (no expressions or constructor resolution)
133
134        context.setClassesTopologicalOrder(topologicallySortClassesAndObjects());
135
136        // Detect and disconnect all loops in the hierarchy
137        detectAndDisconnectLoops();
138
139        // At this point, there are no loops in the type hierarchy
140
141        checkSupertypesForConsistency();
142        //        computeSuperclasses();
143
144        checkTypesInClassHeaders(); // Check bounds in the types used in generic bounds and supertype lists
145    }
146
147    @Nullable
148    private Collection<JetDeclarationContainer> collectNamespacesAndClassifiers(
149            @NotNull JetScope outerScope,
150            @NotNull NamespaceLikeBuilder owner,
151            @NotNull Iterable<? extends PsiElement> declarations
152    ) {
153        Collection<JetDeclarationContainer> forDeferredResolve = new ArrayList<JetDeclarationContainer>();
154
155        ClassifierCollector collector = new ClassifierCollector(outerScope, owner, forDeferredResolve);
156
157        for (PsiElement declaration : declarations) {
158            declaration.accept(collector);
159        }
160
161        return forDeferredResolve;
162    }
163
164
165    @NotNull
166    private static ClassKind getClassKind(@NotNull JetClass jetClass) {
167        if (jetClass.isTrait()) return ClassKind.TRAIT;
168        if (jetClass.isAnnotation()) return ClassKind.ANNOTATION_CLASS;
169        if (jetClass.isEnum()) return ClassKind.ENUM_CLASS;
170        return ClassKind.CLASS;
171    }
172
173    private void createTypeConstructors() {
174        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
175            JetClass jetClass = entry.getKey();
176            MutableClassDescriptor descriptor = entry.getValue();
177            descriptorResolver.resolveMutableClassDescriptor(jetClass, descriptor, trace);
178            descriptor.createTypeConstructor();
179        }
180        for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
181            JetObjectDeclaration objectDeclaration = entry.getKey();
182            MutableClassDescriptor descriptor = entry.getValue();
183            descriptor.setModality(Modality.FINAL);
184            descriptor.setVisibility(ModifiersChecker.resolveVisibilityFromModifiers(objectDeclaration));
185            descriptor.setTypeParameterDescriptors(new ArrayList<TypeParameterDescriptor>(0));
186            descriptor.createTypeConstructor();
187        }
188    }
189
190    private void resolveTypesInClassHeaders() {
191        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
192            JetClass jetClass = entry.getKey();
193            MutableClassDescriptor descriptor = entry.getValue();
194            descriptorResolver.resolveGenericBounds(jetClass, descriptor.getScopeForSupertypeResolution(),
195                                                    (List) descriptor.getTypeConstructor().getParameters(), trace);
196            descriptorResolver.resolveSupertypesForMutableClassDescriptor(jetClass, descriptor, trace);
197        }
198        for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
199            JetClassOrObject jetClass = entry.getKey();
200            MutableClassDescriptor descriptor = entry.getValue();
201            descriptorResolver.resolveSupertypesForMutableClassDescriptor(jetClass, descriptor, trace);
202        }
203    }
204
205    private List<MutableClassDescriptorLite> topologicallySortClassesAndObjects() {
206        // A topsort is needed only for better diagnostics:
207        //    edges that get removed to disconnect loops are more reasonable in this case
208        return DFS.topologicalOrder(
209                ContainerUtil.<MutableClassDescriptorLite>concat(context.getClasses().values(), context.getObjects().values()),
210                new DFS.Neighbors<MutableClassDescriptorLite>() {
211                    @NotNull
212                    @Override
213                    public Iterable<MutableClassDescriptorLite> getNeighbors(MutableClassDescriptorLite current) {
214                        List<MutableClassDescriptorLite> result = Lists.newArrayList();
215                        for (JetType supertype : current.getSupertypes()) {
216                            DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
217                            if (declarationDescriptor instanceof MutableClassDescriptorLite) {
218                                MutableClassDescriptorLite classDescriptor = (MutableClassDescriptorLite) declarationDescriptor;
219                                result.add(classDescriptor);
220                            }
221                        }
222                        return result;
223                    }
224                });
225
226    }
227
228    private void detectAndDisconnectLoops() {
229        // Loop detection and disconnection
230        Set<ClassDescriptor> visited = Sets.newHashSet();
231        Set<ClassDescriptor> beingProcessed = Sets.newHashSet();
232        List<ClassDescriptor> currentPath = Lists.newArrayList();
233        for (MutableClassDescriptorLite klass : context.getClassesTopologicalOrder()) {
234            traverseTypeHierarchy(klass, visited, beingProcessed, currentPath);
235        }
236    }
237
238    private void traverseTypeHierarchy(
239            MutableClassDescriptorLite currentClass,
240            Set<ClassDescriptor> visited,
241            Set<ClassDescriptor> beingProcessed,
242            List<ClassDescriptor> currentPath
243    ) {
244        if (!visited.add(currentClass)) {
245            if (beingProcessed.contains(currentClass)) {
246                markCycleErrors(currentPath, currentClass);
247                assert !currentPath.isEmpty() : "Cycle cannot be found on an empty currentPath";
248                ClassDescriptor subclassOfCurrent = currentPath.get(currentPath.size() - 1);
249                assert subclassOfCurrent instanceof MutableClassDescriptor;
250                // Disconnect the loop
251                for (Iterator<JetType> iterator = ((MutableClassDescriptor) subclassOfCurrent).getSupertypes().iterator();
252                     iterator.hasNext(); ) {
253                    JetType type = iterator.next();
254                    if (type.getConstructor() == currentClass.getTypeConstructor()) {
255                        iterator.remove();
256                        break;
257                    }
258                }
259            }
260            return;
261        }
262
263        beingProcessed.add(currentClass);
264        currentPath.add(currentClass);
265        for (JetType supertype : Lists.newArrayList(currentClass.getSupertypes())) {
266            DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
267            if (declarationDescriptor instanceof MutableClassDescriptor) {
268                MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) declarationDescriptor;
269                traverseTypeHierarchy(mutableClassDescriptor, visited, beingProcessed, currentPath);
270            }
271        }
272        beingProcessed.remove(currentClass);
273        currentPath.remove(currentPath.size() - 1);
274    }
275
276    private void markCycleErrors(List<ClassDescriptor> currentPath, @NotNull ClassDescriptor current) {
277        int size = currentPath.size();
278        for (int i = size - 1; i >= 0; i--) {
279            ClassDescriptor classDescriptor = currentPath.get(i);
280
281            ClassDescriptor superclass = (i < size - 1) ? currentPath.get(i + 1) : current;
282            PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
283
284            PsiElement elementToMark = null;
285            if (psiElement instanceof JetClassOrObject) {
286                JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
287                for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
288                    JetTypeReference typeReference = delegationSpecifier.getTypeReference();
289                    if (typeReference == null) continue;
290                    JetType supertype = trace.get(TYPE, typeReference);
291                    if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
292                        elementToMark = typeReference;
293                    }
294                }
295            }
296            if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
297                PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
298                PsiElement nameIdentifier = namedElement.getNameIdentifier();
299                if (nameIdentifier != null) {
300                    elementToMark = nameIdentifier;
301                }
302            }
303            if (elementToMark != null) {
304                trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
305            }
306
307            if (classDescriptor == current) {
308                // Beginning of cycle is found
309                break;
310            }
311        }
312    }
313
314    private void checkSupertypesForConsistency() {
315        for (MutableClassDescriptorLite mutableClassDescriptor : context.getClassesTopologicalOrder()) {
316            Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
317                    .buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType());
318            for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
319                Collection<TypeProjection> projections = entry.getValue();
320                if (projections.size() > 1) {
321                    TypeConstructor typeConstructor = entry.getKey();
322                    DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
323                    assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
324                    TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
325
326                    // Immediate arguments of supertypes cannot be projected
327                    Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
328                    for (TypeProjection projection : projections) {
329                        conflictingTypes.add(projection.getType());
330                    }
331                    switch (typeParameterDescriptor.getVariance()) {
332                        case INVARIANT:
333                            // Leave conflicting types as is
334                            break;
335                        case IN_VARIANCE:
336                            // Filter out those who have supertypes in this set (common supertype)
337                            Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
338                            break;
339                        case OUT_VARIANCE:
340                            // Filter out those who have subtypes in this set (common subtype)
341                            Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
342                            break;
343                    }
344
345                    if (conflictingTypes.size() > 1) {
346                        DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
347                        assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
348                        JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
349                                .classDescriptorToDeclaration(trace.getBindingContext(), mutableClassDescriptor);
350                        JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
351                        assert delegationSpecifierList != null;
352                        //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
353                        trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
354                                             .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
355                                                 conflictingTypes));
356                    }
357                }
358            }
359        }
360    }
361
362    private enum Filter {
363        REMOVE_IF_SUBTYPE_IN_THE_SET {
364            @Override
365            public boolean removeNeeded(JetType subject, JetType other) {
366                return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
367            }
368        },
369        REMOVE_IF_SUPERTYPE_IN_THE_SET {
370            @Override
371            public boolean removeNeeded(JetType subject, JetType other) {
372                return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
373            }
374        };
375
376        private void proceed(Set<JetType> conflictingTypes) {
377            for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
378                JetType type = iterator.next();
379                for (JetType otherType : conflictingTypes) {
380                    boolean subtypeOf = removeNeeded(type, otherType);
381                    if (type != otherType && subtypeOf) {
382                        iterator.remove();
383                        break;
384                    }
385                }
386            }
387        }
388
389        public abstract boolean removeNeeded(JetType subject, JetType other);
390    }
391
392    private void checkTypesInClassHeaders() {
393        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
394            JetClass jetClass = entry.getKey();
395
396            for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
397                JetTypeReference typeReference = delegationSpecifier.getTypeReference();
398                if (typeReference != null) {
399                    JetType type = trace.getBindingContext().get(TYPE, typeReference);
400                    if (type != null) {
401                        descriptorResolver.checkBounds(typeReference, type, trace);
402                    }
403                }
404            }
405
406            for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
407                JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
408                if (extendsBound != null) {
409                    JetType type = trace.getBindingContext().get(TYPE, extendsBound);
410                    if (type != null) {
411                        descriptorResolver.checkBounds(extendsBound, type, trace);
412                    }
413                }
414            }
415
416            for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
417                JetTypeReference extendsBound = constraint.getBoundTypeReference();
418                if (extendsBound != null) {
419                    JetType type = trace.getBindingContext().get(TYPE, extendsBound);
420                    if (type != null) {
421                        descriptorResolver.checkBounds(extendsBound, type, trace);
422                    }
423                }
424            }
425        }
426    }
427
428    private class ClassifierCollector extends JetVisitorVoid {
429        private final JetScope outerScope;
430        private final NamespaceLikeBuilder owner;
431        private final Collection<JetDeclarationContainer> forDeferredResolve;
432
433        public ClassifierCollector(@NotNull JetScope outerScope,
434                @NotNull NamespaceLikeBuilder owner,
435                @NotNull Collection<JetDeclarationContainer> forDeferredResolve
436        ) {
437            this.outerScope = outerScope;
438            this.owner = owner;
439            this.forDeferredResolve = forDeferredResolve;
440        }
441
442        @Override
443        public void visitJetFile(JetFile file) {
444            NamespaceDescriptorImpl namespaceDescriptor = namespaceFactory.createNamespaceDescriptorPathIfNeeded(
445                    file, outerScope, RedeclarationHandler.DO_NOTHING);
446            context.getNamespaceDescriptors().put(file, namespaceDescriptor);
447
448            WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(),
449                                                                     new TraceBasedRedeclarationHandler(trace), "namespace");
450            namespaceScope.changeLockLevel(WritableScope.LockLevel.BOTH);
451            context.getNamespaceScopes().put(file, namespaceScope);
452
453            if (file.isScript()) {
454                scriptHeaderResolver.processScriptHierarchy(file.getScript(), namespaceScope);
455            }
456
457            prepareForDeferredCall(namespaceScope, namespaceDescriptor, file);
458        }
459
460        @Override
461        public void visitClass(JetClass klass) {
462            MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
463
464            owner.addClassifierDescriptor(mutableClassDescriptor);
465        }
466
467        @Override
468        public void visitObjectDeclaration(JetObjectDeclaration declaration) {
469            MutableClassDescriptor objectDescriptor =
470                    createClassDescriptorForObject(declaration, owner, outerScope, JetPsiUtil.safeName(declaration.getName()),
471                                                   ClassKind.OBJECT);
472            owner.addObjectDescriptor(objectDescriptor);
473            trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(declaration), objectDescriptor);
474        }
475
476        @Override
477        public void visitEnumEntry(JetEnumEntry enumEntry) {
478            // TODO: Bad casting
479            MutableClassDescriptorLite ownerClassDescriptor = (MutableClassDescriptorLite) owner.getOwnerForChildren();
480            MutableClassDescriptorLite classObjectDescriptor = ownerClassDescriptor.getClassObjectDescriptor();
481
482            assert classObjectDescriptor != null : enumEntry.getParent().getText();
483            createClassDescriptorForEnumEntry(enumEntry, classObjectDescriptor);
484        }
485
486        @Override
487        public void visitTypedef(JetTypedef typedef) {
488            trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
489        }
490
491        @Override
492        public void visitClassObject(JetClassObject classObject) {
493            JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
494            if (objectDeclaration != null) {
495                Name classObjectName = getClassObjectName(owner.getOwnerForChildren().getName());
496
497                MutableClassDescriptor classObjectDescriptor = createClassDescriptorForObject(
498                        objectDeclaration, owner, outerScope,
499                        classObjectName, ClassKind.CLASS_OBJECT);
500
501                NamespaceLikeBuilder.ClassObjectStatus status = owner.setClassObjectDescriptor(classObjectDescriptor);
502                switch (status) {
503                    case DUPLICATE:
504                        trace.report(MANY_CLASS_OBJECTS.on(classObject));
505                        break;
506                    case NOT_ALLOWED:
507                        trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
508                        break;
509                    case OK:
510                        // Everything is OK so no errors to trace.
511                        break;
512                }
513            }
514        }
515
516        private void createClassObjectForEnumClass(JetClass klass, MutableClassDescriptor mutableClassDescriptor) {
517            if (mutableClassDescriptor.getKind() == ClassKind.ENUM_CLASS) {
518                MutableClassDescriptor classObjectDescriptor =
519                        createClassObjectDescriptor(mutableClassDescriptor, ModifiersChecker.resolveVisibilityFromModifiers(klass));
520                mutableClassDescriptor.getBuilder().setClassObjectDescriptor(classObjectDescriptor);
521                classObjectDescriptor.getBuilder().addFunctionDescriptor(
522                        DescriptorResolver.createEnumClassObjectValuesMethod(classObjectDescriptor, trace));
523                classObjectDescriptor.getBuilder().addFunctionDescriptor(
524                        DescriptorResolver.createEnumClassObjectValueOfMethod(classObjectDescriptor, trace));
525            }
526        }
527
528        @NotNull
529        private MutableClassDescriptor createClassObjectDescriptor(
530                @NotNull ClassDescriptor classDescriptor,
531                @NotNull Visibility visibility
532        ) {
533            MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(
534                    classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false, getClassObjectName(classDescriptor.getName()));
535            classObjectDescriptor.setModality(Modality.FINAL);
536            classObjectDescriptor.setVisibility(visibility);
537            classObjectDescriptor.setTypeParameterDescriptors(new ArrayList<TypeParameterDescriptor>(0));
538            classObjectDescriptor.createTypeConstructor();
539            ConstructorDescriptorImpl primaryConstructorForObject = createPrimaryConstructorForObject(null, classObjectDescriptor);
540            primaryConstructorForObject.setReturnType(classObjectDescriptor.getDefaultType());
541            return classObjectDescriptor;
542        }
543
544        @NotNull
545        private MutableClassDescriptor createClassDescriptorForClass(
546                @NotNull JetClass klass,
547                @NotNull DeclarationDescriptor containingDeclaration
548        ) {
549            ClassKind kind = getClassKind(klass);
550            // Kind check is needed in order to not consider enums as inner in any case
551            // (otherwise it would be impossible to create a class object in the enum)
552            boolean isInner = kind == ClassKind.CLASS && klass.isInner();
553            MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
554                    containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName()));
555            context.getClasses().put(klass, mutableClassDescriptor);
556            trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(klass), mutableClassDescriptor);
557
558            createClassObjectForEnumClass(klass, mutableClassDescriptor);
559
560            JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
561
562            prepareForDeferredCall(classScope, mutableClassDescriptor, klass);
563
564            return mutableClassDescriptor;
565        }
566
567        @NotNull
568        private MutableClassDescriptor createClassDescriptorForObject(
569                @NotNull JetObjectDeclaration declaration, @NotNull NamespaceLikeBuilder owner,
570                @NotNull JetScope scope, @NotNull Name name, @NotNull ClassKind kind
571        ) {
572            MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
573                    owner.getOwnerForChildren(), scope, kind, false, name);
574
575            context.getObjects().put(declaration, mutableClassDescriptor);
576
577            JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
578
579            prepareForDeferredCall(classScope, mutableClassDescriptor, declaration);
580
581            createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
582            trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
583            return mutableClassDescriptor;
584        }
585
586        private MutableClassDescriptor createClassDescriptorForEnumEntry(
587                @NotNull JetEnumEntry declaration,
588                @NotNull MutableClassDescriptorLite classObjectDescriptor
589        ) {
590            NamespaceLikeBuilder owner = classObjectDescriptor.getBuilder();
591            MutableClassDescriptor mutableClassObjectDescriptor = (MutableClassDescriptor) classObjectDescriptor;
592
593            MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
594                    owner.getOwnerForChildren(), mutableClassObjectDescriptor.getScopeForMemberResolution(), ClassKind.ENUM_ENTRY,
595                    false, JetPsiUtil.safeName(declaration.getName()));
596            context.getClasses().put(declaration, mutableClassDescriptor);
597
598            prepareForDeferredCall(mutableClassDescriptor.getScopeForMemberResolution(), mutableClassDescriptor, declaration);
599
600            // ??? - is enum entry object?
601            createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
602            owner.addObjectDescriptor(mutableClassDescriptor);
603            trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
604            return mutableClassDescriptor;
605        }
606
607        private ConstructorDescriptorImpl createPrimaryConstructorForObject(
608                @Nullable PsiElement object,
609                MutableClassDescriptor mutableClassDescriptor
610        ) {
611            ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
612                    .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
613            mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor, trace);
614            return constructorDescriptor;
615        }
616
617        private void prepareForDeferredCall(
618                @NotNull JetScope outerScope,
619                @NotNull DeclarationDescriptor descriptorForDeferredResolve,
620                @NotNull JetDeclarationContainer container
621        ) {
622            forDeferredResolve.add(container);
623            context.normalScope.put(container, outerScope);
624            context.forDeferredResolver.put(container, descriptorForDeferredResolve);
625        }
626    }
627}