Files
sdk/pkg/front_end/testcases/patterns/simple_pattern_variable_declaration.dart.strong.modular.expect
Jens Johansen 3175e427d8 [CFE] Keep const locals by default; expression evaluation can evaluate const locals
Note: Const locals are still off for VM aot and dart2js for the entry
points I've found in an attempt to retain the old behaviour there.
It might be better if those targets could remove such locals in a
whole-world analysis instead.

 * Keep const locals by default (except as noted above). Update the
   verifier to accept that. For the platforms this has increased the
   size by at most 6584 bytes. With this the VM will pass in any const
   locals as it does normal locals, but as the variable is never
   captured it will never pass a const local defined in a method when
   inside a local function in that method.
 * Change the dart scope calculation(s) to return the found variables
   instead of just the types of the found variables.
 * When the incremental compilers expression compilation - via the dart
   scope calculation - finds a const local that it wasn't told about, it
   will pass it on as an extra variable that it knows about, allowing
   for evaluating const locals in the case not covered by the first
   bullet.

With luck this can in future CLs be extended to know about other
variables that we're not told about, allowing to give a message saying
something like
"yes, we know what 'foo' is, but you can't currently use it" as wanted
in for instance https://github.com/dart-lang/sdk/issues/60316 and
https://github.com/dart-lang/sdk/issues/53996.

Tested: Existing tests for existing functionality; new tests for the new
Change-Id: I1ec24350273e6f81574bb2888f6bf46e3b8b1b47
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445461
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
2025-08-19 04:30:41 -07:00

65 lines
4.0 KiB
Plaintext

library;
import self as self;
import "dart:core" as core;
static method test1(dynamic x) → dynamic {
hoisted has-declared-initializer core::int y;
{
final synthesized dynamic #0#0 = x as{TypeError,ForDynamic} core::List<core::int>;
final const synthesized core::int #0#3 = #C1;
synthesized dynamic #0#6;
synthesized core::bool #0#6#isSet = false;
if(!(#0#0 is core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && ((#0#6#isSet ?{dynamic} #0#6 : let final dynamic #t1 = #0#6#isSet = true in #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic}) is core::int && (let final dynamic #t2 = y = (#0#6#isSet ?{dynamic} #0#6 : let final dynamic #t3 = #0#6#isSet = true in #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic}) as{Unchecked} core::int in true))))
throw{for-error-handling} new core::StateError::•("Pattern matching error");
}
return y;
}
static method test2(dynamic x) → dynamic {
hoisted has-declared-initializer core::String a;
hoisted has-declared-initializer core::String b;
{
final synthesized dynamic #0#0 = x as{TypeError,ForDynamic} core::List<core::String>;
synthesized core::int #0#2;
synthesized core::bool #0#2#isSet = false;
final const synthesized core::int #0#3 = #C2;
synthesized dynamic #0#6;
synthesized core::bool #0#6#isSet = false;
synthesized dynamic #0#7;
synthesized core::bool #0#7#isSet = false;
if(!(#0#0 is core::List<dynamic> && (#0#2#isSet ?{core::int} #0#2 : let final dynamic #t4 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::>=}(#C2){(core::num) → core::bool} && ((#0#6#isSet ?{dynamic} #0#6 : let final dynamic #t5 = #0#6#isSet = true in #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic}) is core::String && (let final dynamic #t6 = a = (#0#6#isSet ?{dynamic} #0#6 : let final dynamic #t7 = #0#6#isSet = true in #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic}) as{Unchecked} core::String in true)) && ((#0#7#isSet ?{dynamic} #0#7 : let final dynamic #t8 = #0#7#isSet = true in #0#7 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2 : let final dynamic #t9 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic}) is core::String && (let final dynamic #t10 = b = (#0#7#isSet ?{dynamic} #0#7 : let final dynamic #t11 = #0#7#isSet = true in #0#7 = #0#0{core::List<dynamic>}.{core::List::[]}((#0#2#isSet ?{core::int} #0#2 : let final dynamic #t12 = #0#2#isSet = true in #0#2 = #0#0{core::List<dynamic>}.{core::List::length}{core::int}).{core::num::-}(1){(core::num) → core::int}){(core::int) → dynamic}) as{Unchecked} core::String in true))))
throw{for-error-handling} new core::StateError::•("Pattern matching error");
}
return a.{core::String::+}(b){(core::String) → core::String};
}
static method main() → dynamic {
self::expectEquals(self::test1(<core::int>[0]), 0);
self::expectThrows(() → void => self::test1(<dynamic>[]));
self::expectThrows(() → void => self::test1(<core::int>[0, 1, 2]));
self::expectEquals(self::test2(<core::String>["one", "two", "three", "four"]), "onefour");
self::expectThrows(() → void => self::test2(<core::String>["one"]));
self::expectThrows(() → void => self::test2("one"));
self::expectThrows(() → void => self::test2(null));
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected ${x} to be equal to ${y}.";
}
}
static method expectThrows(() → void f) → dynamic {
core::bool hasThrown = true;
try {
f(){() → void};
hasThrown = false;
}
on core::Object catch(final core::Object e) {
}
if(!hasThrown) {
throw "Expected function to throw.";
}
}
constants {
#C1 = 1
#C2 = 2
}