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.Sets;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
022    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor;
023    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
024    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
026    import org.jetbrains.jet.lang.resolve.name.Name;
027    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
028    import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
029    import org.jetbrains.jet.lang.types.*;
030    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
031    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032    import org.jetbrains.jet.renderer.DescriptorRenderer;
033    import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
034    
035    import java.util.Collections;
036    import java.util.List;
037    import java.util.Set;
038    
039    public class TypeParameterDescriptorImpl extends DeclarationDescriptorNonRootImpl implements TypeParameterDescriptor {
040        public static TypeParameterDescriptor createWithDefaultBound(
041                @NotNull DeclarationDescriptor containingDeclaration,
042                @NotNull List<AnnotationDescriptor> annotations,
043                boolean reified,
044                @NotNull Variance variance,
045                @NotNull Name name,
046                int index) {
047            TypeParameterDescriptorImpl typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index);
048            typeParameterDescriptor.addUpperBound(KotlinBuiltIns.getInstance().getDefaultBound());
049            typeParameterDescriptor.setInitialized();
050            return typeParameterDescriptor;
051        }
052    
053        public static TypeParameterDescriptorImpl createForFurtherModification(
054                @NotNull DeclarationDescriptor containingDeclaration,
055                @NotNull List<AnnotationDescriptor> annotations,
056                boolean reified,
057                @NotNull Variance variance,
058                @NotNull Name name,
059                int index) {
060            return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index);
061        }
062    
063        // 0-based
064        private final int index;
065        private final Variance variance;
066        private final Set<JetType> upperBounds;
067        private JetType upperBoundsAsType;
068        private final TypeConstructor typeConstructor;
069        private JetType defaultType;
070        private final Set<JetType> classObjectUpperBounds = Sets.newLinkedHashSet();
071        private JetType classObjectBoundsAsType;
072    
073        private final boolean reified;
074    
075        private boolean initialized = false;
076    
077        private TypeParameterDescriptorImpl(
078                @NotNull DeclarationDescriptor containingDeclaration,
079                @NotNull List<AnnotationDescriptor> annotations,
080                boolean reified,
081                @NotNull Variance variance,
082                @NotNull Name name,
083                int index) {
084            super(containingDeclaration, annotations, name);
085            this.index = index;
086            this.variance = variance;
087            this.upperBounds = Sets.newLinkedHashSet();
088            this.reified = reified;
089            // TODO: Should we actually pass the annotations on to the type constructor?
090            this.typeConstructor = new TypeConstructorImpl(
091                    this,
092                    annotations,
093                    false,
094                    name.asString(),
095                    Collections.<TypeParameterDescriptor>emptyList(),
096                    upperBounds);
097        }
098    
099        private void checkInitialized() {
100            if (!initialized) {
101                throw new IllegalStateException("Type parameter descriptor in not initialized: " + nameForAssertions());
102            }
103        }
104    
105        private void checkUninitialized() {
106            if (initialized) {
107                throw new IllegalStateException("Type parameter descriptor is already initialized: " + nameForAssertions());
108            }
109        }
110    
111        private String nameForAssertions() {
112            return getName() + " declared in " + DescriptorUtils.getFQName(getContainingDeclaration());
113        }
114    
115        public void setInitialized() {
116            checkUninitialized();
117            initialized = true;
118        }
119    
120        @Override
121        public boolean isReified() {
122            checkInitialized();
123            return reified;
124        }
125    
126        @Override
127        public Variance getVariance() {
128            return variance;
129        }
130    
131        public void addUpperBound(@NotNull JetType bound) {
132            checkUninitialized();
133            doAddUpperBound(bound);
134        }
135    
136        private void doAddUpperBound(JetType bound) {
137            upperBounds.add(bound); // TODO : Duplicates?
138        }
139    
140        public void addDefaultUpperBound() {
141            checkUninitialized();
142    
143            if (upperBounds.isEmpty()) {
144                doAddUpperBound(KotlinBuiltIns.getInstance().getDefaultBound());
145            }
146        }
147    
148        @Override
149        @NotNull
150        public Set<JetType> getUpperBounds() {
151            checkInitialized();
152            return upperBounds;
153        }
154    
155        @Override
156        @NotNull
157        public JetType getUpperBoundsAsType() {
158            checkInitialized();
159            if (upperBoundsAsType == null) {
160                assert upperBounds != null : "Upper bound list is null in " + getName();
161                assert upperBounds.size() > 0 : "Upper bound list is empty in " + getName();
162                upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
163                if (upperBoundsAsType == null) {
164                    upperBoundsAsType = KotlinBuiltIns.getInstance().getNothingType();
165                }
166            }
167            return upperBoundsAsType;
168        }
169    
170        @Override
171        @NotNull
172        public Set<JetType> getLowerBounds() {
173            //checkInitialized();
174            return Collections.singleton(KotlinBuiltIns.getInstance().getNothingType());
175        }
176    
177        @Override
178        @NotNull
179        public JetType getLowerBoundsAsType() {
180            checkInitialized();
181            return KotlinBuiltIns.getInstance().getNothingType();
182        }
183        
184        
185        @NotNull
186        @Override
187        public TypeConstructor getTypeConstructor() {
188            //checkInitialized();
189            return typeConstructor;
190        }
191    
192        @Override
193        public String toString() {
194            try {
195                return DescriptorRenderer.TEXT.render(this);
196            } catch (Exception e) {
197                return this.getClass().getName() + "@" + System.identityHashCode(this);
198            }
199        }
200    
201        @NotNull
202        @Override
203        @Deprecated
204        public TypeParameterDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
205            throw new UnsupportedOperationException();
206        }
207    
208        @Override
209        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
210            checkInitialized();
211            return visitor.visitTypeParameterDescriptor(this, data);
212        }
213    
214        @NotNull
215        @Override
216        public JetType getDefaultType() {
217            //checkInitialized();
218            if (defaultType == null) {
219                defaultType = new JetTypeImpl(
220                                Collections.<AnnotationDescriptor>emptyList(),
221                                getTypeConstructor(),
222                                TypeUtils.hasNullableLowerBound(this),
223                                Collections.<TypeProjection>emptyList(),
224                                new LazyScopeAdapter(new RecursionIntolerantLazyValue<JetScope>() {
225                                    @Override
226                                    protected JetScope compute() {
227                                        return getUpperBoundsAsType().getMemberScope();
228                                    }
229                                }));
230            }
231            return defaultType;
232        }
233    
234        @Override
235        public JetType getClassObjectType() {
236            checkInitialized();
237            if (classObjectUpperBounds.isEmpty()) return null;
238    
239            if (classObjectBoundsAsType == null) {
240                classObjectBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, classObjectUpperBounds);
241                if (classObjectBoundsAsType == null) {
242                    classObjectBoundsAsType = KotlinBuiltIns.getInstance().getNothingType();
243                }
244            }
245            return classObjectBoundsAsType;
246        }
247    
248        public void addClassObjectBound(@NotNull JetType bound) {
249            checkUninitialized();
250            classObjectUpperBounds.add(bound); // TODO : Duplicates?
251        }
252    
253        @Override
254        public int getIndex() {
255            checkInitialized();
256            return index;
257        }
258    }