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
017package org.jetbrains.jet.lang.resolve.lazy.descriptors;
018
019import com.google.common.collect.Sets;
020import com.intellij.openapi.util.Computable;
021import com.intellij.psi.util.PsiTreeUtil;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
024import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorVisitor;
026import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
027import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
028import org.jetbrains.jet.lang.psi.*;
029import org.jetbrains.jet.lang.resolve.lazy.LazyDescriptor;
030import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
031import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
032import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
033import org.jetbrains.jet.lang.resolve.name.Name;
034import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
036import org.jetbrains.jet.lang.types.*;
037import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
038import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039import org.jetbrains.jet.lexer.JetTokens;
040import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
041
042import java.util.Collection;
043import java.util.Collections;
044import java.util.List;
045import java.util.Set;
046
047public 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}