Return values collected from CF data
This commit is contained in:
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang;
|
|||||||
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.JetScope;
|
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||||
import org.jetbrains.jet.lang.resolve.OverloadResolver;
|
import org.jetbrains.jet.lang.resolve.OverloadResolver;
|
||||||
@@ -44,8 +45,8 @@ public class JetSemanticServices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetTypeInferrer getTypeInferrer(BindingTrace trace) {
|
public JetTypeInferrer getTypeInferrer(BindingTrace trace, JetFlowInformationProvider flowInformationProvider) {
|
||||||
return new JetTypeInferrer(trace, this);
|
return new JetTypeInferrer(trace, flowInformationProvider, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public interface JetControlFlowBuilder {
|
|||||||
JetElement getCurrentSubroutine();
|
JetElement getCurrentSubroutine();
|
||||||
|
|
||||||
void returnValue(@NotNull JetElement subroutine);
|
void returnValue(@NotNull JetElement subroutine);
|
||||||
void returnNoValue(@NotNull JetElement subroutine);
|
void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine);
|
||||||
|
|
||||||
void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
void writeNode(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnNoValue(@NotNull JetElement subroutine) {
|
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
|
||||||
builder.returnNoValue(subroutine);
|
builder.returnNoValue(expression, subroutine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
if (subroutine != null) {
|
if (subroutine != null) {
|
||||||
if (returnedExpression == null) {
|
if (returnedExpression == null) {
|
||||||
builder.returnNoValue(subroutine);
|
builder.returnNoValue(expression, subroutine);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
builder.returnValue(subroutine);
|
builder.returnValue(subroutine);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.jetbrains.jet.lang.cfg;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public interface JetFlowInformationProvider {
|
||||||
|
JetFlowInformationProvider ERROR = new JetFlowInformationProvider() {
|
||||||
|
@Override
|
||||||
|
public void collectReturnedInformation(@NotNull JetFunction function, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void collectReturnedInformation(@NotNull JetFunction function, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit);
|
||||||
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class FunctionLiteralValueInstruction extends InstructionWithNext {
|
public class FunctionLiteralValueInstruction extends ReadValueInstruction {
|
||||||
|
|
||||||
private Pseudocode body;
|
private Pseudocode body;
|
||||||
|
|
||||||
public FunctionLiteralValueInstruction(@NotNull JetElement element) {
|
public FunctionLiteralValueInstruction(@NotNull JetFunctionLiteralExpression expression) {
|
||||||
super(element);
|
super(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pseudocode getBody() {
|
public Pseudocode getBody() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class InstructionVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||||
visitInstructionWithNext(instruction);
|
visitReadValue(instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ public interface JetControlFlowDataTraceFactory {
|
|||||||
JetControlFlowDataTraceFactory EMPTY = new JetControlFlowDataTraceFactory() {
|
JetControlFlowDataTraceFactory EMPTY = new JetControlFlowDataTraceFactory() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JetControlFlowDataTrace createTrace(JetElement element) {
|
public JetPseudocodeTrace createTrace(JetElement element) {
|
||||||
return JetControlFlowDataTrace.EMPTY;
|
return JetPseudocodeTrace.EMPTY;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
JetControlFlowDataTrace createTrace(JetElement element);
|
JetPseudocodeTrace createTrace(JetElement element);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.cfg.Label;
|
|||||||
import org.jetbrains.jet.lang.psi.JetBlockExpression;
|
import org.jetbrains.jet.lang.psi.JetBlockExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -21,9 +22,9 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
private int labelCount = 0;
|
private int labelCount = 0;
|
||||||
|
|
||||||
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
|
private final Stack<JetControlFlowInstructionsGeneratorWorker> builders = new Stack<JetControlFlowInstructionsGeneratorWorker>();
|
||||||
private final JetControlFlowDataTrace trace;
|
private final JetPseudocodeTrace trace;
|
||||||
|
|
||||||
public JetControlFlowInstructionsGenerator(JetControlFlowDataTrace trace) {
|
public JetControlFlowInstructionsGenerator(JetPseudocodeTrace trace) {
|
||||||
super(null);
|
super(null);
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
}
|
}
|
||||||
@@ -60,7 +61,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine);
|
JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine);
|
||||||
if (functionLiteral) {
|
if (functionLiteral) {
|
||||||
JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
|
JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
|
||||||
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine);
|
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction((JetFunctionLiteralExpression) subroutine);
|
||||||
instruction.setBody(worker.getPseudocode());
|
instruction.setBody(worker.getPseudocode());
|
||||||
builder.add(instruction);
|
builder.add(instruction);
|
||||||
}
|
}
|
||||||
@@ -155,8 +156,8 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void returnNoValue(@NotNull JetElement subroutine) {
|
public void returnNoValue(@NotNull JetElement expression, @NotNull JetElement subroutine) {
|
||||||
add(new ReturnNoValueInstruction(getExitPoint(subroutine)));
|
add(new ReturnNoValueInstruction(expression, getExitPoint(subroutine)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+2
-2
@@ -6,9 +6,9 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetControlFlowDataTrace {
|
public interface JetPseudocodeTrace {
|
||||||
|
|
||||||
JetControlFlowDataTrace EMPTY = new JetControlFlowDataTrace() {
|
JetPseudocodeTrace EMPTY = new JetPseudocodeTrace() {
|
||||||
@Override
|
@Override
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,8 @@ public class Pseudocode {
|
|||||||
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
private final List<PseudocodeLabel> labels = new ArrayList<PseudocodeLabel>();
|
||||||
|
|
||||||
private final JetElement correspondingElement;
|
private final JetElement correspondingElement;
|
||||||
|
private SubroutineExitInstruction exitInstruction;
|
||||||
|
private boolean postPrecessed = false;
|
||||||
|
|
||||||
public Pseudocode(JetElement correspondingElement) {
|
public Pseudocode(JetElement correspondingElement) {
|
||||||
this.correspondingElement = correspondingElement;
|
this.correspondingElement = correspondingElement;
|
||||||
@@ -69,6 +71,16 @@ public class Pseudocode {
|
|||||||
|
|
||||||
public void addInstruction(Instruction instruction) {
|
public void addInstruction(Instruction instruction) {
|
||||||
instructions.add(instruction);
|
instructions.add(instruction);
|
||||||
|
if (instruction instanceof SubroutineExitInstruction) {
|
||||||
|
SubroutineExitInstruction exitInstruction = (SubroutineExitInstruction) instruction;
|
||||||
|
assert this.exitInstruction == null;
|
||||||
|
this.exitInstruction = exitInstruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public SubroutineExitInstruction getExitInstruction() {
|
||||||
|
return exitInstruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindLabel(Label label) {
|
public void bindLabel(Label label) {
|
||||||
@@ -76,6 +88,8 @@ public class Pseudocode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void postProcess() {
|
public void postProcess() {
|
||||||
|
if (postPrecessed) return;
|
||||||
|
postPrecessed = true;
|
||||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||||
Instruction instruction = instructions.get(i);
|
Instruction instruction = instructions.get(i);
|
||||||
final int currentPosition = i;
|
final int currentPosition = i;
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.cfg.Label;
|
import org.jetbrains.jet.lang.cfg.Label;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class ReturnNoValueInstruction extends AbstractJumpInstruction {
|
public class ReturnNoValueInstruction extends AbstractJumpInstruction {
|
||||||
|
|
||||||
public ReturnNoValueInstruction(Label targetLabel) {
|
private final JetElement element;
|
||||||
|
|
||||||
|
public ReturnNoValueInstruction(@NotNull JetElement element, Label targetLabel) {
|
||||||
super(targetLabel);
|
super(targetLabel);
|
||||||
|
this.element = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JetElement getElement() {
|
||||||
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,11 +4,15 @@ import com.intellij.lang.ASTNode;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -305,7 +309,7 @@ public class ClassDescriptorResolver {
|
|||||||
type = ErrorUtils.createErrorType("No type, no body");
|
type = ErrorUtils.createErrorType("No type, no body");
|
||||||
} else {
|
} else {
|
||||||
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
|
||||||
type = semanticServices.getTypeInferrer(trace).getType(scope, initializer, false);
|
type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(scope, initializer, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = typeResolver.resolveType(scope, propertyTypeRef);
|
type = typeResolver.resolveType(scope, propertyTypeRef);
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace;
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
@@ -25,7 +23,6 @@ public class TopDownAnalyzer {
|
|||||||
private final JetSemanticServices semanticServices;
|
private final JetSemanticServices semanticServices;
|
||||||
private final ClassDescriptorResolver classDescriptorResolver;
|
private final ClassDescriptorResolver classDescriptorResolver;
|
||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
private final JetTypeInferrer typeInferrer;
|
|
||||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||||
private boolean readyToProcessExpressions = false;
|
private boolean readyToProcessExpressions = false;
|
||||||
|
|
||||||
@@ -33,7 +30,6 @@ public class TopDownAnalyzer {
|
|||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
||||||
this.trace = bindingTrace;
|
this.trace = bindingTrace;
|
||||||
this.typeInferrer = semanticServices.getTypeInferrer(trace);
|
|
||||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +37,6 @@ public class TopDownAnalyzer {
|
|||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
this.classDescriptorResolver = new ClassDescriptorResolver(semanticServices, bindingTrace);
|
||||||
this.trace = bindingTrace;
|
this.trace = bindingTrace;
|
||||||
this.typeInferrer = semanticServices.getTypeInferrer(trace);
|
|
||||||
this.flowDataTraceFactory = JetControlFlowDataTraceFactory.EMPTY;
|
this.flowDataTraceFactory = JetControlFlowDataTraceFactory.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +96,7 @@ public class TopDownAnalyzer {
|
|||||||
if (importDirective.isAllUnder()) {
|
if (importDirective.isAllUnder()) {
|
||||||
JetExpression importedReference = importDirective.getImportedReference();
|
JetExpression importedReference = importDirective.getImportedReference();
|
||||||
if (importedReference != null) {
|
if (importedReference != null) {
|
||||||
JetType type = typeInferrer.getType(namespaceScope, importedReference, false);
|
JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(namespaceScope, importedReference, false);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
namespaceScope.importScope(type.getMemberScope());
|
namespaceScope.importScope(type.getMemberScope());
|
||||||
}
|
}
|
||||||
@@ -263,71 +258,137 @@ public class TopDownAnalyzer {
|
|||||||
WritableScope declaringScope = declaringScopes.get(declaration);
|
WritableScope declaringScope = declaringScopes.get(declaration);
|
||||||
assert declaringScope != null;
|
assert declaringScope != null;
|
||||||
|
|
||||||
WritableScope parameterScope = semanticServices.createWritableScope(declaringScope, descriptor);
|
|
||||||
for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
|
|
||||||
parameterScope.addTypeParameterDescriptor(typeParameter);
|
|
||||||
}
|
|
||||||
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getUnsubstitutedValueParameters()) {
|
|
||||||
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
|
|
||||||
}
|
|
||||||
parameterScope.addLabeledDeclaration(descriptor);
|
|
||||||
|
|
||||||
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
|
assert declaration instanceof JetFunction || declaration instanceof JetConstructor;
|
||||||
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
|
JetDeclarationWithBody declarationWithBody = (JetDeclarationWithBody) declaration;
|
||||||
|
|
||||||
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
|
JetExpression bodyExpression = declarationWithBody.getBodyExpression();
|
||||||
|
|
||||||
if (bodyExpression != null) {
|
if (declaration instanceof JetFunction) {
|
||||||
JetControlFlowDataTrace controlFlowDataTrace = flowDataTraceFactory.createTrace(declaration);
|
JetFunction function = (JetFunction) declaration;
|
||||||
JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(controlFlowDataTrace);
|
FunctionDescriptorImpl functionDescriptorImpl = (FunctionDescriptorImpl) descriptor;
|
||||||
new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(declaration, bodyExpression);
|
if (bodyExpression != null) {
|
||||||
controlFlowDataTrace.close();
|
JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression);
|
||||||
|
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
|
||||||
|
|
||||||
boolean preferBlock = true;
|
assert readyToProcessExpressions : "Must be ready collecting types";
|
||||||
FunctionDescriptorImpl functionDescriptorImpl = null;
|
|
||||||
if (declaration instanceof JetFunction) {
|
|
||||||
JetFunction jetFunction = (JetFunction) declaration;
|
|
||||||
preferBlock = jetFunction.hasBlockBody();
|
|
||||||
functionDescriptorImpl = (FunctionDescriptorImpl) descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
JetType returnType = resolveExpression(parameterScope, bodyExpression, preferBlock, controlFlowDataTrace);
|
|
||||||
|
|
||||||
if (declaration instanceof JetFunction) {
|
|
||||||
JetFunction function = (JetFunction) declaration;
|
|
||||||
if (function.getReturnTypeRef() != null) {
|
if (function.getReturnTypeRef() != null) {
|
||||||
if (returnType != null) {
|
typeInferrer.checkFunctionReturnType(declaringScope, function, descriptor);
|
||||||
if (!semanticServices.getTypeChecker().isConvertibleTo(returnType, descriptor.getUnsubstitutedReturnType())) {
|
|
||||||
semanticServices.getErrorHandler().typeMismatch(bodyExpression, descriptor.getUnsubstitutedReturnType(), returnType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
JetType safeReturnType = returnType;
|
JetType returnType = typeInferrer.getFunctionReturnType(declaringScope, function, descriptor);
|
||||||
if (safeReturnType == null) {
|
if (returnType == null) {
|
||||||
safeReturnType = ErrorUtils.createErrorType("Unable to infer body type");
|
returnType = ErrorUtils.createErrorType("Unable to infer body type");
|
||||||
}
|
}
|
||||||
functionDescriptorImpl.setUnsubstitutedReturnType(safeReturnType);
|
functionDescriptorImpl.setUnsubstitutedReturnType(returnType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
else {
|
|
||||||
if (declaration instanceof JetFunction) {
|
|
||||||
JetFunction function = (JetFunction) declaration;
|
|
||||||
if (function.getReturnTypeRef() == null) {
|
if (function.getReturnTypeRef() == null) {
|
||||||
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element");
|
semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element");
|
||||||
((FunctionDescriptorImpl) descriptor).setUnsubstitutedReturnType(ErrorUtils.createErrorType("No type, no body"));
|
((FunctionDescriptorImpl) descriptor).setUnsubstitutedReturnType(ErrorUtils.createErrorType("No type, no body"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (declaration instanceof JetConstructor) {
|
||||||
|
if (bodyExpression != null) {
|
||||||
|
computeFlowData(declaration, bodyExpression);
|
||||||
|
JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression);
|
||||||
|
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
|
||||||
|
typeInferrer.getType(FunctionDescriptorUtil.getFunctionInnerScope(declaringScope, descriptor, semanticServices), bodyExpression, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
assert descriptor.getUnsubstitutedReturnType() != null;
|
assert descriptor.getUnsubstitutedReturnType() != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
|
||||||
private JetType resolveExpression(@NotNull JetScope scope, JetExpression expression, boolean preferBlock, JetControlFlowDataTrace controlFlowDataTrace) {
|
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||||
assert readyToProcessExpressions : "Must be ready collecting types";
|
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||||
return typeInferrer.getType(scope, expression, preferBlock);
|
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||||
|
@Override
|
||||||
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
|
pseudocodeTrace.recordControlFlowData(element, pseudocode);
|
||||||
|
pseudocodeMap.put(element, pseudocode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
pseudocodeTrace.close();
|
||||||
|
for (Pseudocode pseudocode : pseudocodeMap.values()) {
|
||||||
|
pseudocode.postProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace);
|
||||||
|
new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(declaration, bodyExpression);
|
||||||
|
wrappedTrace.close();
|
||||||
|
return new JetFlowInformationProvider() {
|
||||||
|
@Override
|
||||||
|
public void collectReturnedInformation(@NotNull JetFunction function, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) {
|
||||||
|
Pseudocode pseudocode = pseudocodeMap.get(function);
|
||||||
|
assert pseudocode != null;
|
||||||
|
|
||||||
|
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
|
||||||
|
processPreviousInstructions(exitInstruction, returnedExpressions, elementsReturningUnit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPreviousInstructions(Instruction previousFor, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
|
||||||
|
Collection<Instruction> previousInstructions = previousFor.getPreviousInstructions();
|
||||||
|
InstructionVisitor visitor = new InstructionVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visitReadValue(ReadValueInstruction instruction) {
|
||||||
|
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||||
|
processPreviousInstructions(instruction, returnedExpressions, elementsReturningUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||||
|
elementsReturningUnit.add(instruction.getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
||||||
|
elementsReturningUnit.add(instruction.getSubroutine());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
|
||||||
|
semanticServices.getErrorHandler().genericError(instruction.getElement().getNode(), "Unsupported by control-flow builder");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||||
|
elementsReturningUnit.add(writeValueInstruction.getElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitJump(AbstractJumpInstruction instruction) {
|
||||||
|
processPreviousInstructions(instruction, returnedExpressions, elementsReturningUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInstruction(Instruction instruction) {
|
||||||
|
if (instruction instanceof JetElementInstruction) {
|
||||||
|
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||||
|
semanticServices.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new UnsupportedOperationException(instruction.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (Instruction previousInstruction : previousInstructions) {
|
||||||
|
previousInstruction.accept(visitor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package org.jetbrains.jet.lang.types;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
|
import org.jetbrains.jet.lang.resolve.JetScope;
|
||||||
|
import org.jetbrains.jet.lang.resolve.WritableScope;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -116,4 +119,17 @@ public class FunctionDescriptorUtil {
|
|||||||
);
|
);
|
||||||
return substitutedDescriptor;
|
return substitutedDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JetScope getFunctionInnerScope(@NotNull JetScope outerScope, @NotNull FunctionDescriptor descriptor, @NotNull JetSemanticServices semanticServices) {
|
||||||
|
WritableScope parameterScope = semanticServices.createWritableScope(outerScope, descriptor);
|
||||||
|
for (TypeParameterDescriptor typeParameter : descriptor.getTypeParameters()) {
|
||||||
|
parameterScope.addTypeParameterDescriptor(typeParameter);
|
||||||
|
}
|
||||||
|
for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getUnsubstitutedValueParameters()) {
|
||||||
|
parameterScope.addPropertyDescriptor(valueParameterDescriptor);
|
||||||
|
}
|
||||||
|
parameterScope.addLabeledDeclaration(descriptor);
|
||||||
|
return parameterScope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
@@ -60,16 +61,20 @@ public class JetTypeInferrer {
|
|||||||
assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS);
|
assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Map<JetExpression, JetType> typeCache = new HashMap<JetExpression, JetType>();
|
||||||
|
|
||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
private final JetSemanticServices semanticServices;
|
private final JetSemanticServices semanticServices;
|
||||||
private final TypeResolver typeResolver;
|
private final TypeResolver typeResolver;
|
||||||
private final ClassDescriptorResolver classDescriptorResolver;
|
private final ClassDescriptorResolver classDescriptorResolver;
|
||||||
|
private final JetFlowInformationProvider flowInformationProvider;
|
||||||
|
|
||||||
public JetTypeInferrer(BindingTrace trace, JetSemanticServices semanticServices) {
|
public JetTypeInferrer(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) {
|
||||||
this.trace = trace;
|
this.trace = new CachedBindingTrace(trace);
|
||||||
this.semanticServices = semanticServices;
|
this.semanticServices = semanticServices;
|
||||||
this.typeResolver = new TypeResolver(trace, semanticServices);
|
this.typeResolver = new TypeResolver(trace, semanticServices);
|
||||||
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
|
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
|
||||||
|
this.flowInformationProvider = flowInformationProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -107,7 +112,6 @@ public class JetTypeInferrer {
|
|||||||
@NotNull JetReferenceExpression reference,
|
@NotNull JetReferenceExpression reference,
|
||||||
@NotNull String name,
|
@NotNull String name,
|
||||||
@NotNull JetType receiverType,
|
@NotNull JetType receiverType,
|
||||||
|
|
||||||
@NotNull List<JetType> argumentTypes,
|
@NotNull List<JetType> argumentTypes,
|
||||||
boolean reportUnresolved) {
|
boolean reportUnresolved) {
|
||||||
OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name);
|
OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name);
|
||||||
@@ -264,21 +268,75 @@ public class JetTypeInferrer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getFunctionReturnType(@NotNull JetScope outerScope, JetFunction function, FunctionDescriptor functionDescriptor) {
|
||||||
|
Map<JetElement, JetType> typeMap = getReturnedExpressions(outerScope, function, functionDescriptor);
|
||||||
|
Collection<JetType> types = typeMap.values();
|
||||||
|
return types.isEmpty() ? JetStandardClasses.getNothingType() : semanticServices.getTypeChecker().commonSupertype(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JetType getCachedType(@NotNull JetExpression expression) {
|
||||||
|
// assert typeCache.containsKey(expression) : "No type cached for " + expression.getText();
|
||||||
|
return typeCache.get(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetFunction function, @NotNull FunctionDescriptor functionDescriptor) {
|
||||||
|
Map<JetElement, JetType> typeMap = getReturnedExpressions(outerScope, function, functionDescriptor);
|
||||||
|
if (typeMap.isEmpty()) {
|
||||||
|
return; // The function returns Nothing
|
||||||
|
}
|
||||||
|
JetType expectedReturnType = functionDescriptor.getUnsubstitutedReturnType();
|
||||||
|
for (Map.Entry<JetElement, JetType> entry : typeMap.entrySet()) {
|
||||||
|
JetType actualType = entry.getValue();
|
||||||
|
JetElement element = entry.getKey();
|
||||||
|
if (!semanticServices.getTypeChecker().isConvertibleTo(actualType, expectedReturnType)) {
|
||||||
|
if (element instanceof JetExpression) {
|
||||||
|
JetExpression expression = (JetExpression) element;
|
||||||
|
semanticServices.getErrorHandler().typeMismatch(expression, expectedReturnType, actualType);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
semanticServices.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<JetElement, JetType> getReturnedExpressions(JetScope outerScope, JetFunction function, FunctionDescriptor functionDescriptor) {
|
||||||
|
JetExpression bodyExpression = function.getBodyExpression();
|
||||||
|
assert bodyExpression != null;
|
||||||
|
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, semanticServices);
|
||||||
|
getType(functionInnerScope, bodyExpression, function.hasBlockBody());
|
||||||
|
Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
|
||||||
|
Collection<JetElement> elementsReturningUnit = new ArrayList<JetElement>();
|
||||||
|
flowInformationProvider.collectReturnedInformation(function, returnedExpressions, elementsReturningUnit);
|
||||||
|
Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>();
|
||||||
|
for (JetExpression returnedExpression : returnedExpressions) {
|
||||||
|
JetType cachedType = getCachedType(returnedExpression);
|
||||||
|
if (cachedType != null) {
|
||||||
|
typeMap.put(returnedExpression, cachedType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (JetElement jetElement : elementsReturningUnit) {
|
||||||
|
typeMap.put(jetElement, JetStandardClasses.getUnitType());
|
||||||
|
}
|
||||||
|
return typeMap;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull List<JetElement> block, @NotNull LabeledJumpDomain jumpDomain) {
|
private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull List<JetElement> block) {
|
||||||
if (block.isEmpty()) {
|
if (block.isEmpty()) {
|
||||||
return JetStandardClasses.getUnitType();
|
return JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
|
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
|
||||||
WritableScope scope = semanticServices.createWritableScope(outerScope, containingDescriptor);
|
WritableScope scope = semanticServices.createWritableScope(outerScope, containingDescriptor);
|
||||||
return getBlockReturnedTypeWithWritableScope(scope, block, jumpDomain);
|
return getBlockReturnedTypeWithWritableScope(scope, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, @NotNull LabeledJumpDomain jumpDomain) {
|
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block) {
|
||||||
assert !block.isEmpty();
|
assert !block.isEmpty();
|
||||||
|
|
||||||
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, jumpDomain);
|
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true);
|
||||||
|
|
||||||
JetType result = null;
|
JetType result = null;
|
||||||
for (JetElement statement : block) {
|
for (JetElement statement : block) {
|
||||||
@@ -305,18 +363,12 @@ public class JetTypeInferrer {
|
|||||||
private class TypeInferrerVisitor extends JetVisitor {
|
private class TypeInferrerVisitor extends JetVisitor {
|
||||||
private final JetScope scope;
|
private final JetScope scope;
|
||||||
private final boolean preferBlock;
|
private final boolean preferBlock;
|
||||||
private final LabeledJumpDomain jumpDomain;
|
|
||||||
|
|
||||||
protected JetType result;
|
protected JetType result;
|
||||||
|
|
||||||
private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull LabeledJumpDomain jumpDomain) {
|
private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock) {
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
this.preferBlock = preferBlock;
|
this.preferBlock = preferBlock;
|
||||||
this.jumpDomain = jumpDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeInferrerVisitor(JetScope scope, boolean preferBlock) {
|
|
||||||
this(scope, preferBlock, LabeledJumpDomain.EMPTY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -379,7 +431,7 @@ public class JetTypeInferrer {
|
|||||||
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
|
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
|
||||||
if (preferBlock && !expression.hasParameterSpecification()) {
|
if (preferBlock && !expression.hasParameterSpecification()) {
|
||||||
trace.recordBlock(expression);
|
trace.recordBlock(expression);
|
||||||
result = getBlockReturnedType(scope, expression.getBody(), LabeledJumpDomain.ERROR);
|
result = getBlockReturnedType(scope, expression.getBody());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +468,7 @@ public class JetTypeInferrer {
|
|||||||
writableScope.addPropertyDescriptor(propertyDescriptor);
|
writableScope.addPropertyDescriptor(propertyDescriptor);
|
||||||
}
|
}
|
||||||
writableScope.setThisType(receiverType);
|
writableScope.setThisType(receiverType);
|
||||||
returnType = getBlockReturnedType(writableScope, body, LabeledJumpDomain.ERROR);
|
returnType = getBlockReturnedType(writableScope, body);
|
||||||
}
|
}
|
||||||
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
|
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
|
||||||
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
|
||||||
@@ -477,7 +529,6 @@ public class JetTypeInferrer {
|
|||||||
else {
|
else {
|
||||||
returnedType = JetStandardClasses.getUnitType();
|
returnedType = JetStandardClasses.getUnitType();
|
||||||
}
|
}
|
||||||
jumpDomain.registerReturn(expression, returnedType);
|
|
||||||
|
|
||||||
result = JetStandardClasses.getNothingType();
|
result = JetStandardClasses.getNothingType();
|
||||||
}
|
}
|
||||||
@@ -485,15 +536,11 @@ public class JetTypeInferrer {
|
|||||||
@Override
|
@Override
|
||||||
public void visitBreakExpression(JetBreakExpression expression) {
|
public void visitBreakExpression(JetBreakExpression expression) {
|
||||||
result = JetStandardClasses.getNothingType();
|
result = JetStandardClasses.getNothingType();
|
||||||
|
|
||||||
jumpDomain.registerBreakOrContinue(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitContinueExpression(JetContinueExpression expression) {
|
public void visitContinueExpression(JetContinueExpression expression) {
|
||||||
result = JetStandardClasses.getNothingType();
|
result = JetStandardClasses.getNothingType();
|
||||||
|
|
||||||
jumpDomain.registerBreakOrContinue(expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -603,7 +650,7 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBlockExpression(JetBlockExpression expression) {
|
public void visitBlockExpression(JetBlockExpression expression) {
|
||||||
result = getBlockReturnedType(scope, expression.getStatements(), jumpDomain);
|
result = getBlockReturnedType(scope, expression.getStatements());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -692,7 +739,7 @@ public class JetTypeInferrer {
|
|||||||
if (!function.hasParameterSpecification()) {
|
if (!function.hasParameterSpecification()) {
|
||||||
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
|
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
|
||||||
conditionScope = writableScope;
|
conditionScope = writableScope;
|
||||||
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), LabeledJumpDomain.ERROR); // TODO
|
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody());
|
||||||
trace.recordBlock(function);
|
trace.recordBlock(function);
|
||||||
} else {
|
} else {
|
||||||
getType(scope, body, true);
|
getType(scope, body, true);
|
||||||
@@ -701,7 +748,7 @@ public class JetTypeInferrer {
|
|||||||
else if (body != null) {
|
else if (body != null) {
|
||||||
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
|
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
|
||||||
conditionScope = writableScope;
|
conditionScope = writableScope;
|
||||||
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), LabeledJumpDomain.ERROR); // TODO
|
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body));
|
||||||
}
|
}
|
||||||
checkCondition(conditionScope, expression.getCondition());
|
checkCondition(conditionScope, expression.getCondition());
|
||||||
result = JetStandardClasses.getUnitType();
|
result = JetStandardClasses.getUnitType();
|
||||||
@@ -1240,8 +1287,8 @@ public class JetTypeInferrer {
|
|||||||
private class TypeInferrerVisitorWithWritableScope extends TypeInferrerVisitor {
|
private class TypeInferrerVisitorWithWritableScope extends TypeInferrerVisitor {
|
||||||
private final WritableScope scope;
|
private final WritableScope scope;
|
||||||
|
|
||||||
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock, @NotNull LabeledJumpDomain jumpDomain) {
|
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock) {
|
||||||
super(scope, preferBlock, jumpDomain);
|
super(scope, preferBlock);
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1358,30 +1405,44 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface LabeledJumpDomain {
|
private class CachedBindingTrace extends BindingTrace {
|
||||||
LabeledJumpDomain EMPTY = new LabeledJumpDomain() {
|
private final BindingTrace originalTrace;
|
||||||
@Override
|
|
||||||
public void registerReturn(@NotNull JetReturnExpression expression, JetType returnedExpressionType) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public CachedBindingTrace(BindingTrace originalTrace) {
|
||||||
public void registerBreakOrContinue(@NotNull JetLabelQualifiedExpression expression) {
|
this.originalTrace = originalTrace;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
LabeledJumpDomain ERROR = new LabeledJumpDomain() {
|
public void recordExpressionType(@NotNull JetExpression expression, @NotNull JetType type) {
|
||||||
@Override
|
originalTrace.recordExpressionType(expression, type);
|
||||||
public void registerReturn(@NotNull JetReturnExpression expression, JetType returnedExpressionType) {
|
typeCache.put(expression, type);
|
||||||
// throw new UnsupportedOperationException();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public void recordReferenceResolution(@NotNull JetReferenceExpression expression, @NotNull DeclarationDescriptor descriptor) {
|
||||||
public void registerBreakOrContinue(@NotNull JetLabelQualifiedExpression expression) {
|
originalTrace.recordReferenceResolution(expression, descriptor);
|
||||||
// throw new UnsupportedOperationException();
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void registerReturn(@NotNull JetReturnExpression expression, JetType returnedExpressionType);
|
public void recordLabelResolution(@NotNull JetReferenceExpression expression, @NotNull PsiElement element) {
|
||||||
void registerBreakOrContinue(@NotNull JetLabelQualifiedExpression expression);
|
originalTrace.recordLabelResolution(expression, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) {
|
||||||
|
originalTrace.recordDeclarationResolution(declaration, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordTypeResolution(@NotNull JetTypeReference typeReference, @NotNull JetType type) {
|
||||||
|
originalTrace.recordTypeResolution(typeReference, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToplevelScope(JetScope toplevelScope) {
|
||||||
|
originalTrace.setToplevelScope(toplevelScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordBlock(JetFunctionLiteralExpression expression) {
|
||||||
|
originalTrace.recordBlock(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) {
|
||||||
|
originalTrace.removeReferenceResolution(referenceExpression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
== empty ==
|
||||||
|
fun empty() {}
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fun empty() {}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
== short ==
|
||||||
|
fun short() = 1
|
||||||
|
---------------------
|
||||||
|
l0:
|
||||||
|
<START>
|
||||||
|
r(1)
|
||||||
|
l1:
|
||||||
|
<END>
|
||||||
|
=====================
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fun short() = 1
|
||||||
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.JetTestCaseBase;
|
import org.jetbrains.jet.JetTestCaseBase;
|
||||||
import org.jetbrains.jet.lang.ErrorHandler;
|
import org.jetbrains.jet.lang.ErrorHandler;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTrace;
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||||
import org.jetbrains.jet.lang.psi.JetElement;
|
import org.jetbrains.jet.lang.psi.JetElement;
|
||||||
@@ -42,7 +42,7 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
JetFile file = (JetFile) getFile();
|
JetFile file = (JetFile) getFile();
|
||||||
|
|
||||||
final Map<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
final Map<JetElement, Pseudocode> data = new LinkedHashMap<JetElement, Pseudocode>();
|
||||||
final JetControlFlowDataTrace jetControlFlowDataTrace = new JetControlFlowDataTrace() {
|
final JetPseudocodeTrace pseudocodeTrace = new JetPseudocodeTrace() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||||
@@ -51,6 +51,9 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
for (Pseudocode pseudocode : data.values()) {
|
||||||
|
pseudocode.postProcess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -58,8 +61,8 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.THROW_EXCEPTION, new JetControlFlowDataTraceFactory() {
|
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.THROW_EXCEPTION, new JetControlFlowDataTraceFactory() {
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JetControlFlowDataTrace createTrace(JetElement element) {
|
public JetPseudocodeTrace createTrace(JetElement element) {
|
||||||
return jetControlFlowDataTrace;
|
return pseudocodeTrace;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -75,9 +78,6 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
|||||||
|
|
||||||
private void processCFData(String name, Map<JetElement, Pseudocode> data) throws IOException {
|
private void processCFData(String name, Map<JetElement, Pseudocode> data) throws IOException {
|
||||||
Collection<Pseudocode> pseudocodes = data.values();
|
Collection<Pseudocode> pseudocodes = data.values();
|
||||||
for (Pseudocode pseudocode : pseudocodes) {
|
|
||||||
pseudocode.postProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder instructionDump = new StringBuilder();
|
StringBuilder instructionDump = new StringBuilder();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.project.Project;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.ErrorHandler;
|
import org.jetbrains.jet.lang.ErrorHandler;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
|
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||||
import org.jetbrains.jet.lang.psi.JetChangeUtil;
|
import org.jetbrains.jet.lang.psi.JetChangeUtil;
|
||||||
import org.jetbrains.jet.lang.psi.JetClass;
|
import org.jetbrains.jet.lang.psi.JetClass;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
@@ -455,14 +456,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
private void assertType(String expression, JetType expectedType) {
|
private void assertType(String expression, JetType expectedType) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY).getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
||||||
assertTrue(type + " != " + expectedType, JetTypeImpl.equalTypes(type, expectedType));
|
assertTrue(type + " != " + expectedType, JetTypeImpl.equalTypes(type, expectedType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertErrorType(String expression) {
|
private void assertErrorType(String expression) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false);
|
||||||
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
|
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +486,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
||||||
Project project = getProject();
|
Project project = getProject();
|
||||||
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
|
||||||
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY).getType(scope, jetExpression, false);
|
JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.ERROR).getType(scope, jetExpression, false);
|
||||||
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
|
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
|
||||||
assertEquals(expectedType, type);
|
assertEquals(expectedType, type);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user