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