提交 cf799137 编写于 作者: A Andrey Breslav

Unreachable code with Nothing-returning functions

上级 4d92f751
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
<dictionary name="abreslav"> <dictionary name="abreslav">
<words> <words>
<w>accessor</w> <w>accessor</w>
<w>dominator</w>
<w>inferrer</w> <w>inferrer</w>
<w>nondeterministic</w> <w>nondeterministic</w>
<w>nullable</w> <w>nullable</w>
......
...@@ -265,9 +265,6 @@ public class JetControlFlowProcessor { ...@@ -265,9 +265,6 @@ public class JetControlFlowProcessor {
builder.readUnit(expression); builder.readUnit(expression);
} }
builder.bindLabel(resultLabel); builder.bindLabel(resultLabel);
// if (!inCondition) {
// builder.readNode(expression);
// }
} }
@Override @Override
......
...@@ -10,18 +10,50 @@ import java.util.Collection; ...@@ -10,18 +10,50 @@ import java.util.Collection;
* @author abreslav * @author abreslav
*/ */
public interface JetFlowInformationProvider { public interface JetFlowInformationProvider {
JetFlowInformationProvider ERROR = new JetFlowInformationProvider() { JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
@Override @Override
public void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) { public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements) { public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
throw new UnsupportedOperationException();
}
@Override
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
}; };
void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit); JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements); @Override
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
}
@Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
}
@Override
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
}
};
void collectReturnedInformation(
@NotNull JetElement subroutine,
@NotNull Collection<JetExpression> returnedExpressions,
@NotNull Collection<JetElement> elementsReturningUnit);
void collectUnreachableExpressions(
@NotNull JetElement subroutine,
@NotNull Collection<JetElement> unreachableElements);
void collectDominatedExpressions(
@NotNull JetExpression dominator,
@NotNull Collection<JetElement> dominated);
} }
...@@ -9,7 +9,7 @@ import java.util.Collections; ...@@ -9,7 +9,7 @@ import java.util.Collections;
/** /**
* @author abreslav * @author abreslav
*/ */
public abstract class AbstractJumpInstruction extends Instruction { public abstract class AbstractJumpInstruction extends InstructionImpl {
private final Label targetLabel; private final Label targetLabel;
private Instruction resolvedTarget; private Instruction resolvedTarget;
......
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.annotations.Nullable;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashSet;
/** /**
* @author abreslav * @author abreslav
*/ */
public abstract class Instruction { public interface Instruction {
private Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>(); @NotNull
Pseudocode getOwner();
public Collection<Instruction> getPreviousInstructions() { void setOwner(@NotNull Pseudocode owner);
return previousInstructions;
}
@NotNull Collection<Instruction> getPreviousInstructions();
public abstract Collection<Instruction> getNextInstructions();
@Nullable @NotNull
protected Instruction outgoingEdgeTo(@Nullable Instruction target) { Collection<Instruction> getNextInstructions();
if (target != null) {
target.getPreviousInstructions().add(this);
}
return target;
}
public abstract void accept(InstructionVisitor visitor); void accept(InstructionVisitor visitor);
} }
package org.jetbrains.jet.lang.cfg.pseudocode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.LinkedHashSet;
/**
* @author abreslav
*/
public abstract class InstructionImpl implements Instruction {
private Pseudocode owner;
private final Collection<Instruction> previousInstructions = new LinkedHashSet<Instruction>();
protected InstructionImpl() {
}
@Override
@NotNull
public Pseudocode getOwner() {
return owner;
}
@Override
public void setOwner(@NotNull Pseudocode owner) {
this.owner = owner;
}
@Override
public Collection<Instruction> getPreviousInstructions() {
return previousInstructions;
}
@Nullable
protected Instruction outgoingEdgeTo(@Nullable Instruction target) {
if (target != null) {
target.getPreviousInstructions().add(this);
}
return target;
}
}
...@@ -83,8 +83,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd ...@@ -83,8 +83,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
return pseudocode; return pseudocode;
} }
private void add(Instruction instruction) { private void add(@NotNull Instruction instruction) {
pseudocode.addInstruction(instruction); pseudocode.addInstruction(instruction);
instruction.setOwner(pseudocode);
if (instruction instanceof JetElementInstruction) {
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
trace.recordRepresentativeInstruction(elementInstruction.getElement(), instruction);
}
} }
@NotNull @NotNull
......
...@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement; ...@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface JetElementInstruction { public interface JetElementInstruction extends Instruction {
@NotNull @NotNull
JetElement getElement(); JetElement getElement();
} }
...@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement; ...@@ -6,7 +6,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
/** /**
* @author abreslav * @author abreslav
*/ */
public abstract class JetElementInstructionImpl extends Instruction implements JetElementInstruction { public abstract class JetElementInstructionImpl extends InstructionImpl implements JetElementInstruction {
protected final JetElement element; protected final JetElement element;
public JetElementInstructionImpl(@NotNull JetElement element) { public JetElementInstructionImpl(@NotNull JetElement element) {
......
...@@ -13,12 +13,18 @@ public interface JetPseudocodeTrace { ...@@ -13,12 +13,18 @@ public interface JetPseudocodeTrace {
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
} }
@Override
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
}
@Override @Override
public void close() { public void close() {
} }
}; };
void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode); void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode);
void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction);
void close(); void close();
} }
...@@ -9,7 +9,7 @@ import java.util.Collections; ...@@ -9,7 +9,7 @@ import java.util.Collections;
/** /**
* @author abreslav * @author abreslav
*/ */
public class SubroutineExitInstruction extends Instruction { public class SubroutineExitInstruction extends InstructionImpl {
private final JetElement subroutine; private final JetElement subroutine;
public SubroutineExitInstruction(@NotNull JetElement subroutine) { public SubroutineExitInstruction(@NotNull JetElement subroutine) {
......
...@@ -3,6 +3,10 @@ package org.jetbrains.jet.lang.psi; ...@@ -3,6 +3,10 @@ package org.jetbrains.jet.lang.psi;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/** /**
* @author abreslav * @author abreslav
*/ */
...@@ -20,4 +24,27 @@ public class JetPsiUtil { ...@@ -20,4 +24,27 @@ public class JetPsiUtil {
public static String safeName(String name) { public static String safeName(String name) {
return name == null ? "<no name provided>" : name; return name == null ? "<no name provided>" : name;
} }
@NotNull
public static Set<JetElement> findRootExpressions(@NotNull Collection<JetElement> unreachableElements) {
Set<JetElement> rootElements = new HashSet<JetElement>();
final Set<JetElement> shadowedElements = new HashSet<JetElement>();
JetVisitor shadowAllChildren = new JetVisitor() {
@Override
public void visitJetElement(JetElement elem) {
if (shadowedElements.add(elem)) {
elem.acceptChildren(this);
}
}
};
for (JetElement element : unreachableElements) {
if (shadowedElements.contains(element)) continue;
element.acceptChildren(shadowAllChildren);
rootElements.removeAll(shadowedElements);
rootElements.add(element);
}
return rootElements;
}
} }
...@@ -27,4 +27,5 @@ public interface BindingContext { ...@@ -27,4 +27,5 @@ public interface BindingContext {
PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor); PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor);
boolean isBlock(JetFunctionLiteralExpression expression); boolean isBlock(JetFunctionLiteralExpression expression);
boolean isStatement(JetExpression expression);
} }
...@@ -21,6 +21,8 @@ public class BindingTraceContext extends BindingTrace implements BindingContext ...@@ -21,6 +21,8 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>(); private final Map<DeclarationDescriptor, PsiElement> descriptorToDeclarations = new HashMap<DeclarationDescriptor, PsiElement>();
private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>(); private final Map<PsiElement, DeclarationDescriptor> declarationsToDescriptors = new HashMap<PsiElement, DeclarationDescriptor>();
private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>(); private final Set<JetFunctionLiteralExpression> blocks = new HashSet<JetFunctionLiteralExpression>();
private final Set<JetElement> statements = new HashSet<JetElement>();
private JetScope toplevelScope; private JetScope toplevelScope;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
...@@ -61,6 +63,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext ...@@ -61,6 +63,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
blocks.add(expression); blocks.add(expression);
} }
@Override
public void recordStatement(@NotNull JetElement statement) {
statements.add(statement);
}
public void setToplevelScope(JetScope toplevelScope) { public void setToplevelScope(JetScope toplevelScope) {
this.toplevelScope = toplevelScope; this.toplevelScope = toplevelScope;
} }
...@@ -135,4 +142,9 @@ public class BindingTraceContext extends BindingTrace implements BindingContext ...@@ -135,4 +142,9 @@ public class BindingTraceContext extends BindingTrace implements BindingContext
public boolean isBlock(JetFunctionLiteralExpression expression) { public boolean isBlock(JetFunctionLiteralExpression expression) {
return !expression.hasParameterSpecification() && blocks.contains(expression); return !expression.hasParameterSpecification() && blocks.contains(expression);
} }
@Override
public boolean isStatement(@NotNull JetExpression expression) {
return statements.contains(expression);
}
} }
...@@ -309,7 +309,7 @@ public class ClassDescriptorResolver { ...@@ -309,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, JetFlowInformationProvider.ERROR).getType(scope, initializer, false); type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(scope, initializer, false);
} }
} else { } else {
type = typeResolver.resolveType(scope, propertyTypeRef); type = typeResolver.resolveType(scope, propertyTypeRef);
......
...@@ -96,7 +96,7 @@ public class TopDownAnalyzer { ...@@ -96,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 = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.ERROR).getType(namespaceScope, importedReference, false); JetType type = semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).getType(namespaceScope, importedReference, false);
if (type != null) { if (type != null) {
namespaceScope.importScope(type.getMemberScope()); namespaceScope.importScope(type.getMemberScope());
} }
...@@ -288,7 +288,7 @@ public class TopDownAnalyzer { ...@@ -288,7 +288,7 @@ public class TopDownAnalyzer {
flowInformationProvider.collectUnreachableExpressions(function, unreachableElements); flowInformationProvider.collectUnreachableExpressions(function, unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well // This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
Set<JetElement> rootElements = findRootExpressions(unreachableElements); Set<JetElement> rootElements = JetPsiUtil.findRootExpressions(unreachableElements);
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable // TODO : (return 1) || (return 2) -- only || and right of it is unreachable
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable, // TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
...@@ -318,31 +318,10 @@ public class TopDownAnalyzer { ...@@ -318,31 +318,10 @@ public class TopDownAnalyzer {
} }
} }
private Set<JetElement> findRootExpressions(List<JetElement> unreachableElements) {
Set<JetElement> rootElements = new HashSet<JetElement>();
final Set<JetElement> shadowedElements = new HashSet<JetElement>();
JetVisitor shadowAllChildren = new JetVisitor() {
@Override
public void visitJetElement(JetElement elem) {
if (shadowedElements.add(elem)) {
elem.acceptChildren(this);
}
}
};
for (JetElement element : unreachableElements) {
if (shadowedElements.contains(element)) continue;
element.acceptChildren(shadowAllChildren);
rootElements.removeAll(shadowedElements);
rootElements.add(element);
}
return rootElements;
}
private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) { private JetFlowInformationProvider computeFlowData(@NotNull JetDeclaration declaration, @NotNull JetExpression bodyExpression) {
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration); final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>(); final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() { JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
@Override @Override
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) { public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
...@@ -350,6 +329,12 @@ public class TopDownAnalyzer { ...@@ -350,6 +329,12 @@ public class TopDownAnalyzer {
pseudocodeMap.put(element, pseudocode); pseudocodeMap.put(element, pseudocode);
} }
@Override
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
Instruction oldValue = representativeInstructions.put(element, instruction);
// assert oldValue == null : element.getText();
}
@Override @Override
public void close() { public void close() {
pseudocodeTrace.close(); pseudocodeTrace.close();
...@@ -363,7 +348,7 @@ public class TopDownAnalyzer { ...@@ -363,7 +348,7 @@ public class TopDownAnalyzer {
wrappedTrace.close(); wrappedTrace.close();
return new JetFlowInformationProvider() { return new JetFlowInformationProvider() {
@Override @Override
public void collectReturnedInformation(@NotNull JetElement subroutine, Collection<JetExpression> returnedExpressions, Collection<JetElement> elementsReturningUnit) { public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine); Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null; assert pseudocode != null;
...@@ -372,7 +357,7 @@ public class TopDownAnalyzer { ...@@ -372,7 +357,7 @@ public class TopDownAnalyzer {
} }
@Override @Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, Collection<JetElement> unreachableElements) { public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine); Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null; assert pseudocode != null;
...@@ -385,7 +370,38 @@ public class TopDownAnalyzer { ...@@ -385,7 +370,38 @@ public class TopDownAnalyzer {
unreachableElements.add(((JetElementInstruction) instruction).getElement()); unreachableElements.add(((JetElementInstruction) instruction).getElement());
} }
} }
}
@Override
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
Instruction dominatorInstruction = representativeInstructions.get(dominator);
if (dominatorInstruction == null) {
// assert
// dominator instanceof JetContinueExpression ||
// dominator instanceof JetBreakExpression ||
// dominator instanceof JetReturnExpression ||
// dominator instanceof JetBlockExpression ||
// dominator instanceof JetFunctionLiteralExpression
// : "No representative instruction for a Nothing-typed expression: " + dominator.getText();
return;
}
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
Set<Instruction> reachable = new HashSet<Instruction>();
collectReachable(enterInstruction, reachable);
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
reachableWithDominatorProhibited.add(dominatorInstruction);
collectReachable(enterInstruction, reachableWithDominatorProhibited);
for (Instruction instruction : reachable) {
if (instruction instanceof JetElementInstruction
&& reachable.contains(instruction)
&& !reachableWithDominatorProhibited.contains(instruction)) {
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
dominated.add(elementInstruction.getElement());
}
}
} }
}; };
} }
......
...@@ -38,6 +38,10 @@ public class BindingTrace { ...@@ -38,6 +38,10 @@ public class BindingTrace {
} }
public void recordStatement(@NotNull JetElement statement) {
}
public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) { public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) {
} }
......
...@@ -250,7 +250,8 @@ public class JetStandardClasses { ...@@ -250,7 +250,8 @@ public class JetStandardClasses {
} }
public static boolean isNothing(@NotNull JetType type) { public static boolean isNothing(@NotNull JetType type) {
return type.getConstructor() == NOTHING_CLASS.getTypeConstructor(); return !(type instanceof NamespaceType) &&
type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
} }
public static JetType getTupleType(List<Attribute> attributes, List<JetType> arguments) { public static JetType getTupleType(List<Attribute> attributes, List<JetType> arguments) {
......
...@@ -356,7 +356,9 @@ public class JetTypeInferrer { ...@@ -356,7 +356,9 @@ public class JetTypeInferrer {
JetType result = null; JetType result = null;
for (JetElement statement : block) { for (JetElement statement : block) {
result = blockLevelVisitor.getType((JetExpression) statement); trace.recordStatement(statement);
JetExpression statementExpression = (JetExpression) statement;
result = blockLevelVisitor.getType(statementExpression);
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope? blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
} }
return result; return result;
...@@ -407,7 +409,11 @@ public class JetTypeInferrer { ...@@ -407,7 +409,11 @@ public class JetTypeInferrer {
expression.accept(this); expression.accept(this);
if (result != null) { if (result != null) {
trace.recordExpressionType(expression, result); trace.recordExpressionType(expression, result);
if (JetStandardClasses.isNothing(result)) {
markDominatedExpressionsAsUnreachable(expression);
}
} }
return result; return result;
} }
...@@ -415,6 +421,18 @@ public class JetTypeInferrer { ...@@ -415,6 +421,18 @@ public class JetTypeInferrer {
result = null; result = null;
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void markDominatedExpressionsAsUnreachable(JetExpression expression) {
List<JetElement> dominated = new ArrayList<JetElement>();
flowInformationProvider.collectDominatedExpressions(expression, dominated);
Set<JetElement> rootExpressions = JetPsiUtil.findRootExpressions(dominated);
for (JetElement rootExpression : rootExpressions) {
semanticServices.getErrorHandler().genericError(rootExpression.getNode(),
"This code is unreachable, because '" + expression.getText() + "' never terminates normally");
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override @Override
...@@ -488,7 +506,7 @@ public class JetTypeInferrer { ...@@ -488,7 +506,7 @@ public class JetTypeInferrer {
} }
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;
result = JetStandardClasses.getFunctionType(null, effectiveReceiverType, parameterTypes, safeReturnType); result = JetStandardClasses.getFunctionType(Collections.<Attribute>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType);
} }
@Override @Override
......
package org.jetbrains.jet.plugin; package org.jetbrains.jet.plugin;
import com.intellij.lang.documentation.QuickDocumentationProvider; import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
...@@ -11,10 +12,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext; ...@@ -11,10 +12,13 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.DeclarationDescriptor; import org.jetbrains.jet.lang.types.DeclarationDescriptor;
import org.jetbrains.jet.resolve.DescriptorUtil; import org.jetbrains.jet.resolve.DescriptorUtil;
import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public class JetQuickDocumentationProvider extends QuickDocumentationProvider { public class JetQuickDocumentationProvider implements DocumentationProvider {
@Override @Override
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
...@@ -51,5 +55,23 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider { ...@@ -51,5 +55,23 @@ public class JetQuickDocumentationProvider extends QuickDocumentationProvider {
return text; return text;
} }
@Override
public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
return Collections.emptyList();
}
@Override
public String generateDoc(PsiElement element, PsiElement originalElement) {
return "<no doc>";
}
@Override
public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
return null;
}
@Override
public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
return null;
}
} }
...@@ -435,3 +435,26 @@ l3: ...@@ -435,3 +435,26 @@ l3:
l1: l1:
<END> <END>
===================== =====================
== tf ==
fun tf() {
try {
return 1
}
finally {
return 2
}
}
---------------------
l0:
<START>
jmp?(l2)
r(1)
r(2)
ret(*) l1
ret(*) l1
l2:
r(2)
ret(*) l1
l1:
<END>
=====================
...@@ -127,10 +127,10 @@ fun t8() { ...@@ -127,10 +127,10 @@ fun t8() {
fun blockAndAndMismatch() : Boolean { fun blockAndAndMismatch() : Boolean {
<error>(return true) || (return false)</error> <error>(return true) || (return false)</error>
<error>1</error> <error>true</error>
} }
fun tf() { fun tf() {
try {return} finally{return} try {<error>return</error>} finally{return}
<error>1</error> <error>1</error>
} }
\ No newline at end of file
...@@ -56,6 +56,10 @@ public class JetControlFlowTest extends JetTestCaseBase { ...@@ -56,6 +56,10 @@ public class JetControlFlowTest extends JetTestCaseBase {
} }
} }
@Override
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
}
}; };
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() { AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() {
......
...@@ -459,14 +459,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { ...@@ -459,14 +459,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, JetFlowInformationProvider.ERROR).getType(classDefinitions.BASIC_SCOPE, jetExpression, false); JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).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, JetFlowInformationProvider.ERROR).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false); JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).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));
} }
...@@ -489,7 +489,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { ...@@ -489,7 +489,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, JetFlowInformationProvider.ERROR).getType(scope, jetExpression, false); JetType type = semanticServices.getTypeInferrer(BindingTrace.DUMMY, JetFlowInformationProvider.NONE).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.
先完成此消息的编辑!
想要评论请 注册