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.Sets;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
022import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor;
023import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
024import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025import org.jetbrains.jet.lang.resolve.DescriptorUtils;
026import org.jetbrains.jet.lang.resolve.name.Name;
027import org.jetbrains.jet.lang.resolve.scopes.JetScope;
028import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
029import org.jetbrains.jet.lang.types.*;
030import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
031import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032import org.jetbrains.jet.renderer.DescriptorRenderer;
033import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
034
035import java.util.Collections;
036import java.util.List;
037import java.util.Set;
038
039public 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}