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.calls.callUtil.CallUtilPackage;
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.results.OverloadResolutionResults;
037 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsUtil;
038 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
039 import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject;
040 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
041 import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant;
042 import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
043 import org.jetbrains.jet.lang.types.ErrorUtils;
044 import org.jetbrains.jet.lang.types.JetType;
045 import org.jetbrains.jet.lang.types.JetTypeInfo;
046 import org.jetbrains.jet.lang.types.TypeUtils;
047 import org.jetbrains.jet.lang.types.expressions.BasicExpressionTypingVisitor;
048 import org.jetbrains.jet.lang.types.expressions.DataFlowUtils;
049 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
050 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
051 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052 import org.jetbrains.jet.lexer.JetTokens;
053
054 import javax.inject.Inject;
055 import java.util.Collections;
056
057 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
058 import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT;
059 import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage.createQualifier;
060 import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiversPackage.resolveAsStandaloneExpression;
061 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
062
063 public class CallExpressionResolver {
064 @NotNull
065 private ExpressionTypingServices expressionTypingServices;
066
067 @Inject
068 public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
069 this.expressionTypingServices = expressionTypingServices;
070 }
071
072 @Nullable
073 public ResolvedCall<FunctionDescriptor> getResolvedCallForFunction(
074 @NotNull Call call, @NotNull JetExpression callExpression,
075 @NotNull ResolutionContext context, @NotNull CheckValueArgumentsMode checkArguments,
076 @NotNull boolean[] result
077 ) {
078 CallResolver callResolver = expressionTypingServices.getCallResolver();
079 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveFunctionCall(
080 BasicCallResolutionContext.create(context, call, checkArguments));
081 if (!results.isNothing()) {
082 checkSuper(call.getExplicitReceiver(), results, context.trace, callExpression);
083 result[0] = true;
084 return OverloadResolutionResultsUtil.getResultingCall(results, context.contextDependency);
085 }
086 result[0] = false;
087 return null;
088 }
089
090 @Nullable
091 private JetType getVariableType(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
092 @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context, @NotNull boolean[] result
093 ) {
094 TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
095 context, "trace to resolve as local variable or property", nameExpression);
096 CallResolver callResolver = expressionTypingServices.getCallResolver();
097 Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
098 BasicCallResolutionContext contextForVariable = BasicCallResolutionContext.create(
099 context.replaceTraceAndCache(temporaryForVariable),
100 call, CheckValueArgumentsMode.ENABLED);
101 OverloadResolutionResults<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(contextForVariable);
102
103 // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
104 boolean isLHSOfDot = JetPsiUtil.isLHSOfDot(nameExpression);
105 if (!resolutionResult.isNothing()) {
106 boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult()
107 && resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject;
108 if (!isQualifier) {
109 result[0] = true;
110 temporaryForVariable.commit();
111 checkSuper(receiver, resolutionResult, context.trace, nameExpression);
112 return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
113 }
114 }
115
116 QualifierReceiver qualifier = createQualifier(nameExpression, receiver, context);
117 if (qualifier != null) {
118 result[0] = true;
119 if (!isLHSOfDot) {
120 resolveAsStandaloneExpression(qualifier, context);
121 }
122 return null;
123 }
124 temporaryForVariable.commit();
125 result[0] = !resolutionResult.isNothing();
126 return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
127 }
128
129 @NotNull
130 public JetTypeInfo getSimpleNameExpressionTypeInfo(@NotNull JetSimpleNameExpression nameExpression, @NotNull ReceiverValue receiver,
131 @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
132 ) {
133 boolean[] result = new boolean[1];
134
135 TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
136 context, "trace to resolve as variable", nameExpression);
137 JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result);
138 if (result[0]) {
139 temporaryForVariable.commit();
140 return JetTypeInfo.create(type, context.dataFlowInfo);
141 }
142
143 Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.<ValueArgument>emptyList());
144 TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
145 context, "trace to resolve as function", nameExpression);
146 ResolutionContext newContext = context.replaceTraceAndCache(temporaryForFunction);
147 ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
148 call, nameExpression, newContext, CheckValueArgumentsMode.ENABLED, result);
149 if (result[0]) {
150 FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
151 temporaryForFunction.commit();
152 boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
153 context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters));
154 type = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
155 return JetTypeInfo.create(type, context.dataFlowInfo);
156 }
157
158 temporaryForVariable.commit();
159 return JetTypeInfo.create(null, context.dataFlowInfo);
160 }
161
162 @NotNull
163 public JetTypeInfo getCallExpressionTypeInfo(
164 @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
165 @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
166 ) {
167 JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context);
168 if (context.contextDependency == INDEPENDENT) {
169 DataFlowUtils.checkType(typeInfo, callExpression, context);
170 }
171 return typeInfo;
172 }
173
174 @NotNull
175 public JetTypeInfo getCallExpressionTypeInfoWithoutFinalTypeCheck(
176 @NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
177 @Nullable ASTNode callOperationNode, @NotNull ExpressionTypingContext context
178 ) {
179 boolean[] result = new boolean[1];
180 Call call = CallMaker.makeCall(receiver, callOperationNode, callExpression);
181
182 TemporaryTraceAndCache temporaryForFunction = TemporaryTraceAndCache.create(
183 context, "trace to resolve as function call", callExpression);
184 ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCallForFunction(
185 call, callExpression, context.replaceTraceAndCache(temporaryForFunction),
186 CheckValueArgumentsMode.ENABLED, result);
187 if (result[0]) {
188 FunctionDescriptor functionDescriptor = resolvedCall != null ? resolvedCall.getResultingDescriptor() : null;
189 temporaryForFunction.commit();
190 if (callExpression.getValueArgumentList() == null && callExpression.getFunctionLiteralArguments().isEmpty()) {
191 // there are only type arguments
192 boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0;
193 context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters));
194 }
195 if (functionDescriptor == null) {
196 return JetTypeInfo.create(null, context.dataFlowInfo);
197 }
198 if (functionDescriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) {
199 if (!canInstantiateAnnotationClass(callExpression)) {
200 context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
201 }
202 }
203
204 JetType type = functionDescriptor.getReturnType();
205
206 return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo());
207 }
208
209 JetExpression calleeExpression = callExpression.getCalleeExpression();
210 if (calleeExpression instanceof JetSimpleNameExpression && callExpression.getTypeArgumentList() == null) {
211 TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create(
212 context, "trace to resolve as variable with 'invoke' call", callExpression);
213 JetType type = getVariableType((JetSimpleNameExpression) calleeExpression, receiver, callOperationNode,
214 context.replaceTraceAndCache(temporaryForVariable), result);
215 Qualifier qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression);
216 if (result[0] && (qualifier == null || qualifier.getPackageView() == null)) {
217 temporaryForVariable.commit();
218 context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
219 type != null ? type : ErrorUtils.createErrorType("")));
220 return JetTypeInfo.create(null, context.dataFlowInfo);
221 }
222 }
223 temporaryForFunction.commit();
224 return JetTypeInfo.create(null, context.dataFlowInfo);
225 }
226
227 private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
228 PsiElement parent = expression.getParent();
229 if (parent instanceof JetValueArgument) {
230 return PsiTreeUtil.getParentOfType(parent, JetAnnotationEntry.class) != null;
231 }
232 else if (parent instanceof JetParameter) {
233 JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
234 if (jetClass != null) {
235 return jetClass.hasModifier(JetTokens.ANNOTATION_KEYWORD);
236 }
237 }
238 return false;
239 }
240
241 private static void checkSuper(
242 @NotNull ReceiverValue receiverValue,
243 @NotNull OverloadResolutionResults<?> results,
244 @NotNull BindingTrace trace,
245 @NotNull JetExpression expression
246 ) {
247 if (!results.isSingleResult()) return;
248 if (!(receiverValue instanceof ExpressionReceiver)) return;
249 JetExpression receiver = ((ExpressionReceiver) receiverValue).getExpression();
250 CallableDescriptor descriptor = results.getResultingDescriptor();
251 if (receiver instanceof JetSuperExpression && descriptor instanceof MemberDescriptor) {
252 if (((MemberDescriptor) descriptor).getModality() == Modality.ABSTRACT) {
253 trace.report(ABSTRACT_SUPER_CALL.on(expression));
254 }
255 }
256 }
257
258 @NotNull
259 private JetTypeInfo getSelectorReturnTypeInfo(
260 @NotNull ReceiverValue receiver,
261 @Nullable ASTNode callOperationNode,
262 @Nullable JetExpression selectorExpression,
263 @NotNull ExpressionTypingContext context
264 ) {
265 if (selectorExpression instanceof JetCallExpression) {
266 return getCallExpressionTypeInfoWithoutFinalTypeCheck((JetCallExpression) selectorExpression, receiver,
267 callOperationNode, context);
268 }
269 else if (selectorExpression instanceof JetSimpleNameExpression) {
270 return getSimpleNameExpressionTypeInfo((JetSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
271 }
272 else if (selectorExpression != null) {
273 context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
274 }
275 return JetTypeInfo.create(null, context.dataFlowInfo);
276 }
277
278 @NotNull
279 public JetTypeInfo getQualifiedExpressionTypeInfo(
280 @NotNull JetQualifiedExpression expression, @NotNull ExpressionTypingContext context
281 ) {
282 // TODO : functions as values
283 JetExpression selectorExpression = expression.getSelectorExpression();
284 JetExpression receiverExpression = expression.getReceiverExpression();
285 ResolutionContext contextForReceiver = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
286 JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver);
287 JetType receiverType = receiverTypeInfo.getType();
288 QualifierReceiver qualifierReceiver = (QualifierReceiver) context.trace.get(BindingContext.QUALIFIER, receiverExpression);
289
290 if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText());
291
292 context = context.replaceDataFlowInfo(receiverTypeInfo.getDataFlowInfo());
293
294 ReceiverValue receiver = qualifierReceiver == null ? new ExpressionReceiver(receiverExpression, receiverType) : qualifierReceiver;
295 JetTypeInfo selectorReturnTypeInfo = getSelectorReturnTypeInfo(
296 receiver, expression.getOperationTokenNode(), selectorExpression, context);
297 JetType selectorReturnType = selectorReturnTypeInfo.getType();
298
299 resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
300 checkNestedClassAccess(expression, context);
301
302 //TODO move further
303 if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
304 if (selectorReturnType != null && !KotlinBuiltIns.getInstance().isUnit(selectorReturnType)) {
305 if (TypeUtils.isNullableType(receiverType)) {
306 selectorReturnType = TypeUtils.makeNullable(selectorReturnType);
307 }
308 }
309 }
310
311 // TODO : this is suspicious: remove this code?
312 if (selectorReturnType != null) {
313 context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
314 }
315
316 CompileTimeConstant<?> value = ConstantExpressionEvaluator.OBJECT$.evaluate(expression, context.trace, context.expectedType);
317 if (value instanceof IntegerValueConstant && ((IntegerValueConstant) value).isPure()) {
318 return BasicExpressionTypingVisitor.createCompileTimeConstantTypeInfo(value, expression, context);
319 }
320
321 JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
322 if (context.contextDependency == INDEPENDENT) {
323 DataFlowUtils.checkType(typeInfo, expression, context);
324 }
325 return typeInfo;
326 }
327
328 private static void resolveDeferredReceiverInQualifiedExpression(
329 @Nullable QualifierReceiver qualifierReceiver,
330 @NotNull JetQualifiedExpression qualifiedExpression,
331 @NotNull ExpressionTypingContext context
332 ) {
333 if (qualifierReceiver == null) return;
334 JetExpression calleeExpression =
335 JetPsiUtil.deparenthesize(CallUtilPackage.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression()), false);
336 DeclarationDescriptor selectorDescriptor =
337 calleeExpression instanceof JetReferenceExpression
338 ? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
339 ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
340 }
341
342 private static void checkNestedClassAccess(
343 @NotNull JetQualifiedExpression expression,
344 @NotNull ExpressionTypingContext context
345 ) {
346 JetExpression selectorExpression = expression.getSelectorExpression();
347 if (selectorExpression == null) return;
348
349 // A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers
350 // a.B - if B is a nested class accessed by instance reference, 'a.B' was marked as a qualifier, but 'a' was not (it's an expression)
351
352 Qualifier expressionQualifier = context.trace.get(BindingContext.QUALIFIER, expression);
353 Qualifier receiverQualifier = context.trace.get(BindingContext.QUALIFIER, expression.getReceiverExpression());
354
355 if (receiverQualifier == null && expressionQualifier != null) {
356 assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
357 "Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
358 context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, (ClassDescriptor)expressionQualifier.getClassifier()));
359 }
360 }
361 }