Skip to content

Commit 9eac90d

Browse files
Check void usage and invalid returns
Second take on 1100179, but we treat all the problems as warnings. This reverts commit 5c9c90f. Change-Id: Id9fdeabf5d49fefb48cfe4a0ca1b6da2be7dff59 Reviewed-on: https://dart-review.googlesource.com/66160 Reviewed-by: Dmitry Stefantsov <[email protected]> Commit-Queue: Peter von der Ahé <[email protected]>
1 parent 6da9058 commit 9eac90d

12 files changed

+304
-94
lines changed

pkg/front_end/lib/src/fasta/fasta_codes_generated.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5967,6 +5967,17 @@ const MessageCode messageRequiredParameterWithDefault = const MessageCode(
59675967
tip:
59685968
r"""Try removing the default value or making the parameter optional.""");
59695969

5970+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5971+
const Code<Null> codeReturnFromVoidFunction = messageReturnFromVoidFunction;
5972+
5973+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
5974+
const MessageCode messageReturnFromVoidFunction = const MessageCode(
5975+
"ReturnFromVoidFunction",
5976+
analyzerCode: "RETURN_OF_INVALID_TYPE",
5977+
dart2jsCode: "*fatal*",
5978+
severity: Severity.warning,
5979+
message: r"""Can't return a value from a void function.""");
5980+
59705981
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
59715982
const Code<Null> codeReturnTypeFunctionExpression =
59725983
messageReturnTypeFunctionExpression;
@@ -7068,6 +7079,16 @@ const MessageCode messageVarReturnType = const MessageCode("VarReturnType",
70687079
tip:
70697080
r"""Try removing the keyword 'var', or replacing it with the name of the return type.""");
70707081

7082+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7083+
const Code<Null> codeVoidExpression = messageVoidExpression;
7084+
7085+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
7086+
const MessageCode messageVoidExpression = const MessageCode("VoidExpression",
7087+
analyzerCode: "USE_OF_VOID_RESULT",
7088+
dart2jsCode: "*fatal*",
7089+
severity: Severity.warning,
7090+
message: r"""This expression has type 'void' and can't be used.""");
7091+
70717092
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
70727093
const Template<
70737094
Message Function(

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ import '../scanner/token.dart' show isBinaryOperator, isMinusOperator;
5656

5757
import '../scope.dart' show ProblemBuilder;
5858

59+
import '../severity.dart' show Severity;
60+
5961
import '../source/outline_builder.dart' show OutlineBuilder;
6062

6163
import '../source/scope_listener.dart'
@@ -3968,6 +3970,28 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
39683970
context: context);
39693971
}
39703972

3973+
@override
3974+
Expression wrapInProblem(Expression expression, Message message, int length,
3975+
{List<LocatedMessage> context}) {
3976+
int charOffset = expression.fileOffset;
3977+
Severity severity = message.code.severity;
3978+
if (severity == null) {
3979+
addCompileTimeError(message, charOffset, length, context: context);
3980+
internalProblem(
3981+
fasta.templateInternalProblemMissingSeverity
3982+
.withArguments(message.code.name),
3983+
charOffset,
3984+
uri);
3985+
} else if (severity == Severity.error ||
3986+
severity == Severity.errorLegacyWarning &&
3987+
library.loader.target.strongMode) {
3988+
return wrapInCompileTimeError(expression, message, context: context);
3989+
} else {
3990+
addProblem(message, charOffset, length, context: context);
3991+
}
3992+
return expression;
3993+
}
3994+
39713995
@override
39723996
Expression wrapInLocatedCompileTimeError(
39733997
Expression expression, LocatedMessage message,

pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ abstract class ExpressionGeneratorHelper implements InferenceHelper {
7777

7878
Expression wrapInCompileTimeError(Expression expression, Message message);
7979

80+
Expression wrapInProblem(Expression expression, Message message, int length,
81+
{List<LocatedMessage> context});
82+
8083
Expression deprecated_buildCompileTimeError(String error,
8184
[int offset, Message message]);
8285

pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,11 @@ class KernelIndexedAccessGenerator extends KernelGenerator
794794
@override
795795
Expression _finish(
796796
Expression body, ComplexAssignmentJudgment complexAssignment) {
797+
int offset = offsetForToken(token);
797798
return super._finish(
798-
makeLet(receiverVariable, makeLet(indexVariable, body)),
799+
makeLet(
800+
receiverVariable, makeLet(indexVariable, body)..fileOffset = offset)
801+
..fileOffset = offset,
799802
complexAssignment);
800803
}
801804

@@ -1055,7 +1058,9 @@ class KernelSuperIndexedAccessGenerator extends KernelGenerator
10551058
@override
10561059
Expression _finish(
10571060
Expression body, ComplexAssignmentJudgment complexAssignment) {
1058-
return super._finish(makeLet(indexVariable, body), complexAssignment);
1061+
return super._finish(
1062+
makeLet(indexVariable, body)..fileOffset = offsetForToken(token),
1063+
complexAssignment);
10591064
}
10601065

10611066
@override

pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import '../../base/instrumentation.dart'
3939

4040
import '../fasta_codes.dart'
4141
show
42+
messageVoidExpression,
4243
noLength,
4344
templateCantInferTypeDueToCircularity,
4445
templateCantUseSuperBoundedTypeForInstanceCreation,
@@ -439,7 +440,8 @@ class CascadeJudgment extends Let implements ExpressionJudgment {
439440
variable.type = inferredType;
440441
}
441442
for (var judgment in cascadeJudgments) {
442-
inferrer.inferExpression(factory, judgment, const UnknownType(), false);
443+
inferrer.inferExpression(factory, judgment, const UnknownType(), false,
444+
isVoidAllowed: true);
443445
}
444446
inferrer.listener.cascadeExpression(this, fileOffset, inferredType);
445447
return null;
@@ -1176,7 +1178,8 @@ class ForInJudgment extends ForInStatement implements StatementJudgment {
11761178
this.variable.type,
11771179
syntheticAssignment.rhs,
11781180
syntheticAssignment.rhs.fileOffset,
1179-
template: templateForInLoopElementTypeNotAssignable);
1181+
template: templateForInLoopElementTypeNotAssignable,
1182+
isVoidAllowed: true);
11801183
if (syntheticAssignment is PropertyAssignmentJudgment) {
11811184
syntheticAssignment._handleWriteContravariance(
11821185
inferrer, inferrer.thisType);
@@ -1510,6 +1513,10 @@ class IfNullJudgment extends Let implements ExpressionJudgment {
15101513
inferrer.inferExpression(factory, rightJudgment, typeContext, _forceLub);
15111514
}
15121515
var rhsType = rightJudgment.inferredType;
1516+
if (rhsType is VoidType) {
1517+
inferrer.helper?.addProblem(
1518+
messageVoidExpression, rightJudgment.fileOffset, noLength);
1519+
}
15131520
// - Let T = greatest closure of K with respect to `?` if K is not `_`, else
15141521
// UP(t0, t1)
15151522
// - Then the inferred type is T.
@@ -2514,7 +2521,7 @@ class ReturnJudgment extends ReturnStatement implements StatementJudgment {
25142521
Factory<Expression, Statement, Initializer, Type> factory) {
25152522
var judgment = this.judgment;
25162523
var closureContext = inferrer.closureContext;
2517-
var typeContext = !closureContext.isGenerator
2524+
DartType typeContext = !closureContext.isGenerator
25182525
? closureContext.returnOrYieldContext
25192526
: const UnknownType();
25202527
DartType inferredType;
@@ -2528,8 +2535,8 @@ class ReturnJudgment extends ReturnStatement implements StatementJudgment {
25282535
// inferred type of the closure. TODO(paulberry): is this what we want
25292536
// for Fasta?
25302537
if (judgment != null) {
2531-
closureContext.handleReturn(
2532-
inferrer, inferredType, expression, fileOffset);
2538+
closureContext.handleReturn(inferrer, inferredType, expression,
2539+
fileOffset, !identical(returnKeyword?.lexeme, "return"));
25332540
}
25342541
inferrer.listener
25352542
.returnStatement(this, fileOffset, returnKeyword, null, semicolon);
@@ -3313,7 +3320,8 @@ class ShadowTypeInferrer extends TypeInferrerImpl {
33133320
Factory<Expression, Statement, Initializer, Type> factory,
33143321
kernel.Expression expression,
33153322
DartType typeContext,
3316-
bool typeNeeded) {
3323+
bool typeNeeded,
3324+
{bool isVoidAllowed: false}) {
33173325
// `null` should never be used as the type context. An instance of
33183326
// `UnknownType` should be used instead.
33193327
assert(typeContext != null);
@@ -3339,7 +3347,34 @@ class ShadowTypeInferrer extends TypeInferrerImpl {
33393347
// so that the type hierarchy will be simpler (which may speed up "is"
33403348
// checks).
33413349
expression.infer(this, factory, typeContext);
3342-
return expression.inferredType;
3350+
DartType inferredType = expression.inferredType;
3351+
if (inferredType is VoidType && !isVoidAllowed) {
3352+
TreeNode parent = expression.parent;
3353+
if (parent is ReturnStatement ||
3354+
parent is ExpressionStatement ||
3355+
parent is AsExpression) {
3356+
return inferredType;
3357+
} else if (parent is ForStatement &&
3358+
parent.updates.contains(expression)) {
3359+
return inferredType;
3360+
} else if (parent is VariableDeclaration) {
3361+
TreeNode grandParent = parent.parent;
3362+
if (grandParent is ForStatement &&
3363+
parent.name == null &&
3364+
grandParent.variables.contains(parent)) {
3365+
return inferredType;
3366+
}
3367+
} else if (parent is ConditionalExpression) {
3368+
if (parent.then == expression || parent.otherwise == expression) {
3369+
return inferredType;
3370+
}
3371+
} else if (parent is DeferredCheckJudgment) {
3372+
return inferredType;
3373+
}
3374+
helper?.addProblem(
3375+
messageVoidExpression, expression.fileOffset, noLength);
3376+
}
3377+
return inferredType;
33433378
} else {
33443379
// Encountered an expression type for which type inference is not yet
33453380
// implemented, so just infer dynamic for now.

pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ abstract class InferenceHelper {
1616
FunctionType function, Arguments arguments, int offset);
1717

1818
void addProblem(Message message, int charOffset, int length);
19+
20+
Expression wrapInProblem(Expression expression, Message message, int length,
21+
{List<LocatedMessage> context});
1922
}

0 commit comments

Comments
 (0)