diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart index c4fe216315a..d200491e8be 100644 --- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart @@ -3056,7 +3056,21 @@ class ConstantEvaluator implements ExpressionVisitor { if (value is AbortConstant) return value; env.addVariableValue(parameter, value); } - return executeBody(function.body); + + final Constant result = executeBody(function.body); + if (result is NullConstant && + function.returnType.nullability == Nullability.nonNullable) { + // Ensure that the evaluated constant returned is not null if the + // function has a non-nullable return type. + return createErrorConstant( + function, + templateConstEvalInvalidType.withArguments( + result, + function.returnType, + result.getType(_staticTypeContext), + isNonNullableByDefault)); + } + return result; } if (functionEnvironment != null) { @@ -3822,6 +3836,8 @@ class StatementConstantEvaluator extends StatementVisitor { if (node.initializer != null) { value = evaluate(node.initializer); if (value is AbortConstant) return new AbortStatus(value); + } else { + value = new NullConstant(); } exprEvaluator.env.addVariableValue(node, value); return const ProceedStatus(); diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart index 20071a4127d..7f6d6fe41ac 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart @@ -62,6 +62,12 @@ int function8() { return a; } +const var9 = function9(); +int? function9() { + int? x; + return x; +} + void main() { Expect.equals(var1, 4); Expect.equals(var1_1, 5); @@ -72,4 +78,5 @@ void main() { Expect.equals(var6, 2); Expect.equals(var7, 2); Expect.equals(var8, 2); + Expect.equals(var9, null); } diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.expect index e424e71643a..d270f74b3b6 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.expect @@ -14,6 +14,7 @@ static const field core::int var5 = #C6; static const field core::int var6 = #C5; static const field core::int var7 = #C5; static const field core::int var8 = #C5; +static const field core::int? var9 = #C7; static method function1(core::int a, core::int b) → core::int { core::int x = 1.{core::num::+}(a).{core::num::+}(b); return x; @@ -52,6 +53,10 @@ static method function8() → core::int { a = 2; return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; } +static method function9() → core::int? { + core::int? x; + return x; +} static method main() → void { exp::Expect::equals(#C1, 4); exp::Expect::equals(#C2, 5); @@ -62,6 +67,7 @@ static method main() → void { exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); + exp::Expect::equals(#C7, null); } constants { @@ -71,4 +77,5 @@ constants { #C4 = 6 #C5 = 2 #C6 = -2 + #C7 = null } diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.transformed.expect index 611523b47a3..3ec97cd31bb 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.strong.transformed.expect @@ -14,6 +14,7 @@ static const field core::int var5 = #C6; static const field core::int var6 = #C5; static const field core::int var7 = #C5; static const field core::int var8 = #C5; +static const field core::int? var9 = #C7; static method function1(core::int a, core::int b) → core::int { core::int x = 1.{core::num::+}(a).{core::num::+}(b); return x; @@ -52,6 +53,10 @@ static method function8() → core::int { a = 2; return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; } +static method function9() → core::int? { + core::int? x; + return x; +} static method main() → void { exp::Expect::equals(#C1, 4); exp::Expect::equals(#C2, 5); @@ -62,6 +67,7 @@ static method main() → void { exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); + exp::Expect::equals(#C7, null); } constants { @@ -71,8 +77,9 @@ constants { #C4 = 6 #C5 = 2 #C6 = -2 + #C7 = null } Extra constant evaluation status: -Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_variable_declarations.dart:71:23 -> IntConstant(-2) -Extra constant evaluation: evaluated: 33, effectively constant: 1 +Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_variable_declarations.dart:77:23 -> IntConstant(-2) +Extra constant evaluation: evaluated: 35, effectively constant: 1 diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline.expect index 1c817fd2a1a..2a0d7a9b70d 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline.expect @@ -17,4 +17,6 @@ const var7 = function7(); int function7() {} const var8 = function8(); int function8() {} +const var9 = function9(); +int? function9() {} void main() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline_modelled.expect index 2d98733616c..519ab22dbcf 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline_modelled.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.textual_outline_modelled.expect @@ -10,6 +10,8 @@ const var5 = function5(); const var6 = function6(); const var7 = function7(); const var8 = function8(); +const var9 = function9(); +int? function9() {} int function1(int a, int b) {} int function3() {} int function4() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.expect index e424e71643a..d270f74b3b6 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.expect @@ -14,6 +14,7 @@ static const field core::int var5 = #C6; static const field core::int var6 = #C5; static const field core::int var7 = #C5; static const field core::int var8 = #C5; +static const field core::int? var9 = #C7; static method function1(core::int a, core::int b) → core::int { core::int x = 1.{core::num::+}(a).{core::num::+}(b); return x; @@ -52,6 +53,10 @@ static method function8() → core::int { a = 2; return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; } +static method function9() → core::int? { + core::int? x; + return x; +} static method main() → void { exp::Expect::equals(#C1, 4); exp::Expect::equals(#C2, 5); @@ -62,6 +67,7 @@ static method main() → void { exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); + exp::Expect::equals(#C7, null); } constants { @@ -71,4 +77,5 @@ constants { #C4 = 6 #C5 = 2 #C6 = -2 + #C7 = null } diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.outline.expect index 50fbc0fb12d..09275b245db 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.outline.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.outline.expect @@ -13,6 +13,7 @@ static const field core::int var5 = self::function5(); static const field core::int var6 = self::function6(); static const field core::int var7 = self::function7(); static const field core::int var8 = self::function8(); +static const field core::int? var9 = self::function9(); static method function1(core::int a, core::int b) → core::int ; static method function2() → core::String @@ -29,5 +30,7 @@ static method function7() → core::int ; static method function8() → core::int ; +static method function9() → core::int? + ; static method main() → void ; diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.transformed.expect index 611523b47a3..3ec97cd31bb 100644 --- a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations.dart.weak.transformed.expect @@ -14,6 +14,7 @@ static const field core::int var5 = #C6; static const field core::int var6 = #C5; static const field core::int var7 = #C5; static const field core::int var8 = #C5; +static const field core::int? var9 = #C7; static method function1(core::int a, core::int b) → core::int { core::int x = 1.{core::num::+}(a).{core::num::+}(b); return x; @@ -52,6 +53,10 @@ static method function8() → core::int { a = 2; return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; } +static method function9() → core::int? { + core::int? x; + return x; +} static method main() → void { exp::Expect::equals(#C1, 4); exp::Expect::equals(#C2, 5); @@ -62,6 +67,7 @@ static method main() → void { exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); exp::Expect::equals(#C5, 2); + exp::Expect::equals(#C7, null); } constants { @@ -71,8 +77,9 @@ constants { #C4 = 6 #C5 = 2 #C6 = -2 + #C7 = null } Extra constant evaluation status: -Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_variable_declarations.dart:71:23 -> IntConstant(-2) -Extra constant evaluation: evaluated: 33, effectively constant: 1 +Evaluated: MethodInvocation @ org-dartlang-testcase:///const_functions_variable_declarations.dart:77:23 -> IntConstant(-2) +Extra constant evaluation: evaluated: 35, effectively constant: 1 diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart new file mode 100644 index 00000000000..e8b764349a9 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart @@ -0,0 +1,22 @@ +// 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 erroneous variable declaration usage within const functions. + +import "package:expect/expect.dart"; + +const var1 = fn1(); +int fn1() { + var a; + return a; +} + +const var2 = fn2(); +int fn2() { + var x; + x = "string"; + return x; +} + +void main() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.expect new file mode 100644 index 00000000000..39434268fb9 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.expect @@ -0,0 +1,41 @@ +library /*isNonNullableByDefault*/; +// +// Problems in library: +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:14: Error: Constant evaluation error: +// const var1 = fn1(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:12:10: Context: Expected constant 'null' to be of type 'int', but was of type 'Null'. +// return a; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:7: Context: While analyzing: +// const var1 = fn1(); +// ^ +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:14: Error: Constant evaluation error: +// const var2 = fn2(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:19:10: Context: Expected constant '"string"' to be of type 'int', but was of type 'String'. +// return x; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:7: Context: While analyzing: +// const var2 = fn2(); +// ^ +// +import self as self; +import "dart:core" as core; + +import "package:expect/expect.dart"; + +static const field core::int var1 = invalid-expression "Expected constant 'null' to be of type 'int', but was of type 'Null'."; +static const field core::int var2 = invalid-expression "Expected constant '\"string\"' to be of type 'int', but was of type 'String'."; +static method fn1() → core::int { + dynamic a; + return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method fn2() → core::int { + dynamic x; + x = "string"; + return x as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method main() → void {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.transformed.expect new file mode 100644 index 00000000000..39434268fb9 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.strong.transformed.expect @@ -0,0 +1,41 @@ +library /*isNonNullableByDefault*/; +// +// Problems in library: +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:14: Error: Constant evaluation error: +// const var1 = fn1(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:12:10: Context: Expected constant 'null' to be of type 'int', but was of type 'Null'. +// return a; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:7: Context: While analyzing: +// const var1 = fn1(); +// ^ +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:14: Error: Constant evaluation error: +// const var2 = fn2(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:19:10: Context: Expected constant '"string"' to be of type 'int', but was of type 'String'. +// return x; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:7: Context: While analyzing: +// const var2 = fn2(); +// ^ +// +import self as self; +import "dart:core" as core; + +import "package:expect/expect.dart"; + +static const field core::int var1 = invalid-expression "Expected constant 'null' to be of type 'int', but was of type 'Null'."; +static const field core::int var2 = invalid-expression "Expected constant '\"string\"' to be of type 'int', but was of type 'String'."; +static method fn1() → core::int { + dynamic a; + return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method fn2() → core::int { + dynamic x; + x = "string"; + return x as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method main() → void {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline.expect new file mode 100644 index 00000000000..422a5ed9820 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline.expect @@ -0,0 +1,7 @@ +import "package:expect/expect.dart"; + +const var1 = fn1(); +int fn1() {} +const var2 = fn2(); +int fn2() {} +void main() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..d67a0d961e7 --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.textual_outline_modelled.expect @@ -0,0 +1,7 @@ +import "package:expect/expect.dart"; + +const var1 = fn1(); +const var2 = fn2(); +int fn1() {} +int fn2() {} +void main() {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.expect new file mode 100644 index 00000000000..9d6fa65c58f --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.expect @@ -0,0 +1,41 @@ +library /*isNonNullableByDefault*/; +// +// Problems in library: +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:14: Error: Constant evaluation error: +// const var1 = fn1(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:10:8: Context: Expected constant 'null' to be of type 'int', but was of type 'Null'. +// int fn1() { +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:7: Context: While analyzing: +// const var1 = fn1(); +// ^ +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:14: Error: Constant evaluation error: +// const var2 = fn2(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:19:10: Context: Expected constant '"string"' to be of type 'int', but was of type 'String'. +// return x; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:7: Context: While analyzing: +// const var2 = fn2(); +// ^ +// +import self as self; +import "dart:core" as core; + +import "package:expect/expect.dart"; + +static const field core::int var1 = invalid-expression "Expected constant 'null' to be of type 'int', but was of type 'Null'."; +static const field core::int var2 = invalid-expression "Expected constant '\"string\"' to be of type 'int', but was of type 'String'."; +static method fn1() → core::int { + dynamic a; + return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method fn2() → core::int { + dynamic x; + x = "string"; + return x as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method main() → void {} diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.outline.expect new file mode 100644 index 00000000000..68a781da94a --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.outline.expect @@ -0,0 +1,14 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "dart:core" as core; + +import "package:expect/expect.dart"; + +static const field core::int var1 = self::fn1(); +static const field core::int var2 = self::fn2(); +static method fn1() → core::int + ; +static method fn2() → core::int + ; +static method main() → void + ; diff --git a/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.transformed.expect new file mode 100644 index 00000000000..9d6fa65c58f --- /dev/null +++ b/pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart.weak.transformed.expect @@ -0,0 +1,41 @@ +library /*isNonNullableByDefault*/; +// +// Problems in library: +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:14: Error: Constant evaluation error: +// const var1 = fn1(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:10:8: Context: Expected constant 'null' to be of type 'int', but was of type 'Null'. +// int fn1() { +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:9:7: Context: While analyzing: +// const var1 = fn1(); +// ^ +// +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:14: Error: Constant evaluation error: +// const var2 = fn2(); +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:19:10: Context: Expected constant '"string"' to be of type 'int', but was of type 'String'. +// return x; +// ^ +// pkg/front_end/testcases/const_functions/const_functions_variable_declarations_error.dart:15:7: Context: While analyzing: +// const var2 = fn2(); +// ^ +// +import self as self; +import "dart:core" as core; + +import "package:expect/expect.dart"; + +static const field core::int var1 = invalid-expression "Expected constant 'null' to be of type 'int', but was of type 'Null'."; +static const field core::int var2 = invalid-expression "Expected constant '\"string\"' to be of type 'int', but was of type 'String'."; +static method fn1() → core::int { + dynamic a; + return a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method fn2() → core::int { + dynamic x; + x = "string"; + return x as{TypeError,ForDynamic,ForNonNullableByDefault} core::int; +} +static method main() → void {} diff --git a/tests/language/const_functions/const_functions_variable_declarations_error_test.dart b/tests/language/const_functions/const_functions_variable_declarations_error_test.dart index 56cf08399ae..59cce22356e 100644 --- a/tests/language/const_functions/const_functions_variable_declarations_error_test.dart +++ b/tests/language/const_functions/const_functions_variable_declarations_error_test.dart @@ -16,3 +16,13 @@ int fn1() { var a; return a; } + +const var2 = fn2(); +// ^^^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE +// [cfe] Constant evaluation error: +int fn2() { + var x; + x = "string"; + return x; +} diff --git a/tests/language/const_functions/const_functions_variable_declarations_test.dart b/tests/language/const_functions/const_functions_variable_declarations_test.dart index ec6a8ecec56..29a87c0bb3a 100644 --- a/tests/language/const_functions/const_functions_variable_declarations_test.dart +++ b/tests/language/const_functions/const_functions_variable_declarations_test.dart @@ -82,6 +82,14 @@ int function8() { return a; } +const var9 = function9(); +// ^^^^^^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE +int? function9() { + int? x; + return x; +} + void main() { Expect.equals(var1, 4); Expect.equals(var1_1, 5); @@ -92,4 +100,5 @@ void main() { Expect.equals(var6, 2); Expect.equals(var7, 2); Expect.equals(var8, 2); + Expect.equals(var9, null); }