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