some draft for inline functions (to return to it after M1)

This commit is contained in:
svtk
2011-10-28 13:32:45 +04:00
parent 1de766ff0d
commit 7f2e309ed7
4 changed files with 102 additions and 164 deletions
@@ -5,10 +5,12 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
@@ -590,6 +592,17 @@ public class JetControlFlowProcessor {
@Override
public void visitCallExpression(JetCallExpression expression) {
//inline functions after M1
// ResolvedCall<? extends CallableDescriptor> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
// assert resolvedCall != null;
// CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
// PsiElement element = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, resultingDescriptor);
// if (element instanceof JetNamedFunction) {
// JetNamedFunction namedFunction = (JetNamedFunction) element;
// if (namedFunction.hasModifier(JetTokens.INLINE_KEYWORD)) {
// }
// }
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
value(typeArgument, false);
}
@@ -726,6 +739,9 @@ public class JetControlFlowProcessor {
@Override
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
// for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
// value(delegationSpecifier, inCondition);
// }
Queue<Label> declarationLabels = new LinkedList<Label>();
List<JetDeclaration> declarations = declaration.getDeclarations();
for (JetDeclaration localDeclaration : declarations) {
@@ -734,27 +750,19 @@ public class JetControlFlowProcessor {
builder.nondeterministicJump(Lists.newArrayList(declarationLabels));
for (JetDeclaration localDeclaration : declarations) {
if (localDeclaration instanceof JetNamedDeclaration) {
if (localDeclaration instanceof JetFunction) {
//TODO
generate(localDeclaration, ((JetFunction) localDeclaration).getBodyExpression());
if (localDeclaration instanceof JetDeclarationWithBody) {
JetExpression bodyExpression = ((JetDeclarationWithBody) localDeclaration).getBodyExpression();
generate(localDeclaration, bodyExpression != null ? bodyExpression : localDeclaration);
}
else {
generate(localDeclaration, localDeclaration);
}
}
}
else {
//todo
generate(declaration, localDeclaration);
}
builder.bindLabel(declarationLabels.remove());
}
// for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
// value(delegationSpecifier, inCondition);
// }
// for (JetDeclaration jetDeclaration : declaration.getDeclarations()) {
// //FOR_LOCAL_CLASSES.
// value(jetDeclaration, false);
// }
}
@Override
@@ -8,10 +8,13 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.LocalVariableDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors;
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.types.JetStandardClasses;
import java.util.*;
@@ -256,103 +259,25 @@ public class JetFlowInformationProvider {
// }
// }
private <D> Map<Instruction, D> traverseInstructionGraphUntilFactsStabilization(
Pseudocode pseudocode,
InstructionsMergeHandler<D> instructionsMergeHandler,
D initialDataValue,
D initialDataValueForEnterInstruction,
boolean straightDirection) {
Map<Instruction, D> 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.<Instruction>emptyList(), straightDirection, dataMap, changed, false);
}
return dataMap;
}
private <D> void initializeDataMap(
Map<Instruction, D> dataMap,
Pseudocode pseudocode,
D initialDataValue) {
List<Instruction> instructions = pseudocode.getInstructions();
for (Instruction instruction : instructions) {
dataMap.put(instruction, initialDataValue);
if (instruction instanceof LocalDeclarationInstruction) {
initializeDataMap(dataMap, ((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
}
}
}
private <D> void traverseSubGraph(
Pseudocode pseudocode,
InstructionsMergeHandler<D> instructionsMergeHandler,
Collection<Instruction> previousSubGraphInstructions,
boolean straightDirection,
Map<Instruction, D> dataMap,
boolean[] changed,
boolean isLocal) {
List<Instruction> instructions = pseudocode.getInstructions();
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
for (Instruction instruction : instructions) {
if (!isLocal && instruction instanceof SubroutineEnterInstruction) continue;
Collection<Instruction> allPreviousInstructions;
Collection<Instruction> 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, true);
}
D previousDataValue = dataMap.get(instruction);
Collection<D> incomingEdgesData = Sets.newHashSet();
for (Instruction previousInstruction : allPreviousInstructions) {
incomingEdgesData.add(dataMap.get(previousInstruction));
}
D mergedData = instructionsMergeHandler.merge(instruction, incomingEdgesData);
if (!mergedData.equals(previousDataValue)) {
changed[0] = true;
dataMap.put(instruction, mergedData);
}
}
}
public void markUninitializedVariables(@NotNull JetElement subroutine) {
public void markUninitializedVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> initializedVariables) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
Collection<Instruction> instructions = pseudocode.getInstructions();
InstructionsMergeHandler<Map<LocalVariableDescriptor, InitializationPoints>> instructionsMergeHandler = new InstructionsMergeHandler<Map<LocalVariableDescriptor, InitializationPoints>>() {
JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>> instructionsMergeStrategy = new JetControlFlowGraphTraverser.InstructionsMergeStrategy<Map<VariableDescriptor, InitializationPoints>>() {
@Override
public Map<LocalVariableDescriptor, InitializationPoints> merge(
public Map<VariableDescriptor, InitializationPoints> execute(
Instruction instruction,
Collection<Map<LocalVariableDescriptor, InitializationPoints>> incomingEdgesData) {
Collection<Map<VariableDescriptor, InitializationPoints>> incomingEdgesData) {
Set<LocalVariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<LocalVariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
Set<VariableDescriptor> variablesInScope = Sets.newHashSet();
for (Map<VariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
variablesInScope.addAll(edgePointsMap.keySet());
}
Map<LocalVariableDescriptor, InitializationPoints> pointsMap = Maps.newHashMap();
for (LocalVariableDescriptor variable : variablesInScope) {
Map<VariableDescriptor, InitializationPoints> pointsMap = Maps.newHashMap();
for (VariableDescriptor variable : variablesInScope) {
Set<InitializationPoints> edgesDataForVariable = Sets.newHashSet();
for (Map<LocalVariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
for (Map<VariableDescriptor, InitializationPoints> edgePointsMap : incomingEdgesData) {
InitializationPoints points = edgePointsMap.get(variable);
if (points != null) {
edgesDataForVariable.add(points);
@@ -362,81 +287,95 @@ public class JetFlowInformationProvider {
}
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;
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement());
pointsMap.put(variableDescriptor, initializationAtThisPoint);
// }
}
return pointsMap;
}
};
Set<LocalVariableDescriptor> localVariables = collectAllLocalVariables(pseudocode);
Map<LocalVariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
InitializationPoints initialPoints = new InitializationPoints();
for (LocalVariableDescriptor variable : localVariables) {
initialMapForStartInstruction.put(variable, initialPoints);
Set<VariableDescriptor> localVariables = collectAllLocalVariables(pseudocode);
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = Maps.newHashMap();
InitializationPoints initialPointsForLocalVariable = new InitializationPoints(true);
for (VariableDescriptor variable : localVariables) {
initialMapForStartInstruction.put(variable, initialPointsForLocalVariable);
}
Map<Instruction, Map<LocalVariableDescriptor, InitializationPoints>> dataMap =
traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.<LocalVariableDescriptor, InitializationPoints>emptyMap(), initialMapForStartInstruction, true);
InitializationPoints initialPointsForParameter = new InitializationPoints(false);
for (VariableDescriptor initializedVariable : initializedVariables) {
initialMapForStartInstruction.put(initializedVariable, initialPointsForParameter);
}
final Map<Instruction, Map<VariableDescriptor, InitializationPoints>> dataMap =
JetControlFlowGraphTraverser.traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeStrategy, Collections.<VariableDescriptor, InitializationPoints>emptyMap(), initialMapForStartInstruction, true);
InstructionDataAnalyzer<Map<LocalVariableDescriptor, InitializationPoints>> instructionDataAnalyzer = new InstructionDataAnalyzer<Map<LocalVariableDescriptor, InitializationPoints>>() {
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
@Override
public void analyze(Instruction instruction, Map<Instruction, Map<LocalVariableDescriptor, InitializationPoints>> dataMap) {
Map<LocalVariableDescriptor, InitializationPoints> variablesData = dataMap.get(instruction);
public void execute(Instruction instruction) {
Map<VariableDescriptor, InitializationPoints> variablesData = dataMap.get(instruction);
if (instruction instanceof ReadValueInstruction) {
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) {
// DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
// if (descriptor instanceof LocalVariableDescriptor) {
if (element instanceof JetSimpleNameExpression && variableDescriptor 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();
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
VariableDescriptor 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));
}
// }
}
}
}
};
traverseAndAnalyzeInstructionGraph(instructions, dataMap, instructionDataAnalyzer);
});
}
public void markNotOnlyInvokedFunctionVariables(@NotNull JetElement subroutine, List<? extends VariableDescriptor> variables) {
final List<VariableDescriptor> functionVariables = Lists.newArrayList();
for (VariableDescriptor variable : variables) {
if (JetStandardClasses.isFunctionType(variable.getReturnType())) {
functionVariables.add(variable);
}
}
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
@Override
public void execute(Instruction instruction) {
if (instruction instanceof ReadValueInstruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (variableDescriptor != null && functionVariables.contains(variableDescriptor)) {
//check that we only invoke this variable
JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression && !(element.getParent() instanceof JetCallExpression)) {
trace.report(Errors.FUNCTION_PARAMETERS_OF_INLINE_FUNCTION.on((JetSimpleNameExpression)element, variableDescriptor));
}
}
}
}
});
}
@Nullable
private LocalVariableDescriptor extractVariableDescriptorIfAny(Instruction instruction) {
LocalVariableDescriptor variableDescriptor = null;
private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction) {
VariableDescriptor 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;
if (descriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) descriptor;
}
}
}
@@ -449,51 +388,34 @@ public class JetFlowInformationProvider {
else if (lValue instanceof JetSimpleNameExpression) {
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
}
if (descriptor instanceof LocalVariableDescriptor) {
variableDescriptor = (LocalVariableDescriptor) descriptor;
if (descriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) descriptor;
}
}
return variableDescriptor;
}
private Set<LocalVariableDescriptor> collectAllLocalVariables(Pseudocode pseudocode) {
final Set<LocalVariableDescriptor> localVariables = Sets.newHashSet();
InstructionDataAnalyzer<Void> analyzer = new InstructionDataAnalyzer<Void>() {
private Set<VariableDescriptor> collectAllLocalVariables(Pseudocode pseudocode) {
final Set<VariableDescriptor> localVariables = Sets.newHashSet();
JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy analyzeStrategy = new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy() {
@Override
public void analyze(Instruction instruction, Map<Instruction, Void> dataMap) {
LocalVariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
public void execute(Instruction instruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction);
if (variableDescriptor != null) {
localVariables.add(variableDescriptor);
}
}
};
traverseAndAnalyzeInstructionGraph(pseudocode.getInstructions(), Collections.<Instruction, Void>emptyMap(), analyzer);
JetControlFlowGraphTraverser.traverseAndAnalyzeInstructionGraph(pseudocode, analyzeStrategy);
return localVariables;
}
private <D> void traverseAndAnalyzeInstructionGraph(Collection<Instruction> instructions, Map<Instruction, D> dataMap, InstructionDataAnalyzer<D> instructionDataAnalyzer) {
for (Instruction instruction : instructions) {
if (instruction instanceof LocalDeclarationInstruction) {
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer);
}
instructionDataAnalyzer.analyze(instruction, dataMap);
}
}
interface InstructionsMergeHandler<D> {
D merge(Instruction instruction, Collection<D> incomingEdgesData);
}
interface InstructionDataAnalyzer<D> {
void analyze(Instruction instruction, Map<Instruction, D> dataMap);
}
private static class InitializationPoints {
private Set<JetElement> possiblePoints = Sets.newHashSet();
private boolean canBeUninitialized;
public InitializationPoints() {
canBeUninitialized = true;
public InitializationPoints(boolean canBeUninitialized) {
this.canBeUninitialized = canBeUninitialized;
}
public InitializationPoints(JetElement element) {
@@ -145,6 +145,8 @@ public interface Errors {
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME);
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Funciton parameters of inline funciton can only be invoked", NAME);
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class");
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.List;
import java.util.Map;
@@ -113,7 +114,12 @@ public class ControlFlowAnalyzer {
});
}
if (!declaredLocally) {
flowInformationProvider.markUninitializedVariables(function.asElement());
flowInformationProvider.markUninitializedVariables(function.asElement(), functionDescriptor.getValueParameters());
if (((JetDeclaration) function).hasModifier(JetTokens.INLINE_KEYWORD)) {
//inline functions after M1
// flowInformationProvider.markNotOnlyInvokedFunctionVariables(function.asElement(), functionDescriptor.getValueParameters());
}
}
}