JET-34 Require a return statement in a function with a block body

JET-77 Require a return type annotation for non-Unit returning functions with block bodies
This commit is contained in:
Andrey Breslav
2011-06-17 18:03:30 +04:00
parent c4eecea575
commit 94f00509e2
17 changed files with 303 additions and 144 deletions
@@ -17,6 +17,11 @@ public interface JetFlowInformationProvider {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
throw new UnsupportedOperationException();
}
@Override @Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) { public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@@ -40,6 +45,11 @@ public interface JetFlowInformationProvider {
} }
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
}
@Override @Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) { public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
@@ -57,11 +67,19 @@ public interface JetFlowInformationProvider {
}; };
/**
* Collects expressions returned from the given subroutine and 'return;' expressions
*/
void collectReturnedInformation( void collectReturnedInformation(
@NotNull JetElement subroutine, @NotNull JetElement subroutine,
@NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetExpression> returnedExpressions,
@NotNull Collection<JetElement> elementsReturningUnit); @NotNull Collection<JetElement> elementsReturningUnit);
/**
* Collects all 'return ...' expressions that return from the given subroutine and all the expressions that precede the exit point
*/
void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions);
void collectUnreachableExpressions( void collectUnreachableExpressions(
@NotNull JetElement subroutine, @NotNull JetElement subroutine,
@NotNull Collection<JetElement> unreachableElements); @NotNull Collection<JetElement> unreachableElements);
@@ -197,7 +197,7 @@ public class ClassDescriptorResolver {
@Override @Override
protected JetType compute() { protected JetType compute() {
JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression); JetFlowInformationProvider flowInformationProvider = computeFlowData(function, bodyExpression);
return semanticServices.getTypeInferrer(trace, flowInformationProvider).getFunctionReturnType(scope, function, functionDescriptor); return semanticServices.getTypeInferrer(trace, flowInformationProvider).inferFunctionReturnType(scope, function, functionDescriptor);
} }
}); });
} }
@@ -525,7 +525,7 @@ public class ClassDescriptorResolver {
LazyValue<JetType> lazyValue = new LazyValue<JetType>() { LazyValue<JetType> lazyValue = new LazyValue<JetType>() {
@Override @Override
protected JetType compute() { protected JetType compute() {
return semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false); return semanticServices.getTypeInferrer(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false, null); // TODO
} }
}; };
if (allowDeferred) { if (allowDeferred) {
@@ -733,7 +733,7 @@ public class ClassDescriptorResolver {
} }
} }
public JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull JetExpression bodyExpression) { public JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull final 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>(); final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
@@ -779,6 +779,45 @@ public class ClassDescriptorResolver {
processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit); processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
} }
@Override
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null;
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) {
previousInstruction.accept(new InstructionVisitor() {
@Override
public void visitReturnValue(ReturnValueInstruction instruction) {
returnedExpressions.add((JetExpression) instruction.getElement());
}
@Override
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
returnedExpressions.add((JetExpression) instruction.getElement());
}
@Override
public void visitJump(AbstractJumpInstruction instruction) {
// Nothing
}
@Override
public void visitInstruction(Instruction instruction) {
if (instruction instanceof JetElementInstruction) {
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
returnedExpressions.add((JetExpression) elementInstruction.getElement());
}
else {
throw new IllegalStateException(instruction + " precedes the exit point");
}
}
});
}
}
@Override @Override
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) { public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
Pseudocode pseudocode = pseudocodeMap.get(subroutine); Pseudocode pseudocode = pseudocodeMap.get(subroutine);
@@ -1,8 +1,6 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
@@ -33,7 +31,6 @@ public class TopDownAnalyzer {
private final Map<JetDeclaration, ConstructorDescriptor> constructors = Maps.newLinkedHashMap(); private final Map<JetDeclaration, ConstructorDescriptor> constructors = Maps.newLinkedHashMap();
private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>(); private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>();
private final Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap(); private final Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap();
private final Multimap<DeclarationDescriptor, PropertyDescriptor> declaringScopesToProperties = ArrayListMultimap.create();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet(); private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
private final JetSemanticServices semanticServices; private final JetSemanticServices semanticServices;
@@ -572,7 +569,7 @@ public class TopDownAnalyzer {
JetExpression delegateExpression = specifier.getDelegateExpression(); JetExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) { if (delegateExpression != null) {
JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor; JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor;
JetType type = typeInferrer.getType(scope, delegateExpression, false); JetType type = typeInferrer.getType(scope, delegateExpression, false, null);
JetType supertype = trace.getBindingContext().resolveTypeReference(specifier.getTypeReference()); JetType supertype = trace.getBindingContext().resolveTypeReference(specifier.getTypeReference());
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible? if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type); trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
@@ -644,7 +641,7 @@ public class TopDownAnalyzer {
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true); final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
for (JetClassInitializer anonymousInitializer : anonymousInitializers) { for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true); typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true, null);
} }
} }
else { else {
@@ -730,7 +727,7 @@ public class TopDownAnalyzer {
JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression); JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression);
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider);
typeInferrer.getType(functionInnerScope, bodyExpression, true); typeInferrer.getType(functionInnerScope, bodyExpression, true, null);
} }
} }
@@ -860,7 +857,7 @@ public class TopDownAnalyzer {
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) { private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15 JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider);
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, false); JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, false, null);
JetType expectedType; JetType expectedType;
PropertySetterDescriptor setter = propertyDescriptor.getSetter(); PropertySetterDescriptor setter = propertyDescriptor.getSetter();
@@ -905,20 +902,6 @@ public class TopDownAnalyzer {
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor); typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
List<JetElement> unreachableElements = new ArrayList<JetElement>();
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
Set<JetElement> rootElements = JetPsiUtil.findRootExpressions(unreachableElements);
// 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,
// though it'd better be reported more specifically
for (JetElement element : rootElements) {
trace.getErrorHandler().genericError(element.getNode(), "Unreachable code");
}
} }
assert functionDescriptor.getUnsubstitutedReturnType() != null; assert functionDescriptor.getUnsubstitutedReturnType() != null;
@@ -274,6 +274,11 @@ public class JetStandardClasses {
type.getConstructor() == NOTHING_CLASS.getTypeConstructor(); type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
} }
public static boolean isUnit(@NotNull JetType type) {
return !(type instanceof NamespaceType) &&
type.getConstructor() == UNIT_TYPE.getConstructor();
}
public static JetType getTupleType(List<Annotation> annotations, List<JetType> arguments) { public static JetType getTupleType(List<Annotation> annotations, List<JetType> arguments) {
if (annotations.isEmpty() && arguments.isEmpty()) { if (annotations.isEmpty() && arguments.isEmpty()) {
return getUnitType(); return getUnitType();
@@ -26,6 +26,36 @@ import java.util.*;
*/ */
public class JetTypeInferrer { public class JetTypeInferrer {
private static final JetType FORBIDDEN = new JetType() {
@NotNull
@Override
public TypeConstructor getConstructor() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<TypeProjection> getArguments() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public boolean isNullable() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public JetScope getMemberScope() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public List<Annotation> getAnnotations() {
throw new UnsupportedOperationException(); // TODO
}
};
private static final Map<IElementType, String> unaryOperationNames = ImmutableMap.<IElementType, String>builder() private static final Map<IElementType, String> unaryOperationNames = ImmutableMap.<IElementType, String>builder()
.put(JetTokens.PLUSPLUS, "inc") .put(JetTokens.PLUSPLUS, "inc")
.put(JetTokens.MINUSMINUS, "dec") .put(JetTokens.MINUSMINUS, "dec")
@@ -33,8 +63,8 @@ public class JetTypeInferrer {
.put(JetTokens.MINUS, "minus") .put(JetTokens.MINUS, "minus")
.put(JetTokens.EXCL, "not") .put(JetTokens.EXCL, "not")
.build(); .build();
private static final Map<IElementType, String> binaryOperationNames = new HashMap<IElementType, String>(); private static final Map<IElementType, String> binaryOperationNames = new HashMap<IElementType, String>();
static { static {
binaryOperationNames.put(JetTokens.MUL, "times"); binaryOperationNames.put(JetTokens.MUL, "times");
binaryOperationNames.put(JetTokens.PLUS, "plus"); binaryOperationNames.put(JetTokens.PLUS, "plus");
@@ -44,12 +74,12 @@ public class JetTypeInferrer {
binaryOperationNames.put(JetTokens.ARROW, "arrow"); binaryOperationNames.put(JetTokens.ARROW, "arrow");
binaryOperationNames.put(JetTokens.RANGE, "rangeTo"); binaryOperationNames.put(JetTokens.RANGE, "rangeTo");
} }
private static final Set<IElementType> comparisonOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.LT, JetTokens.GT, JetTokens.LTEQ, JetTokens.GTEQ)); private static final Set<IElementType> comparisonOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.LT, JetTokens.GT, JetTokens.LTEQ, JetTokens.GTEQ));
private static final Set<IElementType> equalsOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.EQEQ, JetTokens.EXCLEQ)); private static final Set<IElementType> equalsOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.EQEQ, JetTokens.EXCLEQ));
private static final Set<IElementType> inOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.IN_KEYWORD, JetTokens.NOT_IN));
private static final Set<IElementType> inOperations = new HashSet<IElementType>(Arrays.asList(JetTokens.IN_KEYWORD, JetTokens.NOT_IN));
public static final Map<IElementType, String> assignmentOperationNames = new HashMap<IElementType, String>(); public static final Map<IElementType, String> assignmentOperationNames = new HashMap<IElementType, String>();
static { static {
assignmentOperationNames.put(JetTokens.MULTEQ, "timesAssign"); assignmentOperationNames.put(JetTokens.MULTEQ, "timesAssign");
assignmentOperationNames.put(JetTokens.DIVEQ, "divAssign"); assignmentOperationNames.put(JetTokens.DIVEQ, "divAssign");
@@ -57,8 +87,8 @@ public class JetTypeInferrer {
assignmentOperationNames.put(JetTokens.PLUSEQ, "plusAssign"); assignmentOperationNames.put(JetTokens.PLUSEQ, "plusAssign");
assignmentOperationNames.put(JetTokens.MINUSEQ, "minusAssign"); assignmentOperationNames.put(JetTokens.MINUSEQ, "minusAssign");
} }
private static final Map<IElementType, IElementType> assignmentOperationCounterparts = new HashMap<IElementType, IElementType>(); private static final Map<IElementType, IElementType> assignmentOperationCounterparts = new HashMap<IElementType, IElementType>();
static { static {
assignmentOperationCounterparts.put(JetTokens.MULTEQ, JetTokens.MUL); assignmentOperationCounterparts.put(JetTokens.MULTEQ, JetTokens.MUL);
assignmentOperationCounterparts.put(JetTokens.DIVEQ, JetTokens.DIV); assignmentOperationCounterparts.put(JetTokens.DIVEQ, JetTokens.DIV);
@@ -66,7 +96,6 @@ public class JetTypeInferrer {
assignmentOperationCounterparts.put(JetTokens.PLUSEQ, JetTokens.PLUS); assignmentOperationCounterparts.put(JetTokens.PLUSEQ, JetTokens.PLUS);
assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS); assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS);
} }
private final BindingTrace trace; private final BindingTrace trace;
private final JetSemanticServices semanticServices; private final JetSemanticServices semanticServices;
private final TypeResolver typeResolver; private final TypeResolver typeResolver;
@@ -84,8 +113,8 @@ public class JetTypeInferrer {
} }
@NotNull @NotNull
public JetType safeGetType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { public JetType safeGetType(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock, @Nullable JetType expectedType) {
JetType type = getType(scope, expression, preferBlock); JetType type = getType(scope, expression, preferBlock, expectedType);
if (type != null) { if (type != null) {
return type; return type;
} }
@@ -93,12 +122,12 @@ public class JetTypeInferrer {
} }
@Nullable @Nullable
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock, @Nullable JetType expectedType) {
return new TypeInferrerVisitor(scope, preferBlock, DataFlowInfo.getEmpty()).getType(expression); return new TypeInferrerVisitor(scope, preferBlock, DataFlowInfo.getEmpty(), expectedType, null).getType(expression);
} }
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) { public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock) {
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, DataFlowInfo.getEmpty()).getType(expression); return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, DataFlowInfo.getEmpty(), null, null).getType(expression);
} }
@Nullable @Nullable
@@ -277,64 +306,112 @@ public class JetTypeInferrer {
}; };
} }
@NotNull
public JetType getFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressions(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 JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) { public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressions(outerScope, function, functionDescriptor); final JetType expectedReturnType = functionDescriptor.getUnsubstitutedReturnType();
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();
JetTypeChecker typeChecker = semanticServices.getTypeChecker();
if (!typeChecker.isSubtypeOf(actualType, expectedReturnType)) {
if (typeChecker.isConvertibleBySpecialConversion(actualType, expectedReturnType)) {
if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor())
&& element.getParent() instanceof JetReturnExpression) {
trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type Unit");
}
}
else {
if (element == function) {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null;
trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
}
else if (element instanceof JetExpression) {
JetExpression expression = (JetExpression) element;
trace.getErrorHandler().typeMismatch(expression, expectedReturnType, actualType);
}
else {
trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType);
}
}
}
}
}
private Map<JetElement, JetType> collectReturnedExpressions(JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
JetExpression bodyExpression = function.getBodyExpression(); JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null; assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace); JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
getType(functionInnerScope, bodyExpression, function.hasBlockBody()); new TypeInferrerVisitor(functionInnerScope, function.hasBlockBody(), DataFlowInfo.getEmpty(), null, expectedReturnType).getType(bodyExpression);
List<JetElement> unreachableElements = Lists.newArrayList();
flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
final Set<JetElement> rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements);
// 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,
// though it'd better be reported more specifically
for (JetElement element : rootUnreachableElements) {
trace.getErrorHandler().genericError(element.getNode(), "Unreachable code");
}
final boolean blockBody = function.hasBlockBody();
List<JetExpression> returnedExpressions = Lists.newArrayList();
flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions);
boolean nothingReturned = returnedExpressions.isEmpty();
returnedExpressions.remove(function); // This will be the only "expression" if the body is empty
if (!JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) {
trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
}
for (JetExpression returnedExpression : returnedExpressions) {
returnedExpression.accept(new JetVisitor() {
@Override
public void visitReturnExpression(JetReturnExpression expression) {
if (!blockBody) {
trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'");
}
}
@Override
public void visitExpression(JetExpression expression) {
if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')");
}
}
});
}
// Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType);
// if (typeMap.isEmpty()) {
// return; // The function returns Nothing
// }
// for (Map.Entry<JetElement, JetType> entry : typeMap.entrySet()) {
// JetType actualType = entry.getValue();
// JetElement element = entry.getKey();
// JetTypeChecker typeChecker = semanticServices.getTypeChecker();
// if (!typeChecker.isSubtypeOf(actualType, expectedReturnType)) {
// if (typeChecker.isConvertibleBySpecialConversion(actualType, expectedReturnType)) {
// if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor())
// && element.getParent() instanceof JetReturnExpression) {
// trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type Unit");
// }
// }
// else {
// if (element == function) {
// JetExpression bodyExpression = function.getBodyExpression();
// assert bodyExpression != null;
// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
// }
// else if (element instanceof JetExpression) {
// JetExpression expression = (JetExpression) element;
// trace.getErrorHandler().typeMismatch(expression, expectedReturnType, actualType);
// }
// else {
// trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType);
// }
// }
// }
// }
}
@NotNull
public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor);
Collection<JetType> types = typeMap.values();
return types.isEmpty()
? JetStandardClasses.getNothingType()
: semanticServices.getTypeChecker().commonSupertype(types);
}
private Map<JetElement, JetType> collectReturnedExpressionsWithTypes(
JetScope outerScope,
JetDeclarationWithBody function,
FunctionDescriptor functionDescriptor) {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
new TypeInferrerVisitor(functionInnerScope, function.hasBlockBody(), DataFlowInfo.getEmpty(), null, FORBIDDEN).getType(bodyExpression);
Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>(); Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
Collection<JetElement> elementsReturningUnit = new ArrayList<JetElement>(); Collection<JetElement> elementsReturningUnit = new ArrayList<JetElement>();
flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit); flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit);
Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>(); Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>();
for (JetExpression returnedExpression : returnedExpressions) { for (JetExpression returnedExpression : returnedExpressions) {
JetType cachedType = trace.getBindingContext().getExpressionType(returnedExpression);// getCachedType(returnedExpression); JetType cachedType = trace.getBindingContext().getExpressionType(returnedExpression);
trace.removeStatementRecord(returnedExpression); trace.removeStatementRecord(returnedExpression);
if (cachedType != null) { if (cachedType != null) {
typeMap.put(returnedExpression, cachedType); typeMap.put(returnedExpression, cachedType);
@@ -347,22 +424,22 @@ public class JetTypeInferrer {
} }
@Nullable @Nullable
private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull List<JetElement> block, DataFlowInfo dataFlowInfo) { private JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull List<JetElement> block, DataFlowInfo dataFlowInfo, JetType extectedReturnType) {
if (block.isEmpty()) { if (block.isEmpty()) {
return JetStandardClasses.getUnitType(); return JetStandardClasses.getUnitType();
} }
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration(); DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, trace.getErrorHandler()); WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, trace.getErrorHandler());
return getBlockReturnedTypeWithWritableScope(scope, block, dataFlowInfo); return getBlockReturnedTypeWithWritableScope(scope, block, dataFlowInfo, extectedReturnType);
} }
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, DataFlowInfo dataFlowInfo) { private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, DataFlowInfo dataFlowInfo, JetType extectedReturnType) {
if (block.isEmpty()) { if (block.isEmpty()) {
return JetStandardClasses.getUnitType(); return JetStandardClasses.getUnitType();
} }
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, dataFlowInfo); TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, dataFlowInfo, null, extectedReturnType);
JetType result = null; JetType result = null;
for (JetElement statement : block) { for (JetElement statement : block) {
@@ -378,7 +455,7 @@ public class JetTypeInferrer {
// newScope = scope; // newScope = scope;
// } // }
if (newDataFlowInfo != dataFlowInfo) {// || newScope != scope) { if (newDataFlowInfo != dataFlowInfo) {// || newScope != scope) {
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo); blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo, null, extectedReturnType);
} }
else { else {
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?
@@ -449,7 +526,7 @@ public class JetTypeInferrer {
List<JetType> valueArgumentTypes = new ArrayList<JetType>(); List<JetType> valueArgumentTypes = new ArrayList<JetType>();
for (JetExpression valueArgument : positionedValueArguments) { for (JetExpression valueArgument : positionedValueArguments) {
valueArgumentTypes.add(safeGetType(scope, valueArgument, false)); valueArgumentTypes.add(safeGetType(scope, valueArgument, false, null)); // TODO
} }
OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, valueArgumentTypes); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, valueArgumentTypes);
@@ -602,12 +679,18 @@ public class JetTypeInferrer {
protected JetType result; protected JetType result;
protected DataFlowInfo resultDataFlowInfo; protected DataFlowInfo resultDataFlowInfo;
protected final JetType extectedType;
protected final JetType extectedReturnType;
// protected WritableScope resultScope; // protected WritableScope resultScope;
private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo) { private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
this.scope = scope; this.scope = scope;
this.preferBlock = preferBlock; this.preferBlock = preferBlock;
this.dataFlowInfo = dataFlowInfo; this.dataFlowInfo = dataFlowInfo;
this.extectedType = expectedType;
this.extectedReturnType = expectedReturnType;
} }
@Nullable @Nullable
@@ -637,7 +720,7 @@ public class JetTypeInferrer {
visitor = this; visitor = this;
} }
else { else {
visitor = createNew(scope, preferBlock, dataFlowInfo); visitor = createNew(scope, preferBlock, dataFlowInfo, extectedType, extectedReturnType);
} }
JetType type = visitor.getType(expression); JetType type = visitor.getType(expression);
visitor.result = null; visitor.result = null;
@@ -645,8 +728,8 @@ public class JetTypeInferrer {
} }
@NotNull @NotNull
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) { public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
return new TypeInferrerVisitor(scope, preferBlock, dataFlowInfo); return new TypeInferrerVisitor(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
} }
@Nullable @Nullable
@@ -803,7 +886,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(), dataFlowInfo); result = getBlockReturnedType(scope, expression.getBody(), dataFlowInfo, extectedReturnType);
return; return;
} }
@@ -852,7 +935,7 @@ public class JetTypeInferrer {
writableScope.addVariableDescriptor(variableDescriptor); writableScope.addVariableDescriptor(variableDescriptor);
} }
writableScope.setThisType(receiverType); writableScope.setThisType(receiverType);
returnType = getBlockReturnedType(writableScope, expression.getBody(), dataFlowInfo); returnType = getBlockReturnedType(writableScope, expression.getBody(), dataFlowInfo, extectedReturnType);
} }
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType; JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
functionDescriptor.setReturnType(safeReturnType); functionDescriptor.setReturnType(safeReturnType);
@@ -929,10 +1012,26 @@ public class JetTypeInferrer {
@Override @Override
public void visitReturnExpression(JetReturnExpression expression) { public void visitReturnExpression(JetReturnExpression expression) {
if (extectedReturnType == FORBIDDEN) {
trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here");
return;
}
JetExpression returnedExpression = expression.getReturnedExpression(); JetExpression returnedExpression = expression.getReturnedExpression();
JetType returnedType = JetStandardClasses.getUnitType();
if (returnedExpression != null) { if (returnedExpression != null) {
getType(scope, returnedExpression, false); returnedType = getType(scope, returnedExpression, false);
}
else {
if (extectedReturnType != null && !JetStandardClasses.isUnit(extectedReturnType)) {
trace.getErrorHandler().genericError(expression.getNode(), "This function must return a value of type " + extectedReturnType);
}
}
if (extectedReturnType != null && returnedType != null) {
if (!semanticServices.getTypeChecker().isSubtypeOf(returnedType, extectedReturnType)) {
trace.getErrorHandler().typeMismatch(returnedExpression == null ? expression : returnedExpression, extectedReturnType, returnedType);
}
} }
result = JetStandardClasses.getNothingType(); result = JetStandardClasses.getNothingType();
@@ -950,7 +1049,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitTypeofExpression(JetTypeofExpression expression) { public void visitTypeofExpression(JetTypeofExpression expression) {
JetType type = safeGetType(scope, expression.getBaseExpression(), false); JetType type = safeGetType(scope, expression.getBaseExpression(), false, null); // TODO
result = semanticServices.getStandardLibrary().getTypeInfoType(type); result = semanticServices.getStandardLibrary().getTypeInfoType(type);
} }
@@ -1006,7 +1105,7 @@ public class JetTypeInferrer {
List<JetExpression> entries = expression.getEntries(); List<JetExpression> entries = expression.getEntries();
List<JetType> types = new ArrayList<JetType>(); List<JetType> types = new ArrayList<JetType>();
for (JetExpression entry : entries) { for (JetExpression entry : entries) {
types.add(safeGetType(scope, entry, false)); types.add(safeGetType(scope, entry, false, null)); // TODO
} }
// TODO : labels // TODO : labels
result = JetStandardClasses.getTupleType(types); result = JetStandardClasses.getTupleType(types);
@@ -1114,7 +1213,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitBlockExpression(JetBlockExpression expression) { public void visitBlockExpression(JetBlockExpression expression) {
result = getBlockReturnedType(scope, expression.getStatements(), dataFlowInfo); result = getBlockReturnedType(scope, expression.getStatements(), dataFlowInfo, extectedReturnType);
} }
@Override @Override
@@ -1122,7 +1221,7 @@ public class JetTypeInferrer {
// TODO :change scope according to the bound value in the when header // TODO :change scope according to the bound value in the when header
final JetExpression subjectExpression = expression.getSubjectExpression(); final JetExpression subjectExpression = expression.getSubjectExpression();
final JetType subjectType = subjectExpression != null ? safeGetType(scope, subjectExpression, false) : ErrorUtils.createErrorType("Unknown type"); final JetType subjectType = subjectExpression != null ? safeGetType(scope, subjectExpression, false, null) : ErrorUtils.createErrorType("Unknown type");
final VariableDescriptor variableDescriptor = subjectExpression != null ? getVariableDescriptorFromSimpleName(subjectExpression) : null; final VariableDescriptor variableDescriptor = subjectExpression != null ? getVariableDescriptorFromSimpleName(subjectExpression) : null;
// TODO : exhaustive patterns // TODO : exhaustive patterns
@@ -1564,7 +1663,7 @@ public class JetTypeInferrer {
if (!function.hasParameterSpecification()) { if (!function.hasParameterSpecification()) {
WritableScope writableScope = newWritableScopeImpl(); WritableScope writableScope = newWritableScopeImpl();
conditionScope = writableScope; conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo); getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo, extectedReturnType);
trace.recordBlock(function); trace.recordBlock(function);
} else { } else {
getType(scope, body, true); getType(scope, body, true);
@@ -1573,7 +1672,7 @@ public class JetTypeInferrer {
else if (body != null) { else if (body != null) {
WritableScope writableScope = newWritableScopeImpl(); WritableScope writableScope = newWritableScopeImpl();
conditionScope = writableScope; conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo); getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo, extectedReturnType);
} }
JetExpression condition = expression.getCondition(); JetExpression condition = expression.getCondition();
checkCondition(conditionScope, condition); checkCondition(conditionScope, condition);
@@ -1588,7 +1687,7 @@ public class JetTypeInferrer {
return newWritableScopeImpl(scope); return newWritableScopeImpl(scope);
} }
private WritableScopeImpl newWritableScopeImpl(JetScope scopeToExtend) { protected WritableScopeImpl newWritableScopeImpl(JetScope scopeToExtend) {
return new WritableScopeImpl(scopeToExtend, scopeToExtend.getContainingDeclaration(), trace.getErrorHandler()); return new WritableScopeImpl(scopeToExtend, scopeToExtend.getContainingDeclaration(), trace.getErrorHandler());
} }
@@ -1722,7 +1821,7 @@ public class JetTypeInferrer {
// TODO : functions as values // TODO : functions as values
JetExpression selectorExpression = expression.getSelectorExpression(); JetExpression selectorExpression = expression.getSelectorExpression();
JetExpression receiverExpression = expression.getReceiverExpression(); JetExpression receiverExpression = expression.getReceiverExpression();
JetType receiverType = new TypeInferrerVisitorWithNamespaces(scope, false, dataFlowInfo).getType(receiverExpression); JetType receiverType = new TypeInferrerVisitorWithNamespaces(scope, false, dataFlowInfo, null, null).getType(receiverExpression);
if (receiverType != null) { if (receiverType != null) {
ErrorHandlerWithRegions errorHandler = trace.getErrorHandler(); ErrorHandlerWithRegions errorHandler = trace.getErrorHandler();
errorHandler.openRegion(); errorHandler.openRegion();
@@ -2099,7 +2198,7 @@ public class JetTypeInferrer {
@Nullable @Nullable
protected List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) { protected List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) {
List<JetType> argumentTypes = new ArrayList<JetType>(); List<JetType> argumentTypes = new ArrayList<JetType>();
TypeInferrerVisitor typeInferrerVisitor = new TypeInferrerVisitor(scope, false, dataFlowInfo); TypeInferrerVisitor typeInferrerVisitor = new TypeInferrerVisitor(scope, false, dataFlowInfo, null, null);
for (JetExpression indexExpression : indexExpressions) { for (JetExpression indexExpression : indexExpressions) {
JetType type = typeInferrerVisitor.getType(indexExpression); JetType type = typeInferrerVisitor.getType(indexExpression);
if (type == null) { if (type == null) {
@@ -2190,8 +2289,8 @@ public class JetTypeInferrer {
} }
private class TypeInferrerVisitorWithNamespaces extends TypeInferrerVisitor { private class TypeInferrerVisitorWithNamespaces extends TypeInferrerVisitor {
private TypeInferrerVisitorWithNamespaces(@NotNull JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) { private TypeInferrerVisitorWithNamespaces(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
super(scope, preferBlock, dataFlowInfo); super(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
} }
@Override @Override
@@ -2201,8 +2300,8 @@ public class JetTypeInferrer {
@NotNull @NotNull
@Override @Override
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) { public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, dataFlowInfo); return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
} }
@Override @Override
@@ -2221,8 +2320,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, DataFlowInfo dataFlowInfo) { public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
super(scope, preferBlock, dataFlowInfo); super(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
this.scope = scope; this.scope = scope;
} }
@@ -2356,8 +2455,9 @@ public class JetTypeInferrer {
@NotNull @NotNull
@Override @Override
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) { public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
return new TypeInferrerVisitorWithWritableScope(new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()), preferBlock, dataFlowInfo); WritableScopeImpl writableScope = newWritableScopeImpl(scope);
return new TypeInferrerVisitorWithWritableScope(writableScope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
} }
} }
} }
+1 -1
View File
@@ -8,7 +8,7 @@ fun <T, E> T.foo(x : E, y : A) : T {
this<warning>?.</warning>minus<T>(this) this<warning>?.</warning>minus<T>(this)
this return this
} }
class A class A
+19 -5
View File
@@ -5,6 +5,19 @@ fun unitEmpty() : Unit {}
fun unitEmptyReturn() : Unit {return} fun unitEmptyReturn() : Unit {return}
fun unitIntReturn() : Unit {return <error>1</error>} fun unitIntReturn() : Unit {return <error>1</error>}
fun unitUnitReturn() : Unit {return ()} fun unitUnitReturn() : Unit {return ()}
fun test1() : Any = {<error>return</error>}
fun test2() : Any = @a {return@a 1}
fun test3() : Any { <error>return</error> }
fun foo(expr: StringBuilder): Int {
val c = 'a'
when(c) {
'\0' => throw Exception("zero")
else => throw Exception("nonzero" + c)
}
}
fun unitShort() : Unit = () fun unitShort() : Unit = ()
fun unitShortConv() : Unit = 1 fun unitShortConv() : Unit = 1
fun unitShortNull() : Unit = null fun unitShortNull() : Unit = null
@@ -13,7 +26,8 @@ fun intEmpty() : Int <error>{}</error>
fun intShortInfer() = 1 fun intShortInfer() = 1
fun intShort() : Int = 1 fun intShort() : Int = 1
//fun intBlockInfer() {1} //fun intBlockInfer() {1}
fun intBlock() : Int {1} fun intBlock() : Int {return 1}
fun intBlock() : Int {<error>1</error>}
fun blockReturnUnitMismatch() : Int {<error>return</error>} fun blockReturnUnitMismatch() : Int {<error>return</error>}
fun blockReturnValueTypeMismatch() : Int {return <error>3.4</error>} fun blockReturnValueTypeMismatch() : Int {return <error>3.4</error>}
@@ -40,7 +54,7 @@ fun blockAndAndMismatch() : Int {
<error>(return <error>true</error>) || (return <error>false</error>)</error> <error>(return <error>true</error>) || (return <error>false</error>)</error>
} }
fun blockReturnValueTypeMatch() : Int { fun blockReturnValueTypeMatch() : Int {
return if (1 > 2) <error>1.0</error> else <error>2.0</error> return <error>if (1 > 2) 1.0 else 2.0</error>
} }
fun blockReturnValueTypeMatch() : Int { fun blockReturnValueTypeMatch() : Int {
return <error>if (1 > 2) 1</error> return <error>if (1 > 2) 1</error>
@@ -79,7 +93,7 @@ fun blockReturnValueTypeMatch() : Int {
<error>1.0</error></error> <error>1.0</error></error>
} }
fun blockReturnValueTypeMatch() : Int { fun blockReturnValueTypeMatch() : Int {
<error>if (1 > 2) return <error>if (1 > 2)
1</error> 1</error>
} }
fun blockReturnValueTypeMatch() : Int { fun blockReturnValueTypeMatch() : Int {
@@ -88,6 +102,6 @@ fun blockReturnValueTypeMatch() : Int {
} }
fun blockReturnValueTypeMatch() : Int { fun blockReturnValueTypeMatch() : Int {
if (1 > 2) if (1 > 2)
1 return 1
else <error>1.0</error> else return <error>1.0</error>
} }
+1 -1
View File
@@ -29,7 +29,7 @@ namespace closures {
val y = this@A : A val y = this@A : A
val z = this : B val z = this : B
val Int.xx = this : Int val Int.xx = this : Int
fun Char.xx() { fun Char.xx() : Any {
this : Char this : Char
val a = {Double.() => this : Double + this@xx : Char} val a = {Double.() => this : Double + this@xx : Char}
val b = @a{Double.() => this@a : Double + this@xx : Char} val b = @a{Double.() => this@a : Double + this@xx : Char}
+11 -11
View File
@@ -58,7 +58,7 @@ fun t4break(a : Boolean) : Int {
break break
} }
while (<error>a</error>) while (<error>a</error>)
1 return 1
} }
fun t5() : Int { fun t5() : Int {
@@ -67,7 +67,7 @@ fun t5() : Int {
<error>2</error> <error>2</error>
} }
while (<error>1 > 2</error>) while (<error>1 > 2</error>)
<error>1</error> <error>return 1</error>
} }
fun t6() : Int { fun t6() : Int {
@@ -75,7 +75,7 @@ fun t6() : Int {
return 1 return 1
<error>2</error> <error>2</error>
} }
1 return 1
} }
fun t6break() : Int { fun t6break() : Int {
@@ -83,7 +83,7 @@ fun t6break() : Int {
break break
<error>2</error> <error>2</error>
} }
1 return 1
} }
fun t7(b : Int) : Int { fun t7(b : Int) : Int {
@@ -91,7 +91,7 @@ fun t7(b : Int) : Int {
return 1 return 1
<error>2</error> <error>2</error>
} }
1 return 1
} }
fun t7break(b : Int) : Int { fun t7break(b : Int) : Int {
@@ -99,7 +99,7 @@ fun t7break(b : Int) : Int {
return 1 return 1
<error>2</error> <error>2</error>
} }
1 return 1
} }
fun t7() : Int { fun t7() : Int {
@@ -110,7 +110,7 @@ fun t7() : Int {
catch (e : Any) { catch (e : Any) {
2 2
} }
1 // this is OK, like in Java return 1 // this is OK, like in Java
} }
fun t8() : Int { fun t8() : Int {
@@ -122,24 +122,24 @@ fun t8() : Int {
return 1 return 1
<error>2</error> <error>2</error>
} }
<error>1</error> <error>return 1</error>
} }
fun blockAndAndMismatch() : Boolean { fun blockAndAndMismatch() : Boolean {
<error>(return true) || (return false)</error> <error>(return true) || (return false)</error>
<error>true</error> <error>return true</error>
} }
fun tf() : Int { fun tf() : Int {
try {<error>return 1</error>} finally{return 1} try {<error>return 1</error>} finally{return 1}
<error>1</error> <error>return 1</error>
} }
fun failtest(a : Int) : Int { fun failtest(a : Int) : Int {
<error>if (fail() || true) { <error>if (fail() || true) {
}</error> }</error>
<error>1</error> <error>return 1</error>
} }
fun foo(a : Nothing) : Unit { fun foo(a : Nothing) : Unit {
+1 -1
View File
@@ -16,7 +16,7 @@ fun foo() : Int {
<warning>?.</warning>equals(1) => 1 <warning>?.</warning>equals(1) => 1
else => 1 else => 1
} }
when (<warning>x</warning>?:null) { return when (<warning>x</warning>?:null) {
<error>.</error>equals(1) => 1 <error>.</error>equals(1) => 1
?.equals(1).equals(2) => 1 ?.equals(1).equals(2) => 1
} }
@@ -14,9 +14,9 @@ class Test() {
val c3 : Int val c3 : Int
<info>get</info>() { return 1 } <info>get</info>() { return 1 }
val c4 : Int val c4 : Int
<info>get</info>() { 1 } <info>get</info>() = 1
val <info>c5</info> : Int val <info>c5</info> : Int
<info>get</info>() { $c5 + 1 } <info>get</info>() = $c5 + 1
<info>abstract</info> var y : Int <info>abstract</info> var y : Int
<info>abstract</info> var y1 : Int <info>get</info> <info>abstract</info> var y1 : Int <info>get</info>
@@ -29,5 +29,5 @@ fun box() : String {
val p4 = P4(240, y) val p4 = P4(240, y)
if (p4.x + p4.y != 239) return "FAIL #7" if (p4.x + p4.y != 239) return "FAIL #7"
"OK" return "OK"
} }
@@ -5,5 +5,5 @@ fun concat(l: List<String>): String? {
for(s in l) { for(s in l) {
sb.append(s) sb.append(s)
} }
sb.toString() return sb.toString()
} }
@@ -3,5 +3,5 @@ fun concat(l: Array<String>): String? {
for(s in l) { for(s in l) {
sb.append(s) sb.append(s)
} }
sb.toString() return sb.toString()
} }
+1 -1
View File
@@ -2,5 +2,5 @@ fun f(a:Int) : Int {
val x = 42 val x = 42
val y = 50 val y = 50
y return y
} }
@@ -57,7 +57,7 @@ public class PatternMatchingTest extends CodegenTestCase {
} }
public void testNoReturnType() throws Exception { public void testNoReturnType() throws Exception {
loadText("fun foo(x: String) = when(x) { is * => return \"x\" }"); loadText("fun foo(x: String) = when(x) { is * => \"x\" }");
Method foo = generateFunction(); Method foo = generateFunction();
assertEquals("x", foo.invoke(null, "")); assertEquals("x", foo.invoke(null, ""));
} }
@@ -493,14 +493,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(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).getType(classDefinitions.BASIC_SCOPE, jetExpression, false); JetType type = semanticServices.getTypeInferrer(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).getType(classDefinitions.BASIC_SCOPE, jetExpression, false, null);
assertTrue(type + " != " + expectedType, type.equals(expectedType)); assertTrue(type + " != " + expectedType, type.equals(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(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false); JetType type = semanticServices.getTypeInferrer(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).safeGetType(classDefinitions.BASIC_SCOPE, jetExpression, false, null);
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type)); assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
} }
@@ -523,7 +523,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(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).getType(scope, jetExpression, false); JetType type = semanticServices.getTypeInferrer(JetTestUtils.DUMMY, JetFlowInformationProvider.NONE).getType(scope, jetExpression, false, null);
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr); JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
assertEquals(expectedType, type); assertEquals(expectedType, type);
} }
@@ -613,4 +613,4 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
} }
}; };
} }
} }