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    
017    package org.jetbrains.jet.lang.descriptors.impl;
018    
019    import com.google.common.collect.Lists;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024    import org.jetbrains.jet.lang.resolve.name.Name;
025    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026    import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
027    import org.jetbrains.jet.lang.types.*;
028    
029    import java.util.Collection;
030    import java.util.List;
031    
032    public class LazySubstitutingClassDescriptor implements ClassDescriptor {
033    
034        private final ClassDescriptor original;
035        private final TypeSubstitutor originalSubstitutor;
036        private TypeSubstitutor newSubstitutor;
037        private List<TypeParameterDescriptor> typeParameters;
038        private TypeConstructor typeConstructor;
039        private JetType superclassType;
040    
041        public LazySubstitutingClassDescriptor(ClassDescriptor descriptor, TypeSubstitutor substitutor) {
042            this.original = descriptor;
043            this.originalSubstitutor = substitutor;
044        }
045    
046        private TypeSubstitutor getSubstitutor() {
047            if (newSubstitutor == null) {
048                if (originalSubstitutor.isEmpty()) {
049                    newSubstitutor = originalSubstitutor;
050                }
051                else {
052                    typeParameters = Lists.newArrayList();
053                    newSubstitutor = DescriptorSubstitutor.substituteTypeParameters(original.getTypeConstructor().getParameters(), originalSubstitutor, this, typeParameters);
054                }
055            }
056            return newSubstitutor;
057        }
058    
059        @NotNull
060        @Override
061        public TypeConstructor getTypeConstructor() {
062            TypeConstructor originalTypeConstructor = original.getTypeConstructor();
063            if (originalSubstitutor.isEmpty()) {
064                return originalTypeConstructor;
065            }
066    
067            if (typeConstructor == null) {
068                TypeSubstitutor substitutor = getSubstitutor();
069    
070                Collection<JetType> supertypes = Lists.newArrayList();
071                for (JetType supertype : originalTypeConstructor.getSupertypes()) {
072                    supertypes.add(substitutor.substitute(supertype, Variance.INVARIANT));
073                }
074    
075                typeConstructor = new TypeConstructorImpl(
076                        this,
077                        originalTypeConstructor.getAnnotations(),
078                        originalTypeConstructor.isSealed(),
079                        originalTypeConstructor.toString(),
080                        typeParameters,
081                        supertypes
082                );
083            }
084    
085            return typeConstructor;
086        }
087    
088        @NotNull
089        @Override
090        public JetScope getMemberScope(List<TypeProjection> typeArguments) {
091            JetScope memberScope = original.getMemberScope(typeArguments);
092            if (originalSubstitutor.isEmpty()) {
093                return memberScope;
094            }
095            return new SubstitutingScope(memberScope, getSubstitutor());
096        }
097    
098        @NotNull
099        @Override
100        public JetType getDefaultType() {
101            throw new UnsupportedOperationException(); // TODO
102        }
103    
104        @NotNull
105        @Override
106        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
107            throw new UnsupportedOperationException(); // TODO
108        }
109    
110        @NotNull
111        @Override
112        public Collection<ConstructorDescriptor> getConstructors() {
113            Collection<ConstructorDescriptor> r = Lists.newArrayList();
114            for (ConstructorDescriptor constructor : original.getConstructors()) {
115                r.add((ConstructorDescriptor) constructor.substitute(getSubstitutor()));
116            }
117            return r;
118        }
119    
120        @Override
121        public List<AnnotationDescriptor> getAnnotations() {
122            return original.getAnnotations();
123        }
124    
125        @NotNull
126        @Override
127        public Name getName() {
128            return original.getName();
129        }
130    
131        @NotNull
132        @Override
133        public DeclarationDescriptor getOriginal() {
134            return original.getOriginal();
135        }
136    
137        @NotNull
138        @Override
139        public DeclarationDescriptor getContainingDeclaration() {
140            return original.getContainingDeclaration();
141        }
142    
143        @NotNull
144        @Override
145        public ClassDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
146            if (substitutor.isEmpty()) return this;
147            return new LazySubstitutingClassDescriptor(this, TypeSubstitutor.create(substitutor.getSubstitution(), getSubstitutor().getSubstitution()));
148        }
149    
150        @Override
151        public JetType getClassObjectType() {
152            return original.getClassObjectType();
153        }
154    
155        @Override
156        public ClassDescriptor getClassObjectDescriptor() {
157            return original.getClassObjectDescriptor();
158        }
159    
160        @NotNull
161        @Override
162        public ClassKind getKind() {
163            return original.getKind();
164        }
165    
166        @Override
167        @NotNull
168        public Modality getModality() {
169            return original.getModality();
170        }
171    
172        @NotNull
173        @Override
174        public Visibility getVisibility() {
175            return original.getVisibility();
176        }
177    
178        @Override
179        public boolean isInner() {
180            return original.isInner();
181        }
182    
183        @Override
184        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
185            return visitor.visitClassDescriptor(this, data);
186        }
187    
188        @Override
189        public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
190            throw new UnsupportedOperationException(); // TODO
191        }
192    
193        @NotNull
194        @Override
195        public JetScope getUnsubstitutedInnerClassesScope() {
196            return original.getUnsubstitutedInnerClassesScope();
197        }
198    
199        @Nullable
200        @Override
201        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
202            return original.getUnsubstitutedPrimaryConstructor();
203        }
204    }