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