Control-Flow Analysis: Compute STATEMENT slice using control-flow information
This commit is contained in:
@@ -1252,8 +1252,6 @@ public class JetControlFlowProcessor {
|
||||
generateInstructions(subjectExpression);
|
||||
}
|
||||
|
||||
boolean hasElse = false;
|
||||
|
||||
List<JetExpression> branches = new ArrayList<JetExpression>();
|
||||
|
||||
Label doneLabel = builder.createUnboundLabel();
|
||||
@@ -1265,7 +1263,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
boolean isElse = whenEntry.isElse();
|
||||
if (isElse) {
|
||||
hasElse = true;
|
||||
if (iterator.hasNext()) {
|
||||
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
||||
}
|
||||
@@ -1300,9 +1297,6 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
}
|
||||
builder.bindLabel(doneLabel);
|
||||
if (!hasElse && WhenChecker.mustHaveElse(expression, trace)) {
|
||||
trace.report(NO_ELSE_IN_WHEN.on(expression));
|
||||
}
|
||||
|
||||
mergeValues(branches, expression);
|
||||
}
|
||||
@@ -1407,6 +1401,11 @@ public class JetControlFlowProcessor {
|
||||
builder.magic(specifier, specifier, arguments, PseudocodePackage.expectedTypeFor(expectedTypePredicate, arguments), MagicKind.VALUE_CONSUMER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDelegationSpecifierList(@NotNull JetDelegationSpecifierList list) {
|
||||
list.acceptChildren(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetFile(@NotNull JetFile file) {
|
||||
for (JetDeclaration declaration : file.getDeclarations()) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableInitState;
|
||||
import org.jetbrains.jet.lang.cfg.PseudocodeVariablesData.VariableUseState;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudoValue;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeUtil;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.Instruction;
|
||||
@@ -121,6 +122,10 @@ public class JetFlowInformationProvider {
|
||||
markUnusedVariables();
|
||||
|
||||
markUnusedLiteralsInBlock();
|
||||
|
||||
markStatements();
|
||||
|
||||
markWhenWithoutElse();
|
||||
}
|
||||
|
||||
public void checkFunction(@Nullable JetType expectedReturnType) {
|
||||
@@ -697,6 +702,48 @@ public class JetFlowInformationProvider {
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
|
||||
public void markStatements() {
|
||||
PseudocodeTraverserPackage.traverse(
|
||||
pseudocode, FORWARD, new JetFlowInformationProvider.FunctionVoid1<Instruction>() {
|
||||
@Override
|
||||
public void execute(@NotNull Instruction instruction) {
|
||||
PseudoValue value = instruction instanceof InstructionWithValue
|
||||
? ((InstructionWithValue) instruction).getOutputValue()
|
||||
: null;
|
||||
Pseudocode pseudocode = instruction.getOwner();
|
||||
boolean isUsedAsExpression = !pseudocode.getUsages(value).isEmpty();
|
||||
for (JetElement element : pseudocode.getValueElements(value)) {
|
||||
trace.record(BindingContext.USED_AS_EXPRESSION, element, isUsedAsExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void markWhenWithoutElse() {
|
||||
PseudocodeTraverserPackage.traverse(
|
||||
pseudocode, FORWARD, new JetFlowInformationProvider.FunctionVoid1<Instruction>() {
|
||||
@Override
|
||||
public void execute(@NotNull Instruction instruction) {
|
||||
PseudoValue value = instruction instanceof InstructionWithValue
|
||||
? ((InstructionWithValue) instruction).getOutputValue()
|
||||
: null;
|
||||
for (JetElement element : instruction.getOwner().getValueElements(value)) {
|
||||
if (element instanceof JetWhenExpression) {
|
||||
JetWhenExpression whenExpression = (JetWhenExpression) element;
|
||||
if (whenExpression.getElseExpression() == null && WhenChecker.mustHaveElse(whenExpression, trace)) {
|
||||
trace.report(NO_ELSE_IN_WHEN.on(whenExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tail calls
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
@@ -37,7 +38,7 @@ public final class WhenChecker {
|
||||
JetType expectedType = trace.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expression);
|
||||
boolean isUnit = expectedType != null && KotlinBuiltIns.getInstance().isUnit(expectedType);
|
||||
// Some "statements" are actually expressions returned from lambdas, their expected types are non-null
|
||||
boolean isStatement = Boolean.TRUE.equals(trace.get(BindingContext.STATEMENT, expression)) && expectedType == null;
|
||||
boolean isStatement = BindingContextUtilPackage.isUsedAsStatement(expression, trace.getBindingContext()) && expectedType == null;
|
||||
|
||||
return !isUnit && !isStatement && !isWhenExhaustive(expression, trace);
|
||||
}
|
||||
|
||||
@@ -33,9 +33,6 @@ import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import org.jetbrains.jet.lang.types.JetType
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction
|
||||
|
||||
fun JetExpression.isStatement(pseudocode: Pseudocode): Boolean =
|
||||
pseudocode.getUsages(pseudocode.getElementValue(this)).isEmpty()
|
||||
|
||||
fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: ReceiverValue): TypePredicate? {
|
||||
val callableDescriptor = resolvedCall.getResultingDescriptor()
|
||||
if (callableDescriptor == null) return null
|
||||
|
||||
@@ -136,7 +136,7 @@ public interface BindingContext {
|
||||
* Has type of current expression has been already resolved
|
||||
*/
|
||||
WritableSlice<JetExpression, Boolean> PROCESSED = Slices.createSimpleSetSlice();
|
||||
WritableSlice<JetElement, Boolean> STATEMENT = Slices.createRemovableSetSlice();
|
||||
WritableSlice<JetElement, Boolean> USED_AS_EXPRESSION = Slices.createRemovableSetSlice();
|
||||
|
||||
WritableSlice<VariableDescriptor, CaptureKind> CAPTURED_IN_CLOSURE = new BasicWritableSlice<VariableDescriptor, CaptureKind>(DO_NOTHING);
|
||||
|
||||
|
||||
@@ -139,3 +139,6 @@ public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingConte
|
||||
.dropWhile { it is AnonymousFunctionDescriptor }
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
public fun JetExpression.isUsedAsExpression(context: BindingContext): Boolean = context[BindingContext.USED_AS_EXPRESSION, this]!!
|
||||
public fun JetExpression.isUsedAsStatement(context: BindingContext): Boolean = !isUsedAsExpression(context)
|
||||
|
||||
-3
@@ -49,7 +49,6 @@ import javax.inject.Inject;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.*;
|
||||
import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT;
|
||||
|
||||
@@ -253,7 +252,6 @@ public class ExpressionTypingServices {
|
||||
);
|
||||
JetTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
|
||||
|
||||
trace.record(STATEMENT, bodyExpression, false);
|
||||
JetType type = typeInfo.getType();
|
||||
if (type != null) {
|
||||
return type;
|
||||
@@ -283,7 +281,6 @@ public class ExpressionTypingServices {
|
||||
if (!(statement instanceof JetExpression)) {
|
||||
continue;
|
||||
}
|
||||
trace.record(STATEMENT, statement);
|
||||
JetExpression statementExpression = (JetExpression) statement;
|
||||
if (!iterator.hasNext()) {
|
||||
result = getTypeOfLastExpressionInBlock(
|
||||
|
||||
-4
@@ -71,10 +71,6 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
|
||||
public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
|
||||
if (isStatement) {
|
||||
contextWithExpectedType.trace.record(BindingContext.STATEMENT, expression);
|
||||
}
|
||||
|
||||
DataFlowUtils.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
|
||||
|
||||
ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT);
|
||||
|
||||
Reference in New Issue
Block a user