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.resolve.lazy.descriptors;
018    
019    import com.google.common.collect.Sets;
020    import com.intellij.openapi.util.Computable;
021    import com.intellij.psi.util.PsiTreeUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
024    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor;
026    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
027    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.lazy.LazyDescriptor;
030    import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
031    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
032    import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
033    import org.jetbrains.jet.lang.resolve.name.Name;
034    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035    import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
036    import org.jetbrains.jet.lang.types.*;
037    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
038    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039    import org.jetbrains.jet.lexer.JetTokens;
040    import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
041    
042    import java.util.Collection;
043    import java.util.Collections;
044    import java.util.List;
045    import java.util.Set;
046    
047    public class LazyTypeParameterDescriptor implements TypeParameterDescriptor, LazyDescriptor {
048        private final ResolveSession resolveSession;
049    
050        private final JetTypeParameter jetTypeParameter;
051        private final Variance variance;
052        private final boolean reified;
053        private final int index;
054        private final LazyClassDescriptor containingDeclaration;
055        private final Name name;
056    
057        private final NotNullLazyValue<TypeConstructor> typeConstructor;
058        private final NotNullLazyValue<JetType> defaultType;
059        private final NotNullLazyValue<Set<JetType>> upperBounds;
060        private final NotNullLazyValue<JetType> upperBoundsAsType;
061    
062        public LazyTypeParameterDescriptor(
063                @NotNull ResolveSession resolveSession,
064                @NotNull LazyClassDescriptor containingDeclaration,
065                @NotNull JetTypeParameter jetTypeParameter,
066                int index) {
067            this.resolveSession = resolveSession;
068            this.jetTypeParameter = jetTypeParameter;
069            this.variance = jetTypeParameter.getVariance();
070            this.containingDeclaration = containingDeclaration;
071            this.index = index;
072            this.name = jetTypeParameter.getNameAsName();
073            this.reified = jetTypeParameter.hasModifier(JetTokens.REIFIED_KEYWORD);
074    
075            StorageManager storageManager = resolveSession.getStorageManager();
076            this.typeConstructor = storageManager.createLazyValue(new Computable<TypeConstructor>() {
077                @Override
078                public TypeConstructor compute() {
079                    return createTypeConstructor();
080                }
081            });
082            this.defaultType = storageManager.createLazyValue(new Computable<JetType>() {
083                @Override
084                public JetType compute() {
085                    return createDefaultType();
086                }
087            });
088            this.upperBounds = storageManager.createLazyValue(new Computable<Set<JetType>>() {
089                @Override
090                public Set<JetType> compute() {
091                    return resolveUpperBounds();
092                }
093            });
094            this.upperBoundsAsType = storageManager.createLazyValue(new Computable<JetType>() {
095                @Override
096                public JetType compute() {
097                    return computeUpperBoundsAsType();
098                }
099            });
100        }
101    
102        @Override
103        public boolean isReified() {
104            return reified;
105        }
106    
107        @Override
108        public Variance getVariance() {
109            return variance;
110        }
111    
112        @NotNull
113        @Override
114        public Set<JetType> getUpperBounds() {
115            return upperBounds.compute();
116        }
117    
118        @NotNull
119        private Set<JetType> resolveUpperBounds() {
120            Set<JetType> upperBounds = Sets.newLinkedHashSet();
121    
122            JetTypeParameter jetTypeParameter = this.jetTypeParameter;
123    
124            resolveUpperBoundsFromWhereClause(upperBounds, false);
125    
126            JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
127            if (extendsBound != null) {
128                upperBounds.add(resolveBoundType(extendsBound));
129            }
130    
131            if (upperBounds.isEmpty()) {
132                upperBounds.add(KotlinBuiltIns.getInstance().getDefaultBound());
133            }
134    
135            return upperBounds;
136        }
137    
138        private void resolveUpperBoundsFromWhereClause(Set<JetType> upperBounds, boolean forClassObject) {
139            JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(jetTypeParameter, JetClassOrObject.class);
140            if (classOrObject instanceof JetClass) {
141                JetClass jetClass = (JetClass) classOrObject;
142                for (JetTypeConstraint jetTypeConstraint : jetClass.getTypeConstraints()) {
143                    if (jetTypeConstraint.isClassObjectContraint() != forClassObject) continue;
144    
145                    JetSimpleNameExpression constrainedParameterName = jetTypeConstraint.getSubjectTypeParameterName();
146                    if (constrainedParameterName != null) {
147                        if (name.equals(constrainedParameterName.getReferencedNameAsName())) {
148    
149                            JetTypeReference boundTypeReference = jetTypeConstraint.getBoundTypeReference();
150                            if (boundTypeReference != null) {
151                                upperBounds.add(resolveBoundType(boundTypeReference));
152                            }
153                        }
154                    }
155                }
156            }
157    
158        }
159    
160        private JetType resolveBoundType(@NotNull JetTypeReference boundTypeReference) {
161            return resolveSession.getInjector().getTypeResolver()
162                        .resolveType(containingDeclaration.getScopeForClassHeaderResolution(), boundTypeReference,
163                                     resolveSession.getTrace(), false);
164        }
165    
166        @NotNull
167        @Override
168        public JetType getUpperBoundsAsType() {
169            return upperBoundsAsType.compute();
170        }
171    
172        @NotNull
173        private JetType computeUpperBoundsAsType() {
174            Set<JetType> upperBounds = getUpperBounds();
175            assert upperBounds.size() > 0 : "Upper bound list is empty in " + getName();
176            JetType upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.INSTANCE, upperBounds);
177            if (upperBoundsAsType == null) {
178                upperBoundsAsType = KotlinBuiltIns.getInstance().getNothingType();
179            }
180            return upperBoundsAsType;
181        }
182    
183        @NotNull
184        @Override
185        public Set<JetType> getLowerBounds() {
186            return Collections.singleton(getLowerBoundsAsType());
187        }
188    
189        @NotNull
190        @Override
191        public JetType getLowerBoundsAsType() {
192            return KotlinBuiltIns.getInstance().getNothingType();
193        }
194    
195        @NotNull
196        @Override
197        public TypeConstructor getTypeConstructor() {
198            return typeConstructor.compute();
199        }
200    
201        @NotNull
202        private TypeConstructor createTypeConstructor() {
203            return new TypeConstructor() {
204                @NotNull
205                @Override
206                public Collection<JetType> getSupertypes() {
207                    return LazyTypeParameterDescriptor.this.getUpperBounds();
208                }
209    
210                @NotNull
211                @Override
212                public List<TypeParameterDescriptor> getParameters() {
213                    return Collections.emptyList();
214                }
215    
216                @Override
217                public boolean isSealed() {
218                    return false;
219                }
220    
221                @Override
222                public ClassifierDescriptor getDeclarationDescriptor() {
223                    return LazyTypeParameterDescriptor.this;
224                }
225    
226                @Override
227                public List<AnnotationDescriptor> getAnnotations() {
228                    return LazyTypeParameterDescriptor.this.getAnnotations();
229                }
230    
231                @Override
232                public String toString() {
233                    return getName().toString();
234                }
235            };
236        }
237    
238        @NotNull
239        @Override
240        public JetType getDefaultType() {
241            return defaultType.compute();
242        }
243    
244        @NotNull
245        private JetType createDefaultType() {
246            return new JetTypeImpl(getTypeConstructor(), new LazyScopeAdapter(new RecursionIntolerantLazyValue<JetScope>() {
247                            @Override
248                            protected JetScope compute() {
249                                return getUpperBoundsAsType().getMemberScope();
250                            }
251                        }));
252        }
253    
254        @Override
255        public JetType getClassObjectType() {
256            return null;
257        }
258    
259        @NotNull
260        @Override
261        public DeclarationDescriptor getOriginal() {
262            return this;
263        }
264    
265        @NotNull
266        @Override
267        public DeclarationDescriptor getContainingDeclaration() {
268            return containingDeclaration;
269        }
270    
271        @NotNull
272        @Override
273        @Deprecated
274        public TypeParameterDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
275            throw new UnsupportedOperationException("Don't call substitute() on type parameters");
276        }
277    
278        @Override
279        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
280            return visitor.visitTypeParameterDescriptor(this, data);
281        }
282    
283        @Override
284        public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
285            visitor.visitTypeParameterDescriptor(this, null);
286        }
287    
288        @Override
289        public int getIndex() {
290            return index;
291        }
292    
293        @Override
294        public List<AnnotationDescriptor> getAnnotations() {
295            return Collections.emptyList(); // TODO
296        }
297    
298        @NotNull
299        @Override
300        public Name getName() {
301            return name;
302        }
303    
304        @Override
305        public String toString() {
306            return getName().toString();
307        }
308    
309        @Override
310        public void forceResolveAllContents() {
311            getAnnotations();
312            getClassObjectType();
313            getContainingDeclaration();
314            getDefaultType();
315            getIndex();
316            getLowerBounds();
317            getLowerBoundsAsType();
318            getOriginal();
319            getTypeConstructor();
320            getUpperBounds();
321            getUpperBoundsAsType();
322            getVariance();
323        }
324    }