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.*;
023    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
024    import org.jetbrains.kotlin.name.Name;
025    import org.jetbrains.kotlin.resolve.DescriptorUtils;
026    import org.jetbrains.kotlin.storage.LockBasedStorageManager;
027    import org.jetbrains.kotlin.types.KotlinType;
028    import org.jetbrains.kotlin.types.Variance;
029    
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getBuiltIns;
034    
035    public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor {
036        @Nullable
037        private final Function1<KotlinType, Void> reportCycleError;
038    
039        public static TypeParameterDescriptor createWithDefaultBound(
040                @NotNull DeclarationDescriptor containingDeclaration,
041                @NotNull Annotations annotations,
042                boolean reified,
043                @NotNull Variance variance,
044                @NotNull Name name,
045                int index
046        ) {
047            TypeParameterDescriptorImpl typeParameterDescriptor =
048                    createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, SourceElement.NO_SOURCE);
049            typeParameterDescriptor.addUpperBound(getBuiltIns(containingDeclaration).getDefaultBound());
050            typeParameterDescriptor.setInitialized();
051            return typeParameterDescriptor;
052        }
053    
054        public static TypeParameterDescriptorImpl createForFurtherModification(
055                @NotNull DeclarationDescriptor containingDeclaration,
056                @NotNull Annotations annotations,
057                boolean reified,
058                @NotNull Variance variance,
059                @NotNull Name name,
060                int index,
061                @NotNull SourceElement source
062        ) {
063            return createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index, source,
064                                                /* reportSupertypeLoopError = */ null, SupertypeLoopChecker.EMPTY.INSTANCE);
065        }
066    
067        public static TypeParameterDescriptorImpl createForFurtherModification(
068                @NotNull DeclarationDescriptor containingDeclaration,
069                @NotNull Annotations annotations,
070                boolean reified,
071                @NotNull Variance variance,
072                @NotNull Name name,
073                int index,
074                @NotNull SourceElement source,
075                @Nullable Function1<KotlinType, Void> reportCycleError,
076                @NotNull SupertypeLoopChecker supertypeLoopsResolver
077        ) {
078            return new TypeParameterDescriptorImpl(containingDeclaration, annotations, reified, variance, name, index, source, reportCycleError,
079                                                   supertypeLoopsResolver);
080        }
081    
082        private final List<KotlinType> upperBounds = new ArrayList<KotlinType>(1);
083        private boolean initialized = false;
084    
085        private TypeParameterDescriptorImpl(
086                @NotNull DeclarationDescriptor containingDeclaration,
087                @NotNull Annotations annotations,
088                boolean reified,
089                @NotNull Variance variance,
090                @NotNull Name name,
091                int index,
092                @NotNull SourceElement source,
093                @Nullable Function1<KotlinType, Void> reportCycleError,
094                @NotNull SupertypeLoopChecker supertypeLoopsChecker
095        ) {
096            super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, annotations, name, variance, reified, index, source,
097                  supertypeLoopsChecker);
098            this.reportCycleError = reportCycleError;
099        }
100    
101        private void checkInitialized() {
102            if (!initialized) {
103                throw new IllegalStateException("Type parameter descriptor is 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        public void addUpperBound(@NotNull KotlinType bound) {
123            checkUninitialized();
124            doAddUpperBound(bound);
125        }
126    
127        private void doAddUpperBound(KotlinType bound) {
128            if (bound.isError()) return;
129            upperBounds.add(bound); // TODO : Duplicates?
130        }
131    
132        public void addDefaultUpperBound() {
133            checkUninitialized();
134    
135            if (upperBounds.isEmpty()) {
136                doAddUpperBound(getBuiltIns(getContainingDeclaration()).getDefaultBound());
137            }
138        }
139    
140        @Override
141        protected void reportSupertypeLoopError(@NotNull KotlinType type) {
142            if (reportCycleError == null) return;
143            reportCycleError.invoke(type);
144        }
145    
146        @NotNull
147        @Override
148        protected List<KotlinType> resolveUpperBounds() {
149            checkInitialized();
150            return upperBounds;
151        }
152    }