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