Version 2.12.0-59.0.dev
Merge commit '57cbfa73edc01f54dc8e32c4f2d497b8d5519ce7' into 'dev'
diff --git a/pkg/dartdev/lib/src/commands/fix.dart b/pkg/dartdev/lib/src/commands/fix.dart
index 9f4d350..6cb007f 100644
--- a/pkg/dartdev/lib/src/commands/fix.dart
+++ b/pkg/dartdev/lib/src/commands/fix.dart
@@ -17,7 +17,9 @@
class FixCommand extends DartdevCommand {
static const String cmdName = 'fix';
- // This command is hidden as it's currently experimental.
+ static final NumberFormat _numberFormat = NumberFormat.decimalPattern();
+
+ /// This command is hidden as it's currently experimental.
FixCommand() : super(cmdName, 'Fix Dart source code.', hidden: true) {
argParser.addFlag('dry-run',
abbr: 'n',
@@ -74,69 +76,67 @@
if (edits.isEmpty) {
log.stdout('Nothing to fix!');
} else {
- if (dryRun) {
- var details = fixes.details;
- details.sort((f1, f2) => path
- .relative(f1.path, from: dir.path)
- .compareTo(path.relative(f2.path, from: dir.path)));
+ var details = fixes.details;
+ details.sort((f1, f2) => path
+ .relative(f1.path, from: dir.path)
+ .compareTo(path.relative(f2.path, from: dir.path)));
- var fileCount = 0;
- var fixCount = 0;
+ var fileCount = 0;
+ var fixCount = 0;
- details.forEach((d) {
- ++fileCount;
- d.fixes.forEach((f) {
- fixCount += f.occurrences;
- });
+ details.forEach((d) {
+ ++fileCount;
+ d.fixes.forEach((f) {
+ fixCount += f.occurrences;
});
+ });
+ if (dryRun) {
log.stdout('');
-
- final bullet = log.ansi.bullet;
-
- for (var detail in details) {
- log.stdout(path.relative(detail.path, from: dir.path));
- final fixes = detail.fixes.toList();
- fixes.sort((a, b) => a.code.compareTo(b.code));
- for (var fix in fixes) {
- log.stdout(' ${fix.code} $bullet '
- '${_format(fix.occurrences)} ${_pluralFix(fix.occurrences)}');
- }
- log.stdout('');
- }
-
log.stdout('${_format(fixCount)} proposed ${_pluralFix(fixCount)} '
'in ${_format(fileCount)} ${pluralize("file", fileCount)}.');
+ _printDetails(details, dir);
} else {
progress = log.progress('Applying fixes');
- var fileCount = await _applyFixes(edits);
+ _applyFixes(edits);
progress.finish(showTiming: true);
- if (fileCount > 0) {
- log.stdout(
- 'Fixed ${_format(fileCount)} ${pluralize("file", fileCount)}.');
- }
+ _printDetails(details, dir);
+ log.stdout('${_format(fixCount)} ${_pluralFix(fixCount)} made in '
+ '${_format(fileCount)} ${pluralize("file", fileCount)}.');
}
}
return 0;
}
- Future<int> _applyFixes(List<SourceFileEdit> edits) async {
- var files = <String>{};
+ void _applyFixes(List<SourceFileEdit> edits) {
for (var edit in edits) {
var fileName = edit.file;
- files.add(fileName);
var file = io.File(fileName);
- var code = await file.exists() ? await file.readAsString() : '';
+ var code = file.existsSync() ? file.readAsStringSync() : '';
code = SourceEdit.applySequence(code, edit.edits);
- await file.writeAsString(code);
+ file.writeAsStringSync(code);
}
- return files.length;
}
String _pluralFix(int count) => count == 1 ? 'fix' : 'fixes';
- static final NumberFormat _numberFormat = NumberFormat.decimalPattern();
+ void _printDetails(List<BulkFix> details, io.Directory workingDir) {
+ log.stdout('');
+
+ final bullet = log.ansi.bullet;
+
+ for (var detail in details) {
+ log.stdout(path.relative(detail.path, from: workingDir.path));
+ final fixes = detail.fixes.toList();
+ fixes.sort((a, b) => a.code.compareTo(b.code));
+ for (var fix in fixes) {
+ log.stdout(' ${fix.code} $bullet '
+ '${_format(fix.occurrences)} ${_pluralFix(fix.occurrences)}');
+ }
+ log.stdout('');
+ }
+ }
static String _format(int value) => _numberFormat.format(value);
}
diff --git a/pkg/dartdev/test/commands/fix_test.dart b/pkg/dartdev/test/commands/fix_test.dart
index ff885d6..3303da3 100644
--- a/pkg/dartdev/test/commands/fix_test.dart
+++ b/pkg/dartdev/test/commands/fix_test.dart
@@ -44,7 +44,13 @@
var result = p.runSync('fix', [], workingDir: p.dirPath);
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
- expect(result.stdout, contains('Fixed 1 file.'));
+ expect(
+ result.stdout,
+ stringContainsInOrder([
+ 'Applying fixes...',
+ 'lib${Platform.pathSeparator}main.dart',
+ ' prefer_single_quotes $bullet 1 fix',
+ ]));
});
test('dry-run', () {
@@ -68,10 +74,14 @@
var result = p.runSync('fix', ['--dry-run', '.'], workingDir: p.dirPath);
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
- expect(result.stdout, contains('3 proposed fixes in 1 file.'));
- expect(result.stdout, contains('lib${Platform.pathSeparator}main.dart'));
- expect(result.stdout, contains(' annotate_overrides $bullet 1 fix'));
- expect(result.stdout, contains(' prefer_single_quotes $bullet 2 fixes'));
+ expect(
+ result.stdout,
+ stringContainsInOrder([
+ '3 proposed fixes in 1 file.',
+ 'lib${Platform.pathSeparator}main.dart',
+ ' annotate_overrides $bullet 1 fix',
+ ' prefer_single_quotes $bullet 2 fixes',
+ ]));
});
test('.', () {
@@ -88,7 +98,14 @@
var result = p.runSync('fix', ['.'], workingDir: p.dirPath);
expect(result.exitCode, 0);
expect(result.stderr, isEmpty);
- expect(result.stdout, contains('Fixed 1 file.'));
+ expect(
+ result.stdout,
+ stringContainsInOrder([
+ 'Applying fixes...',
+ 'lib${Platform.pathSeparator}main.dart',
+ ' prefer_single_quotes $bullet 1 fix',
+ '1 fix made in 1 file.',
+ ]));
});
test('excludes', () {
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 48eb3ed..0580af9 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -50,27 +50,36 @@
class SetupCompilerOptions {
static final sdkRoot = computePlatformBinariesLocation();
- static final sdkSummaryPath = p.join(sdkRoot.path, 'ddc_sdk.dill');
+ static final sdkUnsoundSummaryPath = p.join(sdkRoot.path, 'ddc_sdk.dill');
+ static final sdkSoundSummaryPath =
+ p.join(sdkRoot.path, 'ddc_outline_sound.dill');
static final librariesSpecificationUri =
p.join(p.dirname(p.dirname(getSdkPath())), 'libraries.json');
- static CompilerOptions getOptions() {
+ static CompilerOptions getOptions(bool soundNullSafety) {
var options = CompilerOptions()
..verbose = false // set to true for debugging
..sdkRoot = sdkRoot
..target = DevCompilerTarget(TargetFlags())
..librariesSpecificationUri = Uri.base.resolve('sdk/lib/libraries.json')
..omitPlatform = true
- ..sdkSummary = sdkRoot.resolve(sdkSummaryPath)
+ ..sdkSummary = sdkRoot.resolve(
+ soundNullSafety ? sdkSoundSummaryPath : sdkUnsoundSummaryPath)
..environmentDefines = const {};
return options;
}
- List<String> errors;
- final CompilerOptions options;
+ static final String dartUnsoundComment = '// @dart = 2.9';
+ static final String dartSoundComment = '//';
- SetupCompilerOptions() : options = getOptions() {
- errors = <String>[];
+ final List<String> errors = [];
+ final CompilerOptions options;
+ final String dartLangComment;
+
+ SetupCompilerOptions(bool soundNullSafety)
+ : options = getOptions(soundNullSafety),
+ dartLangComment =
+ soundNullSafety ? dartSoundComment : dartUnsoundComment {
options.onDiagnostic = (DiagnosticMessage m) {
errors.addAll(m.plainTextFormatted);
};
@@ -281,1563 +290,1564 @@
}
void main() {
- var options = SetupCompilerOptions();
+ group('Unsound null safety', () {
+ var options = SetupCompilerOptions(false);
- group('Expression compiler tests in extension method:', () {
- const source = '''
- // @dart = 2.9
- extension NumberParsing on String {
- int parseInt() {
- var ret = int.parse(this);
- /* evaluation placeholder */
- return ret;
- }
- }
- main() => 0;
- ''';
-
- TestDriver driver;
-
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'ret': '1234'},
- expression: 'typo',
- expectedError: "Error: Getter not found: 'typo'");
- });
-
- test('local (trimmed scope)', () async {
- // Test that current expression evaluation works in extension methods.
- //
- // Note: the actual scope is {#this, ret}, but #this is effectively
- // removed in the expression compilator because it does not exist
- // in JavaScript code.
- // See (full scope) tests for what will the evaluation will look like
- // when the mapping from dart symbols to JavaScipt symbols is added.
- await driver.check(
- scope: <String, String>{'ret': '1234'},
- expression: 'ret',
- expectedResult: '''
- (function(ret) {
+ group('Expression compiler tests in extension method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ var ret = int.parse(this);
+ /* evaluation placeholder */
return ret;
- }(
- 1234
- ))
- ''');
- });
-
- test('local (full scope)', () async {
- // Test evalution in extension methods in the future when the mapping
- // from kernel symbols to dartdevc symbols is added.
- //
- // Note: this currently fails due to
- // - incremental compiler not allowing #this as a parameter name
- await driver.check(
- scope: <String, String>{'ret': '1234', '#this': 'this'},
- expression: 'ret',
- expectedError:
- "Illegal parameter name '#this' found during expression compilation.");
- });
-
- test('this (full scope)', () async {
- // Test evalution in extension methods in the future when the mapping
- // from kernel symbols to dartdevc symbols is added.
- //
- // Note: this currently fails due to
- // - incremental compiler not allowing #this as a parameter name
- // - incremental compiler not mapping 'this' from user input to '#this'
- await driver.check(
- scope: <String, String>{'ret': '1234', '#this': 'this'},
- expression: 'this',
- expectedError:
- "Illegal parameter name '#this' found during expression compilation.");
- });
- });
-
- group('Expression compiler tests in static function:', () {
- const source = '''
- // @dart = 2.9
- int foo(int x, {int y}) {
- int z = 0;
- /* evaluation placeholder */
- return x + y + z;
- }
-
- main() => 0;
+ }
+ }
+ main() => 0;
''';
- TestDriver driver;
+ TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'ret': '1234'},
+ expression: 'typo',
+ expectedError: "Error: Getter not found: 'typo'");
+ });
+
+ test('local (trimmed scope)', () async {
+ // Test that current expression evaluation works in extension methods.
+ //
+ // Note: the actual scope is {#this, ret}, but #this is effectively
+ // removed in the expression compilator because it does not exist
+ // in JavaScript code.
+ // See (full scope) tests for what will the evaluation will look like
+ // when the mapping from dart symbols to JavaScipt symbols is added.
+ await driver.check(
+ scope: <String, String>{'ret': '1234'},
+ expression: 'ret',
+ expectedResult: '''
+ (function(ret) {
+ return ret;
+ }(
+ 1234
+ ))
+ ''');
+ });
+
+ test('local (full scope)', () async {
+ // Test evalution in extension methods in the future when the mapping
+ // from kernel symbols to dartdevc symbols is added.
+ //
+ // Note: this currently fails due to
+ // - incremental compiler not allowing #this as a parameter name
+ await driver.check(
+ scope: <String, String>{'ret': '1234', '#this': 'this'},
+ expression: 'ret',
+ expectedError:
+ "Illegal parameter name '#this' found during expression compilation.");
+ });
+
+ test('this (full scope)', () async {
+ // Test evalution in extension methods in the future when the mapping
+ // from kernel symbols to dartdevc symbols is added.
+ //
+ // Note: this currently fails due to
+ // - incremental compiler not allowing #this as a parameter name
+ // - incremental compiler not mapping 'this' from user input to '#this'
+ await driver.check(
+ scope: <String, String>{'ret': '1234', '#this': 'this'},
+ expression: 'this',
+ expectedError:
+ "Illegal parameter name '#this' found during expression compilation.");
+ });
});
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
- expression: 'typo',
- expectedError: "Getter not found: \'typo\'");
- });
-
- test('local', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
- expression: 'x',
- expectedResult: '''
- (function(x, y, z) {
- return x;
- }(
- 1,
- 2,
- 3
- ))
- ''');
- });
-
- test('formal', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
- expression: 'y',
- expectedResult: '''
- (function(x, y, z) {
- return y;
- }(
- 1,
- 2,
- 3
- ))
- ''');
- });
-
- test('named formal', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
- expression: 'z',
- expectedResult: '''
- (function(x, y, z) {
- return z;
- }(
- 1,
- 2,
- 3
- ))
- ''');
- });
-
- test('function', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
- expression: 'main',
- expectedResult: '''
- (function(x, y, z) {
- var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
- dart.defineLazy(CT, {
- get C0() {
- return C0 = dart.fn(foo.main, VoidTodynamic());
- }
- }, false);
- var C0;
- return C0 || CT.C0;
- }(
- 1,
- 2,
- 3
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in method:', () {
- const source = '''
- // @dart = 2.9
- extension NumberParsing on String {
- int parseInt() {
- return int.parse(this);
- }
- }
-
- int global = 42;
-
- class C {
- C(int this.field, int this._field);
-
- static int staticField = 0;
- static int _staticField = 1;
-
- int _field;
- int field;
-
- int methodFieldAccess(int x) {
+ group('Expression compiler tests in static function:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int foo(int x, {int y}) {
+ int z = 0;
/* evaluation placeholder */
- return x + _field + _staticField;
+ return x + y + z;
}
- Future<int> asyncMethod(int x) async {
- return x;
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'typo',
+ expectedError: "Getter not found: \'typo\'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, y, z) {
+ return x;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ });
+
+ test('formal', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'y',
+ expectedResult: '''
+ (function(x, y, z) {
+ return y;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ });
+
+ test('named formal', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'z',
+ expectedResult: '''
+ (function(x, y, z) {
+ return z;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ });
+
+ test('function', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'main',
+ expectedResult: '''
+ (function(x, y, z) {
+ var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.fn(foo.main, VoidTodynamic());
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
}
- }
- main() => 0;
- ''';
+ int global = 42;
- TestDriver driver;
+ class C {
+ C(int this.field, int this._field);
- setUp(() {
- driver = TestDriver(options, source);
- });
+ static int staticField = 0;
+ static int _staticField = 1;
- tearDown(() {
- driver.delete();
- });
+ int _field;
+ int field;
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'typo',
- expectedError: "The getter 'typo' isn't defined for the class 'C'");
- });
+ int methodFieldAccess(int x) {
+ /* evaluation placeholder */
+ return x + _field + _staticField;
+ }
- test('local', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x',
- expectedResult: '''
- (function(x) {
+ Future<int> asyncMethod(int x) async {
return x;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('this', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'this',
- expectedResult: '''
- (function(x) {
- return this;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using locals', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + 1',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + 1;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C.staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C._staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + field',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(this.field);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _field',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return dart.notNull(x) + dart.notNull(this[_field]);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using globals', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + global',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.global);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'methodFieldAccess(2)',
- expectedResult: '''
- (function(x) {
- return this.methodFieldAccess(2);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('async method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'asyncMethod(2)',
- expectedResult: '''
- (function(x) {
- return this.asyncMethod(2);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('extension method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '"1234".parseInt()',
- expectedResult: '''
- (function(x) {
- return foo['NumberParsing|parseInt']("1234");
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_field = 2',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return this[_field] = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'field = 2',
- expectedResult: '''
- (function(x) {
- return this.field = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C._staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C.staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in method with no field access:', () {
- const source = '''
- // @dart = 2.9
- extension NumberParsing on String {
- int parseInt() {
- return int.parse(this);
+ }
}
- }
- int global = 42;
+ main() => 0;
+ ''';
- class C {
- C(int this.field, int this._field);
+ TestDriver driver;
- static int staticField = 0;
- static int _staticField = 1;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
- int _field;
- int field;
+ tearDown(() {
+ driver.delete();
+ });
- int methodNoFieldAccess(int x) {
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using locals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + 1',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + 1;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using globals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + global',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.global);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.methodFieldAccess(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'asyncMethod(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.asyncMethod(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x) {
+ return foo['NumberParsing|parseInt']("1234");
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in method with no field access:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field);
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodNoFieldAccess(int x) {
+ /* evaluation placeholder */
+ return x;
+ }
+
+ Future<int> asyncMethod(int x) async {
+ return x;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in async method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ class C {
+ C(int this.field, int this._field);
+
+ int _field;
+ int field;
+
+ Future<int> asyncMethod(int x) async {
+ /* evaluation placeholder */
+ return x;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in global function:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field);
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodFieldAccess(int x) {
+ return (x + _field + _staticField);
+ }
+ int methodFieldAccess(int x) {
+ return (x)
+ }
+
+ Future<int> asyncMethod(int x) async {
+ return x;
+ }
+ }
+
+ int main() {
+ int x = 15;
+ var c = C(1, 2);
/* evaluation placeholder */
- return x;
+ return 0;
}
+ ''';
- Future<int> asyncMethod(int x) async {
- return x;
- }
- }
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
- main() => 0;
- ''';
+ tearDown(() {
+ driver.delete();
+ });
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'typo',
+ expectedError: "Getter not found: 'typo'.");
+ });
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'typo',
- expectedError: "The getter 'typo' isn't defined for the class 'C'");
- });
-
- test('expression using static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C.staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C._staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + field',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(this.field);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _field',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return dart.notNull(x) + dart.notNull(this[_field]);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_field = 2',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return this[_field] = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'field = 2',
- expectedResult: '''
- (function(x) {
- return this.field = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C._staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C.staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in async method:', () {
- const source = '''
- // @dart = 2.9
- class C {
- C(int this.field, int this._field);
-
- int _field;
- int field;
-
- Future<int> asyncMethod(int x) async {
- /* evaluation placeholder */
- return x;
- }
- }
-
- main() => 0;
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'typo',
- expectedError: "The getter 'typo' isn't defined for the class 'C'");
- });
-
- test('local', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x',
- expectedResult: '''
- (function(x) {
- return x;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('this', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'this',
- expectedResult: '''
- (function(x) {
- return this;
- }.bind(this)(
- 1
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in global function:', () {
- const source = '''
- // @dart = 2.9
- extension NumberParsing on String {
- int parseInt() {
- return int.parse(this);
- }
- }
-
- int global = 42;
-
- class C {
- C(int this.field, int this._field);
-
- static int staticField = 0;
- static int _staticField = 1;
-
- int _field;
- int field;
-
- int methodFieldAccess(int x) {
- return (x + _field + _staticField);
- }
- int methodFieldAccess(int x) {
- return (x)
- }
-
- Future<int> asyncMethod(int x) async {
- return x;
- }
- }
-
- int main() {
- int x = 15;
- var c = C(1, 2);
- /* evaluation placeholder */
- return 0;
- }
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'typo',
- expectedError: "Getter not found: 'typo'.");
- });
-
- test('local with primitive type', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'x',
- expectedResult: '''
- (function(x, c) {
- return x;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('local object', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c',
- expectedResult: '''
- (function(x, c) {
- return c;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('create new object', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C(1,3)',
- expectedResult: '''
+ test('local with primitive type', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'x',
+ expectedResult: '''
(function(x, c) {
- return new foo.C.new(1, 3);
+ return x;
}(
1,
null
))
''');
- });
+ });
- test('access field of new object', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C(1,3)._field',
- expectedResult: '''
- (function(x, c) {
- let _field = dart.privateName(foo, "_field");
- return new foo.C.new(1, 3)[_field];
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('access static field', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C.staticField',
- expectedResult: '''
- (function(x, c) {
- return foo.C.staticField;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('expression using private static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C._staticField',
- expectedError: "Error: Getter not found: '_staticField'.");
- });
-
- test('access field', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c.field',
- expectedResult: '''
- (function(x, c) {
- return c.field;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('access private field', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c._field',
- expectedResult: '''
- (function(x, c) {
- let _field = dart.privateName(foo, "_field");
- return c[_field];
- }(
+ test('local object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c',
+ expectedResult: '''
+ (function(x, c) {
+ return c;
+ }(
1,
null
- ))
- ''');
+ ))
+ ''');
+ });
+
+ test('create new object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C(1,3)',
+ expectedResult: '''
+ (function(x, c) {
+ return new foo.C.new(1, 3);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('access field of new object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C(1,3)._field',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return new foo.C.new(1, 3)[_field];
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('access static field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C.staticField',
+ expectedResult: '''
+ (function(x, c) {
+ return foo.C.staticField;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C._staticField',
+ expectedError: "Error: Getter not found: '_staticField'.");
+ });
+
+ test('access field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.field',
+ expectedResult: '''
+ (function(x, c) {
+ return c.field;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('access private field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c._field',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return c[_field];
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x, c) {
+ return c.methodFieldAccess(2);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.asyncMethod(2)',
+ expectedResult: '''
+ (function(x, c) {
+ return c.asyncMethod(2);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x, c) {
+ return foo['NumberParsing|parseInt']("1234");
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c._field = 2',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return c[_field] = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.field = 2',
+ expectedResult: '''
+ (function(x, c) {
+ return c.field = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C._staticField = 2',
+ expectedError: "Setter not found: '_staticField'.");
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C.staticField = 2',
+ expectedResult: '''
+ (function(x, c) {
+ return foo.C.staticField = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('call global function from core library', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'print(x)',
+ expectedResult: '''
+ (function(x, c) {
+ return core.print(x);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
});
- test('method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c.methodFieldAccess(2)',
- expectedResult: '''
- (function(x, c) {
- return c.methodFieldAccess(2);
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('async method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c.asyncMethod(2)',
- expectedResult: '''
- (function(x, c) {
- return c.asyncMethod(2);
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('extension method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: '"1234".parseInt()',
- expectedResult: '''
- (function(x, c) {
- return foo['NumberParsing|parseInt']("1234");
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('private field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c._field = 2',
- expectedResult: '''
- (function(x, c) {
- let _field = dart.privateName(foo, "_field");
- return c[_field] = 2;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'c.field = 2',
- expectedResult: '''
- (function(x, c) {
- return c.field = 2;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('private static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C._staticField = 2',
- expectedError: "Setter not found: '_staticField'.");
- });
-
- test('static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'C.staticField = 2',
- expectedResult: '''
- (function(x, c) {
- return foo.C.staticField = 2;
- }(
- 1,
- null
- ))
- ''');
- });
-
- test('call global function from core library', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'print(x)',
- expectedResult: '''
- (function(x, c) {
- return core.print(x);
- }(
- 1,
- null
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in closures:', () {
- const source = r'''
- // @dart = 2.9
- int globalFunction() {
- int x = 15;
- var c = C(1, 2);
-
- var outerClosure = (int y) {
- var closureCaptureInner = (int z) {
- /* evaluation placeholder */
- print('$y+$z');
- };
- closureCaptureInner(0);
- };
-
- outerClosure(3);
- return 0;
- }
-
- main() => 0;
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
- expression: 'typo',
- expectedError: "Getter not found: 'typo'.");
- });
-
- test('expression using uncaptured variables', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
- expression: r"'$x+$y+$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- return dart.str(x) + "+" + dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
-
- test('expression using captured variables', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
- expression: r"'$y+$z'",
- expectedResult: '''
- (function(x, c, y, z) {
- return dart.str(y) + "+" + dart.str(z);
- }(
- 1,
- null,
- 3,
- 0
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in method with no type use', () {
- const source = '''
- // @dart = 2.9
- abstract class Key {
- const factory Key(String value) = ValueKey;
- const Key.empty();
- }
-
- abstract class LocalKey extends Key {
- const LocalKey() : super.empty();
- }
-
- class ValueKey implements LocalKey {
- const ValueKey(this.value);
- final String value;
- }
-
- class MyClass {
- const MyClass(this._t);
- final int _t;
- }
-
- int bar(int p){
- return p;
- }
- int baz(String t){
- return t;
- }
- void main() {
- var k = Key('t');
- MyClass c = MyClass(0);
- int p = 1;
- const t = 1;
-
- /* evaluation placeholder */
- print('\$c, \$k, \$t');
- }
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('call function using type', () async {
- await driver.check(
- scope: <String, String>{'p': '1'},
- expression: 'bar(p)',
- expectedResult: '''
- (function(p) {
- return foo.bar(p);
- }(
- 1
- ))
- ''');
- });
-
- test('call function using type', () async {
- await driver.check(
- scope: <String, String>{'p': '0'},
- expression: 'baz(p as String)',
- expectedResult: '''
- (function(p) {
- var StringL = () => (StringL = dart.constFn(dart.legacy(core.String)))();
- return foo.baz(StringL().as(p));
- }(
- 0
- ))
- ''');
- });
-
- test('evaluate new const expression', () async {
- await driver.check(
- scope: <String, String>{'p': '1'},
- expression: 'const MyClass(1)',
- expectedResult: '''
- (function(p) {
- dart.defineLazy(CT, {
- get C0() {
- return C0 = dart.const({
- __proto__: foo.MyClass.prototype,
- [_t]: 1
- });
- }
- }, false);
- var C0;
- return C0 || CT.C0;
- }(
- 1
- ))
- ''');
- });
-
- test('evaluate optimized const expression', () async {
- await driver.check(
- scope: <String, String>{},
- expression: 't',
- expectedResult: '''
- (function() {
- return 1;
- }(
- ))
- ''');
- },
- skip: 'Cannot compile constants optimized away by the frontend. '
- 'Issue: https://github.com/dart-lang/sdk/issues/41999');
-
- test('evaluate factory constructor call', () async {
- await driver.check(
- scope: <String, String>{'p': '1'},
- expression: "Key('t')",
- expectedResult: '''
- (function(p) {
- return new foo.ValueKey.new("t");
- }(
- 1
- ))
- ''');
- });
-
- test('evaluate const factory constructor call', () async {
- await driver.check(
- scope: <String, String>{'p': '1'},
- expression: "const Key('t')",
- expectedResult: '''
- (function(p) {
- dart.defineLazy(CT, {
- get C0() {
- return C0 = dart.const({
- __proto__: foo.ValueKey.prototype,
- [value]: "t"
- });
- }
- }, false);
- var C0;
- return C0 || CT.C0;
- }(
- 1
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in constructor:', () {
- const source = '''
- // @dart = 2.9
- extension NumberParsing on String {
- int parseInt() {
- return int.parse(this);
- }
- }
-
- int global = 42;
-
- class C {
- C(int this.field, int this._field) {
- int x = 1;
- /* evaluation placeholder */
- print(this.field);
- }
-
- static int staticField = 0;
- static int _staticField = 1;
-
- int _field;
- int field;
-
- int methodFieldAccess(int t) {
- return t + _field + _staticField;
- }
-
- Future<int> asyncMethod(int t) async {
- return t;
- }
- }
-
- main() => 0;
- ''';
-
- TestDriver driver;
-
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('compilation error', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'typo',
- expectedError: "The getter 'typo' isn't defined for the class 'C'");
- });
-
- test('local', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x',
- expectedResult: '''
- (function(x) {
- return x;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('this', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'this',
- expectedResult: '''
- (function(x) {
- return this;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using locals', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + 1',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + 1;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C.staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private static fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _staticField',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.C._staticField);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + field',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(this.field);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using private fields', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + _field',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return dart.notNull(x) + dart.notNull(this[_field]);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('expression using globals', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'x + global',
- expectedResult: '''
- (function(x) {
- return dart.notNull(x) + dart.notNull(foo.global);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'methodFieldAccess(2)',
- expectedResult: '''
- (function(x) {
- return this.methodFieldAccess(2);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('async method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'asyncMethod(2)',
- expectedResult: '''
- (function(x) {
- return this.asyncMethod(2);
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('extension method call', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '"1234".parseInt()',
- expectedResult: '''
- (function(x) {
- return foo['NumberParsing|parseInt']("1234");
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_field = 2',
- expectedResult: '''
- (function(x) {
- let _field = dart.privateName(foo, "_field");
- return this[_field] = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'field = 2',
- expectedResult: '''
- (function(x) {
- return this.field = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('private static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: '_staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C._staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
-
- test('static field modification', () async {
- await driver.check(
- scope: <String, String>{'x': '1'},
- expression: 'staticField = 2',
- expectedResult: '''
- (function(x) {
- return foo.C.staticField = 2;
- }.bind(this)(
- 1
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in loops:', () {
- const source = r'''
- // @dart = 2.9
- int globalFunction() {
+ group('Expression compiler tests in closures:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
int x = 15;
var c = C(1, 2);
- for(int i = 0; i < 10; i++) {
- /* evaluation placeholder */
- print('$i+$x');
+ var outerClosure = (int y) {
+ var closureCaptureInner = (int z) {
+ /* evaluation placeholder */
+ print('\$y+\$z');
+ };
+ closureCaptureInner(0);
};
+
+ outerClosure(3);
return 0;
}
main() => 0;
''';
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: 'typo',
+ expectedError: "Getter not found: 'typo'.");
+ });
+
+ test('expression using uncaptured variables', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: r"'$x+$y+$z'",
+ expectedResult: '''
+ (function(x, c, y, z) {
+ return dart.str(x) + "+" + dart.str(y) + "+" + dart.str(z);
+ }(
+ 1,
+ null,
+ 3,
+ 0
+ ))
+ ''');
+ });
+
+ test('expression using captured variables', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: r"'$y+$z'",
+ expectedResult: '''
+ (function(x, c, y, z) {
+ return dart.str(y) + "+" + dart.str(z);
+ }(
+ 1,
+ null,
+ 3,
+ 0
+ ))
+ ''');
+ });
});
- tearDown(() {
- driver.delete();
- });
-
- test('expression using local', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
- expression: 'x',
- expectedResult: '''
- (function(x, c, i) {
- return x;
- }(
- 1,
- null,
- 0
- ))
- ''');
- });
-
- test('expression using loop variable', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
- expression: 'i',
- expectedResult: '''
- (function(x, c, i) {
- return i;
- }(
- 1,
- null,
- 0
- ))
- ''');
- });
- });
-
- group('Expression compiler tests in conditional (then):', () {
- const source = r'''
- // @dart = 2.9
- int globalFunction() {
- int x = 1;
- var c = C(1, 2);
-
- if (x == 14) {
- int y = 3;
- /* evaluation placeholder */
- print('$y+$x');
- } else {
- int z = 3;
- print('$z+$x');
+ group('Expression compiler tests in method with no type use', () {
+ var source = '''
+ ${options.dartLangComment}
+ abstract class Key {
+ const factory Key(String value) = ValueKey;
+ const Key.empty();
}
- return 0;
- }
- main() => 0;
- ''';
-
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
-
- tearDown(() {
- driver.delete();
- });
-
- test('expression using local', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
- expression: 'y',
- expectedResult: '''
- (function(x, c, y) {
- return y;
- }(
- 1,
- null,
- 3
- ))
- ''');
- });
-
- test('expression using local out of scope', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
- expression: 'z',
- expectedError: "Error: Getter not found: 'z'");
- });
- });
-
- group('Expression compiler tests in conditional (else):', () {
- const source = r'''
- // @dart = 2.9
- int globalFunction() {
- int x = 1;
- var c = C(1, 2);
-
- if (x == 14) {
- int y = 3;
- print('$y+$x');
- } else {
- int z = 3;
- /* evaluation placeholder */
- print('$z+$x');
+ abstract class LocalKey extends Key {
+ const LocalKey() : super.empty();
}
- return 0;
- }
- main() => 0;
- ''';
+ class ValueKey implements LocalKey {
+ const ValueKey(this.value);
+ final String value;
+ }
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
+ class MyClass {
+ const MyClass(this._t);
+ final int _t;
+ }
+
+ int bar(int p){
+ return p;
+ }
+ int baz(String t){
+ return t;
+ }
+ void main() {
+ var k = Key('t');
+ MyClass c = MyClass(0);
+ int p = 1;
+ const t = 1;
+
+ /* evaluation placeholder */
+ print('\$c, \$k, \$t');
+ }
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('call function using type', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: 'bar(p)',
+ expectedResult: '''
+ (function(p) {
+ return foo.bar(p);
+ }(
+ 1
+ ))
+ ''');
+ });
+
+ test('call function using type', () async {
+ await driver.check(
+ scope: <String, String>{'p': '0'},
+ expression: 'baz(p as String)',
+ expectedResult: '''
+ (function(p) {
+ var StringL = () => (StringL = dart.constFn(dart.legacy(core.String)))();
+ return foo.baz(StringL().as(p));
+ }(
+ 0
+ ))
+ ''');
+ });
+
+ test('evaluate new const expression', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: 'const MyClass(1)',
+ expectedResult: '''
+ (function(p) {
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.const({
+ __proto__: foo.MyClass.prototype,
+ [_t]: 1
+ });
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1
+ ))
+ ''');
+ });
+
+ test('evaluate optimized const expression', () async {
+ await driver.check(
+ scope: <String, String>{},
+ expression: 't',
+ expectedResult: '''
+ (function() {
+ return 1;
+ }(
+ ))
+ ''');
+ },
+ skip: 'Cannot compile constants optimized away by the frontend. '
+ 'Issue: https://github.com/dart-lang/sdk/issues/41999');
+
+ test('evaluate factory constructor call', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: "Key('t')",
+ expectedResult: '''
+ (function(p) {
+ return new foo.ValueKey.new("t");
+ }(
+ 1
+ ))
+ ''');
+ });
+
+ test('evaluate const factory constructor call', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: "const Key('t')",
+ expectedResult: '''
+ (function(p) {
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.const({
+ __proto__: foo.ValueKey.prototype,
+ [value]: "t"
+ });
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1
+ ))
+ ''');
+ });
});
- tearDown(() {
- driver.delete();
- });
+ group('Expression compiler tests in constructor:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
- test('expression using local', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
- expression: 'z',
- expectedResult: '''
- (function(x, c, z) {
- return z;
- }(
- 1,
- null,
- 3
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field) {
+ int x = 1;
+ /* evaluation placeholder */
+ print(this.field);
+ }
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodFieldAccess(int t) {
+ return t + _field + _staticField;
+ }
+
+ Future<int> asyncMethod(int t) async {
+ return t;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using locals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + 1',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + 1;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using globals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + global',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.global);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.methodFieldAccess(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'asyncMethod(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.asyncMethod(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x) {
+ return foo['NumberParsing|parseInt']("1234");
+ }.bind(this)(
+ 1
))
''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
});
- test('expression using local out of scope', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
- expression: 'y',
- expectedError: "Error: Getter not found: 'y'");
- });
- });
+ group('Expression compiler tests in loops:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 15;
+ var c = C(1, 2);
- group('Expression compiler tests after conditionals:', () {
- const source = r'''
- // @dart = 2.9
+ for(int i = 0; i < 10; i++) {
+ /* evaluation placeholder */
+ print('\$i+\$x');
+ };
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, c, i) {
+ return x;
+ }(
+ 1,
+ null,
+ 0
+ ))
+ ''');
+ });
+
+ test('expression using loop variable', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
+ expression: 'i',
+ expectedResult: '''
+ (function(x, c, i) {
+ return i;
+ }(
+ 1,
+ null,
+ 0
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in conditional (then):', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 1;
+ var c = C(1, 2);
+
+ if (x == 14) {
+ int y = 3;
+ /* evaluation placeholder */
+ print('\$y+\$x');
+ } else {
+ int z = 3;
+ print('\$z+\$x');
+ }
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
+ expression: 'y',
+ expectedResult: '''
+ (function(x, c, y) {
+ return y;
+ }(
+ 1,
+ null,
+ 3
+ ))
+ ''');
+ });
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
+ expression: 'z',
+ expectedError: "Error: Getter not found: 'z'");
+ });
+ });
+
+ group('Expression compiler tests in conditional (else):', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 1;
+ var c = C(1, 2);
+
+ if (x == 14) {
+ int y = 3;
+ print('\$y+\$x');
+ } else {
+ int z = 3;
+ /* evaluation placeholder */
+ print('\$z+\$x');
+ }
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
+ expression: 'z',
+ expectedResult: '''
+ (function(x, c, z) {
+ return z;
+ }(
+ 1,
+ null,
+ 3
+ ))
+ ''');
+ });
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
+ expression: 'y',
+ expectedError: "Error: Getter not found: 'y'");
+ });
+ });
+
+ group('Expression compiler tests after conditionals:', () {
+ var source = '''
+ ${options.dartLangComment}
int globalFunction() {
int x = 1;
var c = C(1, 2);
if (x == 14) {
int y = 3;
- print('$y+$x');
+ print('\$y+\$x');
} else {
int z = 3;
- print('$z+$x');
+ print('\$z+\$x');
}
/* evaluation placeholder */
return 0;
@@ -1846,20 +1856,20 @@
main() => 0;
''';
- TestDriver driver;
- setUp(() {
- driver = TestDriver(options, source);
- });
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
- tearDown(() {
- driver.delete();
- });
+ tearDown(() {
+ driver.delete();
+ });
- test('expression using local', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'x',
- expectedResult: '''
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'x',
+ expectedResult: '''
(function(x, c) {
return x;
}(
@@ -1867,13 +1877,1612 @@
null
))
''');
+ });
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'z',
+ expectedError: "Error: Getter not found: 'z'");
+ });
+ });
+ });
+
+ group('Sound null safety', () {
+ var options = SetupCompilerOptions(true);
+
+ group('Expression compiler tests in extension method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ var ret = int.parse(this);
+ /* evaluation placeholder */
+ return ret;
+ }
+ }
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'ret': '1234'},
+ expression: 'typo',
+ expectedError: "Error: Getter not found: 'typo'");
+ });
+
+ test('local (trimmed scope)', () async {
+ // Test that current expression evaluation works in extension methods.
+ //
+ // Note: the actual scope is {#this, ret}, but #this is effectively
+ // removed in the expression compilator because it does not exist
+ // in JavaScript code.
+ // See (full scope) tests for what will the evaluation will look like
+ // when the mapping from dart symbols to JavaScipt symbols is added.
+ await driver.check(
+ scope: <String, String>{'ret': '1234'},
+ expression: 'ret',
+ expectedResult: '''
+ (function(ret) {
+ return ret;
+ }(
+ 1234
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('local (full scope)', () async {
+ // Test evalution in extension methods in the future when the mapping
+ // from kernel symbols to dartdevc symbols is added.
+ //
+ // Note: this currently fails due to
+ // - incremental compiler not allowing #this as a parameter name
+ await driver.check(
+ scope: <String, String>{'ret': '1234', '#this': 'this'},
+ expression: 'ret',
+ expectedError:
+ "Illegal parameter name '#this' found during expression compilation.");
+ });
+
+ test('this (full scope)', () async {
+ // Test evalution in extension methods in the future when the mapping
+ // from kernel symbols to dartdevc symbols is added.
+ //
+ // Note: this currently fails due to
+ // - incremental compiler not allowing #this as a parameter name
+ // - incremental compiler not mapping 'this' from user input to '#this'
+ await driver.check(
+ scope: <String, String>{'ret': '1234', '#this': 'this'},
+ expression: 'this',
+ expectedError:
+ "Illegal parameter name '#this' found during expression compilation.");
+ });
});
- test('expression using local out of scope', () async {
- await driver.check(
- scope: <String, String>{'x': '1', 'c': 'null'},
- expression: 'z',
- expectedError: "Error: Getter not found: 'z'");
+ group('Expression compiler tests in static function:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int foo(int x, {int y}) {
+ int z = 0;
+ /* evaluation placeholder */
+ return x + y + z;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'typo',
+ expectedError: "Getter not found: \'typo\'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, y, z) {
+ return x;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('formal', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'y',
+ expectedResult: '''
+ (function(x, y, z) {
+ return y;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('named formal', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'z',
+ expectedResult: '''
+ (function(x, y, z) {
+ return z;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('function', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+ expression: 'main',
+ expectedResult: '''
+ (function(x, y, z) {
+ var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.fn(foo.main, VoidTodynamic());
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1,
+ 2,
+ 3
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field);
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodFieldAccess(int x) {
+ /* evaluation placeholder */
+ return x + _field + _staticField;
+ }
+
+ Future<int> asyncMethod(int x) async {
+ return x;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using locals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + 1',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + 1;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using globals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + global',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.global);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.methodFieldAccess(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'asyncMethod(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.asyncMethod(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x) {
+ return foo['NumberParsing|parseInt']("1234");
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in method with no field access:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field);
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodNoFieldAccess(int x) {
+ /* evaluation placeholder */
+ return x;
+ }
+
+ Future<int> asyncMethod(int x) async {
+ return x;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in async method:', () {
+ var source = '''
+ ${options.dartLangComment}
+ class C {
+ C(int this.field, int this._field);
+
+ int _field;
+ int field;
+
+ Future<int> asyncMethod(int x) async {
+ /* evaluation placeholder */
+ return x;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in global function:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field);
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodFieldAccess(int x) {
+ return (x + _field + _staticField);
+ }
+ int methodFieldAccess(int x) {
+ return (x)
+ }
+
+ Future<int> asyncMethod(int x) async {
+ return x;
+ }
+ }
+
+ int main() {
+ int x = 15;
+ var c = C(1, 2);
+ /* evaluation placeholder */
+ return 0;
+ }
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'typo',
+ expectedError: "Getter not found: 'typo'.");
+ });
+
+ test('local with primitive type', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, c) {
+ return x;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('local object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c',
+ expectedResult: '''
+ (function(x, c) {
+ return c;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('create new object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C(1,3)',
+ expectedResult: '''
+ (function(x, c) {
+ return new foo.C.new(1, 3);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('access field of new object', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C(1,3)._field',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return new foo.C.new(1, 3)[_field];
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('access static field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C.staticField',
+ expectedResult: '''
+ (function(x, c) {
+ return foo.C.staticField;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C._staticField',
+ expectedError: "Error: Getter not found: '_staticField'.");
+ });
+
+ test('access field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.field',
+ expectedResult: '''
+ (function(x, c) {
+ return c.field;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('access private field', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c._field',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return c[_field];
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x, c) {
+ return c.methodFieldAccess(2);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.asyncMethod(2)',
+ expectedResult: '''
+ (function(x, c) {
+ return c.asyncMethod(2);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x, c) {
+ return foo['NumberParsing|parseInt']("1234");
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c._field = 2',
+ expectedResult: '''
+ (function(x, c) {
+ let _field = dart.privateName(foo, "_field");
+ return c[_field] = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'c.field = 2',
+ expectedResult: '''
+ (function(x, c) {
+ return c.field = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C._staticField = 2',
+ expectedError: "Setter not found: '_staticField'.");
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'C.staticField = 2',
+ expectedResult: '''
+ (function(x, c) {
+ return foo.C.staticField = 2;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ });
+
+ test('call global function from core library', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'print(x)',
+ expectedResult: '''
+ (function(x, c) {
+ return core.print(x);
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+ });
+
+ group('Expression compiler tests in closures:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 15;
+ var c = C(1, 2);
+
+ var outerClosure = (int y) {
+ var closureCaptureInner = (int z) {
+ /* evaluation placeholder */
+ print('\$y+\$z');
+ };
+ closureCaptureInner(0);
+ };
+
+ outerClosure(3);
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: 'typo',
+ expectedError: "Getter not found: 'typo'.");
+ });
+
+ test('expression using uncaptured variables', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: r"'$x+$y+$z'",
+ expectedResult: '''
+ (function(x, c, y, z) {
+ return dart.str(x) + "+" + dart.str(y) + "+" + dart.str(z);
+ }(
+ 1,
+ null,
+ 3,
+ 0
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using captured variables', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3', 'z': '0'},
+ expression: r"'$y+$z'",
+ expectedResult: '''
+ (function(x, c, y, z) {
+ return dart.str(y) + "+" + dart.str(z);
+ }(
+ 1,
+ null,
+ 3,
+ 0
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+ });
+
+ group('Expression compiler tests in method with no type use', () {
+ var source = '''
+ ${options.dartLangComment}
+ abstract class Key {
+ const factory Key(String value) = ValueKey;
+ const Key.empty();
+ }
+
+ abstract class LocalKey extends Key {
+ const LocalKey() : super.empty();
+ }
+
+ class ValueKey implements LocalKey {
+ const ValueKey(this.value);
+ final String value;
+ }
+
+ class MyClass {
+ const MyClass(this._t);
+ final int _t;
+ }
+
+ int bar(int p){
+ return p;
+ }
+ int baz(String t){
+ return t;
+ }
+ void main() {
+ var k = Key('t');
+ MyClass c = MyClass(0);
+ int p = 1;
+ const t = 1;
+
+ /* evaluation placeholder */
+ print('\$c, \$k, \$t');
+ }
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('call function not using type', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: 'bar(p)',
+ expectedResult: '''
+ (function(p) {
+ return foo.bar(p);
+ }(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('call function using type', () async {
+ await driver.check(
+ scope: <String, String>{'p': '0'},
+ expression: 'baz(p as String)',
+ expectedResult: '''
+ (function(p) {
+ var StringL = () => (StringL = dart.constFn(dart.legacy(core.String)))();
+ return foo.baz(StringL().as(p));
+ }(
+ 0
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('evaluate new const expression', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: 'const MyClass(1)',
+ expectedResult: '''
+ (function(p) {
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.const({
+ __proto__: foo.MyClass.prototype,
+ [_t]: 1
+ });
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1
+ ))
+ ''');
+ });
+
+ test('evaluate optimized const expression', () async {
+ await driver.check(
+ scope: <String, String>{},
+ expression: 't',
+ expectedResult: '''
+ (function() {
+ return 1;
+ }(
+ ))
+ ''');
+ },
+ skip: 'Cannot compile constants optimized away by the frontend. '
+ 'Issue: https://github.com/dart-lang/sdk/issues/41999');
+
+ test('evaluate factory constructor call', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: "Key('t')",
+ expectedResult: '''
+ (function(p) {
+ return new foo.ValueKey.new("t");
+ }(
+ 1
+ ))
+ ''');
+ });
+
+ test('evaluate const factory constructor call', () async {
+ await driver.check(
+ scope: <String, String>{'p': '1'},
+ expression: "const Key('t')",
+ expectedResult: '''
+ (function(p) {
+ dart.defineLazy(CT, {
+ get C0() {
+ return C0 = dart.const({
+ __proto__: foo.ValueKey.prototype,
+ [value]: "t"
+ });
+ }
+ }, false);
+ var C0;
+ return C0 || CT.C0;
+ }(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in constructor:', () {
+ var source = '''
+ ${options.dartLangComment}
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this);
+ }
+ }
+
+ int global = 42;
+
+ class C {
+ C(int this.field, int this._field) {
+ int x = 1;
+ /* evaluation placeholder */
+ print(this.field);
+ }
+
+ static int staticField = 0;
+ static int _staticField = 1;
+
+ int _field;
+ int field;
+
+ int methodFieldAccess(int t) {
+ return t + _field + _staticField;
+ }
+
+ Future<int> asyncMethod(int t) async {
+ return t;
+ }
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x) {
+ return x;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('this', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'this',
+ expectedResult: '''
+ (function(x) {
+ return this;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('expression using locals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + 1',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + 1;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C.staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _staticField',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.C._staticField);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + field',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(this.field);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using private fields', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + _field',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return dart.notNull(x) + dart.notNull(this[_field]);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using globals', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'x + global',
+ expectedResult: '''
+ (function(x) {
+ return dart.notNull(x) + dart.notNull(foo.global);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'methodFieldAccess(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.methodFieldAccess(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'asyncMethod(2)',
+ expectedResult: '''
+ (function(x) {
+ return this.asyncMethod(2);
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '"1234".parseInt()',
+ expectedResult: '''
+ (function(x) {
+ return foo['NumberParsing|parseInt']("1234");
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_field = 2',
+ expectedResult: '''
+ (function(x) {
+ let _field = dart.privateName(foo, "_field");
+ return this[_field] = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'field = 2',
+ expectedResult: '''
+ (function(x) {
+ return this.field = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: '_staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C._staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1'},
+ expression: 'staticField = 2',
+ expectedResult: '''
+ (function(x) {
+ return foo.C.staticField = 2;
+ }.bind(this)(
+ 1
+ ))
+ ''');
+ });
+ });
+
+ group('Expression compiler tests in loops:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 15;
+ var c = C(1, 2);
+
+ for(int i = 0; i < 10; i++) {
+ /* evaluation placeholder */
+ print('\$i+\$x');
+ };
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, c, i) {
+ return x;
+ }(
+ 1,
+ null,
+ 0
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using loop variable', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'i': '0'},
+ expression: 'i',
+ expectedResult: '''
+ (function(x, c, i) {
+ return i;
+ }(
+ 1,
+ null,
+ 0
+ ))
+ ''');
+ });
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ group('Expression compiler tests in conditional (then):', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 1;
+ var c = C(1, 2);
+
+ if (x == 14) {
+ int y = 3;
+ /* evaluation placeholder */
+ print('\$y+\$x');
+ } else {
+ int z = 3;
+ print('\$z+\$x');
+ }
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
+ expression: 'y',
+ expectedResult: '''
+ (function(x, c, y) {
+ return y;
+ }(
+ 1,
+ null,
+ 3
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'y': '3'},
+ expression: 'z',
+ expectedError: "Error: Getter not found: 'z'");
+ });
+ });
+
+ group('Expression compiler tests in conditional (else):', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 1;
+ var c = C(1, 2);
+
+ if (x == 14) {
+ int y = 3;
+ print('\$y+\$x');
+ } else {
+ int z = 3;
+ /* evaluation placeholder */
+ print('\$z+\$x');
+ }
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
+ expression: 'z',
+ expectedResult: '''
+ (function(x, c, z) {
+ return z;
+ }(
+ 1,
+ null,
+ 3
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null', 'z': '3'},
+ expression: 'y',
+ expectedError: "Error: Getter not found: 'y'");
+ });
+ });
+
+ group('Expression compiler tests after conditionals:', () {
+ var source = '''
+ ${options.dartLangComment}
+ int globalFunction() {
+ int x = 1;
+ var c = C(1, 2);
+
+ if (x == 14) {
+ int y = 3;
+ print('\$y+\$x');
+ } else {
+ int z = 3;
+ print('\$z+\$x');
+ }
+ /* evaluation placeholder */
+ return 0;
+ }
+
+ main() => 0;
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('expression using local', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'x',
+ expectedResult: '''
+ (function(x, c) {
+ return x;
+ }(
+ 1,
+ null
+ ))
+ ''');
+ }, skip: 'https://github.com/dart-lang/sdk/issues/44235');
+
+ test('expression using local out of scope', () async {
+ await driver.check(
+ scope: <String, String>{'x': '1', 'c': 'null'},
+ expression: 'z',
+ expectedError: "Error: Getter not found: 'z'");
+ });
});
});
}
diff --git a/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart b/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart
new file mode 100644
index 0000000..b70a3d4
--- /dev/null
+++ b/runtime/tests/vm/dart/strict_null_safety_checks_in_weak_mode_test.dart
@@ -0,0 +1,152 @@
+// Copyright (c) 2020, 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.
+
+// This test verifies that with --strict_null_safety_checks runtime casts and
+// required parameters have strong mode semantics in weak mode.
+// Derived from tests/language/nnbd/subtyping/type_casts_strong_test.dart
+// and tests/language/nnbd/required_named_parameters/required_named_args_strong_test.dart.
+
+// VMOptions=--strict_null_safety_checks --optimization_counter_threshold=10 --deterministic
+// Requirements=nnbd-weak
+
+import 'package:expect/expect.dart';
+
+class C {}
+
+class W<T> {
+ @pragma('vm:never-inline')
+ asT(arg) => arg as T;
+
+ @pragma('vm:never-inline')
+ asNullableT(arg) => arg as T?;
+
+ @pragma('vm:never-inline')
+ asXT(arg) => arg as X<T>;
+
+ @pragma('vm:never-inline')
+ asNullableXT(arg) => arg as X<T>?;
+
+ @pragma('vm:never-inline')
+ asXNullableT(arg) => arg as X<T?>;
+}
+
+class X<T> {}
+
+class Y {}
+
+class Z extends Y {}
+
+testCasts() {
+ // Testing 'arg as T', T = Y
+ final wy = new W<Y>();
+ wy.asT(new Y());
+ wy.asT(new Z());
+ Expect.throwsTypeError(() {
+ wy.asT(null);
+ });
+ Expect.throwsTypeError(() {
+ wy.asT(new C());
+ });
+
+ // Testing 'arg as T?', T = Y
+ wy.asNullableT(new Y());
+ wy.asNullableT(new Z());
+ wy.asNullableT(null);
+ Expect.throwsTypeError(() {
+ wy.asNullableT(new C());
+ });
+
+ // Testing 'arg as X<T>', T = Y
+ wy.asXT(new X<Y>());
+ wy.asXT(new X<Z>());
+ Expect.throwsTypeError(() {
+ wy.asXT(null);
+ });
+ Expect.throwsTypeError(() {
+ wy.asXT(new X<dynamic>());
+ });
+ Expect.throwsTypeError(() {
+ wy.asXT(new X<Y?>());
+ });
+
+ // Testing 'arg as X<T>?', T = Y
+ wy.asNullableXT(new X<Y>());
+ wy.asNullableXT(new X<Z>());
+ wy.asNullableXT(null);
+ Expect.throwsTypeError(() {
+ wy.asNullableXT(new X<dynamic>());
+ });
+ Expect.throwsTypeError(() {
+ wy.asNullableXT(new X<Y?>());
+ });
+
+ // Testing 'arg as X<T?>', T = Y
+ wy.asXNullableT(new X<Y>());
+ wy.asXNullableT(new X<Z>());
+ wy.asXNullableT(new X<Y?>());
+ Expect.throwsTypeError(() {
+ wy.asXNullableT(null);
+ });
+ Expect.throwsTypeError(() {
+ wy.asXNullableT(new X<dynamic>());
+ });
+
+ // Testing 'arg as X<T>', T = Y?
+ final wny = new W<Y?>();
+ wny.asXT(new X<Y>());
+ wny.asXT(new X<Z>());
+ wny.asXT(new X<Y?>());
+ Expect.throwsTypeError(() {
+ wny.asXT(null);
+ });
+ Expect.throwsTypeError(() {
+ wny.asXT(new X<dynamic>());
+ });
+}
+
+func(String q0, {bool p3 = false, required int p1, required String p2}) => "";
+
+testRequiredParameters() {
+ dynamic f = func;
+
+ // Invalid: Subtype may not redeclare optional parameters as required.
+ Expect.throwsTypeError(() {
+ Function(
+ String p0, {
+ required int p1,
+ String p2,
+ }) t2 = f;
+ });
+
+ // Invalid: Subtype may not declare new required named parameters.
+ Expect.throwsTypeError(() {
+ Function(
+ String p0, {
+ required int p1,
+ }) t3 = f;
+ });
+
+ // Invalid: Invocation with explicit null required named argument.
+ Expect.throwsTypeError(() {
+ f("", p1: null, p2: null);
+ });
+ Expect.throwsTypeError(() {
+ Function.apply(f, [""], {#p1: null, #p2: null});
+ });
+
+ // Invalid: Invocation that omits a required named argument.
+ Expect.throwsNoSuchMethodError(() {
+ f("", p1: 100);
+ });
+ Expect.throwsNoSuchMethodError(() {
+ Function.apply(f, [""], {#p1: 100});
+ });
+}
+
+main() {
+ for (int i = 0; i < 20; ++i) {
+ testCasts();
+ testRequiredParameters();
+ }
+}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index cf20201..546e56c 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2414,7 +2414,8 @@
// Check immediate superclass equality. If type_class is Object, then testing
// supertype may yield a wrong result for Null in NNBD strong mode (because
// Null also extends Object).
- if (!type_class.IsObjectClass() || !Isolate::Current()->null_safety()) {
+ if (!type_class.IsObjectClass() ||
+ !Isolate::Current()->use_strict_null_safety_checks()) {
// We don't use TypeTestABI::kScratchReg for the first scratch register as
// it is not defined on IA32. Instead, we use the subtype test cache
// register, as it is clobbered by the subtype test cache stub call anyway.
@@ -2785,7 +2786,7 @@
if (dst_type.IsNull()) {
__ Comment("AssertAssignable for runtime type");
// kDstTypeReg should already contain the destination type.
- const bool null_safety = isolate()->null_safety();
+ const bool null_safety = isolate()->use_strict_null_safety_checks();
GenerateStubCall(token_pos,
StubCode::GetTypeIsTopTypeForSubtyping(null_safety),
PcDescriptorsLayout::kOther, locs, deopt_id);
@@ -2906,7 +2907,8 @@
if (dst_type.IsObjectType()) {
// Special case: non-nullable Object.
- ASSERT(dst_type.IsNonNullable() && isolate()->null_safety());
+ ASSERT(dst_type.IsNonNullable() &&
+ isolate()->use_strict_null_safety_checks());
__ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
__ BranchIf(NOT_EQUAL, done);
// Fall back to type testing stub in caller to throw the exception.
@@ -2928,7 +2930,8 @@
// Special case: Instantiate the type parameter on the caller side, invoking
// the TTS of the corresponding type parameter in the caller.
const TypeParameter& type_param = TypeParameter::Cast(dst_type);
- if (isolate()->null_safety() && !type_param.IsNonNullable()) {
+ if (isolate()->use_strict_null_safety_checks() &&
+ !type_param.IsNonNullable()) {
// If the type parameter is nullable when running in strong mode, we need
// to handle null before calling the TTS because the type parameter may be
// instantiated with a non-nullable type, where the TTS rejects null.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index 6b69099..2c29653 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -358,7 +358,8 @@
if (dst_type.IsNull()) {
__ Comment("AssertAssignable for runtime type");
// kDstTypeReg should already contain the destination type.
- const bool null_safety = Isolate::Current()->null_safety();
+ const bool null_safety =
+ Isolate::Current()->use_strict_null_safety_checks();
GenerateStubCall(token_pos,
StubCode::GetTypeIsTopTypeForSubtyping(null_safety),
PcDescriptorsLayout::kOther, locs, deopt_id);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index a8bde81..f7327ba 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2102,7 +2102,7 @@
Fragment set,
Fragment not_set) {
// Required named arguments only exist if null_safety is enabled.
- if (!I->null_safety()) return not_set;
+ if (!I->use_strict_null_safety_checks()) return not_set;
Fragment check_required;
// First, we convert the index to be in terms of the number of optional
@@ -2277,7 +2277,7 @@
// required named arguments.
if (info.descriptor.NamedCount() == 0) {
// No work to do if there are no possible required named parameters.
- if (!I->null_safety()) {
+ if (!I->use_strict_null_safety_checks()) {
return Fragment();
}
// If the below changes, we can no longer assume that flag slots existing
diff --git a/runtime/vm/compiler/frontend/prologue_builder.cc b/runtime/vm/compiler/frontend/prologue_builder.cc
index 7fd8c35..bc1808e 100644
--- a/runtime/vm/compiler/frontend/prologue_builder.cc
+++ b/runtime/vm/compiler/frontend/prologue_builder.cc
@@ -306,7 +306,8 @@
} else {
ASSERT(num_opt_named_params > 0);
- bool null_safety = Isolate::Current()->null_safety();
+ bool check_required_params =
+ Isolate::Current()->use_strict_null_safety_checks();
const intptr_t first_name_offset =
compiler::target::ArgumentsDescriptor::first_named_entry_offset() -
compiler::target::Array::data_offset();
@@ -371,8 +372,8 @@
good += Drop();
}
- const bool required =
- null_safety && function_.IsRequiredAt(opt_param_position[i]);
+ const bool required = check_required_params &&
+ function_.IsRequiredAt(opt_param_position[i]);
// If this function cannot be invoked dynamically and this is a required
// named argument, then we can just add this fragment directly without
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 341b4fc..022032b 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -109,6 +109,9 @@
R(enable_asserts, false, bool, false, "Enable assert statements.") \
R(null_assertions, false, bool, false, \
"Enable null assertions for parameters.") \
+ R(strict_null_safety_checks, false, bool, false, \
+ "Enable strict type checks for non-nullable types and required " \
+ "parameters.") \
P(enable_kernel_expression_compilation, bool, true, \
"Compile expressions with the Kernel front-end.") \
P(enable_mirrors, bool, true, \
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 0034b81..9bfb94c 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1337,6 +1337,10 @@
isolate_flags_ = NullSafetyBit::update(null_safety, isolate_flags_);
}
+ bool use_strict_null_safety_checks() const {
+ return null_safety() || FLAG_strict_null_safety_checks;
+ }
+
bool has_attempted_stepping() const {
return HasAttemptedSteppingBit::decode(isolate_flags_);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c1a8c93..83e255f 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5083,7 +5083,7 @@
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
// Nullability of left and right hand sides is verified in strong mode only.
- const bool verified_nullability = !isolate->null_safety() ||
+ const bool verified_nullability = !isolate->use_strict_null_safety_checks() ||
nullability != Nullability::kNullable ||
!other.IsNonNullable();
@@ -7854,7 +7854,7 @@
return false;
}
}
- if (isolate->null_safety()) {
+ if (isolate->use_strict_null_safety_checks()) {
// Verify that all required named parameters are filled.
for (intptr_t j = num_parameters - NumOptionalNamedParameters();
j < num_parameters; j++) {
@@ -8503,7 +8503,7 @@
return false;
}
}
- if (isolate->null_safety()) {
+ if (isolate->use_strict_null_safety_checks()) {
// Check that for each required named parameter in this function, there's a
// corresponding required named parameter in the other function.
String& param_name = other_param_name;
@@ -18266,7 +18266,7 @@
// In weak mode type casts, whether in legacy or opted-in libraries, the null
// instance is detected and handled in inlined code and therefore cannot be
// encountered here as a Dart null receiver.
- ASSERT(Isolate::Current()->null_safety() || !IsNull());
+ ASSERT(Isolate::Current()->use_strict_null_safety_checks() || !IsNull());
// In strong mode, compute NNBD_SUBTYPE(runtimeType, other).
// In weak mode, compute LEGACY_SUBTYPE(runtimeType, other).
return RuntimeTypeIsSubtypeOf(other, other_instantiator_type_arguments,
@@ -18317,7 +18317,7 @@
Zone* zone = thread->zone();
// In weak mode, Null is a bottom type (according to LEGACY_SUBTYPE).
- if (!isolate->null_safety()) {
+ if (!isolate->use_strict_null_safety_checks()) {
return true;
}
// "Left Null" rule: null is assignable when destination type is either
@@ -18348,7 +18348,7 @@
Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
// In weak testing mode, Null type is a subtype of any type.
- if (IsNull() && !isolate->null_safety()) {
+ if (IsNull() && !isolate->use_strict_null_safety_checks()) {
return true;
}
const Class& cls = Class::Handle(zone, clazz());
@@ -18413,7 +18413,7 @@
return false;
}
if (IsNull()) {
- ASSERT(isolate->null_safety());
+ ASSERT(isolate->use_strict_null_safety_checks());
if (instantiated_other.IsNullType()) {
return true;
}
@@ -19139,7 +19139,8 @@
if (cid == kInstanceCid) { // Object type.
// NNBD weak mode uses LEGACY_SUBTYPE for assignability / 'as' tests,
// and non-nullable Object is a top type according to LEGACY_SUBTYPE.
- return !IsNonNullable() || !Isolate::Current()->null_safety();
+ return !IsNonNullable() ||
+ !Isolate::Current()->use_strict_null_safety_checks();
}
if (cid == kFutureOrCid) {
// FutureOr<T> where T is a top type behaves as a top type.
@@ -19298,7 +19299,8 @@
const bool other_is_dart_function_type = other.IsDartFunctionType();
if (other_is_dart_function_type || other.IsFunctionType()) {
if (IsFunctionType()) {
- if (isolate->null_safety() && IsNullable() && other.IsNonNullable()) {
+ if (isolate->use_strict_null_safety_checks() && IsNullable() &&
+ other.IsNonNullable()) {
return false;
}
if (other_is_dart_function_type) {
@@ -19707,7 +19709,7 @@
Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
if (kind == TypeEquality::kInSubtypeTest) {
- if (isolate->null_safety() &&
+ if (isolate->use_strict_null_safety_checks() &&
this_type_nullability == Nullability::kNullable &&
other_type_nullability == Nullability::kNonNullable) {
return false;
@@ -20475,7 +20477,7 @@
Nullability this_type_param_nullability = nullability();
Nullability other_type_param_nullability = other_type_param.nullability();
if (kind == TypeEquality::kInSubtypeTest) {
- if (Isolate::Current()->null_safety() &&
+ if (Isolate::Current()->use_strict_null_safety_checks() &&
(this_type_param_nullability == Nullability::kNullable) &&
(other_type_param_nullability == Nullability::kNonNullable)) {
return false;
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index db0d99f..e5065d0 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -808,7 +808,7 @@
// These are guaranteed on the calling side.
ASSERT(!dst_type.IsDynamicType());
- ASSERT(!src_instance.IsNull() || isolate->null_safety());
+ ASSERT(!src_instance.IsNull() || isolate->use_strict_null_safety_checks());
const bool is_instance_of = src_instance.IsAssignableTo(
dst_type, instantiator_type_arguments, function_type_arguments);
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index f86d082..5f3d862 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -95,8 +95,9 @@
auto isolate = Isolate::Current();
if (type.IsTypeRef()) {
- return isolate->null_safety() ? StubCode::DefaultTypeTest().raw()
- : StubCode::DefaultNullableTypeTest().raw();
+ return isolate->use_strict_null_safety_checks()
+ ? StubCode::DefaultTypeTest().raw()
+ : StubCode::DefaultNullableTypeTest().raw();
}
// During bootstrapping we have no access to stubs yet, so we'll just return
@@ -281,7 +282,8 @@
__ Bind(&continue_checking);
} else if (type.IsObjectType()) {
- ASSERT(type.IsNonNullable() && Isolate::Current()->null_safety());
+ ASSERT(type.IsNonNullable() &&
+ Isolate::Current()->use_strict_null_safety_checks());
compiler::Label continue_checking;
__ CompareObject(TypeTestABI::kInstanceReg, Object::null_object());
__ BranchIf(EQUAL, &continue_checking);
@@ -493,8 +495,8 @@
// Weak NNBD mode uses LEGACY_SUBTYPE which ignores nullability.
// We don't need to check nullability of LHS for nullable and legacy RHS
// ("Right Legacy", "Right Nullable" rules).
- if (Isolate::Current()->null_safety() && !type_arg.IsNullable() &&
- !type_arg.IsLegacy()) {
+ if (Isolate::Current()->use_strict_null_safety_checks() &&
+ !type_arg.IsNullable() && !type_arg.IsLegacy()) {
// Nullable type is not a subtype of non-nullable type.
// TODO(dartbug.com/40736): Allocate a register for instance type argument
// and avoid reloading it.
diff --git a/tools/VERSION b/tools/VERSION
index 3da93db..534b836 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 58
+PRERELEASE 59
PRERELEASE_PATCH 0
\ No newline at end of file