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