Version 2.13.0-211.0.dev
Merge commit '16687346977656e362bd607dc4b94053b11e12d9' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 0274d64..1402102 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -1174,6 +1174,11 @@
}
@override
+ void handleConstFactory(Token constKeyword) {
+ listener?.handleConstFactory(constKeyword);
+ }
+
+ @override
void handleContinueStatement(
bool hasTarget, Token continueKeyword, Token endToken) {
listener?.handleContinueStatement(hasTarget, continueKeyword, endToken);
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index bb635b6..0e08a2e 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -1360,6 +1360,10 @@
logEvent("ConstExpression");
}
+ void handleConstFactory(Token constKeyword) {
+ logEvent("ConstFactory");
+ }
+
/// Called before parsing a "for" control flow list, set, or map entry.
/// Ended by either [endForControlFlow] or [endForInControlFlow].
void beginForControlFlow(Token? awaitToken, Token forToken) {}
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
index 1fe9144..93d7a7b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
@@ -4063,7 +4063,7 @@
} else {
if (varFinalOrConst != null && !optional('native', next)) {
if (optional('const', varFinalOrConst)) {
- reportRecoverableError(varFinalOrConst, codes.messageConstFactory);
+ listener.handleConstFactory(varFinalOrConst);
}
}
token = parseFunctionBody(
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index 6e831aa..9f40d74 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:async';
import 'dart:math' show max, sqrt;
@@ -42,13 +40,13 @@
final Logger logger = Logger('Driver');
/// The diagnostic port for Analysis Server or `null` if none.
- final int diagnosticPort;
+ final int? diagnosticPort;
/// A flag indicating whether the server is running.
bool running = false;
@override
- Server server;
+ late Server server;
/// The results collected while running analysis server.
final Results results = Results();
@@ -65,7 +63,7 @@
/// Perform the given operation.
/// Return a [Future] that completes when the next operation can be performed,
/// or `null` if the next operation can be performed immediately
- Future perform(Operation op) {
+ Future<void>? perform(Operation op) {
return op.perform(this);
}
@@ -75,7 +73,7 @@
/// normal (non-error) response, the future will be completed with the
/// 'result' field from the response. If the server acknowledges the command
/// with an error response, the future will be completed with an error.
- Future<Map<String, dynamic>> send(
+ Future<Map<String, Object?>?> send(
String method, Map<String, dynamic> params) {
return server.send(method, params);
}
@@ -206,14 +204,17 @@
print('');
print('==================================================================');
print('');
- var keys = measurements.keys.toList()..sort();
- var keyLen = keys.fold(0, (int len, String key) => max(len, key.length));
+ var sortedEntries = measurements.entries.toList();
+ sortedEntries.sort((a, b) => a.key.compareTo(b.key));
+ var keyLen = sortedEntries
+ .map((e) => e.key)
+ .fold(0, (int len, String key) => max(len, key.length));
_printGroupHeader('Request/Response', keyLen);
var totalCount = 0;
var totalErrorCount = 0;
var totalUnexpectedResultCount = 0;
- for (var tag in keys) {
- var m = measurements[tag];
+ for (var entry in sortedEntries) {
+ var m = entry.value;
if (!m.notification) {
m.printSummary(keyLen);
totalCount += m.count;
@@ -225,8 +226,8 @@
keyLen, totalCount, totalErrorCount, totalUnexpectedResultCount);
print('');
_printGroupHeader('Notifications', keyLen);
- for (var tag in keys) {
- var m = measurements[tag];
+ for (var entry in sortedEntries) {
+ var m = entry.value;
if (m.notification) {
m.printSummary(keyLen);
}
@@ -252,7 +253,7 @@
}
void recordUnexpectedResults(String tag) {
- measurements[tag].recordUnexpectedResults();
+ measurements[tag]!.recordUnexpectedResults();
}
void _printGroupHeader(String groupName, int keyLen) {
diff --git a/pkg/analysis_server/benchmark/integration/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
index e128456..0f86919 100644
--- a/pkg/analysis_server/benchmark/integration/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -20,14 +18,14 @@
import 'operation.dart';
/// Common input converter superclass for sharing implementation.
-abstract class CommonInputConverter extends Converter<String, Operation> {
+abstract class CommonInputConverter extends Converter<String, Operation?> {
static final ERROR_PREFIX = 'Server responded with an error: ';
final Logger logger = Logger('InstrumentationInputConverter');
final Set<String> eventsSeen = <String>{};
/// A mapping from request/response id to request json
/// for those requests for which a response has not been processed.
- final Map<String, dynamic> requestMap = {};
+ final Map<String, Object?> requestMap = {};
/// A mapping from request/response id to a completer
/// for those requests for which a response has not been processed.
@@ -37,7 +35,7 @@
/// A mapping from request/response id to the actual response result
/// for those responses that have not been processed.
- final Map<String, dynamic> responseMap = {};
+ final Map<String, Object?> responseMap = {};
/// A mapping of current overlay content
/// parallel to what is in the analysis server
@@ -58,16 +56,18 @@
CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap);
- Map<String, dynamic> asMap(dynamic value) => value as Map<String, dynamic>;
+ Map<String, Object?> asMap(dynamic value) => value as Map<String, Object?>;
+
+ Map<String, Object?>? asMap2(dynamic value) => value as Map<String, Object?>?;
/// Return an operation for the notification or `null` if none.
- Operation convertNotification(Map<String, dynamic> json) {
+ Operation? convertNotification(Map<String, dynamic> json) {
String event = json['event'];
if (event == SERVER_NOTIFICATION_STATUS) {
// {"event":"server.status","params":{"analysis":{"isAnalyzing":false}}}
- var params = asMap(json['params']);
+ var params = asMap2(json['params']);
if (params != null) {
- var analysis = asMap(params['analysis']);
+ var analysis = asMap2(params['analysis']);
if (analysis != null && analysis['isAnalyzing'] == false) {
return WaitForAnalysisCompleteOperation();
}
@@ -84,23 +84,20 @@
}
/// Return an operation for the request or `null` if none.
- Operation convertRequest(Map<String, dynamic> origJson) {
+ Operation convertRequest(Map<String, Object?> origJson) {
var json = asMap(translateSrcPaths(origJson));
- requestMap[json['id']] = json;
- String method = json['method'];
+ requestMap[json['id'] as String] = json;
+ var method = json['method'] as String;
// Sanity check operations that modify source
// to ensure that the operation is on source in temp space
if (method == ANALYSIS_REQUEST_UPDATE_CONTENT) {
// Track overlays in parallel with the analysis server
// so that when an overlay is removed, the file can be updated on disk
- var request = Request.fromJson(json);
+ var request = Request.fromJson(json)!;
var params = AnalysisUpdateContentParams.fromRequest(request);
params.files.forEach((String filePath, change) {
if (change is AddContentOverlay) {
var content = change.content;
- if (content == null) {
- throw 'expected new overlay content\n$json';
- }
overlays[filePath] = content;
} else if (change is ChangeContentOverlay) {
var content = overlays[filePath];
@@ -172,8 +169,9 @@
void processErrorResponse(String id, exception) {
var result = exception;
if (exception is UnimplementedError) {
- if (exception.message.startsWith(ERROR_PREFIX)) {
- result = json.decode(exception.message.substring(ERROR_PREFIX.length));
+ var message = exception.message;
+ if (message!.startsWith(ERROR_PREFIX)) {
+ result = json.decode(message.substring(ERROR_PREFIX.length));
}
}
processResponseResult(id, result);
@@ -186,7 +184,7 @@
/// Return a future that completes when the response is received
/// or `null` if the response has already been received
/// and the completer completed.
- Future processExpectedResponse(String id, Completer completer) {
+ Future<void>? processExpectedResponse(String id, Completer completer) {
if (responseMap.containsKey(id)) {
logger.log(Level.INFO, 'processing cached response $id');
completer.complete(responseMap.remove(id));
@@ -228,7 +226,7 @@
return result;
}
if (json is Map) {
- var result = <String, dynamic>{};
+ var result = <String, Object?>{};
json.forEach((origKey, value) {
result[translateSrcPaths(origKey)] = translateSrcPaths(value);
});
@@ -241,7 +239,7 @@
/// [InputConverter] converts an input stream
/// into a series of operations to be sent to the analysis server.
/// The input stream can be either an instrumentation or log file.
-class InputConverter extends Converter<String, Operation> {
+class InputConverter extends Converter<String, Operation?> {
final Logger logger = Logger('InputConverter');
/// A mapping of source path prefixes
@@ -259,7 +257,7 @@
/// The underlying converter used to translate lines into operations
/// or `null` if it has not yet been determined.
- Converter<String, Operation> converter;
+ Converter<String, Operation?>? converter;
/// [active] is `true` if converting lines to operations
/// or `false` if an exception has occurred.
@@ -268,10 +266,11 @@
InputConverter(this.tmpSrcDirPath, this.srcPathMap);
@override
- Operation convert(String line) {
+ Operation? convert(String line) {
if (!active) {
return null;
}
+ var converter = this.converter;
if (converter != null) {
try {
return converter.convert(line);
@@ -335,8 +334,8 @@
}
class _InputSink extends ChunkedConversionSink<String> {
- final Converter<String, Operation> converter;
- final Sink<Operation> outSink;
+ final Converter<String, Operation?> converter;
+ final Sink<Operation?> outSink;
_InputSink(this.converter, this.outSink);
diff --git a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 2cd8783..037c9b0 100644
--- a/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:convert';
import 'package:analyzer/exception/exception.dart';
@@ -23,17 +21,18 @@
/// [readBuffer] holds the contents of the file being read from disk
/// as recorded in the instrumentation log
/// or `null` if not converting a "Read" entry.
- StringBuffer readBuffer;
+ StringBuffer? readBuffer;
InstrumentationInputConverter(String tmpSrcDirPath, PathMap srcPathMap)
: super(tmpSrcDirPath, srcPathMap);
@override
- Operation convert(String line) {
+ Operation? convert(String line) {
List<String> fields;
try {
fields = _parseFields(line);
if (fields.length < 2) {
+ var readBuffer = this.readBuffer;
if (readBuffer != null) {
readBuffer.writeln(fields.length == 1 ? fields[0] : '');
return null;
@@ -78,7 +77,7 @@
return null;
}
- Map<String, dynamic> decodeJson(String line, String text) {
+ Map<String, Object?> decodeJson(String line, String text) {
try {
return asMap(json.decode(text));
} catch (e, s) {
diff --git a/pkg/analysis_server/benchmark/integration/local_runner.dart b/pkg/analysis_server/benchmark/integration/local_runner.dart
index e8353b2..f8a987a 100644
--- a/pkg/analysis_server/benchmark/integration/local_runner.dart
+++ b/pkg/analysis_server/benchmark/integration/local_runner.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:io';
import 'package:path/path.dart';
@@ -77,7 +75,7 @@
}
/// Print help and exit
-void printHelp([String errMsg]) {
+void printHelp([String? errMsg]) {
if (errMsg != null) {
print('');
print('Error: $errMsg');
diff --git a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
index 238a1fa..bd87c70 100644
--- a/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:convert';
import 'package:analyzer/exception/exception.dart';
@@ -25,7 +23,7 @@
: super(tmpSrcDirPath, srcPathMap);
@override
- Operation convert(String line) {
+ Operation? convert(String line) {
try {
var timeStampString = _parseTimeStamp(line);
var data = line.substring(timeStampString.length);
diff --git a/pkg/analysis_server/benchmark/integration/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
index c1c9911..8f0a438 100644
--- a/pkg/analysis_server/benchmark/integration/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -26,9 +24,9 @@
var driver = Driver(diagnosticPort: args.diagnosticPort);
var stream = openInput(args);
- StreamSubscription<Operation> subscription;
- subscription = stream.listen((Operation op) {
- var future = driver.perform(op);
+ late StreamSubscription<Operation?> subscription;
+ subscription = stream.listen((Operation? op) {
+ var future = driver.perform(op!);
if (future != null) {
logger.log(Level.FINE, 'pausing operations for ${op.runtimeType}');
subscription.pause(future.then((_) {
@@ -63,17 +61,15 @@
const VERBOSE_CMDLINE_OPTION = 'verbose';
const VERY_VERBOSE_CMDLINE_OPTION = 'vv';
-ArgParser _argParser;
+late final ArgParser argParser = () {
+ var argParser = ArgParser();
-ArgParser get argParser {
- _argParser = ArgParser();
-
- _argParser.addOption(INPUT_CMDLINE_OPTION,
+ argParser.addOption(INPUT_CMDLINE_OPTION,
abbr: 'i',
help: '<filePath>\n'
'The input file specifying how this client should interact with the server.\n'
'If the input file name is "stdin", then the instructions are read from standard input.');
- _argParser.addMultiOption(MAP_OPTION,
+ argParser.addMultiOption(MAP_OPTION,
abbr: 'm',
splitCommas: false,
help: '<oldSrcPath>,<newSrcPath>\n'
@@ -82,26 +78,26 @@
'to the target source directory <newSrcPath> used during performance testing.\n'
'Multiple mappings can be specified.\n'
'WARNING: The contents of the target directory will be modified');
- _argParser.addOption(TMP_SRC_DIR_OPTION,
+ argParser.addOption(TMP_SRC_DIR_OPTION,
abbr: 't',
help: '<dirPath>\n'
'The temporary directory containing source used during performance measurement.\n'
'WARNING: The contents of the target directory will be modified');
- _argParser.addOption(DIAGNOSTIC_PORT_OPTION,
+ argParser.addOption(DIAGNOSTIC_PORT_OPTION,
abbr: 'd',
help: 'localhost port on which server will provide diagnostic web pages');
- _argParser.addFlag(VERBOSE_CMDLINE_OPTION,
+ argParser.addFlag(VERBOSE_CMDLINE_OPTION,
abbr: 'v', help: 'Verbose logging', negatable: false);
- _argParser.addFlag(VERY_VERBOSE_CMDLINE_OPTION,
+ argParser.addFlag(VERY_VERBOSE_CMDLINE_OPTION,
help: 'Extra verbose logging', negatable: false);
- _argParser.addFlag(HELP_CMDLINE_OPTION,
+ argParser.addFlag(HELP_CMDLINE_OPTION,
abbr: 'h', help: 'Print this help information', negatable: false);
- return _argParser;
-}
+ return argParser;
+}();
/// Open and return the input stream specifying how this client
/// should interact with the analysis server.
-Stream<Operation> openInput(PerfArgs args) {
+Stream<Operation?> openInput(PerfArgs args) {
var logger = Logger('openInput');
Stream<List<int>> inputRaw;
if (args.inputPath == 'stdin') {
@@ -137,12 +133,12 @@
var showHelp = args[HELP_CMDLINE_OPTION] || args.rest.isNotEmpty;
- bool isMissing(key) => args[key] == null || args[key].isEmpty;
-
- perfArgs.inputPath = args[INPUT_CMDLINE_OPTION];
- if (isMissing(INPUT_CMDLINE_OPTION)) {
+ var inputArg = args[INPUT_CMDLINE_OPTION];
+ if (inputArg is! String || inputArg.isEmpty) {
print('missing $INPUT_CMDLINE_OPTION argument');
showHelp = true;
+ } else {
+ perfArgs.inputPath = inputArg;
}
for (String pair in args[MAP_OPTION]) {
@@ -157,18 +153,20 @@
}
}
}
- print('must specifiy $MAP_OPTION <oldSrcPath>,<newSrcPath>');
+ print('must specify $MAP_OPTION <oldSrcPath>,<newSrcPath>');
showHelp = true;
}
- perfArgs.tmpSrcDirPath = _withTrailingSeparator(args[TMP_SRC_DIR_OPTION]);
- if (isMissing(TMP_SRC_DIR_OPTION)) {
+ var tmpSrcDirPathArg = args[TMP_SRC_DIR_OPTION];
+ if (tmpSrcDirPathArg is! String || tmpSrcDirPathArg.isEmpty) {
print('missing $TMP_SRC_DIR_OPTION argument');
showHelp = true;
+ } else {
+ perfArgs.tmpSrcDirPath = _withTrailingSeparator(tmpSrcDirPathArg);
}
- String portText = args[DIAGNOSTIC_PORT_OPTION];
- if (portText != null) {
+ var portText = args[DIAGNOSTIC_PORT_OPTION];
+ if (portText is String) {
if (int.tryParse(portText) == null) {
print('invalid $DIAGNOSTIC_PORT_OPTION: $portText');
showHelp = true;
@@ -202,7 +200,7 @@
/// Ensure that the given path has a trailing separator
String _withTrailingSeparator(String dirPath) {
- if (dirPath != null && dirPath.length > 4) {
+ if (dirPath.length > 4) {
if (!dirPath.endsWith(path.separator)) {
return '$dirPath${path.separator}';
}
@@ -215,7 +213,7 @@
/// The file path of the instrumentation or log file
/// used to drive performance measurement,
/// or 'stdin' if this information should be read from standard input.
- String inputPath;
+ late String inputPath;
/// A mapping from the original source directory
/// when the instrumentation or log file was generated
@@ -224,8 +222,8 @@
/// The temporary directory containing source used during performance
/// measurement.
- String tmpSrcDirPath;
+ late String tmpSrcDirPath;
/// The diagnostic port for Analysis Server or `null` if none.
- int diagnosticPort;
+ int? diagnosticPort;
}
diff --git a/pkg/analysis_server/benchmark/integration/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart
index eb70f44..311e979 100644
--- a/pkg/analysis_server/benchmark/integration/operation.dart
+++ b/pkg/analysis_server/benchmark/integration/operation.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.9
-
import 'dart:async';
import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -15,10 +13,10 @@
/// A [CompletionRequestOperation] tracks response time along with
/// the first and last completion notifications.
class CompletionRequestOperation extends RequestOperation {
- Driver driver;
- StreamSubscription<CompletionResultsParams> subscription;
- String notificationId;
- Stopwatch stopwatch;
+ late Driver driver;
+ late StreamSubscription<CompletionResultsParams> subscription;
+ late String notificationId;
+ late Stopwatch stopwatch;
bool firstNotification = true;
CompletionRequestOperation(
@@ -26,7 +24,7 @@
: super(converter, json);
@override
- Future perform(Driver driver) {
+ Future<void>? perform(Driver driver) {
this.driver = driver;
subscription = driver.onCompletionResults.listen(processNotification);
return super.perform(driver);
@@ -50,8 +48,8 @@
@override
void processResult(
- String id, Map<String, dynamic> result, Stopwatch stopwatch) {
- notificationId = result['id'];
+ String id, Map<String, Object?> result, Stopwatch stopwatch) {
+ notificationId = result['id'] as String;
this.stopwatch = stopwatch;
super.processResult(id, result, stopwatch);
}
@@ -59,7 +57,7 @@
/// An [Operation] represents an action such as sending a request to the server.
abstract class Operation {
- Future perform(Driver driver);
+ Future<void>? perform(Driver driver);
}
/// A [RequestOperation] sends a [JSON] request to the server.
@@ -70,7 +68,7 @@
RequestOperation(this.converter, this.json);
@override
- Future perform(Driver driver) {
+ Future<void>? perform(Driver driver) {
var stopwatch = Stopwatch();
String originalId = json['id'];
String method = json['method'];
@@ -85,11 +83,9 @@
.log(Level.FINE, 'Response received: $method : $elapsed\n $result');
}
- driver
- .send(method, converter.asMap(json['params']))
- .then((Map<String, dynamic> result) {
+ driver.send(method, converter.asMap(json['params'])).then((result) {
recordResult(true, result);
- processResult(originalId, result, stopwatch);
+ processResult(originalId, result!, stopwatch);
}).catchError((exception) {
recordResult(false, exception);
converter.processErrorResponse(originalId, exception);
@@ -98,7 +94,7 @@
}
void processResult(
- String id, Map<String, dynamic> result, Stopwatch stopwatch) {
+ String id, Map<String, Object?> result, Stopwatch stopwatch) {
converter.processResponseResult(id, result);
}
}
@@ -107,19 +103,20 @@
class ResponseOperation extends Operation {
static final Duration responseTimeout = Duration(seconds: 60);
final CommonInputConverter converter;
- final Map<String, dynamic> requestJson;
- final Map<String, dynamic> responseJson;
+ final Map<String, Object?> requestJson;
+ final Map<String, Object?> responseJson;
final Completer completer = Completer();
- Driver driver;
+ late Driver driver;
ResponseOperation(this.converter, this.requestJson, this.responseJson) {
completer.future.then(_processResult).timeout(responseTimeout);
}
@override
- Future perform(Driver driver) {
+ Future<void>? perform(Driver driver) {
this.driver = driver;
- return converter.processExpectedResponse(responseJson['id'], completer);
+ var id = responseJson['id'] as String;
+ return converter.processExpectedResponse(id, completer);
}
bool _equal(expectedResult, actualResult) {
@@ -161,7 +158,8 @@
'expected result:${format(expectedResult)}\n'
'expected error:${format(expectedError)}\n'
'but received:${format(actualResult)}';
- driver.results.recordUnexpectedResults(requestJson['method']);
+ var method = requestJson['method'] as String;
+ driver.results.recordUnexpectedResults(method);
converter.logOverlayContent();
if (expectedError == null) {
converter.logger.log(Level.SEVERE, message);
@@ -184,13 +182,14 @@
Future perform(Driver driver) {
var start = DateTime.now();
driver.logger.log(Level.FINE, 'waiting for analysis to complete');
- StreamSubscription<ServerStatusParams> subscription;
- Timer timer;
+ late StreamSubscription<ServerStatusParams> subscription;
+ late Timer timer;
var completer = Completer();
var isAnalyzing = false;
subscription = driver.onServerStatus.listen((ServerStatusParams params) {
- if (params.analysis != null) {
- if (params.analysis.isAnalyzing) {
+ var analysisStatus = params.analysis;
+ if (analysisStatus != null) {
+ if (analysisStatus.isAnalyzing) {
isAnalyzing = true;
} else {
subscription.cancel();
@@ -214,7 +213,7 @@
}
// Timeout if no communication received within the last 60 seconds.
var currentTime = driver.server.currentElapseTime;
- var lastTime = driver.server.lastCommunicationTime;
+ var lastTime = driver.server.lastCommunicationTime!;
if (currentTime - lastTime > 60) {
subscription.cancel();
timer.cancel();
diff --git a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
index 97a397f..5e45d1e7 100644
--- a/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
+++ b/pkg/analyzer/lib/src/dart/micro/analysis_context.dart
@@ -204,14 +204,7 @@
@override
Future<ResolvedLibraryResult> getResolvedLibrary(String path) async {
- var resolvedUnit = await getResolvedUnit(path);
- return ResolvedLibraryResultImpl(
- this,
- path,
- resolvedUnit.uri,
- resolvedUnit.libraryElement,
- [resolvedUnit],
- );
+ return analysisContext.fileResolver.resolveLibrary(path: path);
}
@override
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 219aadc..03b5275 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -86,7 +86,7 @@
/// It is used to allow assists and fixes without resolving the same file
/// multiple times, as we compute more than one assist, or fixes when there
/// are more than one error on a line.
- final Map<String, ResolvedUnitResult> _cachedResults = {};
+ final Map<String, ResolvedLibraryResult> _cachedResults = {};
FileResolver(
PerformanceLog logger,
@@ -373,6 +373,48 @@
performance ??= OperationPerformanceImpl('<default>');
+ return logger.run('Resolve $path', () {
+ var fileContext = getFileContext(
+ path: path,
+ performance: performance!,
+ );
+ var file = fileContext.file;
+
+ // If we have a `part of` directive, we want to analyze this library.
+ // But the library must include the file, so have its element.
+ var libraryFile = file;
+ var partOfLibrary = file.partOfLibrary;
+ if (partOfLibrary != null) {
+ if (partOfLibrary.libraryFiles.contains(file)) {
+ libraryFile = partOfLibrary;
+ }
+ }
+
+ var libraryUnit = resolveLibrary(
+ completionLine: completionLine,
+ completionColumn: completionColumn,
+ path: libraryFile.path,
+ completionPath: path,
+ performance: performance,
+ );
+ var result =
+ libraryUnit.units!.firstWhere((element) => element.path == path);
+ return result;
+ });
+ }
+
+ /// The [completionLine] and [completionColumn] are zero based.
+ ResolvedLibraryResult resolveLibrary({
+ int? completionLine,
+ int? completionColumn,
+ String? completionPath,
+ required String path,
+ OperationPerformanceImpl? performance,
+ }) {
+ _throwIfNotAbsoluteNormalizedPath(path);
+
+ performance ??= OperationPerformanceImpl('<default>');
+
var cachedResult = _cachedResults[path];
if (cachedResult != null) {
return cachedResult;
@@ -410,10 +452,6 @@
testView?.addResolvedFile(path);
- var content = _getFileContent(path);
- var errorListener = RecordingErrorListener();
- var unit = file.parse(errorListener, content);
-
late Map<FileState, UnitAnalysisResult> results;
logger.run('Compute analysis results', () {
@@ -432,7 +470,7 @@
try {
results = performance!.run('analyze', (performance) {
return libraryAnalyzer.analyzeSync(
- completionPath: completionOffset != null ? path : null,
+ completionPath: completionOffset != null ? completionPath : null,
completionOffset: completionOffset,
performance: performance,
);
@@ -450,19 +488,28 @@
);
}
});
- UnitAnalysisResult fileResult = results[file]!;
- var result = ResolvedUnitResultImpl(
- contextObjects!.analysisSession,
- path,
- file.uri,
- file.exists,
- content,
- unit.lineInfo!,
- false, // isPart
- fileResult.unit,
- fileResult.errors,
- );
+ results.forEach((key, value) {
+ print('$key: $value');
+ });
+ var resolvedUnits = results.values.map((fileResult) {
+ var file = fileResult.file;
+ return ResolvedUnitResultImpl(
+ contextObjects!.analysisSession,
+ file.path,
+ file.uri,
+ file.exists,
+ file.getContent(),
+ file.lineInfo,
+ file.unlinked2.hasPartOfDirective,
+ fileResult.unit,
+ fileResult.errors,
+ );
+ }).toList();
+
+ var libraryUnit = resolvedUnits.first;
+ var result = ResolvedLibraryResultImpl(contextObjects!.analysisSession,
+ path, libraryUnit.uri, libraryUnit.libraryElement, resolvedUnits);
_cachedResults[path] = result;
return result;
});
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index a43c330..0036512 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -11,6 +11,7 @@
messageAbstractLateField,
messageAbstractStaticField,
messageConstConstructorWithBody,
+ messageConstFactory,
messageConstructorWithTypeParameters,
messageDirectiveAfterDeclaration,
messageExpectedStatement,
@@ -2575,6 +2576,13 @@
}
@override
+ void handleConstFactory(Token constKeyword) {
+ debugEvent("ConstFactory");
+ // TODO(kallentu): Removal of const factory error for const function feature
+ handleRecoverableError(messageConstFactory, constKeyword, constKeyword);
+ }
+
+ @override
void handleContinueStatement(
bool hasTarget, Token continueKeyword, Token semicolon) {
assert(optional('continue', continueKeyword));
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index 15b8ebd..aa6dfb3 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -679,6 +679,30 @@
expect(result, isNot(same(result1)));
}
+ test_resolveLibrary() async {
+ var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+ newFile(aPath, content: r'''
+part 'test.dart';
+
+class A {
+ int m;
+}
+''');
+
+ newFile('/workspace/dart/test/lib/test.dart', content: r'''
+part of 'a.dart';
+
+void func() {
+ var a = A();
+ print(a.m);
+}
+''');
+
+ var result = fileResolver.resolveLibrary(path: aPath);
+ expect(result.path, aPath);
+ expect(result.units?.length, 2);
+ }
+
test_reuse_compatibleOptions() async {
newFile('/workspace/dart/aaa/BUILD', content: '');
newFile('/workspace/dart/bbb/BUILD', content: '');
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index ccf323b..11692c2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -4769,6 +4769,15 @@
}
@override
+ void handleConstFactory(Token constKeyword) {
+ debugEvent("ConstFactory");
+ if (!libraryBuilder.enableConstFunctionsInLibrary) {
+ handleRecoverableError(
+ fasta.messageConstFactory, constKeyword, constKeyword);
+ }
+ }
+
+ @override
void beginIfControlFlow(Token ifToken) {
// TODO(danrubel): consider removing this when control flow support is added
// if the ifToken is not needed for error reporting
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 645bbd9..5178dfa 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -2783,6 +2783,11 @@
} else {
name = '${target.enclosingClass.name}.${name}';
}
+
+ if (enableConstFunctions) {
+ return _handleFunctionInvocation(
+ node.target.function, typeArguments, positionals, named);
+ }
}
return createInvalidExpressionConstant(node, "Invocation of $name");
}
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 3d05b76..c5664f8 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -633,6 +633,11 @@
}
@override
+ void handleConstFactory(Token constKeyword) {
+ debugEvent("ConstFactory");
+ }
+
+ @override
void handleNativeFunctionBody(Token nativeToken, Token semicolon) {
debugEvent("NativeFunctionBody");
}
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 96b6ff5..6e7b86a 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -2045,6 +2045,14 @@
}
@override
+ void handleConstFactory(Token constKeyword) {
+ debugEvent("ConstFactory");
+ if (!libraryBuilder.enableConstFunctionsInLibrary) {
+ handleRecoverableError(messageConstFactory, constKeyword, constKeyword);
+ }
+ }
+
+ @override
void endFieldInitializer(Token assignmentOperator, Token token) {
debugEvent("FieldInitializer");
Token beforeLast = assignmentOperator.next;
diff --git a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
index cc76576..fe06b76 100644
--- a/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
+++ b/pkg/front_end/lib/src/fasta/util/direct_parser_ast_helper.dart
@@ -1970,6 +1970,13 @@
seen(data);
}
+ void handleConstFactory(Token constKeyword) {
+ DirectParserASTContentConstFactoryHandle data =
+ new DirectParserASTContentConstFactoryHandle(DirectParserASTType.HANDLE,
+ constKeyword: constKeyword);
+ seen(data);
+ }
+
void beginForControlFlow(Token awaitToken, Token forToken) {
DirectParserASTContentForControlFlowBegin data =
new DirectParserASTContentForControlFlowBegin(DirectParserASTType.BEGIN,
@@ -5814,6 +5821,18 @@
};
}
+class DirectParserASTContentConstFactoryHandle extends DirectParserASTContent {
+ final Token constKeyword;
+
+ DirectParserASTContentConstFactoryHandle(DirectParserASTType type,
+ {this.constKeyword})
+ : super("ConstFactory", type);
+
+ Map<String, Object> get deprecatedArguments => {
+ "constKeyword": constKeyword,
+ };
+}
+
class DirectParserASTContentForControlFlowBegin extends DirectParserASTContent {
final Token awaitToken;
final Token forToken;
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index fca16c8..8ffa24f 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -1765,6 +1765,11 @@
doPrint('endConstExpression(' '$token)');
}
+ void handleConstFactory(Token constKeyword) {
+ seen(constKeyword);
+ doPrint('handleConstFactory(' '$constKeyword)');
+ }
+
void beginForControlFlow(Token? awaitToken, Token forToken) {
seen(awaitToken);
seen(forToken);
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart
new file mode 100644
index 0000000..08f2b76
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests const factories with const functions.
+
+import "package:expect/expect.dart";
+
+const printConst = MessageType.parse("print");
+
+class MessageType {
+ static const print = MessageType._('print');
+
+ static const skip = MessageType._('skip');
+
+ final String name;
+
+ const factory MessageType.parse(String name) {
+ if (name == 'print') {
+ return MessageType.print;
+ }
+ return MessageType.skip;
+ }
+
+ const MessageType._(this.name);
+}
+
+void main() {
+ Expect.equals(printConst, MessageType.print);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect
new file mode 100644
index 0000000..c9674e9
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class MessageType extends core::Object /*hasConstConstructor*/ {
+ static const field self::MessageType print = #C2;
+ static const field self::MessageType skip = #C4;
+ final field core::String name;
+ const constructor _(core::String name) → self::MessageType
+ : self::MessageType::name = name, super core::Object::•()
+ ;
+ static factory parse(core::String name) → self::MessageType {
+ if(name.{core::String::==}("print")) {
+ return #C2;
+ }
+ return #C4;
+ }
+}
+static const field self::MessageType printConst = #C2;
+static method main() → void {
+ exp::Expect::equals(#C2, #C2);
+}
+
+constants {
+ #C1 = "print"
+ #C2 = self::MessageType {name:#C1}
+ #C3 = "skip"
+ #C4 = self::MessageType {name:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_const_factory.dart:
+- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect
new file mode 100644
index 0000000..c9674e9
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.strong.transformed.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class MessageType extends core::Object /*hasConstConstructor*/ {
+ static const field self::MessageType print = #C2;
+ static const field self::MessageType skip = #C4;
+ final field core::String name;
+ const constructor _(core::String name) → self::MessageType
+ : self::MessageType::name = name, super core::Object::•()
+ ;
+ static factory parse(core::String name) → self::MessageType {
+ if(name.{core::String::==}("print")) {
+ return #C2;
+ }
+ return #C4;
+ }
+}
+static const field self::MessageType printConst = #C2;
+static method main() → void {
+ exp::Expect::equals(#C2, #C2);
+}
+
+constants {
+ #C1 = "print"
+ #C2 = self::MessageType {name:#C1}
+ #C3 = "skip"
+ #C4 = self::MessageType {name:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_const_factory.dart:
+- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect
new file mode 100644
index 0000000..5caeeca
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+import "package:expect/expect.dart";
+const printConst = MessageType.parse("print");
+class MessageType {
+ static const print = MessageType._('print');
+ static const skip = MessageType._('skip');
+ final String name;
+ const factory MessageType.parse(String name) {}
+ const MessageType._(this.name);
+}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..cb1859d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+import "package:expect/expect.dart";
+
+class MessageType {
+ const MessageType._(this.name);
+ const factory MessageType.parse(String name) {}
+ final String name;
+ static const print = MessageType._('print');
+ static const skip = MessageType._('skip');
+}
+
+const printConst = MessageType.parse("print");
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect
new file mode 100644
index 0000000..c9674e9
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class MessageType extends core::Object /*hasConstConstructor*/ {
+ static const field self::MessageType print = #C2;
+ static const field self::MessageType skip = #C4;
+ final field core::String name;
+ const constructor _(core::String name) → self::MessageType
+ : self::MessageType::name = name, super core::Object::•()
+ ;
+ static factory parse(core::String name) → self::MessageType {
+ if(name.{core::String::==}("print")) {
+ return #C2;
+ }
+ return #C4;
+ }
+}
+static const field self::MessageType printConst = #C2;
+static method main() → void {
+ exp::Expect::equals(#C2, #C2);
+}
+
+constants {
+ #C1 = "print"
+ #C2 = self::MessageType {name:#C1}
+ #C3 = "skip"
+ #C4 = self::MessageType {name:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_const_factory.dart:
+- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect
new file mode 100644
index 0000000..fe4b863
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.outline.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+class MessageType extends core::Object /*hasConstConstructor*/ {
+ static const field self::MessageType print = const self::MessageType::_("print");
+ static const field self::MessageType skip = const self::MessageType::_("skip");
+ final field core::String name;
+ const constructor _(core::String name) → self::MessageType
+ : self::MessageType::name = name, super core::Object::•()
+ ;
+ static const factory parse(core::String name) → self::MessageType
+ ;
+}
+static const field self::MessageType printConst = const self::MessageType::parse("print");
+static method main() → void
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_const_factory.dart:12:36 -> InstanceConstant(const MessageType{MessageType.name: "print"})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_const_factory.dart:14:35 -> InstanceConstant(const MessageType{MessageType.name: "skip"})
+Extra constant evaluation: evaluated: 4, effectively constant: 2
diff --git a/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect
new file mode 100644
index 0000000..c9674e9
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_const_factory.dart.weak.transformed.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class MessageType extends core::Object /*hasConstConstructor*/ {
+ static const field self::MessageType print = #C2;
+ static const field self::MessageType skip = #C4;
+ final field core::String name;
+ const constructor _(core::String name) → self::MessageType
+ : self::MessageType::name = name, super core::Object::•()
+ ;
+ static factory parse(core::String name) → self::MessageType {
+ if(name.{core::String::==}("print")) {
+ return #C2;
+ }
+ return #C4;
+ }
+}
+static const field self::MessageType printConst = #C2;
+static method main() → void {
+ exp::Expect::equals(#C2, #C2);
+}
+
+constants {
+ #C1 = "print"
+ #C2 = self::MessageType {name:#C1}
+ #C3 = "skip"
+ #C4 = self::MessageType {name:#C3}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_const_factory.dart:
+- MessageType._ (from org-dartlang-testcase:///const_functions_const_factory.dart:25:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 8c4bb20..dc7cac2 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -2,6 +2,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE.md file.
+const_functions/const_functions_const_factory: VerificationError
extension_types/simple: ExpectationFileMismatchSerialized
extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized
extension_types/simple_method_resolution: ExpectationFileMismatchSerialized
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 408c9ce..6dd5ffb 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -20,7 +20,7 @@
regress/issue_39091_2: EmptyOutput
regress/utf_16_le_content.crash: EmptyOutput
-
+const_functions/const_functions_const_factory: FormatterCrash
extensions/extension_constructor: FormatterCrash
extensions/extension_field_with_type_parameter_usage: FormatterCrash
extensions/issue38600: FormatterCrash
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 3d38bf7..0f193da 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -1332,6 +1332,16 @@
body += FloatToDouble();
}
body += Box(kUnboxedDouble);
+ } else if (kind == MethodRecognizer::kFfiLoadInt8 ||
+ kind == MethodRecognizer::kFfiLoadInt16 ||
+ kind == MethodRecognizer::kFfiLoadUint8 ||
+ kind == MethodRecognizer::kFfiLoadUint16) {
+ // LoadIndexed instruction with 8-bit and 16-bit elements
+ // results in value with kUnboxedIntPtr representation
+ // (see LoadIndexedInstr::representation).
+ // Avoid any unnecessary (and potentially deoptimizing) int
+ // conversions by using the correct representation at the first place.
+ body += Box(kUnboxedIntPtr);
} else {
body += Box(native_rep.AsRepresentationOverApprox(zone_));
if (kind == MethodRecognizer::kFfiLoadPointer) {
@@ -1462,6 +1472,16 @@
kind == MethodRecognizer::kFfiStoreFloatUnaligned) {
body += DoubleToFloat();
}
+ } else if (kind == MethodRecognizer::kFfiStoreInt8 ||
+ kind == MethodRecognizer::kFfiStoreInt16 ||
+ kind == MethodRecognizer::kFfiStoreUint8 ||
+ kind == MethodRecognizer::kFfiStoreUint16) {
+ // StoreIndexed instruction with 8-bit and 16-bit elements
+ // takes value with kUnboxedIntPtr representation
+ // (see StoreIndexedInstr::RequiredInputRepresentation).
+ // Avoid any unnecessary (and potentially deoptimizing) int
+ // conversions by using the correct representation at the first place.
+ body += UnboxTruncate(kUnboxedIntPtr);
} else {
body += UnboxTruncate(native_rep.AsRepresentationOverApprox(zone_));
}
diff --git a/tests/ffi/regress_flutter79441_test.dart b/tests/ffi/regress_flutter79441_test.dart
new file mode 100644
index 0000000..7f1336f
--- /dev/null
+++ b/tests/ffi/regress_flutter79441_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/flutter/flutter/issues/79441.
+
+import 'dart:ffi';
+
+// FFI signature
+typedef _dart_memset = void Function(Pointer<Uint8>, int, int);
+typedef _c_memset = Void Function(Pointer<Uint8>, Int32, IntPtr);
+
+_dart_memset? fbMemset;
+
+void _fallbackMemset(Pointer<Uint8> ptr, int byte, int size) {
+ final bytes = ptr.cast<Uint8>();
+ for (var i = 0; i < size; i++) {
+ bytes[i] = byte;
+ }
+}
+
+void main() {
+ try {
+ fbMemset = DynamicLibrary.process()
+ .lookupFunction<_c_memset, _dart_memset>('memset');
+ } catch (_) {
+ // This works:
+ // fbMemset = _fallbackMemset;
+
+ // This doesn't: /aot/precompiler.cc: 2761: error: unreachable code
+ fbMemset = (Pointer<Uint8> ptr, int byte, int size) {
+ final bytes = ptr.cast<Uint8>();
+ for (var i = 0; i < size; i++) {
+ bytes[i] = byte;
+ }
+ };
+ }
+}
diff --git a/tests/ffi_2/regress_flutter79441_test.dart b/tests/ffi_2/regress_flutter79441_test.dart
new file mode 100644
index 0000000..a9b17de
--- /dev/null
+++ b/tests/ffi_2/regress_flutter79441_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for https://github.com/flutter/flutter/issues/79441.
+
+import 'dart:ffi';
+
+// FFI signature
+typedef _dart_memset = void Function(Pointer<Uint8>, int, int);
+typedef _c_memset = Void Function(Pointer<Uint8>, Int32, IntPtr);
+
+_dart_memset fbMemset;
+
+void _fallbackMemset(Pointer<Uint8> ptr, int byte, int size) {
+ final bytes = ptr.cast<Uint8>();
+ for (var i = 0; i < size; i++) {
+ bytes[i] = byte;
+ }
+}
+
+void main() {
+ try {
+ fbMemset = DynamicLibrary.process()
+ .lookupFunction<_c_memset, _dart_memset>('memset');
+ } catch (_) {
+ // This works:
+ // fbMemset = _fallbackMemset;
+
+ // This doesn't: /aot/precompiler.cc: 2761: error: unreachable code
+ fbMemset = (Pointer<Uint8> ptr, int byte, int size) {
+ final bytes = ptr.cast<Uint8>();
+ for (var i = 0; i < size; i++) {
+ bytes[i] = byte;
+ }
+ };
+ }
+}
diff --git a/tests/language/const_functions/const_functions_const_factory_disabled_test.dart b/tests/language/const_functions/const_functions_const_factory_disabled_test.dart
new file mode 100644
index 0000000..e6bf9c6
--- /dev/null
+++ b/tests/language/const_functions/const_functions_const_factory_disabled_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests const factories with const functions disabled.
+
+import "package:expect/expect.dart";
+
+const printConst = MessageType.parse("print");
+
+class MessageType {
+ static const print = MessageType._('print');
+
+ static const skip = MessageType._('skip');
+
+ final String name;
+
+ const factory MessageType.parse(String name) {
+//^^^^^
+// [analyzer] SYNTACTIC_ERROR.CONST_FACTORY
+// [cfe] Only redirecting factory constructors can be declared to be 'const'.
+ if (name == 'print') {
+ return MessageType.print;
+ }
+ return MessageType.skip;
+ }
+
+ const MessageType._(this.name);
+}
diff --git a/tests/language/const_functions/const_functions_const_factory_test.dart b/tests/language/const_functions/const_functions_const_factory_test.dart
new file mode 100644
index 0000000..2ff63bc
--- /dev/null
+++ b/tests/language/const_functions/const_functions_const_factory_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests const factories with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const printConst = MessageType.parse("print");
+
+class MessageType {
+ static const print = MessageType._('print');
+
+ static const skip = MessageType._('skip');
+
+ final String name;
+
+ const factory MessageType.parse(String name) {
+//^^^^^
+// [analyzer] SYNTACTIC_ERROR.CONST_FACTORY
+ if (name == 'print') {
+ return MessageType.print;
+ }
+ return MessageType.skip;
+ }
+
+ const MessageType._(this.name);
+}
+
+void main() {
+ Expect.equals(printConst, MessageType.print);
+}
diff --git a/tools/VERSION b/tools/VERSION
index e5962f7d..f65d244 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 210
+PRERELEASE 211
PRERELEASE_PATCH 0
\ No newline at end of file