[cfe] Invalid empty return statements in const function invocations.

Change-Id: Id1408bff917200f3825846bd6d483e52ca326d5b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194840
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu 2021-04-13 14:49:06 +00:00 committed by commit-bot@chromium.org
parent 4b4ccbaa0d
commit f9536375e1
10 changed files with 252 additions and 3 deletions

View file

@ -1036,15 +1036,22 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
return result;
}
/// Execute the statement using the [StatementConstantEvaluator].
Constant execute(Statement statement) {
/// Execute a function body using the [StatementConstantEvaluator].
Constant executeBody(Statement statement) {
StatementConstantEvaluator statementEvaluator =
new StatementConstantEvaluator(this);
ExecutionStatus status = statement.accept(statementEvaluator);
if (status is ReturnStatus) {
if (status.value == null) {
// Void return type from executing the function body.
return new NullConstant();
}
return status.value;
} else if (status is AbortStatus) {
return status.error;
} else if (status is ProceedStatus) {
// No return statement in function body with void return type.
return new NullConstant();
}
return createInvalidExpressionConstant(statement,
'No valid constant returned from the execution of $statement.');
@ -2870,7 +2877,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
if (value is AbortConstant) return value;
env.addVariableValue(parameter, value);
}
return execute(function.body);
return executeBody(function.body);
}
if (functionEnvironment != null) {

View file

@ -0,0 +1,30 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Tests function invocation return types.
import "package:expect/expect.dart";
const var1 = fn();
void fn() {}
const var2 = fn2();
void fn2() {
return;
}
const var3 = fn3();
int? fn3() => null;
const var4 = fn4();
int? fn4() {
return null;
}
void main() {
Expect.equals((var1 as dynamic), null);
Expect.equals((var2 as dynamic), null);
Expect.equals(var3, null);
Expect.equals(var4, null);
}

View file

@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
static const field void var1 = #C1;
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
static method fn() → void {}
static method fn2() → void {
return;
}
static method fn3() → core::int?
return null;
static method fn4() → core::int? {
return null;
}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
}
constants {
#C1 = null
}

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
static const field void var1 = #C1;
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
static method fn() → void {}
static method fn2() → void {
return;
}
static method fn3() → core::int?
return null;
static method fn4() → core::int? {
return null;
}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
}
constants {
#C1 = null
}
Extra constant evaluation status:
Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:26:23 -> NullConstant(null)
Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:27:23 -> NullConstant(null)
Extra constant evaluation: evaluated: 6, effectively constant: 2

View file

@ -0,0 +1,11 @@
import "package:expect/expect.dart";
const var1 = fn();
void fn() {}
const var2 = fn2();
void fn2() {}
const var3 = fn3();
int? fn3() => null;
const var4 = fn4();
int? fn4() {}
void main() {}

View file

@ -0,0 +1,11 @@
import "package:expect/expect.dart";
const var1 = fn();
const var2 = fn2();
const var3 = fn3();
const var4 = fn4();
int? fn3() => null;
int? fn4() {}
void fn() {}
void fn2() {}
void main() {}

View file

@ -0,0 +1,30 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
static const field void var1 = #C1;
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
static method fn() → void {}
static method fn2() → void {
return;
}
static method fn3() → core::int?
return null;
static method fn4() → core::int? {
return null;
}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
}
constants {
#C1 = null
}

View file

@ -0,0 +1,20 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart";
static const field void var1 = self::fn();
static const field void var2 = self::fn2();
static const field core::int? var3 = self::fn3();
static const field core::int? var4 = self::fn4();
static method fn() → void
;
static method fn2() → void
;
static method fn3() → core::int?
;
static method fn4() → core::int?
;
static method main() → void
;

View file

@ -0,0 +1,35 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
import "package:expect/expect.dart" as exp;
import "package:expect/expect.dart";
static const field void var1 = #C1;
static const field void var2 = #C1;
static const field core::int? var3 = #C1;
static const field core::int? var4 = #C1;
static method fn() → void {}
static method fn2() → void {
return;
}
static method fn3() → core::int?
return null;
static method fn4() → core::int? {
return null;
}
static method main() → void {
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals((#C1) as{ForNonNullableByDefault} dynamic, null);
exp::Expect::equals(#C1, null);
exp::Expect::equals(#C1, null);
}
constants {
#C1 = null
}
Extra constant evaluation status:
Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:26:23 -> NullConstant(null)
Evaluated: AsExpression @ org-dartlang-testcase:///const_functions_return.dart:27:23 -> NullConstant(null)
Extra constant evaluation: evaluated: 6, effectively constant: 2

View file

@ -0,0 +1,40 @@
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Tests function invocation return types.
// SharedOptions=--enable-experiment=const-functions
import "package:expect/expect.dart";
const var1 = fn();
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
void fn() {}
const var2 = fn2();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
void fn2() {
return;
}
const var3 = fn3();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int? fn3() => null;
const var4 = fn4();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int? fn4() {
return null;
}
void main() {
Expect.equals((var1 as dynamic), null);
Expect.equals((var2 as dynamic), null);
Expect.equals(var3, null);
Expect.equals(var4, null);
}