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:
@@ -17,6 +17,11 @@ public interface JetFlowInformationProvider {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
@@ -40,6 +45,11 @@ public interface JetFlowInformationProvider {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
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(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetExpression> returnedExpressions,
|
||||
@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(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetElement> unreachableElements);
|
||||
|
||||
@@ -197,7 +197,7 @@ public class ClassDescriptorResolver {
|
||||
@Override
|
||||
protected JetType compute() {
|
||||
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>() {
|
||||
@Override
|
||||
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) {
|
||||
@@ -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 Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||
@@ -779,6 +779,45 @@ public class ClassDescriptorResolver {
|
||||
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
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -33,7 +31,6 @@ public class TopDownAnalyzer {
|
||||
private final Map<JetDeclaration, ConstructorDescriptor> constructors = Maps.newLinkedHashMap();
|
||||
private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>();
|
||||
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 JetSemanticServices semanticServices;
|
||||
@@ -572,7 +569,7 @@ public class TopDownAnalyzer {
|
||||
JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
if (delegateExpression != null) {
|
||||
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());
|
||||
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
|
||||
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
|
||||
@@ -644,7 +641,7 @@ public class TopDownAnalyzer {
|
||||
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
|
||||
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
|
||||
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
|
||||
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true);
|
||||
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true, null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -730,7 +727,7 @@ public class TopDownAnalyzer {
|
||||
JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(declaration, bodyExpression);
|
||||
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) {
|
||||
JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15
|
||||
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;
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
@@ -905,20 +902,6 @@ public class TopDownAnalyzer {
|
||||
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(trace, flowInformationProvider);
|
||||
|
||||
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;
|
||||
|
||||
@@ -274,6 +274,11 @@ public class JetStandardClasses {
|
||||
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) {
|
||||
if (annotations.isEmpty() && arguments.isEmpty()) {
|
||||
return getUnitType();
|
||||
|
||||
@@ -26,6 +26,36 @@ import java.util.*;
|
||||
*/
|
||||
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()
|
||||
.put(JetTokens.PLUSPLUS, "inc")
|
||||
.put(JetTokens.MINUSMINUS, "dec")
|
||||
@@ -33,8 +63,8 @@ public class JetTypeInferrer {
|
||||
.put(JetTokens.MINUS, "minus")
|
||||
.put(JetTokens.EXCL, "not")
|
||||
.build();
|
||||
|
||||
private static final Map<IElementType, String> binaryOperationNames = new HashMap<IElementType, String>();
|
||||
|
||||
static {
|
||||
binaryOperationNames.put(JetTokens.MUL, "times");
|
||||
binaryOperationNames.put(JetTokens.PLUS, "plus");
|
||||
@@ -44,12 +74,12 @@ public class JetTypeInferrer {
|
||||
binaryOperationNames.put(JetTokens.ARROW, "arrow");
|
||||
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> 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>();
|
||||
|
||||
static {
|
||||
assignmentOperationNames.put(JetTokens.MULTEQ, "timesAssign");
|
||||
assignmentOperationNames.put(JetTokens.DIVEQ, "divAssign");
|
||||
@@ -57,8 +87,8 @@ public class JetTypeInferrer {
|
||||
assignmentOperationNames.put(JetTokens.PLUSEQ, "plusAssign");
|
||||
assignmentOperationNames.put(JetTokens.MINUSEQ, "minusAssign");
|
||||
}
|
||||
|
||||
private static final Map<IElementType, IElementType> assignmentOperationCounterparts = new HashMap<IElementType, IElementType>();
|
||||
|
||||
static {
|
||||
assignmentOperationCounterparts.put(JetTokens.MULTEQ, JetTokens.MUL);
|
||||
assignmentOperationCounterparts.put(JetTokens.DIVEQ, JetTokens.DIV);
|
||||
@@ -66,7 +96,6 @@ public class JetTypeInferrer {
|
||||
assignmentOperationCounterparts.put(JetTokens.PLUSEQ, JetTokens.PLUS);
|
||||
assignmentOperationCounterparts.put(JetTokens.MINUSEQ, JetTokens.MINUS);
|
||||
}
|
||||
|
||||
private final BindingTrace trace;
|
||||
private final JetSemanticServices semanticServices;
|
||||
private final TypeResolver typeResolver;
|
||||
@@ -84,8 +113,8 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType safeGetType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
|
||||
JetType type = getType(scope, expression, preferBlock);
|
||||
public JetType safeGetType(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock, @Nullable JetType expectedType) {
|
||||
JetType type = getType(scope, expression, preferBlock, expectedType);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
@@ -93,12 +122,12 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
|
||||
return new TypeInferrerVisitor(scope, preferBlock, DataFlowInfo.getEmpty()).getType(expression);
|
||||
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock, @Nullable JetType expectedType) {
|
||||
return new TypeInferrerVisitor(scope, preferBlock, DataFlowInfo.getEmpty(), expectedType, null).getType(expression);
|
||||
}
|
||||
|
||||
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, final boolean preferBlock) {
|
||||
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, DataFlowInfo.getEmpty()).getType(expression);
|
||||
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression, boolean preferBlock) {
|
||||
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, DataFlowInfo.getEmpty(), null, null).getType(expression);
|
||||
}
|
||||
|
||||
@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) {
|
||||
Map<JetElement, JetType> typeMap = collectReturnedExpressions(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();
|
||||
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) {
|
||||
final JetType expectedReturnType = functionDescriptor.getUnsubstitutedReturnType();
|
||||
JetExpression bodyExpression = function.getBodyExpression();
|
||||
assert bodyExpression != null;
|
||||
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<JetElement> elementsReturningUnit = new ArrayList<JetElement>();
|
||||
flowInformationProvider.collectReturnedInformation(function.asElement(), returnedExpressions, elementsReturningUnit);
|
||||
Map<JetElement,JetType> typeMap = new HashMap<JetElement, JetType>();
|
||||
for (JetExpression returnedExpression : returnedExpressions) {
|
||||
JetType cachedType = trace.getBindingContext().getExpressionType(returnedExpression);// getCachedType(returnedExpression);
|
||||
JetType cachedType = trace.getBindingContext().getExpressionType(returnedExpression);
|
||||
trace.removeStatementRecord(returnedExpression);
|
||||
if (cachedType != null) {
|
||||
typeMap.put(returnedExpression, cachedType);
|
||||
@@ -347,22 +424,22 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
@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()) {
|
||||
return JetStandardClasses.getUnitType();
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
|
||||
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()) {
|
||||
return JetStandardClasses.getUnitType();
|
||||
}
|
||||
|
||||
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, dataFlowInfo);
|
||||
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, dataFlowInfo, null, extectedReturnType);
|
||||
|
||||
JetType result = null;
|
||||
for (JetElement statement : block) {
|
||||
@@ -378,7 +455,7 @@ public class JetTypeInferrer {
|
||||
// newScope = scope;
|
||||
// }
|
||||
if (newDataFlowInfo != dataFlowInfo) {// || newScope != scope) {
|
||||
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo);
|
||||
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo, null, extectedReturnType);
|
||||
}
|
||||
else {
|
||||
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>();
|
||||
for (JetExpression valueArgument : positionedValueArguments) {
|
||||
valueArgumentTypes.add(safeGetType(scope, valueArgument, false));
|
||||
valueArgumentTypes.add(safeGetType(scope, valueArgument, false, null)); // TODO
|
||||
}
|
||||
|
||||
OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, valueArgumentTypes);
|
||||
@@ -602,12 +679,18 @@ public class JetTypeInferrer {
|
||||
|
||||
protected JetType result;
|
||||
protected DataFlowInfo resultDataFlowInfo;
|
||||
|
||||
protected final JetType extectedType;
|
||||
protected final JetType extectedReturnType;
|
||||
|
||||
// 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.preferBlock = preferBlock;
|
||||
this.dataFlowInfo = dataFlowInfo;
|
||||
this.extectedType = expectedType;
|
||||
this.extectedReturnType = expectedReturnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -637,7 +720,7 @@ public class JetTypeInferrer {
|
||||
visitor = this;
|
||||
}
|
||||
else {
|
||||
visitor = createNew(scope, preferBlock, dataFlowInfo);
|
||||
visitor = createNew(scope, preferBlock, dataFlowInfo, extectedType, extectedReturnType);
|
||||
}
|
||||
JetType type = visitor.getType(expression);
|
||||
visitor.result = null;
|
||||
@@ -645,8 +728,8 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
|
||||
return new TypeInferrerVisitor(scope, preferBlock, dataFlowInfo);
|
||||
public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
|
||||
return new TypeInferrerVisitor(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -803,7 +886,7 @@ public class JetTypeInferrer {
|
||||
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
|
||||
if (preferBlock && !expression.hasParameterSpecification()) {
|
||||
trace.recordBlock(expression);
|
||||
result = getBlockReturnedType(scope, expression.getBody(), dataFlowInfo);
|
||||
result = getBlockReturnedType(scope, expression.getBody(), dataFlowInfo, extectedReturnType);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -852,7 +935,7 @@ public class JetTypeInferrer {
|
||||
writableScope.addVariableDescriptor(variableDescriptor);
|
||||
}
|
||||
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;
|
||||
functionDescriptor.setReturnType(safeReturnType);
|
||||
@@ -929,10 +1012,26 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
public void visitReturnExpression(JetReturnExpression expression) {
|
||||
if (extectedReturnType == FORBIDDEN) {
|
||||
trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here");
|
||||
return;
|
||||
}
|
||||
JetExpression returnedExpression = expression.getReturnedExpression();
|
||||
|
||||
JetType returnedType = JetStandardClasses.getUnitType();
|
||||
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();
|
||||
@@ -950,7 +1049,7 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1006,7 +1105,7 @@ public class JetTypeInferrer {
|
||||
List<JetExpression> entries = expression.getEntries();
|
||||
List<JetType> types = new ArrayList<JetType>();
|
||||
for (JetExpression entry : entries) {
|
||||
types.add(safeGetType(scope, entry, false));
|
||||
types.add(safeGetType(scope, entry, false, null)); // TODO
|
||||
}
|
||||
// TODO : labels
|
||||
result = JetStandardClasses.getTupleType(types);
|
||||
@@ -1114,7 +1213,7 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
public void visitBlockExpression(JetBlockExpression expression) {
|
||||
result = getBlockReturnedType(scope, expression.getStatements(), dataFlowInfo);
|
||||
result = getBlockReturnedType(scope, expression.getStatements(), dataFlowInfo, extectedReturnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1122,7 +1221,7 @@ public class JetTypeInferrer {
|
||||
// TODO :change scope according to the bound value in the when header
|
||||
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;
|
||||
|
||||
// TODO : exhaustive patterns
|
||||
@@ -1564,7 +1663,7 @@ public class JetTypeInferrer {
|
||||
if (!function.hasParameterSpecification()) {
|
||||
WritableScope writableScope = newWritableScopeImpl();
|
||||
conditionScope = writableScope;
|
||||
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo);
|
||||
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo, extectedReturnType);
|
||||
trace.recordBlock(function);
|
||||
} else {
|
||||
getType(scope, body, true);
|
||||
@@ -1573,7 +1672,7 @@ public class JetTypeInferrer {
|
||||
else if (body != null) {
|
||||
WritableScope writableScope = newWritableScopeImpl();
|
||||
conditionScope = writableScope;
|
||||
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo);
|
||||
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo, extectedReturnType);
|
||||
}
|
||||
JetExpression condition = expression.getCondition();
|
||||
checkCondition(conditionScope, condition);
|
||||
@@ -1588,7 +1687,7 @@ public class JetTypeInferrer {
|
||||
return newWritableScopeImpl(scope);
|
||||
}
|
||||
|
||||
private WritableScopeImpl newWritableScopeImpl(JetScope scopeToExtend) {
|
||||
protected WritableScopeImpl newWritableScopeImpl(JetScope scopeToExtend) {
|
||||
return new WritableScopeImpl(scopeToExtend, scopeToExtend.getContainingDeclaration(), trace.getErrorHandler());
|
||||
}
|
||||
|
||||
@@ -1722,7 +1821,7 @@ public class JetTypeInferrer {
|
||||
// TODO : functions as values
|
||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||
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) {
|
||||
ErrorHandlerWithRegions errorHandler = trace.getErrorHandler();
|
||||
errorHandler.openRegion();
|
||||
@@ -2099,7 +2198,7 @@ public class JetTypeInferrer {
|
||||
@Nullable
|
||||
protected List<JetType> getTypes(JetScope scope, List<JetExpression> indexExpressions) {
|
||||
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) {
|
||||
JetType type = typeInferrerVisitor.getType(indexExpression);
|
||||
if (type == null) {
|
||||
@@ -2190,8 +2289,8 @@ public class JetTypeInferrer {
|
||||
}
|
||||
|
||||
private class TypeInferrerVisitorWithNamespaces extends TypeInferrerVisitor {
|
||||
private TypeInferrerVisitorWithNamespaces(@NotNull JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
|
||||
super(scope, preferBlock, dataFlowInfo);
|
||||
private TypeInferrerVisitorWithNamespaces(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
|
||||
super(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2201,8 +2300,8 @@ public class JetTypeInferrer {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
|
||||
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, dataFlowInfo);
|
||||
public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
|
||||
return new TypeInferrerVisitorWithNamespaces(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2221,8 +2320,8 @@ public class JetTypeInferrer {
|
||||
private class TypeInferrerVisitorWithWritableScope extends TypeInferrerVisitor {
|
||||
private final WritableScope scope;
|
||||
|
||||
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
|
||||
super(scope, preferBlock, dataFlowInfo);
|
||||
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
|
||||
super(scope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
@@ -2356,8 +2455,9 @@ public class JetTypeInferrer {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
|
||||
return new TypeInferrerVisitorWithWritableScope(new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()), preferBlock, dataFlowInfo);
|
||||
public TypeInferrerVisitor createNew(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo, @Nullable JetType expectedType, @Nullable JetType expectedReturnType) {
|
||||
WritableScopeImpl writableScope = newWritableScopeImpl(scope);
|
||||
return new TypeInferrerVisitorWithWritableScope(writableScope, preferBlock, dataFlowInfo, expectedType, expectedReturnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ fun <T, E> T.foo(x : E, y : A) : T {
|
||||
|
||||
this<warning>?.</warning>minus<T>(this)
|
||||
|
||||
this
|
||||
return this
|
||||
}
|
||||
|
||||
class A
|
||||
|
||||
@@ -5,6 +5,19 @@ fun unitEmpty() : Unit {}
|
||||
fun unitEmptyReturn() : Unit {return}
|
||||
fun unitIntReturn() : Unit {return <error>1</error>}
|
||||
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 unitShortConv() : Unit = 1
|
||||
fun unitShortNull() : Unit = null
|
||||
@@ -13,7 +26,8 @@ fun intEmpty() : Int <error>{}</error>
|
||||
fun intShortInfer() = 1
|
||||
fun intShort() : Int = 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 blockReturnValueTypeMismatch() : Int {return <error>3.4</error>}
|
||||
@@ -40,7 +54,7 @@ fun blockAndAndMismatch() : Int {
|
||||
<error>(return <error>true</error>) || (return <error>false</error>)</error>
|
||||
}
|
||||
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 {
|
||||
return <error>if (1 > 2) 1</error>
|
||||
@@ -79,7 +93,7 @@ fun blockReturnValueTypeMatch() : Int {
|
||||
<error>1.0</error></error>
|
||||
}
|
||||
fun blockReturnValueTypeMatch() : Int {
|
||||
<error>if (1 > 2)
|
||||
return <error>if (1 > 2)
|
||||
1</error>
|
||||
}
|
||||
fun blockReturnValueTypeMatch() : Int {
|
||||
@@ -88,6 +102,6 @@ fun blockReturnValueTypeMatch() : Int {
|
||||
}
|
||||
fun blockReturnValueTypeMatch() : Int {
|
||||
if (1 > 2)
|
||||
1
|
||||
else <error>1.0</error>
|
||||
return 1
|
||||
else return <error>1.0</error>
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace closures {
|
||||
val y = this@A : A
|
||||
val z = this : B
|
||||
val Int.xx = this : Int
|
||||
fun Char.xx() {
|
||||
fun Char.xx() : Any {
|
||||
this : Char
|
||||
val a = {Double.() => this : Double + this@xx : Char}
|
||||
val b = @a{Double.() => this@a : Double + this@xx : Char}
|
||||
|
||||
@@ -58,7 +58,7 @@ fun t4break(a : Boolean) : Int {
|
||||
break
|
||||
}
|
||||
while (<error>a</error>)
|
||||
1
|
||||
return 1
|
||||
}
|
||||
|
||||
fun t5() : Int {
|
||||
@@ -67,7 +67,7 @@ fun t5() : Int {
|
||||
<error>2</error>
|
||||
}
|
||||
while (<error>1 > 2</error>)
|
||||
<error>1</error>
|
||||
<error>return 1</error>
|
||||
}
|
||||
|
||||
fun t6() : Int {
|
||||
@@ -75,7 +75,7 @@ fun t6() : Int {
|
||||
return 1
|
||||
<error>2</error>
|
||||
}
|
||||
1
|
||||
return 1
|
||||
}
|
||||
|
||||
fun t6break() : Int {
|
||||
@@ -83,7 +83,7 @@ fun t6break() : Int {
|
||||
break
|
||||
<error>2</error>
|
||||
}
|
||||
1
|
||||
return 1
|
||||
}
|
||||
|
||||
fun t7(b : Int) : Int {
|
||||
@@ -91,7 +91,7 @@ fun t7(b : Int) : Int {
|
||||
return 1
|
||||
<error>2</error>
|
||||
}
|
||||
1
|
||||
return 1
|
||||
}
|
||||
|
||||
fun t7break(b : Int) : Int {
|
||||
@@ -99,7 +99,7 @@ fun t7break(b : Int) : Int {
|
||||
return 1
|
||||
<error>2</error>
|
||||
}
|
||||
1
|
||||
return 1
|
||||
}
|
||||
|
||||
fun t7() : Int {
|
||||
@@ -110,7 +110,7 @@ fun t7() : Int {
|
||||
catch (e : Any) {
|
||||
2
|
||||
}
|
||||
1 // this is OK, like in Java
|
||||
return 1 // this is OK, like in Java
|
||||
}
|
||||
|
||||
fun t8() : Int {
|
||||
@@ -122,24 +122,24 @@ fun t8() : Int {
|
||||
return 1
|
||||
<error>2</error>
|
||||
}
|
||||
<error>1</error>
|
||||
<error>return 1</error>
|
||||
}
|
||||
|
||||
fun blockAndAndMismatch() : Boolean {
|
||||
<error>(return true) || (return false)</error>
|
||||
<error>true</error>
|
||||
<error>return true</error>
|
||||
}
|
||||
|
||||
fun tf() : Int {
|
||||
try {<error>return 1</error>} finally{return 1}
|
||||
<error>1</error>
|
||||
<error>return 1</error>
|
||||
}
|
||||
|
||||
fun failtest(a : Int) : Int {
|
||||
<error>if (fail() || true) {
|
||||
|
||||
}</error>
|
||||
<error>1</error>
|
||||
<error>return 1</error>
|
||||
}
|
||||
|
||||
fun foo(a : Nothing) : Unit {
|
||||
|
||||
@@ -16,7 +16,7 @@ fun foo() : Int {
|
||||
<warning>?.</warning>equals(1) => 1
|
||||
else => 1
|
||||
}
|
||||
when (<warning>x</warning>?:null) {
|
||||
return when (<warning>x</warning>?:null) {
|
||||
<error>.</error>equals(1) => 1
|
||||
?.equals(1).equals(2) => 1
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ class Test() {
|
||||
val c3 : Int
|
||||
<info>get</info>() { return 1 }
|
||||
val c4 : Int
|
||||
<info>get</info>() { 1 }
|
||||
<info>get</info>() = 1
|
||||
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 y1 : Int <info>get</info>
|
||||
|
||||
@@ -29,5 +29,5 @@ fun box() : String {
|
||||
val p4 = P4(240, y)
|
||||
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) {
|
||||
sb.append(s)
|
||||
}
|
||||
sb.toString()
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ fun concat(l: Array<String>): String? {
|
||||
for(s in l) {
|
||||
sb.append(s)
|
||||
}
|
||||
sb.toString()
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ fun f(a:Int) : Int {
|
||||
val x = 42
|
||||
val y = 50
|
||||
|
||||
y
|
||||
return y
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class PatternMatchingTest extends CodegenTestCase {
|
||||
}
|
||||
|
||||
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();
|
||||
assertEquals("x", foo.invoke(null, ""));
|
||||
}
|
||||
|
||||
@@ -493,14 +493,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
private void assertType(String expression, JetType expectedType) {
|
||||
Project project = getProject();
|
||||
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));
|
||||
}
|
||||
|
||||
private void assertErrorType(String expression) {
|
||||
Project project = getProject();
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
|
||||
Project project = getProject();
|
||||
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);
|
||||
assertEquals(expectedType, type);
|
||||
}
|
||||
@@ -613,4 +613,4 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user