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.SourceElement;
023    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
024    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
025    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
026    import org.jetbrains.jet.lang.resolve.name.Name;
027    import org.jetbrains.jet.lang.types.JetType;
028    import org.jetbrains.jet.lang.types.TypeConstructor;
029    import org.jetbrains.jet.lang.types.TypeConstructorImpl;
030    import org.jetbrains.jet.lang.types.Variance;
031    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
032    import org.jetbrains.jet.storage.LockBasedStorageManager;
033    
034    import java.util.Collections;
035    import java.util.Set;
036    
037    public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor {
038        public static TypeParameterDescriptor createWithDefaultBound(
039                @NotNull DeclarationDescriptor containingDeclaration,
040                @NotNull Annotations annotations,
041                boolean reified,
042                @NotNull Variance variance,
043                @NotNull Name name,
044                int index
045        ) {
046            TypeParameterDescriptorImpl typeParameterDescriptor =
047                    createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, SourceElement.NO_SOURCE);
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 Annotations annotations,
056                boolean reified,
057                @NotNull Variance variance,
058                @NotNull Name name,
059                int index,
060                @NotNull SourceElement source
061        ) {
062            return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source);
063        }
064    
065        private final Set<JetType> upperBounds = Sets.newLinkedHashSet();
066        private boolean initialized = false;
067    
068        private TypeParameterDescriptorImpl(
069                @NotNull DeclarationDescriptor containingDeclaration,
070                @NotNull Annotations annotations,
071                boolean reified,
072                @NotNull Variance variance,
073                @NotNull Name name,
074                int index,
075                @NotNull SourceElement source
076        ) {
077            super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, annotations, name, variance, reified, index, source);
078        }
079    
080        @NotNull
081        @Override
082        protected TypeConstructor createTypeConstructor() {
083            // TODO: Should we actually pass the annotations on to the type constructor?
084            return TypeConstructorImpl.createForTypeParameter(
085                    this,
086                    getAnnotations(),
087                    false,
088                    getName().asString(),
089                    Collections.<TypeParameterDescriptor>emptyList(),
090                    upperBounds
091            );
092        }
093    
094        private void checkInitialized() {
095            if (!initialized) {
096                throw new IllegalStateException("Type parameter descriptor is not initialized: " + nameForAssertions());
097            }
098        }
099    
100        private void checkUninitialized() {
101            if (initialized) {
102                throw new IllegalStateException("Type parameter descriptor is already initialized: " + nameForAssertions());
103            }
104        }
105    
106        private String nameForAssertions() {
107            return getName() + " declared in " + DescriptorUtils.getFqName(getContainingDeclaration());
108        }
109    
110        public void setInitialized() {
111            checkUninitialized();
112            initialized = true;
113        }
114    
115        public void addUpperBound(@NotNull JetType bound) {
116            checkUninitialized();
117            doAddUpperBound(bound);
118        }
119    
120        private void doAddUpperBound(JetType bound) {
121            upperBounds.add(bound); // TODO : Duplicates?
122        }
123    
124        public void addDefaultUpperBound() {
125            checkUninitialized();
126    
127            if (upperBounds.isEmpty()) {
128                doAddUpperBound(KotlinBuiltIns.getInstance().getDefaultBound());
129            }
130        }
131    
132        @NotNull
133        @Override
134        protected Set<JetType> resolveUpperBounds() {
135            checkInitialized();
136            return upperBounds;
137        }
138    }