001    package org.jetbrains.jet.lang.descriptors.impl;
002    
003    import org.jetbrains.annotations.NotNull;
004    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
005    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
006    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor;
007    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
008    import org.jetbrains.jet.lang.resolve.name.Name;
009    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
010    import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
011    import org.jetbrains.jet.lang.types.*;
012    
013    import java.util.List;
014    import java.util.Map;
015    
016    public abstract class AbstractClassDescriptor implements ClassDescriptor {
017        protected final Name name;
018        protected volatile JetType defaultType;
019    
020        public AbstractClassDescriptor(@NotNull Name name) {
021            this.name = name;
022        }
023    
024        @NotNull
025        @Override
026        public Name getName() {
027            return name;
028        }
029    
030        @NotNull
031        @Override
032        public DeclarationDescriptor getOriginal() {
033            return this;
034        }
035    
036        protected abstract JetScope getScopeForMemberLookup();
037    
038        @NotNull
039        @Override
040        public JetScope getMemberScope(List<? extends TypeProjection> typeArguments) {
041            assert typeArguments.size() == getTypeConstructor().getParameters().size() : "Illegal number of type arguments: expected "
042                                                                                         + getTypeConstructor().getParameters().size() + " but was " + typeArguments.size()
043                                                                                         + " for " + getTypeConstructor() + " " + getTypeConstructor().getParameters();
044            if (typeArguments.isEmpty()) return getScopeForMemberLookup();
045    
046            List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
047            Map<TypeConstructor, TypeProjection> substitutionContext = SubstitutionUtils.buildSubstitutionContext(typeParameters, typeArguments);
048    
049            // Unsafe substitutor is OK, because no recursion can hurt us upon a trivial substitution:
050            // all the types are written explicitly in the code already, they can not get infinite.
051            // One exception is *-projections, but they need to be handled separately anyways.
052            TypeSubstitutor substitutor = TypeSubstitutor.createUnsafe(substitutionContext);
053            return new SubstitutingScope(getScopeForMemberLookup(), substitutor);
054        }
055    
056        @NotNull
057        @Override
058        public ClassDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
059            if (substitutor.isEmpty()) {
060                return this;
061            }
062            return new LazySubstitutingClassDescriptor(this, substitutor);
063        }
064    
065        @NotNull
066        @Override
067        public JetType getDefaultType() {
068            if (defaultType == null) {
069                defaultType = TypeUtils.makeUnsubstitutedType(this, getScopeForMemberLookup());
070            }
071            return defaultType;
072        }
073    
074        @Override
075        public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
076            visitor.visitClassDescriptor(this, null);
077        }
078    
079        @Override
080        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
081            return visitor.visitClassDescriptor(this, data);
082        }
083    }