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.descriptors.impl;
018
019import com.google.common.collect.Lists;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.jet.lang.descriptors.*;
023import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024import org.jetbrains.jet.lang.resolve.name.Name;
025import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
027import org.jetbrains.jet.lang.types.*;
028
029import java.util.Collection;
030import java.util.List;
031
032public 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}