001 /*
002 * Copyright 2010-2015 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.kotlin.types.expressions;
018
019 import com.google.common.collect.Lists;
020 import com.google.common.collect.Maps;
021 import com.intellij.lang.ASTNode;
022 import com.intellij.openapi.diagnostic.Logger;
023 import com.intellij.openapi.util.Ref;
024 import com.intellij.psi.util.PsiTreeUtil;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.kotlin.descriptors.*;
028 import org.jetbrains.kotlin.descriptors.annotations.Annotations;
029 import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
030 import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
031 import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
032 import org.jetbrains.kotlin.lexer.JetTokens;
033 import org.jetbrains.kotlin.name.Name;
034 import org.jetbrains.kotlin.psi.*;
035 import org.jetbrains.kotlin.resolve.BindingContextUtils;
036 import org.jetbrains.kotlin.resolve.BindingTrace;
037 import org.jetbrains.kotlin.resolve.calls.CallResolver;
038 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
039 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemStatus;
040 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintsUtil;
041 import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
042 import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
043 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
044 import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
045 import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
046 import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
047 import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
048 import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
049 import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
050 import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
051 import org.jetbrains.kotlin.types.*;
052
053 import java.util.*;
054
055 import static org.jetbrains.kotlin.resolve.BindingContext.CALL;
056 import static org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL;
057 import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION;
058
059 public class ControlStructureTypingUtils {
060 private static final Logger LOG = Logger.getInstance(ControlStructureTypingUtils.class);
061
062 private final CallResolver callResolver;
063
064 public ControlStructureTypingUtils(@NotNull CallResolver callResolver) {
065 this.callResolver = callResolver;
066 }
067
068 /*package*/ ResolvedCall<FunctionDescriptor> resolveSpecialConstructionAsCall(
069 @NotNull Call call,
070 @NotNull String constructionName,
071 @NotNull List<String> argumentNames,
072 @NotNull List<Boolean> isArgumentNullable,
073 @NotNull ExpressionTypingContext context,
074 @Nullable MutableDataFlowInfoForArguments dataFlowInfoForArguments
075 ) {
076 SimpleFunctionDescriptorImpl function = createFunctionDescriptorForSpecialConstruction(
077 constructionName.toUpperCase(), argumentNames, isArgumentNullable);
078 TracingStrategy tracing = createTracingForSpecialConstruction(call, constructionName, context);
079 ResolutionCandidate<CallableDescriptor> resolutionCandidate = ResolutionCandidate.<CallableDescriptor>create(call, function);
080 OverloadResolutionResults<FunctionDescriptor> results = callResolver.resolveCallWithKnownCandidate(
081 call, tracing, context, resolutionCandidate, dataFlowInfoForArguments);
082 assert results.isSingleResult() : "Not single result after resolving one known candidate";
083 return results.getResultingCall();
084 }
085
086 private static SimpleFunctionDescriptorImpl createFunctionDescriptorForSpecialConstruction(
087 @NotNull String constructionName,
088 @NotNull List<String> argumentNames,
089 @NotNull List<Boolean> isArgumentNullable
090 ) {
091 assert argumentNames.size() == isArgumentNullable.size();
092
093 Name specialFunctionName = Name.identifierNoValidate("<SPECIAL-FUNCTION-FOR-" + constructionName + "-RESOLVE>");
094
095 SimpleFunctionDescriptorImpl function = SimpleFunctionDescriptorImpl.create(
096 ErrorUtils.getErrorModule(),//todo hack to avoid returning true in 'isError(DeclarationDescriptor)'
097 Annotations.EMPTY, specialFunctionName, CallableMemberDescriptor.Kind.DECLARATION, SourceElement.NO_SOURCE);
098
099 TypeParameterDescriptor typeParameter = TypeParameterDescriptorImpl.createWithDefaultBound(
100 function, Annotations.EMPTY, false, Variance.INVARIANT,
101 Name.identifierNoValidate("<TYPE-PARAMETER-FOR-" + constructionName + "-RESOLVE>"), 0);
102
103 JetType type = typeParameter.getDefaultType();
104 JetType nullableType = TypeUtils.makeNullable(type);
105
106 List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(argumentNames.size());
107 for (int i = 0; i < argumentNames.size(); i++) {
108 JetType argumentType = isArgumentNullable.get(i) ? nullableType : type;
109 ValueParameterDescriptorImpl valueParameter = new ValueParameterDescriptorImpl(
110 function, null, i, Annotations.EMPTY, Name.identifier(argumentNames.get(i)),
111 argumentType, false, null, SourceElement.NO_SOURCE
112 );
113 valueParameters.add(valueParameter);
114 }
115 function.initialize(
116 null,
117 ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER,
118 Lists.newArrayList(typeParameter),
119 valueParameters,
120 type,
121 Modality.FINAL,
122 Visibilities.PUBLIC
123 );
124 return function;
125 }
126
127 /*package*/ static MutableDataFlowInfoForArguments createIndependentDataFlowInfoForArgumentsForCall(
128 final Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap
129 ) {
130 return new MutableDataFlowInfoForArguments() {
131 private DataFlowInfo initialDataFlowInfo;
132
133 @Override
134 public void setInitialDataFlowInfo(@NotNull DataFlowInfo dataFlowInfo) {
135 this.initialDataFlowInfo = dataFlowInfo;
136 }
137
138 @Override
139 public void updateInfo(@NotNull ValueArgument valueArgument, @NotNull DataFlowInfo dataFlowInfo) {
140 //todo
141 }
142
143 @NotNull
144 @Override
145 public DataFlowInfo getInfo(@NotNull ValueArgument valueArgument) {
146 return dataFlowInfoForArgumentsMap.get(valueArgument);
147 }
148
149 @NotNull
150 @Override
151 public DataFlowInfo getResultInfo() {
152 //todo merge and use
153 return initialDataFlowInfo;
154 }
155 };
156 }
157
158 public static MutableDataFlowInfoForArguments createDataFlowInfoForArgumentsForIfCall(
159 @NotNull Call callForIf,
160 @NotNull DataFlowInfo thenInfo,
161 @NotNull DataFlowInfo elseInfo
162 ) {
163 Map<ValueArgument, DataFlowInfo> dataFlowInfoForArgumentsMap = Maps.newHashMap();
164 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(0), thenInfo);
165 dataFlowInfoForArgumentsMap.put(callForIf.getValueArguments().get(1), elseInfo);
166 return createIndependentDataFlowInfoForArgumentsForCall(dataFlowInfoForArgumentsMap);
167 }
168
169 /*package*/ static Call createCallForSpecialConstruction(
170 @NotNull final JetExpression expression,
171 @NotNull final JetExpression calleeExpression,
172 @NotNull List<? extends JetExpression> arguments
173 ) {
174 final List<ValueArgument> valueArguments = Lists.newArrayList();
175 for (JetExpression argument : arguments) {
176 valueArguments.add(CallMaker.makeValueArgument(argument));
177 }
178 return new Call() {
179 @Nullable
180 @Override
181 public ASTNode getCallOperationNode() {
182 return expression.getNode();
183 }
184
185 @NotNull
186 @Override
187 public ReceiverValue getExplicitReceiver() {
188 return ReceiverValue.NO_RECEIVER;
189 }
190
191 @NotNull
192 @Override
193 public ReceiverValue getDispatchReceiver() {
194 return ReceiverValue.NO_RECEIVER;
195 }
196
197 @Nullable
198 @Override
199 public JetExpression getCalleeExpression() {
200 return calleeExpression;
201 }
202
203 @Nullable
204 @Override
205 public JetValueArgumentList getValueArgumentList() {
206 return null;
207 }
208
209 @NotNull
210 @Override
211 public List<? extends ValueArgument> getValueArguments() {
212 return valueArguments;
213 }
214
215 @NotNull
216 @Override
217 public List<FunctionLiteralArgument> getFunctionLiteralArguments() {
218 return Collections.emptyList();
219 }
220
221 @NotNull
222 @Override
223 public List<JetTypeProjection> getTypeArguments() {
224 return Collections.emptyList();
225 }
226
227 @Nullable
228 @Override
229 public JetTypeArgumentList getTypeArgumentList() {
230 return null;
231 }
232
233 @NotNull
234 @Override
235 public JetElement getCallElement() {
236 return expression;
237 }
238
239 @NotNull
240 @Override
241 public CallType getCallType() {
242 return CallType.DEFAULT;
243 }
244 };
245 }
246
247 @NotNull
248 /*package*/ static TracingStrategy createTracingForSpecialConstruction(
249 final @NotNull Call call,
250 @NotNull String constructionName,
251 final @NotNull ExpressionTypingContext context
252 ) {
253 class CheckTypeContext {
254 public BindingTrace trace;
255 public JetType expectedType;
256
257 CheckTypeContext(@NotNull BindingTrace trace, @NotNull JetType expectedType) {
258 this.trace = trace;
259 this.expectedType = expectedType;
260 }
261
262 CheckTypeContext makeTypeNullable() {
263 if (TypeUtils.noExpectedType(expectedType)) return this;
264 return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
265 }
266 }
267
268 final JetVisitor<Boolean, CheckTypeContext> checkTypeVisitor = new JetVisitor<Boolean, CheckTypeContext>() {
269
270 private boolean checkExpressionType(@NotNull JetExpression expression, CheckTypeContext c) {
271 JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
272 if (typeInfo == null) return false;
273
274 Ref<Boolean> hasError = Ref.create();
275 DataFlowUtils.checkType(
276 typeInfo.getType(),
277 expression,
278 context
279 .replaceExpectedType(c.expectedType)
280 .replaceDataFlowInfo(typeInfo.getDataFlowInfo())
281 .replaceBindingTrace(c.trace),
282 hasError
283 );
284 return hasError.get();
285 }
286
287 private boolean checkExpressionTypeRecursively(@Nullable JetExpression expression, CheckTypeContext c) {
288 if (expression == null) return false;
289 return expression.accept(this, c);
290 }
291
292 private boolean checkSubExpressions(
293 JetExpression firstSub, JetExpression secondSub, JetExpression expression,
294 CheckTypeContext firstContext, CheckTypeContext secondContext, CheckTypeContext context
295 ) {
296 boolean errorWasReported = checkExpressionTypeRecursively(firstSub, firstContext);
297 errorWasReported |= checkExpressionTypeRecursively(secondSub, secondContext);
298 return errorWasReported || checkExpressionType(expression, context);
299 }
300
301 @Override
302 public Boolean visitIfExpression(@NotNull JetIfExpression ifExpression, CheckTypeContext c) {
303 JetExpression thenBranch = ifExpression.getThen();
304 JetExpression elseBranch = ifExpression.getElse();
305 if (thenBranch == null || elseBranch == null) {
306 return checkExpressionType(ifExpression, c);
307 }
308 return checkSubExpressions(thenBranch, elseBranch, ifExpression, c, c, c);
309 }
310
311 @Override
312 public Boolean visitBlockExpression(@NotNull JetBlockExpression expression, CheckTypeContext c) {
313 if (expression.getStatements().isEmpty()) {
314 return checkExpressionType(expression, c);
315 }
316 JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression);
317 if (lastStatement instanceof JetExpression) {
318 return checkExpressionTypeRecursively((JetExpression) lastStatement, c);
319 }
320 return false;
321 }
322
323 @Override
324 public Boolean visitPostfixExpression(@NotNull JetPostfixExpression expression, CheckTypeContext c) {
325 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
326 return checkExpressionTypeRecursively(expression.getBaseExpression(), c.makeTypeNullable());
327 }
328 return super.visitPostfixExpression(expression, c);
329 }
330
331 @Override
332 public Boolean visitBinaryExpression(@NotNull JetBinaryExpression expression, CheckTypeContext c) {
333 if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
334
335 return checkSubExpressions(expression.getLeft(), expression.getRight(), expression, c.makeTypeNullable(), c, c);
336 }
337 return super.visitBinaryExpression(expression, c);
338 }
339
340 @Override
341 public Boolean visitExpression(@NotNull JetExpression expression, CheckTypeContext c) {
342 return checkExpressionType(expression, c);
343 }
344 };
345
346 return new ThrowingOnErrorTracingStrategy("resolve " + constructionName + " as a call") {
347 @Override
348 public <D extends CallableDescriptor> void bindReference(
349 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
350 ) {
351 //do nothing
352 }
353
354 @Override
355 public void bindCall(@NotNull BindingTrace trace, @NotNull Call call) {
356 trace.record(CALL, call.getCalleeExpression(), call);
357 }
358
359 @Override
360 public <D extends CallableDescriptor> void bindResolvedCall(
361 @NotNull BindingTrace trace, @NotNull ResolvedCall<D> resolvedCall
362 ) {
363 trace.record(RESOLVED_CALL, call, resolvedCall);
364 }
365
366 @Override
367 public void typeInferenceFailed(
368 @NotNull BindingTrace trace, @NotNull InferenceErrorData data
369 ) {
370 ConstraintSystem constraintSystem = data.constraintSystem;
371 ConstraintSystemStatus status = constraintSystem.getStatus();
372 assert !status.isSuccessful() : "Report error only for not successful constraint system";
373
374 if (status.hasErrorInConstrainingTypes() || status.hasUnknownParameters()) {
375 return;
376 }
377 JetExpression expression = (JetExpression) call.getCallElement();
378 if (status.hasOnlyErrorsFromPosition(EXPECTED_TYPE_POSITION.position()) || status.hasConflictingConstraints()) {
379 expression.accept(checkTypeVisitor, new CheckTypeContext(trace, data.expectedType));
380 return;
381 }
382 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetNamedDeclaration.class);
383 logError("Expression: " + (parentDeclaration != null ? parentDeclaration.getText() : expression.getText()) +
384 "\nConstraint system status: \n" + ConstraintsUtil.getDebugMessageForStatus(status));
385 }
386 };
387 }
388
389 private abstract static class ThrowingOnErrorTracingStrategy implements TracingStrategy {
390 private final String debugName;
391
392 protected ThrowingOnErrorTracingStrategy(String debugName) {
393 this.debugName = debugName;
394 }
395
396 private void logError() {
397 logError(null);
398 }
399
400 protected void logError(@Nullable String additionalInformation) {
401 String errorMessage = "Resolution error of this type shouldn't occur for " + debugName;
402 if (additionalInformation != null) {
403 errorMessage += ".\n" + additionalInformation;
404 }
405 LOG.error(errorMessage);
406 }
407
408 @Override
409 public void unresolvedReference(@NotNull BindingTrace trace) {
410 logError();
411 }
412
413 @Override
414 public <D extends CallableDescriptor> void unresolvedReferenceWrongReceiver(
415 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
416 ) {
417 logError();
418 }
419
420 @Override
421 public <D extends CallableDescriptor> void recordAmbiguity(
422 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> candidates
423 ) {
424 logError();
425 }
426
427 @Override
428 public void missingReceiver(
429 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor expectedReceiver
430 ) {
431 logError();
432 }
433
434 @Override
435 public void wrongReceiverType(
436 @NotNull BindingTrace trace, @NotNull ReceiverParameterDescriptor receiverParameter, @NotNull ReceiverValue receiverArgument
437 ) {
438 logError();
439 }
440
441 @Override
442 public void noReceiverAllowed(@NotNull BindingTrace trace) {
443 logError();
444 }
445
446 @Override
447 public void noValueForParameter(
448 @NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter
449 ) {
450 logError();
451 }
452
453 @Override
454 public void wrongNumberOfTypeArguments(@NotNull BindingTrace trace, int expectedTypeArgumentCount) {
455 logError();
456 }
457
458 @Override
459 public <D extends CallableDescriptor> void ambiguity(
460 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
461 ) {
462 logError();
463 }
464
465 @Override
466 public <D extends CallableDescriptor> void noneApplicable(
467 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
468 ) {
469 logError();
470 }
471
472 @Override
473 public <D extends CallableDescriptor> void cannotCompleteResolve(
474 @NotNull BindingTrace trace, @NotNull Collection<? extends ResolvedCall<D>> descriptors
475 ) {
476 logError();
477 }
478
479 @Override
480 public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {
481 logError();
482 }
483
484 @Override
485 public void abstractSuperCall(@NotNull BindingTrace trace) {
486 logError();
487 }
488
489 @Override
490 public void nestedClassAccessViaInstanceReference(
491 @NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor,
492 @NotNull ExplicitReceiverKind explicitReceiverKind
493 ) {
494 logError();
495 }
496
497 @Override
498 public void unsafeCall(
499 @NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
500 ) {
501 logError();
502 }
503
504 @Override
505 public void unnecessarySafeCall(
506 @NotNull BindingTrace trace, @NotNull JetType type
507 ) {
508 logError();
509 }
510
511 @Override
512 public void invisibleMember(
513 @NotNull BindingTrace trace, @NotNull DeclarationDescriptorWithVisibility descriptor
514 ) {
515 logError();
516 }
517
518 @Override
519 public void typeInferenceFailed(
520 @NotNull BindingTrace trace, @NotNull InferenceErrorData inferenceErrorData
521 ) {
522 logError();
523 }
524
525 @Override
526 public void freeFunctionCalledAsExtension(@NotNull BindingTrace trace) {
527 logError();
528 }
529 }
530 }