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