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