001    /*
002     * Copyright 2010-2015 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.kotlin.descriptors.impl;
018    
019    import kotlin.jvm.functions.Function1;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
023    import org.jetbrains.kotlin.descriptors.SourceElement;
024    import org.jetbrains.kotlin.descriptors.SupertypeLoopChecker;
025    import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
026    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
027    import org.jetbrains.kotlin.name.Name;
028    import org.jetbrains.kotlin.resolve.DescriptorUtils;
029    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
030    import org.jetbrains.kotlin.types.KotlinType;
031    import org.jetbrains.kotlin.types.TypeConstructor;
032    import org.jetbrains.kotlin.types.TypeConstructorImpl;
033    import org.jetbrains.kotlin.types.Variance;
034    
035    import java.util.ArrayList;
036    import java.util.Collections;
037    import java.util.List;
038    
039    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
040    
041    public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor {
042        @Nullable
043        private final Function1<KotlinType, Void> reportCycleError;
044        @NotNull
045        private final SupertypeLoopChecker supertypeLoopsChecker;
046    
047        public static TypeParameterDescriptor createWithDefaultBound(
048                @NotNull DeclarationDescriptor containingDeclaration,
049                @NotNull Annotations annotations,
050                boolean reified,
051                @NotNull Variance variance,
052                @NotNull Name name,
053                int index
054        ) {
055            TypeParameterDescriptorImpl typeParameterDescriptor =
056                    createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, SourceElement.NO_SOURCE);
057            typeParameterDescriptor.addUpperBound(getBuiltIns(containingDeclaration).getDefaultBound());
058            typeParameterDescriptor.setInitialized();
059            return typeParameterDescriptor;
060        }
061    
062        public static TypeParameterDescriptorImpl createForFurtherModification(
063                @NotNull DeclarationDescriptor containingDeclaration,
064                @NotNull Annotations annotations,
065                boolean reified,
066                @NotNull Variance variance,
067                @NotNull Name name,
068                int index,
069                @NotNull SourceElement source
070        ) {
071            return createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, source,
072                                                /* reportCycleError = */ null, SupertypeLoopChecker.EMPTY.INSTANCE);
073        }
074    
075        public static TypeParameterDescriptorImpl createForFurtherModification(
076                @NotNull DeclarationDescriptor containingDeclaration,
077                @NotNull Annotations annotations,
078                boolean reified,
079                @NotNull Variance variance,
080                @NotNull Name name,
081                int index,
082                @NotNull SourceElement source,
083                @Nullable Function1<KotlinType, Void> reportCycleError,
084                @NotNull SupertypeLoopChecker supertypeLoopsResolver
085        ) {
086            return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source, reportCycleError,
087                                                   supertypeLoopsResolver);
088        }
089    
090        private final List<KotlinType> upperBounds = new ArrayList<KotlinType>(1);
091        private boolean initialized = false;
092    
093        private TypeParameterDescriptorImpl(
094                @NotNull DeclarationDescriptor containingDeclaration,
095                @NotNull Annotations annotations,
096                boolean reified,
097                @NotNull Variance variance,
098                @NotNull Name name,
099                int index,
100                @NotNull SourceElement source,
101                @Nullable Function1<KotlinType, Void> reportCycleError,
102                @NotNull SupertypeLoopChecker supertypeLoopsChecker
103        ) {
104            super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, annotations, name, variance, reified, index, source);
105            this.reportCycleError = reportCycleError;
106            // ?
107            this.supertypeLoopsChecker = supertypeLoopsChecker;
108        }
109    
110        @NotNull
111        @Override
112        protected TypeConstructor createTypeConstructor() {
113            // TODO: Should we actually pass the annotations on to the type constructor?
114            return TypeConstructorImpl.createForTypeParameter(
115                    this,
116                    getAnnotations(),
117                    false,
118                    getName().asString(),
119                    Collections.<TypeParameterDescriptor>emptyList(),
120                    upperBounds
121            );
122        }
123    
124        private void checkInitialized() {
125            if (!initialized) {
126                throw new IllegalStateException("Type parameter descriptor is not initialized: " + nameForAssertions());
127            }
128        }
129    
130        private void checkUninitialized() {
131            if (initialized) {
132                throw new IllegalStateException("Type parameter descriptor is already initialized: " + nameForAssertions());
133            }
134        }
135    
136        private String nameForAssertions() {
137            return getName() + " declared in " + DescriptorUtils.getFqName(getContainingDeclaration());
138        }
139    
140        public void setInitialized() {
141            checkUninitialized();
142            initialized = true;
143        }
144    
145        public void addUpperBound(@NotNull KotlinType bound) {
146            checkUninitialized();
147            doAddUpperBound(bound);
148        }
149    
150        private void doAddUpperBound(KotlinType bound) {
151            upperBounds.add(bound); // TODO : Duplicates?
152        }
153    
154        public void addDefaultUpperBound() {
155            checkUninitialized();
156    
157            if (upperBounds.isEmpty()) {
158                doAddUpperBound(getBuiltIns(getContainingDeclaration()).getDefaultBound());
159            }
160        }
161    
162        @NotNull
163        @Override
164        protected SupertypeLoopChecker getSupertypeLoopChecker() {
165            return supertypeLoopsChecker;
166        }
167    
168        @Override
169        protected void reportCycleError(@NotNull KotlinType type) {
170            if (reportCycleError == null) return;
171            reportCycleError.invoke(type);
172        }
173    
174        @NotNull
175        @Override
176        protected List<KotlinType> resolveUpperBounds() {
177            checkInitialized();
178            return upperBounds;
179        }
180    }