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.calls; 018 019import com.intellij.lang.ASTNode; 020import org.jetbrains.annotations.NotNull; 021import org.jetbrains.annotations.Nullable; 022import org.jetbrains.jet.lang.descriptors.*; 023import org.jetbrains.jet.lang.psi.*; 024import org.jetbrains.jet.lang.resolve.BindingContext; 025import org.jetbrains.jet.lang.resolve.BindingTrace; 026import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; 027import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; 028import org.jetbrains.jet.lang.resolve.calls.context.*; 029import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 030import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; 031import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; 032import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; 033import org.jetbrains.jet.lang.resolve.calls.util.CallMaker; 034import org.jetbrains.jet.lang.resolve.constants.ConstantUtils; 035import org.jetbrains.jet.lang.resolve.name.Name; 036import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; 037import org.jetbrains.jet.lang.resolve.scopes.JetScope; 038import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl; 039import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; 040import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 041import org.jetbrains.jet.lang.types.*; 042import org.jetbrains.jet.lang.types.expressions.DataFlowUtils; 043import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; 044import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 045import org.jetbrains.jet.lexer.JetTokens; 046 047import javax.inject.Inject; 048import java.util.ArrayList; 049import java.util.Collections; 050import java.util.List; 051 052import static org.jetbrains.jet.lang.diagnostics.Errors.*; 053import static org.jetbrains.jet.lang.resolve.BindingContext.*; 054import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope; 055import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; 056 057public class CallExpressionResolver { 058 @NotNull 059 private ExpressionTypingServices expressionTypingServices; 060 061 @Inject 062 public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) { 063 this.expressionTypingServices = expressionTypingServices; 064 } 065 066 @Nullable 067 private JetType lookupNamespaceOrClassObject(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { 068 Name referencedName = expression.getReferencedNameAsName(); 069 final ClassifierDescriptor classifier = context.scope.getClassifier(referencedName); 070 if (classifier != null) { 071 JetType classObjectType = classifier.getClassObjectType(); 072 if (classObjectType != null) { 073 context.trace.record(REFERENCE_TARGET, expression, classifier); 074 JetType result = getExtendedClassObjectType(classObjectType, referencedName, classifier, context); 075 return DataFlowUtils.checkType(result, expression, context); 076 } 077 } 078 JetType[] result = new JetType[1]; 079 TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create( 080 context.trace, "trace for namespace/class object lookup of name", referencedName); 081 if (furtherNameLookup(expression, result, context.replaceBindingTrace(temporaryTrace))) { 082 temporaryTrace.commit(); 083 return DataFlowUtils.checkType(result[0], expression, context); 084 } 085 // To report NO_CLASS_OBJECT when no namespace found 086 if (classifier != null) { 087 if (classifier instanceof TypeParameterDescriptor) { 088 if (context.expressionPosition == ExpressionPosition.FREE) { 089 context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(expression, (TypeParameterDescriptor) classifier)); 090 } 091 else { 092 context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(expression, (TypeParameterDescriptor) classifier)); 093 } 094 } 095 else if (context.expressionPosition == ExpressionPosition.FREE) { 096 context.trace.report(NO_CLASS_OBJECT.on(expression, classifier)); 097 } 098 context.trace.record(REFERENCE_TARGET, expression, classifier); 099 JetScope scopeForStaticMembersResolution = 100 classifier instanceof ClassDescriptor 101 ? getStaticNestedClassesScope((ClassDescriptor) classifier) 102 : new JetScopeImpl() { 103 @NotNull 104 @Override 105 public DeclarationDescriptor getContainingDeclaration() { 106 return classifier; 107 } 108 109 @Override 110 public String toString() { 111 return "Scope for the type parameter on the left hand side of dot"; 112 } 113 }; 114 return new NamespaceType(referencedName, scopeForStaticMembersResolution); 115 } 116 temporaryTrace.commit(); 117 return result[0]; 118 } 119 120 @NotNull 121 private JetType getExtendedClassObjectType( 122 @NotNull JetType classObjectType, 123 @NotNull Name referencedName, 124 @NotNull ClassifierDescriptor classifier, 125 @NotNull ResolutionContext context 126 ) { 127 if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT && classifier instanceof ClassDescriptor) { 128 List<JetScope> scopes = new ArrayList<JetScope>(3); 129 130 scopes.add(classObjectType.getMemberScope()); 131 scopes.add(getStaticNestedClassesScope((ClassDescriptor) classifier)); 132 133 NamespaceDescriptor namespace = context.scope.getNamespace(referencedName); 134 if (namespace != null) { 135 //for enums loaded from java binaries 136 scopes.add(namespace.getMemberScope()); 137 } 138 139 JetScope scope = new ChainedScope(classifier, scopes.toArray(new JetScope[scopes.size()])); 140 return new NamespaceType(referencedName, scope); 141 } 142 return classObjectType; 143 } 144 145 private boolean furtherNameLookup( 146 @NotNull JetSimpleNameExpression expression, 147 @NotNull JetType[] result, 148 @NotNull ResolutionContext context 149 ) { 150 NamespaceType namespaceType = lookupNamespaceType(expression, context); 151 if (namespaceType == null) { 152 return false; 153 } 154 if (context.expressionPosition == ExpressionPosition.LHS_OF_DOT) { 155 result[0] = namespaceType; 156 return true; 157 } 158 context.trace.report(EXPRESSION_EXPECTED_NAMESPACE_FOUND.on(expression)); 159 result[0] = ErrorUtils.createErrorType("Type for " + expression.getReferencedNameAsName()); 160 return false; 161 } 162 163 @Nullable 164 private NamespaceType lookupNamespaceType(@NotNull JetSimpleNameExpression expression, @NotNull ResolutionContext context) { 165 Name name = expression.getReferencedNameAsName(); 166 NamespaceDescriptor namespace = context.scope.getNamespace(name); 167 if (namespace == null) { 168 return null; 169 } 170 context.trace.record(REFERENCE_TARGET, expression, namespace); 171 172 // Construct a NamespaceType with everything from the namespace and with nested classes of the corresponding class (if any) 173 JetScope scope; 174 ClassifierDescriptor classifier = context.scope.getClassifier(name); 175 if (classifier instanceof ClassDescriptor) { 176 scope = new ChainedScope(namespace, namespace.getMemberScope(), getStaticNestedClassesScope((ClassDescriptor) classifier)); 177 } 178 else { 179 scope = namespace.getMemberScope(); 180 } 181 return new NamespaceType(name, scope); 182 } 183 184 @Nullable 185 public ResolvedCallWithTrace<FunctionDescriptor> getResolvedCallForFunction( 186 @NotNull Call call, @NotNull JetExpression callExpression, 187 @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode, 188 @NotNull CheckValueArgumentsMode checkArguments, @NotNull ResolutionResultsCache resolutionResultsCache, 189 @NotNull boolean[] result 190 ) { 191 CallResolver callResolver = expressionTypingServices.getCallResolver(); 192 OverloadResolutionResultsImpl<FunctionDescriptor> results = callResolver.resolveFunctionCall( 193 BasicCallResolutionContext.create(context, call, resolveMode, checkArguments, resolutionResultsCache)); 194 if (!results.isNothing()) { 195 checkSuper(call.getExplicitReceiver(), results, context.trace, callExpression); 196 result[0] = true; 197 if (results.isSingleResult() && resolveMode == ResolveMode.TOP_LEVEL_CALL) { 198 if (!CallResolverUtil.hasInferredReturnType(results.getResultingCall())) return null; 199 } 200 201 return results.isSingleResult() ? results.getResultingCall() : null; 202 } 203 result[0] = false; 204 return null; 205 } 206 207 @Nullable 208 private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver, 209 @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull boolean[] result 210 ) { 211 TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create( 212 context.trace, "trace to resolve as local variable or property", nameExpression); 213 CallResolver callResolver = expressionTypingServices.getCallResolver(); 214 Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression); 215 OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty( 216 BasicCallResolutionContext.create(context.replaceBindingTrace(traceForVariable), call, ResolveMode.TOP_LEVEL_CALL, 217 CheckValueArgumentsMode.ENABLED, ResolutionResultsCache.create())); 218 if (!resolutionResult.isNothing()) { 219 traceForVariable.commit(); 220 checkSuper(receiver, resolutionResult, context.trace, nameExpression); 221 result[0] = true; 222 return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; 223 } 224 225 ResolutionContext newContext = receiver.exists() 226 ? context.replaceScope(receiver.getType().getMemberScope()) 227 : context; 228 TemporaryBindingTrace traceForNamespaceOrClassObject = TemporaryBindingTrace.create( 229 context.trace, "trace to resolve as namespace or class object", nameExpression); 230 JetType jetType = lookupNamespaceOrClassObject(nameExpression, newContext.replaceBindingTrace(traceForNamespaceOrClassObject)); 231 if (jetType != null) { 232 traceForNamespaceOrClassObject.commit(); 233 234 // Uncommitted changes in temp context 235 context.trace.record(RESOLUTION_SCOPE, nameExpression, context.scope); 236 if (context.dataFlowInfo.hasTypeInfoConstraints()) { 237 context.trace.record(NON_DEFAULT_EXPRESSION_DATA_FLOW, nameExpression, context.dataFlowInfo); 238 } 239 result[0] = true; 240 return jetType; 241 } 242 result[0] = false; 243 return null; 244 } 245 246 @NotNull 247 public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver, 248 @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context 249 ) { 250 boolean[] result = new boolean[1]; 251 252 TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create(context.trace, "trace to resolve as variable", nameExpression); 253 JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceBindingTrace(traceForVariable), result); 254 if (result[0]) { 255 traceForVariable.commit(); 256 if (type instanceof NamespaceType && context.expressionPosition == ExpressionPosition.FREE) { 257 type = null; 258 } 259 return JetTypeInfo.create(type, context.dataFlowInfo); 260 } 261 262 Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList()); 263 TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function", nameExpression); 264 ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction( 265 call, nameExpression, context, ResolveMode.TOP_LEVEL_CALL, CheckValueArgumentsMode.ENABLED, 266 ResolutionResultsCache.create(), result); 267 if (result[0]) { 268 FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null; 269 traceForFunction.commit(); 270 boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0; 271 context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters)); 272 type = functionDescriptor != null ? functionDescriptor.getReturnType() : null; 273 return JetTypeInfo.create(type, context.dataFlowInfo); 274 } 275 276 traceForVariable.commit(); 277 return JetTypeInfo.create(null, context.dataFlowInfo); 278 } 279 280 @NotNull 281 public JetTypeInfo getCallExpressionTypeInfo( 282 @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver, 283 @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode, 284 @NotNull ResolutionResultsCache resolutionResultsCache 285 ) { 286 JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck( 287 callExpression, receiver, callOperationNode, context, resolveMode, resolutionResultsCache); 288 if (resolveMode == ResolveMode.TOP_LEVEL_CALL) { 289 DataFlowUtils.checkType(typeInfo.getType(), callExpression, context, typeInfo.getDataFlowInfo()); 290 } 291 return typeInfo; 292 } 293 294 @NotNull 295 public JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck( 296 @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver, 297 @Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode, 298 @NotNull ResolutionResultsCache resolutionResultsCache 299 ) { 300 boolean[] result = new boolean[1]; 301 Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression); 302 303 TemporaryBindingTrace traceForFunction = TemporaryBindingTrace.create(context.trace, "trace to resolve as function call", callExpression); 304 ResolvedCallWithTrace<FunctionDescriptor> resolvedCall = getResolvedCallForFunction( 305 call, callExpression, context.replaceBindingTrace(traceForFunction), resolveMode, CheckValueArgumentsMode.ENABLED, 306 resolutionResultsCache, result); 307 if (result[0]) { 308 FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null; 309 traceForFunction.commit(); 310 if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) { 311 // there are only type arguments 312 boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0; 313 context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters)); 314 } 315 if (functionDescriptor == null) { 316 return JetTypeInfo.create(null, context.dataFlowInfo); 317 } 318 JetType type = functionDescriptor.getReturnType(); 319 320 return JetTypeInfo.create(type, resolvedCall.getDataFlowInfo()); 321 } 322 323 JetExpression calleeExpression = callExpression.getCalleeExpression(); 324 if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) { 325 TemporaryBindingTrace traceForVariable = TemporaryBindingTrace.create( 326 context.trace, "trace to resolve as variable with 'invoke' call", callExpression); 327 JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode, 328 context.replaceBindingTrace(traceForVariable), result); 329 if (result[0]) { 330 traceForVariable.commit(); 331 context.trace.report(FUNCTION_EXPECTED.on((JetReferenceExpression) calleeExpression, calleeExpression, 332 type != null ? type : ErrorUtils.createErrorType(""))); 333 return JetTypeInfo.create(null, context.dataFlowInfo); 334 } 335 } 336 traceForFunction.commit(); 337 return JetTypeInfo.create(null, context.dataFlowInfo); 338 } 339 340 private void checkSuper(@NotNull ReceiverValue receiverValue, @NotNull OverloadResolutionResults<? extends CallableDescriptor> results, 341 @NotNull BindingTrace trace, @NotNull JetExpression expression) { 342 if (!results.isSingleResult()) return; 343 if (!(receiverValue instanceof ExpressionReceiver)) return; 344 JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression(); 345 CallableDescriptor descriptor = results.getResultingDescriptor(); 346 if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) { 347 if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) { 348 trace.report(ABSTRACT_SUPER_CALL.on(expression)); 349 } 350 } 351 } 352 353 @NotNull 354 private JetTypeInfo getSelectorReturnTypeInfo( 355 @NotNull ReceiverValue receiver, 356 @Nullable ASTNode callOperationNode, 357 @NotNull JetExpression selectorExpression, 358 @NotNull ResolutionContext context, 359 @NotNull ResolveMode resolveMode, 360 @NotNull ResolutionResultsCache resolutionResultsCache 361 ) { 362 if (selectorExpression instanceof JetCallExpression) { 363 return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver, 364 callOperationNode, context, resolveMode, resolutionResultsCache); 365 } 366 else if (selectorExpression instanceof JetSimpleNameExpression) { 367 return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context); 368 } 369 else if (selectorExpression instanceof JetQualifiedExpression) { 370 JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) selectorExpression; 371 JetExpression newReceiverExpression = qualifiedExpression.getReceiverExpression(); 372 JetTypeInfo newReceiverTypeInfo = getSelectorReturnTypeInfo( 373 receiver, callOperationNode, newReceiverExpression, context.replaceExpectedType(NO_EXPECTED_TYPE), resolveMode, resolutionResultsCache); 374 JetType newReceiverType = newReceiverTypeInfo.getType(); 375 DataFlowInfo newReceiverDataFlowInfo = newReceiverTypeInfo.getDataFlowInfo(); 376 JetExpression newSelectorExpression = qualifiedExpression.getSelectorExpression(); 377 if (newReceiverType != null && newSelectorExpression != null) { 378 ExpressionReceiver expressionReceiver = new ExpressionReceiver(newReceiverExpression, newReceiverType); 379 return getSelectorReturnTypeInfo( 380 expressionReceiver, qualifiedExpression.getOperationTokenNode(), 381 newSelectorExpression, context.replaceDataFlowInfo(newReceiverDataFlowInfo), resolveMode, resolutionResultsCache); 382 } 383 } 384 else { 385 context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText())); 386 } 387 return JetTypeInfo.create(null, context.dataFlowInfo); 388 } 389 390 @NotNull 391 public JetTypeInfo getQualifiedExpressionTypeInfo( 392 @NotNull JetQualifiedExpression expression, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode, 393 @NotNull ResolutionResultsCache resolutionResultsCache 394 ) { 395 // TODO : functions as values 396 JetExpression selectorExpression = expression.getSelectorExpression(); 397 JetExpression receiverExpression = expression.getReceiverExpression(); 398 JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfoWithNamespaces( 399 receiverExpression, context.scope, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); 400 JetType receiverType = receiverTypeInfo.getType(); 401 if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo); 402 if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText()); 403 404 context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo()); 405 406 if (selectorExpression instanceof JetSimpleNameExpression) { 407 ConstantUtils.propagateConstantValues(expression, context.trace, (JetSimpleNameExpression) selectorExpression); 408 } 409 410 JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo( 411 new ExpressionReceiver(receiverExpression, receiverType), 412 expression.getOperationTokenNode(), selectorExpression, context, resolveMode, resolutionResultsCache); 413 JetType selectorReturnType = selectorReturnTypeInfo.getType(); 414 415 //TODO move further 416 if (!(receiverType instanceof NamespaceType) && expression.getOperationSign() == JetTokens.SAFE_ACCESS) { 417 if (selectorReturnType != null && !selectorReturnType.isNullable() && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) { 418 if (receiverType.isNullable()) { 419 selectorReturnType = TypeUtils.makeNullable(selectorReturnType); 420 } 421 } 422 } 423 424 // TODO : this is suspicious: remove this code? 425 if (selectorReturnType != null) { 426 context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType); 427 } 428 JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo()); 429 if (resolveMode == ResolveMode.TOP_LEVEL_CALL) { 430 DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo()); 431 } 432 return typeInfo; 433 } 434}