diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilder.java index d7e63e1a982..4035bfba69c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilder.java @@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue; import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode; -import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; import org.jetbrains.kotlin.psi.*; @@ -120,7 +119,6 @@ public interface JetControlFlowBuilder { @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, - @NotNull Map expectedTypes, @NotNull MagicKind kind ); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilderAdapter.java index b3d81011e37..a5ac8a404a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowBuilderAdapter.java @@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue; import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode; -import org.jetbrains.kotlin.cfg.pseudocode.TypePredicate; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; import org.jetbrains.kotlin.psi.*; @@ -71,10 +70,9 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, - @NotNull Map expectedTypes, @NotNull MagicKind kind ) { - return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, expectedTypes, kind); + return getDelegateBuilder().magic(instructionElement, valueElement, inputValues, kind); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java index 8d34e1869e0..009380aa147 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java @@ -17,20 +17,21 @@ package org.jetbrains.kotlin.cfg; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.SmartFMap; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.MultiMap; import kotlin.KotlinPackage; import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.cfg.pseudocode.*; +import org.jetbrains.kotlin.cfg.pseudocode.JetControlFlowInstructionsGenerator; +import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue; +import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode; +import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind; @@ -41,15 +42,12 @@ import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.kotlin.renderer.DescriptorRenderer; -import org.jetbrains.kotlin.resolve.*; -import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage; -import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper; -import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; +import org.jetbrains.kotlin.resolve.BindingContext; +import org.jetbrains.kotlin.resolve.BindingContextUtils; +import org.jetbrains.kotlin.resolve.BindingTrace; +import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils; import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind; -import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate; -import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; @@ -142,7 +140,7 @@ public class JetControlFlowProcessor { if (!generateCall(condition.getOperationReference())) { JetExpression rangeExpression = condition.getRangeExpression(); generateInstructions(rangeExpression); - createUnresolvedCall(condition, rangeExpression); + createNonSyntheticValue(condition, MagicKind.UNRESOLVED_CALL, rangeExpression); } } @@ -209,7 +207,7 @@ public class JetControlFlowProcessor { @NotNull private PseudoValue createSyntheticValue(@NotNull JetElement instructionElement, @NotNull MagicKind kind, JetElement... from) { List values = elementsToValues(from.length > 0 ? Arrays.asList(from) : Collections.emptyList()); - return builder.magic(instructionElement, null, values, defaultTypeMap(values), kind).getOutputValue(); + return builder.magic(instructionElement, null, values, kind).getOutputValue(); } @NotNull @@ -217,7 +215,7 @@ public class JetControlFlowProcessor { @NotNull JetElement to, @NotNull List from, @NotNull MagicKind kind ) { List values = elementsToValues(from); - return builder.magic(to, to, values, defaultTypeMap(values), kind).getOutputValue(); + return builder.magic(to, to, values, kind).getOutputValue(); } @NotNull @@ -225,114 +223,6 @@ public class JetControlFlowProcessor { return createNonSyntheticValue(to, Arrays.asList(from), kind); } - @Nullable - private Map getTypeMapForUnresolvedCall(@NotNull JetElement to, List arguments) { - Call call = CallUtilPackage.getCall(to, trace.getBindingContext()); - if (call == null) return null; - - JetExpression callee = call.getCalleeExpression(); - if (callee == null) return null; - - Collection candidates = KotlinPackage.sortBy( - KotlinPackage.filterIsInstance( - BindingContextUtilPackage.getReferenceTargets(callee, trace.getBindingContext()), - FunctionDescriptor.class - ), - new Function1() { - @Override - public Comparable invoke(FunctionDescriptor descriptor) { - return DescriptorRenderer.DEBUG_TEXT.render(descriptor); - } - } - ); - if (candidates.isEmpty()) return null; - - ReceiverValue explicitReceiver = call.getExplicitReceiver(); - int argValueOffset = explicitReceiver.exists() ? 1 : 0; - - MultiMap valuesToPredicates = new MultiMap(arguments.size(), 1); - - candidateLoop: - for (FunctionDescriptor candidate : candidates) { - ResolvedCallImpl candidateCall = ResolvedCallImpl.create( - ResolutionCandidate.create(call, - candidate, - call.getDispatchReceiver(), - explicitReceiver, - ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, - null), - new DelegatingBindingTrace(trace.getBindingContext(), "Compute type predicates for unresolved call arguments"), - TracingStrategy.EMPTY, - new DataFlowInfoForArgumentsImpl(call) - ); - ValueArgumentsToParametersMapper.Status status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters( - call, - TracingStrategy.EMPTY, - candidateCall, - Sets.newLinkedHashSet() - ); - if (!status.isSuccess()) continue; - - if ((candidate.getExtensionReceiverParameter() == null) == candidateCall.getExtensionReceiver().exists()) continue; - - Map candidateArgumentMap = candidateCall.getValueArguments(); - List callArguments = call.getValueArguments(); - for (int i = 0; i < callArguments.size(); i++) { - int valueIndex = i + argValueOffset; - if (valueIndex >= arguments.size()) continue candidateLoop; - PseudoValue argumentValue = arguments.get(valueIndex); - - ArgumentMapping mapping = candidateCall.getArgumentMapping(callArguments.get(i)); - if (!(mapping instanceof ArgumentMatch)) continue candidateLoop; - - ValueParameterDescriptor candidateParameter = ((ArgumentMatch) mapping).getValueParameter(); - ResolvedValueArgument resolvedArgument = candidateArgumentMap.get(candidateParameter); - JetType expectedType = resolvedArgument instanceof VarargValueArgument - ? candidateParameter.getVarargElementType() - : candidateParameter.getType(); - - valuesToPredicates.putValue(argumentValue, expectedType != null ? new AllSubtypes(expectedType) : AllTypes.INSTANCE$); - } - } - - SmartFMap result = SmartFMap.emptyMap(); - for (Map.Entry> entry : valuesToPredicates.entrySet()) { - result = result.plus(entry.getKey(), PseudocodePackage.or(entry.getValue())); - } - - return result; - } - - @NotNull - private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, @Nullable JetElement valueElement, List arguments) { - Map typeMap = getTypeMapForUnresolvedCall(to, arguments); - if (typeMap == null) { - typeMap = defaultTypeMap(arguments); - } - - return builder.magic(to, valueElement, arguments, typeMap, MagicKind.UNRESOLVED_CALL).getOutputValue(); - } - - @NotNull - private PseudoValue createUnresolvedCallByValues(@NotNull JetElement to, List arguments) { - return createUnresolvedCallByValues(to, to, arguments); - } - - @NotNull - private PseudoValue createUnresolvedCall(@NotNull JetElement to, List from) { - return createUnresolvedCallByValues(to, elementsToValues(from)); - } - - @NotNull - private PseudoValue createUnresolvedCall(@NotNull JetElement to, JetElement... from) { - return createUnresolvedCall(to, Arrays.asList(from)); - } - - @NotNull - private Map defaultTypeMap(List values) { - return PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, values); - } - private void mergeValues(@NotNull List from, @NotNull JetExpression to) { builder.merge(to, elementsToValues(from)); } @@ -414,7 +304,7 @@ public class JetControlFlowProcessor { public void visitThisExpression(@NotNull JetThisExpression expression) { ResolvedCall resolvedCall = getResolvedCall(expression, trace.getBindingContext()); if (resolvedCall == null) { - createUnresolvedCall(expression); + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL); return; } @@ -440,7 +330,7 @@ public class JetControlFlowProcessor { generateCall(variableAsFunctionResolvedCall.getVariableCall()); } else if (!generateCall(expression) && !(expression.getParent() instanceof JetCallExpression)) { - createUnresolvedCall(expression, generateAndGetReceiverIfAny(expression)); + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, generateAndGetReceiverIfAny(expression)); } } @@ -553,7 +443,7 @@ public class JetControlFlowProcessor { generateInstructions(right); } mark(expression); - createUnresolvedCall(expression, left, right); + createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, left, right); } private void visitAssignment( @@ -564,7 +454,7 @@ public class JetControlFlowProcessor { JetExpression left = JetPsiUtil.deparenthesize(lhs); if (left == null) { List arguments = Collections.singletonList(rhsDeferredValue.invoke()); - builder.magic(parentExpression, parentExpression, arguments, defaultTypeMap(arguments), MagicKind.UNSUPPORTED_ELEMENT); + builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNSUPPORTED_ELEMENT); return; } @@ -609,7 +499,7 @@ public class JetControlFlowProcessor { List arguments = KotlinPackage.filterNotNull( Arrays.asList(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke()) ); - createUnresolvedCallByValues(parentExpression, arguments); + builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL); return; } @@ -680,7 +570,7 @@ public class JetControlFlowProcessor { } private void generateArrayAccessWithoutCall(JetArrayAccessExpression arrayAccessExpression) { - createUnresolvedCall(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression)); + createNonSyntheticValue(arrayAccessExpression, generateArrayAccessArguments(arrayAccessExpression), MagicKind.UNRESOLVED_CALL); } private List generateArrayAccessArguments(JetArrayAccessExpression arrayAccessExpression) { @@ -719,7 +609,7 @@ public class JetControlFlowProcessor { } else { generateInstructions(baseExpression); - rhsValue = createUnresolvedCall(expression, baseExpression); + rhsValue = createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression); } if (incrementOrDecrement) { @@ -917,10 +807,7 @@ public class JetControlFlowProcessor { } else { assert condition != null : "Invalid while condition: " + expression.getText(); - List values = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(condition)); - Map typePredicates = - PseudocodePackage.expectedTypeFor(new SingleType(KotlinBuiltIns.getInstance().getBooleanType()), values); - builder.magic(condition, null, values, typePredicates, MagicKind.VALUE_CONSUMER); + createSyntheticValue(condition, MagicKind.VALUE_CONSUMER, condition); } builder.enterLoopBody(expression); @@ -1006,17 +893,10 @@ public class JetControlFlowProcessor { JetMultiDeclaration multiDeclaration = expression.getMultiParameter(); JetExpression loopRange = expression.getLoopRange(); - TypePredicate loopRangeTypePredicate = - getTypePredicateByReceiverValue(trace.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange)); - - PseudoValue loopRangeValue = builder.getBoundValue(loopRange); PseudoValue value = builder.magic( loopRange != null ? loopRange : expression, null, - ContainerUtil.createMaybeSingletonList(loopRangeValue), - loopRangeValue != null - ? Collections.singletonMap(loopRangeValue, loopRangeTypePredicate) - : Collections.emptyMap(), + ContainerUtil.createMaybeSingletonList(builder.getBoundValue(loopRange)), MagicKind.LOOP_RANGE_ITERATION ).getOutputValue(); @@ -1030,17 +910,6 @@ public class JetControlFlowProcessor { } } - private ReceiverValue getExplicitReceiverValue(ResolvedCall resolvedCall) { - switch(resolvedCall.getExplicitReceiverKind()) { - case DISPATCH_RECEIVER: - return resolvedCall.getDispatchReceiver(); - case EXTENSION_RECEIVER: - return resolvedCall.getExtensionReceiver(); - default: - return ReceiverValue.NO_RECEIVER; - } - } - @Override public void visitBreakExpression(@NotNull JetBreakExpression expression) { JetElement loop = getCorrespondingLoop(expression); @@ -1250,7 +1119,7 @@ public class JetControlFlowProcessor { inputExpressions.add(generateAndGetReceiverIfAny(expression)); mark(expression); - createUnresolvedCall(expression, inputExpressions); + createNonSyntheticValue(expression, inputExpressions, MagicKind.UNRESOLVED_CALL); } } @@ -1292,33 +1161,9 @@ public class JetControlFlowProcessor { DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, property); if (!(descriptor instanceof PropertyDescriptor)) return; - PseudoValue delegateValue = builder.getBoundValue(delegate); - if (delegateValue == null) return; + if (builder.getBoundValue(delegate) == null) return; - List typePredicates = KotlinPackage.map( - ((PropertyDescriptor) descriptor).getAccessors(), - new Function1() { - @Override - public TypePredicate invoke(PropertyAccessorDescriptor descriptor) { - return getTypePredicateByReceiverValue(trace.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, descriptor)); - } - } - ); - Map valuesToTypePredicates = SmartFMap - .emptyMap() - .plus(delegateValue, PseudocodePackage.and(KotlinPackage.filterNotNull(typePredicates))); - builder.magic(property, null, Collections.singletonList(delegateValue), valuesToTypePredicates, MagicKind.VALUE_CONSUMER); - } - - private TypePredicate getTypePredicateByReceiverValue(@Nullable ResolvedCall resolvedCall) { - if (resolvedCall == null) return AllTypes.INSTANCE$; - - ReceiverValue receiverValue = getExplicitReceiverValue(resolvedCall); - if (receiverValue.exists()) { - return PseudocodePackage.getReceiverTypePredicate(resolvedCall, receiverValue); - } - - return AllTypes.INSTANCE$; + createSyntheticValue(property, MagicKind.VALUE_CONSUMER, delegate); } @Override @@ -1344,8 +1189,7 @@ public class JetControlFlowProcessor { ).getOutputValue(); } else { - List arguments = ContainerUtil.createMaybeSingletonList(getBoundOrUnreachableValue(initializer)); - writtenValue = createUnresolvedCallByValues(entry, null, arguments); + writtenValue = createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, initializer); } if (generateWriteForEntries) { @@ -1591,19 +1435,15 @@ public class JetControlFlowProcessor { for (JetExpression argument : arguments) { generateInstructions(argument); } - createUnresolvedCall(call, arguments); + createNonSyntheticValue(call, arguments, MagicKind.UNRESOLVED_CALL); } } @Override public void visitDelegationByExpressionSpecifier(@NotNull JetDelegatorByExpressionSpecifier specifier) { - generateInstructions(specifier.getDelegateExpression()); - - List arguments = ContainerUtil.createMaybeSingletonList(builder.getBoundValue(specifier.getDelegateExpression())); - JetType jetType = trace.get(BindingContext.TYPE, specifier.getTypeReference()); - TypePredicate expectedTypePredicate = jetType != null ? PseudocodePackage.getSubtypesPredicate(jetType) : AllTypes.INSTANCE$; - builder.magic(specifier, null, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments), - MagicKind.VALUE_CONSUMER); + JetExpression delegateExpression = specifier.getDelegateExpression(); + generateInstructions(delegateExpression); + createSyntheticValue(specifier, MagicKind.VALUE_CONSUMER, delegateExpression); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 3e54da8759d..c4c87faaa32 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -432,9 +432,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull @Override public InstructionWithValue loadStringTemplate(@NotNull JetStringTemplateExpression expression, @NotNull List inputValues) { - if (inputValues.isEmpty()) return read(expression); - Map predicate = PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, inputValues); - return magic(expression, expression, inputValues, predicate, MagicKind.STRING_TEMPLATE); + return inputValues.isEmpty() ? read(expression) : magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE); } @NotNull @@ -443,11 +441,10 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull JetElement instructionElement, @Nullable JetElement valueElement, @NotNull List inputValues, - @NotNull Map expectedTypes, @NotNull MagicKind kind ) { MagicInstruction instruction = new MagicInstruction( - instructionElement, valueElement, getCurrentScope(), inputValues, expectedTypes, kind, valueFactory + instructionElement, valueElement, getCurrentScope(), inputValues, kind, valueFactory ); add(instruction); return instruction; @@ -499,21 +496,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @NotNull PredefinedOperation operation, @NotNull List inputValues ) { - Map expectedTypes; - switch(operation) { - case AND: - case OR: - SingleType onlyBoolean = new SingleType(KotlinBuiltIns.getInstance().getBooleanType()); - expectedTypes = PseudocodePackage.expectedTypeFor(onlyBoolean, inputValues); - break; - case NOT_NULL_ASSERTION: - expectedTypes = PseudocodePackage.expectedTypeFor(AllTypes.INSTANCE$, inputValues); - break; - default: - throw new IllegalArgumentException("Invalid operation: " + operation); - } - - return magic(expression, expression, inputValues, expectedTypes, getMagicKind(operation)); + return magic(expression, expression, inputValues, getMagicKind(operation)); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/instructions/eval/operationInstructions.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/instructions/eval/operationInstructions.kt index 4547fc2d7aa..2daa3ef0394 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/instructions/eval/operationInstructions.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/instructions/eval/operationInstructions.kt @@ -95,7 +95,6 @@ public class MagicInstruction( element: JetElement, lexicalScope: LexicalScope, inputValues: List, - val expectedTypes: Map, val kind: MagicKind ) : OperationInstruction(element, lexicalScope, inputValues) { public constructor ( @@ -103,10 +102,9 @@ public class MagicInstruction( valueElement: JetElement?, lexicalScope: LexicalScope, inputValues: List, - expectedTypes: Map, kind: MagicKind, factory: PseudoValueFactory - ): this(element, lexicalScope, inputValues, expectedTypes, kind) { + ): this(element, lexicalScope, inputValues, kind) { setResult(factory, valueElement) } @@ -120,7 +118,7 @@ public class MagicInstruction( override fun accept(visitor: InstructionVisitorWithResult): R = visitor.visitMagic(this) override fun createCopy() = - MagicInstruction(element, lexicalScope, inputValues, expectedTypes, kind).setResult(resultValue) + MagicInstruction(element, lexicalScope, inputValues, kind).setResult(resultValue) override fun toString() = renderInstruction("magic[$kind]", render(element)) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtil.kt index b40fbd43d58..2649798f09f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/pseudocodeUtil.kt @@ -16,8 +16,12 @@ package org.jetbrains.kotlin.cfg.pseudocode +import com.google.common.collect.Sets import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.SmartFMap +import com.intellij.util.containers.MultiMap import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ConditionalJumpInstruction @@ -26,23 +30,28 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ThrowExceptionInst import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext -import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.BindingContext.* +import org.jetbrains.kotlin.resolve.DelegatingBindingTrace import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument +import org.jetbrains.kotlin.resolve.calls.ValueArgumentsToParametersMapper +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind +import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate +import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils -import java.util.ArrayList -import java.util.LinkedHashSet +import java.util.* fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? { - val callableDescriptor = resolvedCall.getResultingDescriptor() - if (callableDescriptor == null) return null + val callableDescriptor = resolvedCall.getResultingDescriptor() ?: return null when (receiverValue) { resolvedCall.getExtensionReceiver() -> { @@ -61,13 +70,75 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei } public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingContext): TypePredicate { - val pseudocode = value.createdAt?.owner - if (pseudocode == null) return AllTypes + val pseudocode = value.createdAt?.owner ?: return AllTypes + val builtIns = KotlinBuiltIns.getInstance() val typePredicates = LinkedHashSet() fun addSubtypesOf(jetType: JetType?) = typePredicates.add(jetType?.getSubtypesPredicate()) + fun addByExplicitReceiver(resolvedCall: ResolvedCall<*>?) { + val receiverValue = (resolvedCall ?: return).getExplicitReceiverValue() + if (receiverValue.exists()) typePredicates.add(getReceiverTypePredicate(resolvedCall, receiverValue)) + } + + fun getTypePredicateForUnresolvedCallArgument(to: JetElement, inputValueIndex: Int): TypePredicate? { + if (inputValueIndex < 0) return null + val call = to.getCall(bindingContext) ?: return null + val callee = call.getCalleeExpression() ?: return null + + val candidates = callee.getReferenceTargets(bindingContext) + .filterIsInstance() + .sortBy { DescriptorRenderer.DEBUG_TEXT.render(it) } + if (candidates.isEmpty()) return null + + val explicitReceiver = call.getExplicitReceiver() + val argValueOffset = if (explicitReceiver.exists()) 1 else 0 + + val predicates = ArrayList() + + for (candidate in candidates) { + val resolutionCandidate = ResolutionCandidate.create( + call, + candidate, + call.getDispatchReceiver(), + explicitReceiver, + ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, + null + ) + val candidateCall = ResolvedCallImpl.create( + resolutionCandidate, + DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"), + TracingStrategy.EMPTY, + DataFlowInfoForArgumentsImpl(call) + ) + val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call, + TracingStrategy.EMPTY, + candidateCall, + LinkedHashSet()) + if (!status.isSuccess()) continue + + val candidateArgumentMap = candidateCall.getValueArguments() + val callArguments = call.getValueArguments() + val i = inputValueIndex - argValueOffset + if (i < 0 || i >= callArguments.size()) continue + + val mapping = candidateCall.getArgumentMapping(callArguments.get(i)) + if (mapping !is ArgumentMatch) continue + + val candidateParameter = mapping.valueParameter + val resolvedArgument = candidateArgumentMap.get(candidateParameter) + val expectedType = if (resolvedArgument is VarargValueArgument) + candidateParameter.getVarargElementType() + else + candidateParameter.getType() + + predicates.add(if (expectedType != null) AllSubtypes(expectedType) else AllTypes) + } + + return or(predicates) + } + fun addTypePredicates(value: PseudoValue) { pseudocode.getUsages(value).forEach { when (it) { @@ -75,16 +146,16 @@ public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingC val returnElement = it.element val functionDescriptor = when(returnElement) { is JetReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext) - else -> bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()] + else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.getCorrespondingElement()] } addSubtypesOf((functionDescriptor as? CallableDescriptor)?.getReturnType()) } is ConditionalJumpInstruction -> - addSubtypesOf(KotlinBuiltIns.getInstance().getBooleanType()) + addSubtypesOf(builtIns.getBooleanType()) is ThrowExceptionInstruction -> - addSubtypesOf(KotlinBuiltIns.getInstance().getThrowable().getDefaultType()) + addSubtypesOf(builtIns.getThrowable().getDefaultType()) is MergeInstruction -> addTypePredicates(it.outputValue) @@ -126,8 +197,36 @@ public fun getExpectedTypePredicate(value: PseudoValue, bindingContext: BindingC } } - is MagicInstruction -> - typePredicates.add(it.expectedTypes[value]) + is MagicInstruction -> @suppress("NON_EXHAUSTIVE_WHEN") when (it.kind) { + AND, OR -> + addSubtypesOf(builtIns.getBooleanType()) + + LOOP_RANGE_ITERATION -> + addByExplicitReceiver(bindingContext[LOOP_RANGE_ITERATOR_RESOLVED_CALL, value.element as? JetExpression]) + + VALUE_CONSUMER -> { + val element = it.element + when { + element.getStrictParentOfType()?.getCondition() == element -> + addSubtypesOf(builtIns.getBooleanType()) + + element is JetProperty -> { + val propertyDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor + propertyDescriptor?.getAccessors()?.map { + addByExplicitReceiver(bindingContext[DELEGATED_PROPERTY_RESOLVED_CALL, it]) + } + } + + element is JetDelegatorByExpressionSpecifier -> + addSubtypesOf(bindingContext[TYPE, element.getTypeReference()]) + } + } + + UNRESOLVED_CALL -> { + val typePredicate = getTypePredicateForUnresolvedCallArgument(it.element, it.inputValues.indexOf(value)) + typePredicates.add(typePredicate) + } + } } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt index da03a928a6b..44bca5ea909 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt @@ -26,8 +26,10 @@ import org.jetbrains.kotlin.psi.JetThisExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver // it returns true if call has no dispatch receiver (e.g. resulting descriptor is top-level function or local variable) @@ -66,3 +68,10 @@ private fun ResolvedCall<*>.hasThisOrNoDispatchReceiver( return dispatchReceiverDescriptor == getResultingDescriptor().getOwnerForEffectiveDispatchReceiverParameter() } +public fun ResolvedCall<*>.getExplicitReceiverValue(): ReceiverValue { + return when (getExplicitReceiverKind()) { + ExplicitReceiverKind.DISPATCH_RECEIVER -> getDispatchReceiver() + ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> getExtensionReceiver() + else -> ReceiverValue.NO_RECEIVER + } +} \ No newline at end of file