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 84d0b036d6b..80f8d5b1b0f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.cfg; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; @@ -22,7 +23,7 @@ public class JetFlowInformationProvider { private final Map pseudocodeMap; private BindingTrace trace; - public JetFlowInformationProvider(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) { + public JetFlowInformationProvider(@NotNull JetDeclaration declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) { this.trace = trace; final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); pseudocodeMap = new HashMap(); @@ -247,35 +248,64 @@ public class JetFlowInformationProvider { // } // } - private Map traverseInstructionGraphUntilFactsStabilization(Collection instructions, InstructionsMergeHandler instructionsMergeHandler, D initialDataValue, boolean straightDirection) { - + private Map traverseInstructionGraphUntilFactsStabilization(Pseudocode pseudocode, InstructionsMergeHandler instructionsMergeHandler, D initialDataValue, boolean straightDirection) { Map dataMap = Maps.newHashMap(); - for (Instruction instruction : instructions) { - dataMap.put(instruction, initialDataValue); - } + initializeDataMap(dataMap, pseudocode, initialDataValue); - boolean changed = true; - while (changed) { - changed = false; - for (Instruction instruction : instructions) { - D previousDataValue = dataMap.get(instruction); - - Collection previousInstructions = straightDirection - ? instruction.getPreviousInstructions() - : instruction.getNextInstructions(); - Collection incomingEdgesData = Sets.newHashSet(); - for (Instruction previousInstruction : previousInstructions) { - incomingEdgesData.add(dataMap.get(previousInstruction)); - } - D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData); - if (!mergedData.equals(previousDataValue)) { - changed = true; - dataMap.put(instruction, mergedData); - } - } + boolean[] changed = new boolean[1]; + changed[0] = true; + while (changed[0]) { + changed[0] = false; + traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.emptyList(), straightDirection, dataMap, changed); } return dataMap; } + + private void initializeDataMap(Map dataMap, Pseudocode pseudocode, D initialDataValue) { + List instructions = pseudocode.getInstructions(); + for (Instruction instruction : instructions) { + dataMap.put(instruction, initialDataValue); + if (instruction instanceof LocalDeclarationInstruction) { + initializeDataMap(dataMap, ((LocalDeclarationInstruction) instruction).getBody(), initialDataValue); + } + } + } + + private void traverseSubGraph(Pseudocode pseudocode, InstructionsMergeHandler instructionsMergeHandler, Collection previousSubGraphInstructions, boolean straightDirection, Map dataMap, boolean[] changed) { + List instructions = pseudocode.getInstructions(); + SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction(); + for (Instruction instruction : instructions) { + Collection allPreviousInstructions; + Collection previousInstructions = straightDirection + ? instruction.getPreviousInstructions() + : instruction.getNextInstructions(); + + if (instruction == enterInstruction && !previousSubGraphInstructions.isEmpty()) { + allPreviousInstructions = Lists.newArrayList(previousInstructions); + allPreviousInstructions.addAll(previousSubGraphInstructions); + } + else { + allPreviousInstructions = previousInstructions; + } + + if (instruction instanceof LocalDeclarationInstruction) { + Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody(); + traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed); + } + D previousDataValue = dataMap.get(instruction); + + Collection incomingEdgesData = Sets.newHashSet(); + + for (Instruction previousInstruction : allPreviousInstructions) { + incomingEdgesData.add(dataMap.get(previousInstruction)); + } + D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData); + if (!mergedData.equals(previousDataValue)) { + changed[0] = true; + dataMap.put(instruction, mergedData); + } + } + } public void markUninitializedVariables(@NotNull JetElement subroutine) { Pseudocode pseudocode = pseudocodeMap.get(subroutine); @@ -292,16 +322,16 @@ public class JetFlowInformationProvider { } if (instruction instanceof WriteValueInstruction) { - JetElement element = ((WriteValueInstruction) instruction).getElement(); DeclarationDescriptor descriptor = null; - if (element instanceof JetBinaryExpression) { - JetExpression left = ((JetBinaryExpression) element).getLeft(); - if (left instanceof JetSimpleNameExpression) { - descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) left); - } + JetElement lValue = ((WriteValueInstruction) instruction).getlValue(); + if (lValue instanceof JetProperty) { + descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue); } - else if (element instanceof JetProperty) { - descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + else if (lValue instanceof JetSimpleNameExpression) { + descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue); + } + else if (lValue instanceof JetParameter) { + descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue); } if (descriptor instanceof LocalVariableDescriptor) { initializedVariables.add((LocalVariableDescriptor) descriptor); @@ -310,36 +340,52 @@ public class JetFlowInformationProvider { return initializedVariables; } }; - Map> dataMap = traverseInstructionGraphUntilFactsStabilization(instructions, instructionsMergeHandler, Collections.emptySet(), true); + Map> dataMap = traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.emptySet(), true); + InstructionDataAnalyzer instructionDataAnalyzer = new InstructionDataAnalyzer>() { + @Override + public void analyze(Instruction instruction, Map> dataMap) { + Set initializedVariables = dataMap.get(instruction); + 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) { + if (!initializedVariables.contains(descriptor)) { + trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor)); + } + } + } + } + else if (instruction instanceof WriteValueInstruction) { + JetElement element = ((WriteValueInstruction) instruction).getElement(); + 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)); + } + } + } + } + } + }; + traverseInstructionGraphAndReportErrors(instructions, dataMap, instructionDataAnalyzer); + } + private void traverseInstructionGraphAndReportErrors(Collection instructions, Map> dataMap, InstructionDataAnalyzer> instructionDataAnalyzer) { for (Instruction instruction : instructions) { - Set initializedVariables = dataMap.get(instruction); - 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) { - if (!initializedVariables.contains(descriptor)) { - trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor)); - } - } - } - } - else if (instruction instanceof WriteValueInstruction) { - JetElement element = ((WriteValueInstruction) instruction).getElement(); - 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)); - } - } - } + if (instruction instanceof LocalDeclarationInstruction) { + traverseInstructionGraphAndReportErrors(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer); } + instructionDataAnalyzer.analyze(instruction, dataMap); } } interface InstructionsMergeHandler { D merge(Instruction instruction, D previousDataValue, Collection incomingEdgesData); } + + interface InstructionDataAnalyzer { + void analyze(Instruction instruction, Map dataMap); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/WriteValueInstruction.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/WriteValueInstruction.java index 4ad4e5ef7b6..862d478b6bf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/WriteValueInstruction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/WriteValueInstruction.java @@ -16,6 +16,11 @@ public class WriteValueInstruction extends InstructionWithNext { this.lValue = lValue; } + @NotNull + public JetElement getlValue() { + return lValue; + } + @Override public void accept(InstructionVisitor visitor) { visitor.visitWriteValue(this); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 861e2cd92a2..4d01f8cbeea 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -142,7 +142,7 @@ public interface Errors { }; PsiElementOnlyDiagnosticFactory3 VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT); - PsiElementOnlyDiagnosticFactory1 UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME); + PsiElementOnlyDiagnosticFactory1 UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be uninitialized", NAME); PsiElementOnlyDiagnosticFactory1 VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME); SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code"); diff --git a/idea/testData/checker/infos/Autocasts.jet b/idea/testData/checker/infos/Autocasts.jet index 062b26b75a2..6749da3c345 100644 --- a/idea/testData/checker/infos/Autocasts.jet +++ b/idea/testData/checker/infos/Autocasts.jet @@ -6,8 +6,7 @@ class B() : A() { fun bar() {} } -fun f9() { - val a : A? +fun f9(a : A?) { a?.foo() a?.bar() if (a is B) { @@ -30,8 +29,7 @@ fun f9() { a.foo() } -fun f10() { - val a : A? +fun f10(a : A?) { if (!(a is B)) { return; } diff --git a/idea/testData/checker/regression/OverrideResolution.jet b/idea/testData/checker/regression/OverrideResolution.jet index b58ac616160..16ae0bf07b1 100644 --- a/idea/testData/checker/regression/OverrideResolution.jet +++ b/idea/testData/checker/regression/OverrideResolution.jet @@ -1,16 +1,16 @@ fun box() { - val a : C + val a : C = C() a.foo() } -open class A { +open class A() { open fun foo() {} } -open class B : A { +open class B() : A() { override fun foo() {} } -open class C : B { +open class C() : B() { override fun foo() {} }