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