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.calls;
018
019 import com.intellij.lang.ASTNode;
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.psi.*;
024 import org.jetbrains.jet.lang.resolve.BindingContext;
025 import org.jetbrains.jet.lang.resolve.BindingTrace;
026 import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
027 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
028 import org.jetbrains.jet.lang.resolve.calls.context.*;
029 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
031 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
032 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl;
033 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
034 import org.jetbrains.jet.lang.resolve.constants.ConstantUtils;
035 import org.jetbrains.jet.lang.resolve.name.Name;
036 import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
037 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038 import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
039 import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
040 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
041 import org.jetbrains.jet.lang.types.*;
042 import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
043 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
044 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
045 import org.jetbrains.jet.lexer.JetTokens;
046
047 import javax.inject.Inject;
048 import java.util.ArrayList;
049 import java.util.Collections;
050 import java.util.List;
051
052 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
053 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
054 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
055 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
056
057 public 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 }