Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Unified Diff: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java

Issue 913623002: Partial backport of analyzer async/await fixes to Java. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix status files Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java
diff --git a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java
index 7089bb75a63fe3093113f2639357ddb4d01a2681..bcb6343d25bc0c73e74ac75becb1796188cdd2a8 100644
--- a/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java
+++ b/editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/verifier/ErrorVerifier.java
@@ -847,6 +847,7 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
CompileTimeErrorCode.INVALID_MODIFIER_ON_SETTER);
}
checkForTypeAnnotationDeferredClass(returnType);
+ checkForIllegalReturnType(returnType);
return super.visitFunctionDeclaration(node);
} finally {
enclosingFunction = outerFunction;
@@ -1028,6 +1029,7 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
checkForConcreteClassWithAbstractMember(node);
checkForAllInvalidOverrideErrorCodesForMethod(node);
checkForTypeAnnotationDeferredClass(returnTypeName);
+ checkForIllegalReturnType(returnTypeName);
return super.visitMethodDeclaration(node);
} finally {
enclosingFunction = previousFunction;
@@ -1254,7 +1256,9 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
@Override
public Void visitYieldStatement(YieldStatement node) {
- if (!inGenerator) {
+ if (inGenerator) {
+ checkForYieldOfInvalidType(node.getExpression(), node.getStar() != null);
+ } else {
CompileTimeErrorCode errorCode;
if (node.getStar() != null) {
errorCode = CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR;
@@ -1932,7 +1936,7 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
}
// RETURN_WITHOUT_VALUE
if (returnExpression == null) {
- if (VoidTypeImpl.getInstance().isAssignableTo(expectedReturnType)) {
+ if (inGenerator || computeReturnTypeForMethod(null).isAssignableTo(expectedReturnType)) {
return false;
}
hasReturnWithoutValue = true;
@@ -3554,6 +3558,35 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
}
/**
+ * If the current function is async, async*, or sync*, verify that its declared return type is
+ * assignable to Future, Stream, or Iterable, respectively. If not, report the error using [node].
+ */
+ private void checkForIllegalReturnType(TypeName node) {
+ if (node == null) {
+ // No declared return type, so the return type must be dynamic, which is assignable to
+ // everything.
+ return;
+ }
+ if (enclosingFunction.isAsynchronous()) {
+ if (enclosingFunction.isGenerator()) {
+ // TODO(paulberry): We should report an error if enclosingFunction.getReturnType() isn't
+ // assignable to Stream<dynamic>. But we can't because the Stream type isn't available in
+ // the type provider. So to avoid bogus warnings, don't do any check.
+ } else {
+ // TODO(paulberry): We should report an error if enclosingFunction.getReturnType() isn't
+ // assignable to Future<dynamic>. But we can't because the Future type isn't available in
+ // the type provider. So to avoid bogus warnings, don't do any check.
+ }
+ } else if (enclosingFunction.isGenerator()) {
+ if (!enclosingFunction.getReturnType().isAssignableTo(typeProvider.getIterableDynamicType())) {
+ errorReporter.reportErrorForNode(
+ StaticTypeWarningCode.ILLEGAL_SYNC_GENERATOR_RETURN_TYPE,
+ node);
+ }
+ }
+ }
+
+ /**
* This verifies that the passed implements clause does not implement classes that are deferred.
*
* @param node the implements clause to test
@@ -5166,7 +5199,13 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
if (enclosingFunction == null) {
return false;
}
- Type staticReturnType = getStaticType(returnExpression);
+ if (inGenerator) {
+ // "return expression;" is disallowed in generators, but this is checked elsewhere. Bare
+ // "return" is always allowed in generators regardless of the return type. So no need to do
+ // any further checking.
+ return false;
+ }
+ Type staticReturnType = computeReturnTypeForMethod(returnExpression);
if (expectedReturnType.isVoid()) {
if (staticReturnType.isVoid() || staticReturnType.isDynamic() || staticReturnType.isBottom()) {
return false;
@@ -5179,22 +5218,6 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
enclosingFunction.getDisplayName());
return true;
}
- if (enclosingFunction.isAsynchronous() && !enclosingFunction.isGenerator()) {
- // TODO(brianwilkerson) Figure out how to get the type "Future" so that we can build the type
- // we need to test against.
-// InterfaceType impliedType = "Future<" + flatten(staticReturnType) + ">"
-// if (impliedType.isAssignableTo(expectedReturnType)) {
-// return false;
-// }
-// errorReporter.reportTypeErrorForNode(
-// StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
-// returnExpression,
-// impliedType,
-// expectedReturnType.getDisplayName(),
-// enclosingFunction.getDisplayName());
-// return true;
- return false;
- }
if (staticReturnType.isAssignableTo(expectedReturnType)) {
return false;
}
@@ -5686,6 +5709,59 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
}
/**
+ * Check for a type mis-match between the yielded type and the declared return type of a generator
+ * function. This method should only be called in generator functions.
+ */
+ private boolean checkForYieldOfInvalidType(Expression yieldExpression, boolean isYieldEach) {
+ if (enclosingFunction == null) {
+ return false;
+ }
+ Type declaredReturnType = enclosingFunction.getReturnType();
+ Type staticYieldedType = getStaticType(yieldExpression);
+ Type impliedReturnType;
+ if (isYieldEach) {
+ impliedReturnType = staticYieldedType;
+ } else if (enclosingFunction.isAsynchronous()) {
+ // TODO(paulberry): We should set impliedReturnType to Stream<staticYieldedType>. But we
+ // can't because the Stream type isn't available in the type provider. So to avoid bogus
+ // warnings, use dynamic.
+ impliedReturnType = typeProvider.getDynamicType();
+ } else {
+ impliedReturnType = typeProvider.getIterableType().substitute(new Type[] {staticYieldedType});
+ }
+ if (!impliedReturnType.isAssignableTo(declaredReturnType)) {
+ errorReporter.reportTypeErrorForNode(
+ StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
+ yieldExpression,
+ impliedReturnType,
+ declaredReturnType);
+ return true;
+ }
+ if (isYieldEach) {
+ // Since the declared return type might have been "dynamic", we need to also check that the
+ // implied return type is assignable to generic Stream/Iterable.
+ Type requiredReturnType;
+ if (enclosingFunction.isAsynchronous()) {
+ // TODO(paulberry): We should set requiredReturnType to Stream<dynamic>. But we can't
+ // because the Stream type isn't available in the type provider. So to avoid bogus
+ // warnings, use dynamic.
+ requiredReturnType = typeProvider.getDynamicType();
+ } else {
+ requiredReturnType = typeProvider.getIterableDynamicType();
+ }
+ if (!impliedReturnType.isAssignableTo(requiredReturnType)) {
+ errorReporter.reportTypeErrorForNode(
+ StaticTypeWarningCode.YIELD_OF_INVALID_TYPE,
+ yieldExpression,
+ impliedReturnType,
+ requiredReturnType);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* This verifies that if the given class declaration implements the class Function that it has a
* concrete implementation of the call method.
*
@@ -5749,6 +5825,29 @@ public class ErrorVerifier extends RecursiveAstVisitor<Void> {
return hasProblem;
}
+ private Type computeReturnTypeForMethod(Expression returnExpression) {
+ // This method should never be called for generators, since generators are never allowed to
+ // contain return statements with expressions.
+ if (returnExpression == null) {
+ if (enclosingFunction.isAsynchronous()) {
+ // TODO(paulberry): We should return Future<Null>. But we can't because the Future type
+ // isn't available in the type provider. So to avoid bogus warnings, return dynamic.
+ return typeProvider.getDynamicType();
+ } else {
+ return VoidTypeImpl.getInstance();
+ }
+ }
+ Type staticReturnType = getStaticType(returnExpression);
+ if (staticReturnType != null && enclosingFunction.isAsynchronous()) {
+ // TODO(paulberry): We should return Future<flatten(staticReturnType)>. But we can't
+ // implement the flatten function, and even if we could, we wouldn't be able to return the
+ // proper type, because the Future type isn't available in the type provider. So to avoid
+ // bogus warnings, return dynamic.
+ return typeProvider.getDynamicType();
+ }
+ return staticReturnType;
+ }
+
/**
* Return the error code that should be used when the given class references itself directly.
*

Powered by Google App Engine
This is Rietveld 408576698