提交 83e0018b 编写于 作者: A Andrey Breslav

Return values collected from CF data

上级 803405f8
...@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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);
......
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);
}
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 { ...@@ -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 { ...@@ -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);
} }
...@@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.cfg.Label; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -6,9 +6,9 @@ import org.jetbrains.jet.lang.psi.JetElement; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
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; ...@@ -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 { ...@@ -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);
......
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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
FunctionDescriptorImpl functionDescriptorImpl = null;
if (declaration instanceof JetFunction) {
JetFunction jetFunction = (JetFunction) declaration;
preferBlock = jetFunction.hasBlockBody();
functionDescriptorImpl = (FunctionDescriptorImpl) descriptor;
}
JetType returnType = resolveExpression(parameterScope, bodyExpression, preferBlock, controlFlowDataTrace); assert readyToProcessExpressions : "Must be ready collecting types";
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; ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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(); }
}
}; public void recordLabelResolution(@NotNull JetReferenceExpression expression, @NotNull PsiElement element) {
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);
}
void registerReturn(@NotNull JetReturnExpression expression, JetType returnedExpressionType); public void recordBlock(JetFunctionLiteralExpression expression) {
void registerBreakOrContinue(@NotNull JetLabelQualifiedExpression expression); originalTrace.recordBlock(expression);
}
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) {
originalTrace.removeReferenceResolution(referenceExpression);
}
} }
} }
== empty ==
fun empty() {}
---------------------
l0:
<START>
l1:
<END>
=====================
fun empty() {}
\ No newline at end of file
== short ==
fun short() = 1
---------------------
l0:
<START>
r(1)
l1:
<END>
=====================
...@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册