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; 018 019import com.intellij.psi.util.PsiTreeUtil; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 024import org.jetbrains.jet.lang.psi.*; 025import org.jetbrains.jet.lang.resolve.scopes.JetScope; 026import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter; 027import org.jetbrains.jet.lang.types.*; 028import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 029import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue; 030 031import javax.inject.Inject; 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.Collections; 035import java.util.List; 036 037import static org.jetbrains.jet.lang.diagnostics.Errors.*; 038import static org.jetbrains.jet.lang.types.Variance.*; 039 040public 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}