Added return label check
This commit is contained in:
@@ -488,15 +488,20 @@ public class JetControlFlowProcessor {
|
||||
String labelName = expression.getLabelName();
|
||||
assert labelName != null;
|
||||
PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement);
|
||||
assert labeledElement instanceof JetElement;
|
||||
subroutine = (JetElement) labeledElement;
|
||||
if (labeledElement != null) {
|
||||
assert labeledElement instanceof JetElement;
|
||||
subroutine = (JetElement) labeledElement;
|
||||
}
|
||||
else {
|
||||
subroutine = null;
|
||||
}
|
||||
//subroutine = resolveLabel(labelName, labelElement, true);
|
||||
}
|
||||
else {
|
||||
subroutine = builder.getCurrentSubroutine();
|
||||
// TODO : a context check
|
||||
}
|
||||
if (subroutine != null) {
|
||||
if (subroutine instanceof JetFunction || subroutine instanceof JetFunctionLiteralExpression) {
|
||||
if (returnedExpression == null) {
|
||||
builder.returnNoValue(expression, subroutine);
|
||||
}
|
||||
@@ -504,6 +509,11 @@ public class JetControlFlowProcessor {
|
||||
builder.returnValue(expression, subroutine);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (labelElement != null) {
|
||||
trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -222,6 +222,7 @@ public interface Errors {
|
||||
SimpleDiagnosticFactory VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION = SimpleDiagnosticFactory.create(ERROR, "A type annotation is required on a value parameter");
|
||||
SimpleDiagnosticFactory BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = SimpleDiagnosticFactory.create(ERROR, "'break' and 'continue' are only allowed inside a loop");
|
||||
ParameterizedDiagnosticFactory1<String> NOT_A_LOOP_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not denote a loop");
|
||||
ParameterizedDiagnosticFactory1<String> NOT_A_RETURN_LABEL = ParameterizedDiagnosticFactory1.create(ERROR, "The label ''{0}'' does not reference to a context from which we can return");
|
||||
|
||||
SimpleDiagnosticFactory ANONYMOUS_INITIALIZER_WITHOUT_CONSTRUCTOR = SimpleDiagnosticFactory.create(ERROR, "Anonymous initializers are only allowed in the presence of a primary constructor");
|
||||
SimpleDiagnosticFactory NULLABLE_SUPERTYPE = SimpleDiagnosticFactory.create(ERROR, "A supertype cannot be nullable");
|
||||
|
||||
@@ -295,7 +295,7 @@ public class JetTypeInferrer {
|
||||
|
||||
private void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) {
|
||||
JetExpression bodyExpression = function.getBodyExpression();
|
||||
assert bodyExpression != null;
|
||||
if (bodyExpression == null) return;
|
||||
|
||||
final boolean blockBody = function.hasBlockBody();
|
||||
final TypeInferenceContext context =
|
||||
@@ -1167,12 +1167,7 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
public JetType visitReturnExpression(JetReturnExpression expression, TypeInferenceContext context) {
|
||||
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||
if (labelElement != null) {
|
||||
String labelName = expression.getLabelName();
|
||||
assert labelName != null;
|
||||
labelsResolver.resolveLabel(labelName, labelElement, true, context);
|
||||
}
|
||||
labelsResolver.recordLabel(expression, context);
|
||||
if (context.expectedReturnType == FORBIDDEN) {
|
||||
// context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here");
|
||||
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
|
||||
@@ -1195,13 +1190,13 @@ public class JetTypeInferrer {
|
||||
|
||||
@Override
|
||||
public JetType visitBreakExpression(JetBreakExpression expression, TypeInferenceContext context) {
|
||||
labelsResolver.resolveCorrespondingLoopLabel(expression, context);
|
||||
labelsResolver.recordLabel(expression, context);
|
||||
return context.services.checkType(JetStandardClasses.getNothingType(), expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JetType visitContinueExpression(JetContinueExpression expression, TypeInferenceContext context) {
|
||||
labelsResolver.resolveCorrespondingLoopLabel(expression, context);
|
||||
labelsResolver.recordLabel(expression, context);
|
||||
return context.services.checkType(JetStandardClasses.getNothingType(), expression, context);
|
||||
}
|
||||
|
||||
@@ -1321,52 +1316,7 @@ public class JetTypeInferrer {
|
||||
ReceiverDescriptor thisReceiver = null;
|
||||
String labelName = expression.getLabelName();
|
||||
if (labelName != null) {
|
||||
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
|
||||
int size = declarationsByLabel.size();
|
||||
final JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
assert targetLabel != null;
|
||||
if (size == 1) {
|
||||
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
|
||||
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
thisReceiver = classDescriptor.getImplicitReceiver();
|
||||
}
|
||||
else if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
|
||||
thisReceiver = functionDescriptor.getReceiver();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
|
||||
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
|
||||
}
|
||||
else if (size == 0) {
|
||||
//todo (first we put to the context, then get from it)
|
||||
JetElement element = labelsResolver.resolveLabel(labelName, targetLabel, false, context);
|
||||
// This uses the info written by the control flow processor
|
||||
//PsiElement psiElement = BindingContextUtils.resolveToDeclarationPsiElement(context.trace.getBindingContext(), targetLabel);
|
||||
if (element instanceof JetFunctionLiteralExpression) {
|
||||
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver();
|
||||
if (thisReceiver.exists()) {
|
||||
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
|
||||
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// context.trace.getErrorHandler().genericError(targetLabel.getNode(), "Ambiguous label");
|
||||
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
|
||||
}
|
||||
thisReceiver = labelsResolver.resolveThisLabel(expression, context, thisReceiver, labelName);
|
||||
}
|
||||
else {
|
||||
thisReceiver = context.scope.getImplicitReceiver();
|
||||
@@ -2881,7 +2831,7 @@ public class JetTypeInferrer {
|
||||
private class LabelsResolver {
|
||||
private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
|
||||
|
||||
private void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
|
||||
public void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
|
||||
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
|
||||
if (deparenthesized != null) {
|
||||
Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
@@ -2893,7 +2843,7 @@ public class JetTypeInferrer {
|
||||
}
|
||||
}
|
||||
|
||||
private void exitLabeledElement(JetExpression expression) {
|
||||
public void exitLabeledElement(@NotNull JetExpression expression) {
|
||||
JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
|
||||
// TODO : really suboptimal
|
||||
for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
|
||||
@@ -2911,20 +2861,15 @@ public class JetTypeInferrer {
|
||||
}
|
||||
}
|
||||
|
||||
private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) {
|
||||
private JetElement resolveControlLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) {
|
||||
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
|
||||
int size = declarationsByLabel.size();
|
||||
|
||||
|
||||
if (size == 1) {
|
||||
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
|
||||
JetElement element;
|
||||
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
|
||||
}
|
||||
else if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
|
||||
element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, functionDescriptor);
|
||||
if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) {
|
||||
element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
@@ -2932,7 +2877,23 @@ public class JetTypeInferrer {
|
||||
context.trace.record(LABEL_TARGET, labelExpression, element);
|
||||
return element;
|
||||
}
|
||||
|
||||
else if (size == 0) {
|
||||
return resolveNamedLabel(labelName, labelExpression, reportUnresolved, context);
|
||||
}
|
||||
context.trace.report(AMBIGUOUS_LABEL.on(labelExpression));
|
||||
return null;
|
||||
}
|
||||
|
||||
public void recordLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) {
|
||||
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||
if (labelElement != null) {
|
||||
String labelName = expression.getLabelName();
|
||||
assert labelName != null;
|
||||
resolveControlLabel(labelName, labelElement, true, context);
|
||||
}
|
||||
}
|
||||
|
||||
private JetElement resolveNamedLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, TypeInferenceContext context) {
|
||||
Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
if (stack == null || stack.isEmpty()) {
|
||||
if (reportUnresolved) {
|
||||
@@ -2949,13 +2910,52 @@ public class JetTypeInferrer {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void resolveCorrespondingLoopLabel(JetLabelQualifiedExpression expression, TypeInferenceContext context) {
|
||||
String labelName = expression.getLabelName();
|
||||
if (labelName != null) {
|
||||
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
assert targetLabel != null;
|
||||
resolveLabel(labelName, targetLabel, true, context);
|
||||
public ReceiverDescriptor resolveThisLabel(JetThisExpression expression, TypeInferenceContext context, ReceiverDescriptor thisReceiver, String labelName) {
|
||||
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
|
||||
int size = declarationsByLabel.size();
|
||||
final JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
assert targetLabel != null;
|
||||
if (size == 1) {
|
||||
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
|
||||
if (declarationDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
thisReceiver = classDescriptor.getImplicitReceiver();
|
||||
}
|
||||
else if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
|
||||
thisReceiver = functionDescriptor.getReceiver();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
PsiElement element = context.trace.get(DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
|
||||
assert element != null;
|
||||
context.trace.record(LABEL_TARGET, targetLabel, element);
|
||||
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
|
||||
}
|
||||
else if (size == 0) {
|
||||
JetElement element = labelsResolver.resolveNamedLabel(labelName, targetLabel, false, context);
|
||||
if (element instanceof JetFunctionLiteralExpression) {
|
||||
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiver();
|
||||
if (thisReceiver.exists()) {
|
||||
context.trace.record(LABEL_TARGET, targetLabel, element);
|
||||
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
|
||||
}
|
||||
return thisReceiver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user