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;
018
019 import com.intellij.psi.util.PsiTreeUtil;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024 import org.jetbrains.jet.lang.psi.*;
025 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026 import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
027 import org.jetbrains.jet.lang.types.*;
028 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029 import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
030
031 import javax.inject.Inject;
032 import java.util.ArrayList;
033 import java.util.Collection;
034 import java.util.Collections;
035 import java.util.List;
036
037 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
038 import static org.jetbrains.jet.lang.types.Variance.*;
039
040 public class TypeResolver {
041
042 private AnnotationResolver annotationResolver;
043 private DescriptorResolver descriptorResolver;
044 private QualifiedExpressionResolver qualifiedExpressionResolver;
045 private ModuleDescriptor moduleDescriptor;
046
047 @Inject
048 public void setDescriptorResolver(DescriptorResolver descriptorResolver) {
049 this.descriptorResolver = descriptorResolver;
050 }
051
052 @Inject
053 public void setAnnotationResolver(AnnotationResolver annotationResolver) {
054 this.annotationResolver = annotationResolver;
055 }
056
057 @Inject
058 public void setQualifiedExpressionResolver(QualifiedExpressionResolver qualifiedExpressionResolver) {
059 this.qualifiedExpressionResolver = qualifiedExpressionResolver;
060 }
061
062 @Inject
063 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
064 this.moduleDescriptor = moduleDescriptor;
065 }
066
067 @NotNull
068 public JetType resolveType(@NotNull JetScope scope, @NotNull JetTypeReference typeReference, BindingTrace trace, boolean checkBounds) {
069 JetType cachedType = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
070 if (cachedType != null) return cachedType;
071
072 List<AnnotationDescriptor> annotations = annotationResolver.getResolvedAnnotations(typeReference.getAnnotations(), trace);
073
074 JetTypeElement typeElement = typeReference.getTypeElement();
075 JetType type = resolveTypeElement(scope, annotations, typeElement, trace, checkBounds);
076 trace.record(BindingContext.TYPE, typeReference, type);
077 trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope);
078
079 return type;
080 }
081
082 @NotNull
083 private JetType resolveTypeElement(final JetScope scope, final List<AnnotationDescriptor> annotations,
084 JetTypeElement typeElement, final BindingTrace trace, final boolean checkBounds) {
085
086 final JetType[] result = new JetType[1];
087 if (typeElement != null) {
088 typeElement.accept(new JetVisitorVoid() {
089 @Override
090 public void visitUserType(JetUserType type) {
091 JetSimpleNameExpression referenceExpression = type.getReferenceExpression();
092 String referencedName = type.getReferencedName();
093 if (referenceExpression == null || referencedName == null) {
094 return;
095 }
096
097 ClassifierDescriptor classifierDescriptor = resolveClass(scope, type, trace);
098 if (classifierDescriptor == null) {
099 resolveTypeProjections(scope, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments(), trace, checkBounds);
100 return;
101 }
102
103 trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor);
104
105 if (classifierDescriptor instanceof TypeParameterDescriptor) {
106 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) classifierDescriptor;
107
108 JetScope scopeForTypeParameter = getScopeForTypeParameter(typeParameterDescriptor, checkBounds);
109 if (scopeForTypeParameter instanceof ErrorUtils.ErrorScope) {
110 result[0] = ErrorUtils.createErrorType("?");
111 }
112 else {
113 result[0] = new JetTypeImpl(
114 annotations,
115 typeParameterDescriptor.getTypeConstructor(),
116 TypeUtils.hasNullableLowerBound(typeParameterDescriptor),
117 Collections.<TypeProjection>emptyList(),
118 scopeForTypeParameter
119 );
120 }
121
122 resolveTypeProjections(scope, ErrorUtils.createErrorType("No type").getConstructor(), type.getTypeArguments(), trace, checkBounds);
123
124 DeclarationDescriptor containing = typeParameterDescriptor.getContainingDeclaration();
125 if (containing instanceof ClassDescriptor) {
126 // Type parameter can't be inherited from member of parent class, so we can skip subclass check
127 DescriptorResolver.checkHasOuterClassInstance(scope, trace, referenceExpression, (ClassDescriptor) containing, false);
128 }
129 }
130 else if (classifierDescriptor instanceof ClassDescriptor) {
131 ClassDescriptor classDescriptor = (ClassDescriptor) classifierDescriptor;
132
133 TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
134 List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments(), trace, checkBounds);
135 List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
136 int expectedArgumentCount = parameters.size();
137 int actualArgumentCount = arguments.size();
138 if (ErrorUtils.isError(typeConstructor)) {
139 result[0] = ErrorUtils.createErrorType("[Error type: " + typeConstructor + "]");
140 }
141 else {
142 if (actualArgumentCount != expectedArgumentCount) {
143 if (actualArgumentCount == 0) {
144 if (rhsOfIsExpression(type) || rhsOfIsPattern(type)) {
145 trace.report(NO_TYPE_ARGUMENTS_ON_RHS_OF_IS_EXPRESSION.on(type, expectedArgumentCount, allStarProjectionsString(typeConstructor)));
146 }
147 else {
148 trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type, expectedArgumentCount));
149 }
150 }
151 else {
152 trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(type.getTypeArgumentList(), expectedArgumentCount));
153 }
154 }
155 else {
156 result[0] = new JetTypeImpl(
157 annotations,
158 typeConstructor,
159 false,
160 arguments,
161 classDescriptor.getMemberScope(arguments)
162 );
163 if (checkBounds) {
164 TypeSubstitutor substitutor = TypeSubstitutor.create(result[0]);
165 for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
166 TypeParameterDescriptor parameter = parameters.get(i);
167 JetType argument = arguments.get(i).getType();
168 JetTypeReference typeReference = type.getTypeArguments().get(i).getTypeReference();
169
170 if (typeReference != null) {
171 descriptorResolver.checkBounds(typeReference, argument, parameter, substitutor, trace);
172 }
173 }
174 }
175 }
176 }
177 }
178 }
179
180 @Override
181 public void visitNullableType(JetNullableType nullableType) {
182 JetType baseType = resolveTypeElement(scope, annotations, nullableType.getInnerType(), trace, checkBounds);
183 if (baseType.isNullable()) {
184 trace.report(REDUNDANT_NULLABLE.on(nullableType));
185 }
186 else if (TypeUtils.hasNullableSuperType(baseType)) {
187 trace.report(BASE_WITH_NULLABLE_UPPER_BOUND.on(nullableType, baseType));
188 }
189 result[0] = TypeUtils.makeNullable(baseType);
190 }
191
192 @Override
193 public void visitFunctionType(JetFunctionType type) {
194 JetTypeReference receiverTypeRef = type.getReceiverTypeRef();
195 JetType receiverType = receiverTypeRef == null ? null : resolveType(scope, receiverTypeRef, trace, checkBounds);
196
197 List<JetType> parameterTypes = new ArrayList<JetType>();
198 for (JetParameter parameter : type.getParameters()) {
199 parameterTypes.add(resolveType(scope, parameter.getTypeReference(), trace, checkBounds));
200 }
201
202 JetTypeReference returnTypeRef = type.getReturnTypeRef();
203 JetType returnType;
204 if (returnTypeRef != null) {
205 returnType = resolveType(scope, returnTypeRef, trace, checkBounds);
206 }
207 else {
208 returnType = KotlinBuiltIns.getInstance().getUnitType();
209 }
210 result[0] = KotlinBuiltIns.getInstance().getFunctionType(annotations, receiverType, parameterTypes, returnType);
211 }
212
213 @Override
214 public void visitJetElement(JetElement element) {
215 trace.report(UNSUPPORTED.on(element, "Self-types are not supported yet"));
216 // throw new IllegalArgumentException("Unsupported type: " + element);
217 }
218 });
219 }
220 if (result[0] == null) {
221 return ErrorUtils.createErrorType(typeElement == null ? "No type element" : typeElement.getText());
222 }
223 return result[0];
224 }
225
226 private static boolean rhsOfIsExpression(@NotNull JetUserType type) {
227 // Look for the FIRST expression containing this type
228 JetExpression outerExpression = PsiTreeUtil.getParentOfType(type, JetExpression.class);
229 if (outerExpression instanceof JetIsExpression) {
230 JetIsExpression isExpression = (JetIsExpression) outerExpression;
231 // If this expression is JetIsExpression, and the type is the outermost on the RHS
232 if (type.getParent() == isExpression.getTypeRef()) {
233 return true;
234 }
235 }
236 return false;
237 }
238
239 private static boolean rhsOfIsPattern(@NotNull JetUserType type) {
240 // Look for the is-pattern containing this type
241 JetWhenConditionIsPattern outerPattern = PsiTreeUtil.getParentOfType(type, JetWhenConditionIsPattern.class, false, JetExpression.class);
242 if (outerPattern == null) return false;
243 // We are interested only in the outermost type on the RHS
244 return type.getParent() == outerPattern.getTypeRef();
245 }
246
247 private JetScope getScopeForTypeParameter(final TypeParameterDescriptor typeParameterDescriptor, boolean checkBounds) {
248 if (checkBounds) {
249 return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
250 }
251 else {
252 return new LazyScopeAdapter(new RecursionIntolerantLazyValue<JetScope>() {
253 @Override
254 protected JetScope compute() {
255 return typeParameterDescriptor.getUpperBoundsAsType().getMemberScope();
256 }
257 });
258 }
259 }
260
261 private List<JetType> resolveTypes(JetScope scope, List<JetTypeReference> argumentElements, BindingTrace trace, boolean checkBounds) {
262 List<JetType> arguments = new ArrayList<JetType>();
263 for (JetTypeReference argumentElement : argumentElements) {
264 arguments.add(resolveType(scope, argumentElement, trace, checkBounds));
265 }
266 return arguments;
267 }
268
269 @NotNull
270 private List<TypeProjection> resolveTypeProjections(JetScope scope, TypeConstructor constructor, List<JetTypeProjection> argumentElements, BindingTrace trace, boolean checkBounds) {
271 List<TypeProjection> arguments = new ArrayList<TypeProjection>();
272 for (int i = 0, argumentElementsSize = argumentElements.size(); i < argumentElementsSize; i++) {
273 JetTypeProjection argumentElement = argumentElements.get(i);
274
275 JetProjectionKind projectionKind = argumentElement.getProjectionKind();
276 JetType type;
277 if (projectionKind == JetProjectionKind.STAR) {
278 List<TypeParameterDescriptor> parameters = constructor.getParameters();
279 if (parameters.size() > i) {
280 TypeParameterDescriptor parameterDescriptor = parameters.get(i);
281 arguments.add(SubstitutionUtils.makeStarProjection(parameterDescriptor));
282 }
283 else {
284 arguments.add(new TypeProjection(OUT_VARIANCE, ErrorUtils.createErrorType("*")));
285 }
286 }
287 else {
288 // TODO : handle the Foo<in *> case
289 type = resolveType(scope, argumentElement.getTypeReference(), trace, checkBounds);
290 Variance kind = resolveProjectionKind(projectionKind);
291 if (constructor.getParameters().size() > i) {
292 TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
293 if (kind != INVARIANT && parameterDescriptor.getVariance() != INVARIANT) {
294 if (kind == parameterDescriptor.getVariance()) {
295 trace.report(REDUNDANT_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
296 }
297 else {
298 trace.report(CONFLICTING_PROJECTION.on(argumentElement, constructor.getDeclarationDescriptor()));
299 }
300 }
301 }
302 arguments.add(new TypeProjection(kind, type));
303 }
304 }
305 return arguments;
306 }
307
308 @NotNull
309 public static Variance resolveProjectionKind(@NotNull JetProjectionKind projectionKind) {
310 Variance kind = null;
311 switch (projectionKind) {
312 case IN:
313 kind = IN_VARIANCE;
314 break;
315 case OUT:
316 kind = OUT_VARIANCE;
317 break;
318 case NONE:
319 kind = INVARIANT;
320 break;
321 default:
322 // NOTE: Star projections must be handled before this method is called
323 throw new IllegalStateException("Illegal projection kind:" + projectionKind);
324 }
325 return kind;
326 }
327
328 @Nullable
329 public ClassifierDescriptor resolveClass(JetScope scope, JetUserType userType, BindingTrace trace) {
330 Collection<? extends DeclarationDescriptor> descriptors = qualifiedExpressionResolver.lookupDescriptorsForUserType(userType, scope, trace);
331 for (DeclarationDescriptor descriptor : descriptors) {
332 if (descriptor instanceof ClassifierDescriptor) {
333 ImportsResolver.reportPlatformClassMappedToKotlin(moduleDescriptor, trace, userType, descriptor);
334 return (ClassifierDescriptor) descriptor;
335 }
336 }
337 return null;
338 }
339
340 @NotNull
341 private static String allStarProjectionsString(@NotNull TypeConstructor constructor) {
342 int size = constructor.getParameters().size();
343 assert size != 0 : "No projections possible for a nilary type constructor" + constructor;
344 ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
345 assert declarationDescriptor != null : "No declaration descriptor for type constructor " + constructor;
346 String name = declarationDescriptor.getName().asString();
347
348 return TypeUtils.getTypeNameAndStarProjectionsString(name, size);
349 }
350 }