diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 88dd8b70018..5880ad7fc20 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -183,17 +183,17 @@ public class JetFlowInformationProvider { // } // } - private boolean collectReachable(Instruction current, Set visited, @Nullable Instruction lookFor) { - if (!visited.add(current)) return false; - if (current == lookFor) return true; - - for (Instruction nextInstruction : current.getNextInstructions()) { - if (collectReachable(nextInstruction, visited, lookFor)) { - return true; - } - } - return false; - } +// private boolean collectReachable(Instruction current, Set visited, @Nullable Instruction lookFor) { +// if (!visited.add(current)) return false; +// if (current == lookFor) return true; +// +// for (Instruction nextInstruction : current.getNextInstructions()) { +// if (collectReachable(nextInstruction, visited, lookFor)) { +// return true; +// } +// } +// return false; +// } // private void processPreviousInstructions(Instruction previousFor, final Set visited, final Collection returnedExpressions, final Collection elementsReturningUnit) { // if (!visited.add(previousFor)) return; @@ -259,16 +259,18 @@ public class JetFlowInformationProvider { private Map traverseInstructionGraphUntilFactsStabilization( Pseudocode pseudocode, InstructionsMergeHandler instructionsMergeHandler, - D initialDataValue, + D initialDataValue, + D initialDataValueForEnterInstruction, boolean straightDirection) { Map dataMap = Maps.newHashMap(); initializeDataMap(dataMap, pseudocode, initialDataValue); + dataMap.put(pseudocode.getEnterInstruction(), initialDataValueForEnterInstruction); boolean[] changed = new boolean[1]; changed[0] = true; while (changed[0]) { changed[0] = false; - traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.emptyList(), straightDirection, dataMap, changed); + traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.emptyList(), straightDirection, dataMap, changed, false); } return dataMap; } @@ -287,15 +289,18 @@ public class JetFlowInformationProvider { } private void traverseSubGraph( - Pseudocode pseudocode, - InstructionsMergeHandler instructionsMergeHandler, - Collection previousSubGraphInstructions, - boolean straightDirection, - Map dataMap, - boolean[] changed) { + Pseudocode pseudocode, + InstructionsMergeHandler instructionsMergeHandler, + Collection previousSubGraphInstructions, + boolean straightDirection, + Map dataMap, + boolean[] changed, + boolean isLocal) { List instructions = pseudocode.getInstructions(); SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); for (Instruction instruction : instructions) { + if (!isLocal && instruction instanceof SubroutineEnterInstruction) continue; + Collection allPreviousInstructions; Collection previousInstructions = straightDirection ? instruction.getPreviousInstructions() @@ -311,7 +316,7 @@ public class JetFlowInformationProvider { if (instruction instanceof LocalDeclarationInstruction) { Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); - traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed); + traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed, true); } D previousDataValue = dataMap.get(instruction); @@ -320,7 +325,7 @@ public class JetFlowInformationProvider { for (Instruction previousInstruction : allPreviousInstructions) { incomingEdgesData.add(dataMap.get(previousInstruction)); } - D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData); + D mergedData = instructionsMergeHandler.merge(instruction, incomingEdgesData); if (!mergedData.equals(previousDataValue)) { changed[0] = true; dataMap.put(instruction, mergedData); @@ -333,86 +338,203 @@ public class JetFlowInformationProvider { assert pseudocode != null; Collection instructions = pseudocode.getInstructions(); - InstructionsMergeHandler> instructionsMergeHandler = new InstructionsMergeHandler>() { + InstructionsMergeHandler> instructionsMergeHandler = new InstructionsMergeHandler>() { @Override - public Set merge(Instruction instruction, Set previousDataValue, Collection> incomingEdgesData) { - Set initializedVariables = Sets.newHashSet(); - initializedVariables.addAll(previousDataValue); - Set edgesDataIntersection = Sets.newHashSet(); - boolean isFirst = true; - for (Set edgeData : incomingEdgesData) { - if (isFirst) { - edgesDataIntersection.addAll(edgeData); - } - else { - edgesDataIntersection = Sets.intersection(edgesDataIntersection, edgeData).immutableCopy(); - } - isFirst = false; - } - initializedVariables.addAll(edgesDataIntersection); + public Map merge( + Instruction instruction, + Collection> incomingEdgesData) { - if (instruction instanceof WriteValueInstruction) { - DeclarationDescriptor descriptor = null; - JetElement lValue = ((WriteValueInstruction) instruction).getlValue(); - if (lValue instanceof JetProperty || lValue instanceof JetParameter) { - descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue); - } - else if (lValue instanceof JetSimpleNameExpression) { - descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue); - } - if (descriptor instanceof LocalVariableDescriptor) { - initializedVariables.add((LocalVariableDescriptor) descriptor); - } + Set variablesInScope = Sets.newHashSet(); + for (Map edgePointsMap : incomingEdgesData) { + variablesInScope.addAll(edgePointsMap.keySet()); } - return initializedVariables; + + Map pointsMap = Maps.newHashMap(); + for (LocalVariableDescriptor variable : variablesInScope) { + Set edgesDataForVariable = Sets.newHashSet(); + for (Map edgePointsMap : incomingEdgesData) { + InitializationPoints points = edgePointsMap.get(variable); + if (points != null) { + edgesDataForVariable.add(points); + } + } + pointsMap.put(variable, new InitializationPoints(edgesDataForVariable)); + } + + if (instruction instanceof WriteValueInstruction) { + LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); +// DeclarationDescriptor descriptor = null; +// JetElement lValue = ((WriteValueInstruction) instruction).getlValue(); +// if (lValue instanceof JetProperty || lValue instanceof JetParameter) { +// descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue); +// } +// else if (lValue instanceof JetSimpleNameExpression) { +// descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue); +// } +// if (descriptor instanceof LocalVariableDescriptor) { +// LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) descriptor; + InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement()); + pointsMap.put(variableDescriptor, initializationAtThisPoint); +// } + } + + return pointsMap; } }; - Map> dataMap = traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.emptySet(), true); - InstructionDataAnalyzer instructionDataAnalyzer = new InstructionDataAnalyzer>() { + + Set localVariables = collectAllLocalVariables(pseudocode); + Map initialMapForStartInstruction = Maps.newHashMap(); + InitializationPoints initialPoints = new InitializationPoints(); + for (LocalVariableDescriptor variable : localVariables) { + initialMapForStartInstruction.put(variable, initialPoints); + } + Map> dataMap = + traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.emptyMap(), initialMapForStartInstruction, true); + + InstructionDataAnalyzer> instructionDataAnalyzer = new InstructionDataAnalyzer>() { @Override - public void analyze(Instruction instruction, Map> dataMap) { - Set initializedVariables = dataMap.get(instruction); + public void analyze(Instruction instruction, Map> dataMap) { + Map variablesData = dataMap.get(instruction); if (instruction instanceof ReadValueInstruction) { + LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); JetElement element = ((ReadValueInstruction) instruction).getElement(); - if (element instanceof JetSimpleNameExpression) { - DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); - if (descriptor instanceof LocalVariableDescriptor) { - if (!initializedVariables.contains(descriptor)) { - trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor)); - } + if (element instanceof JetSimpleNameExpression && variableDescriptor != null) { +// DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); +// if (descriptor instanceof LocalVariableDescriptor) { + InitializationPoints initializationPoints = variablesData.get(variableDescriptor); + assert initializationPoints != null; + if (initializationPoints.canBeUninitialized) { + trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); } +// } } } else if (instruction instanceof WriteValueInstruction) { JetElement element = ((WriteValueInstruction) instruction).getlValue(); - if (element instanceof JetSimpleNameExpression) { - DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); - if (descriptor instanceof LocalVariableDescriptor) { - if (initializedVariables.contains(descriptor) && !((LocalVariableDescriptor) descriptor).isVar()) { - trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, descriptor)); - } + LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); + if (element instanceof JetSimpleNameExpression && variableDescriptor != null) { +// DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); +// if (descriptor instanceof LocalVariableDescriptor) { + InitializationPoints initializationPoints = variablesData.get(variableDescriptor); + assert initializationPoints != null; + if (initializationPoints.hasPossibleInitializers() && !variableDescriptor.isVar()) { + trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, variableDescriptor)); } +// } } } } }; - traverseInstructionGraphAndReportErrors(instructions, dataMap, instructionDataAnalyzer); + traverseAndAnalyzeInstructionGraph(instructions, dataMap, instructionDataAnalyzer); } - private void traverseInstructionGraphAndReportErrors(Collection instructions, Map> dataMap, InstructionDataAnalyzer> instructionDataAnalyzer) { + @Nullable + private LocalVariableDescriptor extractVariableDescriptorIfAny(Instruction instruction) { + LocalVariableDescriptor variableDescriptor = null; + if (instruction instanceof ReadValueInstruction) { + JetElement element = ((ReadValueInstruction) instruction).getElement(); + if (element instanceof JetSimpleNameExpression) { + DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element); + if (descriptor instanceof LocalVariableDescriptor) { + variableDescriptor = (LocalVariableDescriptor) descriptor; + } + } + } + else if (instruction instanceof WriteValueInstruction) { + DeclarationDescriptor descriptor = null; + JetElement lValue = ((WriteValueInstruction) instruction).getlValue(); + if (lValue instanceof JetProperty || lValue instanceof JetParameter) { + descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue); + } + else if (lValue instanceof JetSimpleNameExpression) { + descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue); + } + if (descriptor instanceof LocalVariableDescriptor) { + variableDescriptor = (LocalVariableDescriptor) descriptor; + } + } + return variableDescriptor; + } + + private Set collectAllLocalVariables(Pseudocode pseudocode) { + final Set localVariables = Sets.newHashSet(); + InstructionDataAnalyzer analyzer = new InstructionDataAnalyzer() { + @Override + public void analyze(Instruction instruction, Map dataMap) { + LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); + if (variableDescriptor != null) { + localVariables.add(variableDescriptor); + } + } + }; + traverseAndAnalyzeInstructionGraph(pseudocode.getInstructions(), Collections.emptyMap(), analyzer); + return localVariables; + } + + private void traverseAndAnalyzeInstructionGraph(Collection instructions, Map dataMap, InstructionDataAnalyzer instructionDataAnalyzer) { for (Instruction instruction : instructions) { if (instruction instanceof LocalDeclarationInstruction) { - traverseInstructionGraphAndReportErrors(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer); + traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer); } instructionDataAnalyzer.analyze(instruction, dataMap); } } interface InstructionsMergeHandler { - D merge(Instruction instruction, D previousDataValue, Collection incomingEdgesData); + D merge(Instruction instruction, Collection incomingEdgesData); } interface InstructionDataAnalyzer { void analyze(Instruction instruction, Map dataMap); } -} + + private static class InitializationPoints { + private Set possiblePoints = Sets.newHashSet(); + private boolean canBeUninitialized; + + public InitializationPoints() { + canBeUninitialized = true; + } + + public InitializationPoints(JetElement element) { + canBeUninitialized = false; + possiblePoints.add(element); + } + + public InitializationPoints(Set edgesData) { + canBeUninitialized = false; + for (InitializationPoints edgeData : edgesData) { + if (edgeData.canBeUninitialized) { + canBeUninitialized = true; + } + possiblePoints.addAll(edgeData.possiblePoints); + } + } + + public boolean hasPossibleInitializers() { + return !possiblePoints.isEmpty(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof InitializationPoints)) return false; + + InitializationPoints that = (InitializationPoints) o; + + if (canBeUninitialized != that.canBeUninitialized) return false; + if (possiblePoints != null ? !possiblePoints.equals(that.possiblePoints) : that.possiblePoints != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = possiblePoints != null ? possiblePoints.hashCode() : 0; + result = 31 * result + (canBeUninitialized ? 1 : 0); + return result; + } + } +} \ No newline at end of file