Skip to content
Permalink
Browse files
Turn on avoid_dynamic_calls lint, except packages/flutter tests, make…
… appropriate changes. (#84476)

This adds avoid_dynamic_calls to the list of lints, and fixes all instances where it was violated.

Importantly, this lint is NOT turned on for flutter/packages/test, because those changes are happening in another PR: #84478
  • Loading branch information
gspencergoog committed Jun 14, 2021
1 parent acd68cf commit 88f38110553e5c407649ff59f43ac476c5a64aeb
Showing with 326 additions and 230 deletions.
  1. +1 −1 analysis_options.yaml
  2. +1 −1 dev/bots/prepare_package.dart
  3. +1 −1 dev/bots/test.dart
  4. +1 −1 dev/bots/test/prepare_package_test.dart
  5. +2 −2 dev/bots/unpublish_package.dart
  6. +1 −1 dev/devicelab/bin/tasks/flutter_gallery__transition_perf_with_semantics.dart
  7. +1 −1 dev/devicelab/lib/framework/browser.dart
  8. +15 −8 dev/devicelab/lib/framework/manifest.dart
  9. +1 −1 dev/devicelab/lib/framework/task_result.dart
  10. +19 −0 dev/devicelab/lib/tasks/hot_mode_tests.dart
  11. +12 −10 dev/devicelab/lib/tasks/perf_tests.dart
  12. +1 −1 dev/devicelab/lib/tasks/web_benchmarks.dart
  13. +1 −1 ...integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo_color_picker.dart
  14. +2 −2 dev/integration_tests/flutter_gallery/test_driver/transitions_perf_test.dart
  15. +12 −12 dev/tools/gen_keycodes/lib/logical_key_data.dart
  16. +13 −10 dev/tools/gen_keycodes/lib/physical_key_data.dart
  17. +6 −4 packages/flutter/lib/src/animation/tween.dart
  18. +9 −7 packages/flutter/lib/src/foundation/_isolates_io.dart
  19. +1 −1 packages/flutter/lib/src/painting/_network_image_web.dart
  20. +1 −1 packages/flutter/lib/src/painting/image_cache.dart
  21. +3 −1 packages/flutter/lib/src/services/text_input.dart
  22. +1 −1 packages/flutter/lib/src/widgets/framework.dart
  23. +3 −0 packages/flutter/lib/src/widgets/overscroll_indicator.dart
  24. +7 −0 packages/flutter/test/analysis_options.yaml
  25. +2 −0 packages/flutter/test/services/fake_platform_views.dart
  26. +3 −3 packages/flutter_driver/lib/src/driver/web_driver.dart
  27. +8 −8 packages/flutter_driver/test/src/real_tests/flutter_driver_test.dart
  28. +8 −0 packages/flutter_localizations/test/material/time_picker_test.dart
  29. +3 −3 packages/flutter_test/lib/src/matchers.dart
  30. +3 −2 packages/flutter_test/lib/src/test_text_input.dart
  31. +1 −0 packages/flutter_test/test/window_test.dart
  32. +1 −1 packages/flutter_tools/lib/src/base/multi_root_file_system.dart
  33. +13 −2 packages/flutter_tools/lib/src/build_system/targets/web.dart
  34. +6 −5 packages/flutter_tools/lib/src/dart/analysis.dart
  35. +3 −3 packages/flutter_tools/lib/src/dart/pub.dart
  36. +3 −1 packages/flutter_tools/lib/src/flutter_manifest.dart
  37. +1 −1 packages/flutter_tools/lib/src/ios/simulators.dart
  38. +37 −40 packages/flutter_tools/lib/src/macos/xcdevice.dart
  39. +3 −4 packages/flutter_tools/lib/src/plugins.dart
  40. +2 −2 packages/flutter_tools/lib/src/protocol_discovery.dart
  41. +3 −2 packages/flutter_tools/lib/src/run_hot.dart
  42. +17 −14 packages/flutter_tools/lib/src/test/flutter_web_platform.dart
  43. +1 −1 packages/flutter_tools/lib/src/windows/visual_studio.dart
  44. +8 −7 packages/flutter_tools/test/commands.shard/hermetic/config_test.dart
  45. +11 −9 packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart
  46. +4 −2 packages/flutter_tools/test/commands.shard/permeable/create_test.dart
  47. +24 −17 packages/flutter_tools/test/general.shard/base/analyze_size_test.dart
  48. +8 −6 packages/flutter_tools/test/general.shard/base/fingerprint_test.dart
  49. +1 −1 packages/flutter_tools/test/general.shard/project_test.dart
  50. +1 −1 packages/flutter_tools/test/integration.shard/command_output_test.dart
  51. +2 −2 packages/flutter_tools/test/integration.shard/flutter_gen_test.dart
  52. +2 −2 packages/flutter_tools/test/integration.shard/hot_reload_test.dart
  53. +17 −13 packages/flutter_tools/test/integration.shard/test_driver.dart
  54. +7 −6 packages/flutter_tools/test/src/pubspec_schema.dart
  55. +1 −1 packages/flutter_web_plugins/lib/src/plugin_registry.dart
  56. +7 −3 packages/integration_test/lib/integration_test_driver_extended.dart
@@ -61,7 +61,7 @@ linter:
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
# - avoid_dynamic_calls # not yet tested
- avoid_dynamic_calls
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_escaping_inner_quotes
@@ -595,7 +595,7 @@ class ArchivePublisher {
if (!jsonData.containsKey('current_release')) {
jsonData['current_release'] = <String, String>{};
}
jsonData['current_release'][branchName] = revision;
(jsonData['current_release'] as Map<String, dynamic>)[branchName] = revision;
if (!jsonData.containsKey('releases')) {
jsonData['releases'] = <Map<String, dynamic>>[];
}
@@ -1059,7 +1059,7 @@ Future<void> _ensureChromeDriverIsRunning() async {
final HttpClientResponse response = await request.close();
final Map<String, dynamic> webDriverStatus = json.decode(await response.transform(utf8.decoder).join('')) as Map<String, dynamic>;
client.close();
final bool webDriverReady = webDriverStatus['value']['ready'] as bool;
final bool webDriverReady = (webDriverStatus['value'] as Map<String, dynamic>)['ready'] as bool;
if (!webDriverReady) {
throw Exception('WebDriver not available.');
}
@@ -394,7 +394,7 @@ void main() {
// Make sure the new entry is first (and hopefully it takes less than a
// minute to go from publishArchive above to this line!).
expect(
DateTime.now().difference(DateTime.parse(releases[0]['release_date'] as String)),
DateTime.now().difference(DateTime.parse((releases[0] as Map<String, dynamic>)['release_date'] as String)),
lessThan(const Duration(minutes: 1)),
);
const JsonEncoder encoder = JsonEncoder.withIndent(' ');
@@ -255,15 +255,15 @@ class ArchiveUnpublisher {
});
jsonData['releases'] = releases;
for (final Channel channel in channels) {
if (!revisionsBeingRemoved.contains(jsonData['current_release'][getChannelName(channel)])) {
if (!revisionsBeingRemoved.contains((jsonData['current_release'] as Map<String, dynamic>)[getChannelName(channel)])) {
// Don't replace the current release if it's not one of the revisions we're removing.
continue;
}
final Map<String, String> replacementRelease = releases.firstWhere((Map<String, String> value) => value['channel'] == getChannelName(channel));
if (replacementRelease == null) {
throw UnpublishException('Unable to find previous release for channel ${getChannelName(channel)}.');
}
jsonData['current_release'][getChannelName(channel)] = replacementRelease['hash'];
(jsonData['current_release'] as Map<String, dynamic>)[getChannelName(channel)] = replacementRelease['hash'];
print(
'${confirmed ? 'Reverting' : 'Would revert'} current ${getChannelName(channel)} '
'${getPublishedPlatform(platform)} release to ${replacementRelease['hash']} (version ${replacementRelease['version']}).'
@@ -31,7 +31,7 @@ Future<void> main() async {
final Map<String, dynamic> data = <String, dynamic>{};
for (final String key in withSemantics.benchmarkScoreKeys) {
final String deltaKey = 'delta_$key';
data[deltaKey] = withSemantics.data[key] - withoutSemantics.data[key];
data[deltaKey] = (withSemantics.data[key] as num) - (withoutSemantics.data[key] as num);
data['semantics_$key'] = withSemantics.data[key];
data[key] = withoutSemantics.data[key];
benchmarkScoreKeys.add(deltaKey);
@@ -273,7 +273,7 @@ Future<Uri> _getRemoteDebuggerUrl(Uri base) async {
if (jsonObject == null || jsonObject.isEmpty) {
return base;
}
return base.resolve(jsonObject.first['webSocketDebuggerUrl'] as String);
return base.resolve((jsonObject.first as Map<String, dynamic>)['webSocketDebuggerUrl'] as String);
}

/// Summarizes a Blink trace down to a few interesting values.
@@ -104,11 +104,12 @@ Manifest _validateAndParseManifest(YamlMap manifestYaml) {

List<ManifestTask> _validateAndParseTasks(dynamic tasksYaml) {
_checkType(tasksYaml is YamlMap, tasksYaml, 'Value of "tasks"', 'dictionary');
final List<dynamic> sortedKeys = (tasksYaml as YamlMap).keys.toList()..sort();
return sortedKeys.map<ManifestTask>((dynamic taskName) => _validateAndParseTask(taskName, tasksYaml[taskName])).toList();
final List<String> sortedKeys = (tasksYaml as YamlMap).keys.toList().cast<String>()..sort();
// ignore: avoid_dynamic_calls
return sortedKeys.map<ManifestTask>((String taskName) => _validateAndParseTask(taskName, tasksYaml[taskName])).toList();
}

ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) {
ManifestTask _validateAndParseTask(String taskName, dynamic taskYaml) {
_checkType(taskName is String, taskName, 'Task name', 'string');
_checkType(taskYaml is YamlMap, taskYaml, 'Value of task "$taskName"', 'dictionary');
_checkKeys(taskYaml as YamlMap, 'Value of task "$taskName"', const <String>[
@@ -119,27 +120,32 @@ ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) {
'timeout_in_minutes',
'on_luci',
]);

// ignore: avoid_dynamic_calls
final dynamic isFlaky = taskYaml['flaky'];
if (isFlaky != null) {
_checkType(isFlaky is bool, isFlaky, 'flaky', 'boolean');
}

// ignore: avoid_dynamic_calls
final dynamic timeoutInMinutes = taskYaml['timeout_in_minutes'];
if (timeoutInMinutes != null) {
_checkType(timeoutInMinutes is int, timeoutInMinutes, 'timeout_in_minutes', 'integer');
}

final List<dynamic> capabilities = _validateAndParseCapabilities(taskName as String, taskYaml['required_agent_capabilities']);
// ignore: avoid_dynamic_calls
final List<dynamic> capabilities = _validateAndParseCapabilities(taskName, taskYaml['required_agent_capabilities']);

// ignore: avoid_dynamic_calls
final dynamic onLuci = taskYaml['on_luci'];
if (onLuci != null) {
_checkType(onLuci is bool, onLuci, 'on_luci', 'boolean');
}

return ManifestTask._(
name: taskName as String,
name: taskName,
// ignore: avoid_dynamic_calls
description: taskYaml['description'] as String,
// ignore: avoid_dynamic_calls
stage: taskYaml['stage'] as String,
requiredAgentCapabilities: capabilities as List<String>,
isFlaky: isFlaky as bool ?? false,
@@ -150,8 +156,9 @@ ManifestTask _validateAndParseTask(dynamic taskName, dynamic taskYaml) {

List<String> _validateAndParseCapabilities(String taskName, dynamic capabilitiesYaml) {
_checkType(capabilitiesYaml is List, capabilitiesYaml, 'required_agent_capabilities', 'list');
for (int i = 0; i < (capabilitiesYaml as List<dynamic>).length; i++) {
final dynamic capability = capabilitiesYaml[i];
final List<dynamic> capabilities = capabilitiesYaml as List<dynamic>;
for (int i = 0; i < capabilities.length; i++) {
final dynamic capability = capabilities[i];
_checkType(capability is String, capability, 'required_agent_capabilities[$i]', 'string');
}
return (capabilitiesYaml as List<dynamic>).cast<String>();
@@ -31,7 +31,7 @@ class TaskResult {
'result data ${prettyJson.convert(data)}';
} else if (data[key] is! num) {
throw 'Invalid benchmark score for key "$key". It is expected to be a num '
'but was ${data[key].runtimeType}: ${prettyJson.convert(data[key])}';
'but was ${(data[key] as Object).runtimeType}: ${prettyJson.convert(data[key])}';
}
}
}
@@ -151,24 +151,43 @@ TaskFunction createHotModeTest({String deviceIdOverride, Map<String, String> env

return TaskResult.success(
<String, dynamic> {
// ignore: avoid_dynamic_calls
'hotReloadInitialDevFSSyncMilliseconds': smallReloadData['hotReloadInitialDevFSSyncMilliseconds'][0],
// ignore: avoid_dynamic_calls
'hotRestartMillisecondsToFrame': smallReloadData['hotRestartMillisecondsToFrame'][0],
// ignore: avoid_dynamic_calls
'hotReloadMillisecondsToFrame' : smallReloadData['hotReloadMillisecondsToFrame'][0],
// ignore: avoid_dynamic_calls
'hotReloadDevFSSyncMilliseconds': smallReloadData['hotReloadDevFSSyncMilliseconds'][0],
// ignore: avoid_dynamic_calls
'hotReloadFlutterReassembleMilliseconds': smallReloadData['hotReloadFlutterReassembleMilliseconds'][0],
// ignore: avoid_dynamic_calls
'hotReloadVMReloadMilliseconds': smallReloadData['hotReloadVMReloadMilliseconds'][0],
// ignore: avoid_dynamic_calls
'hotReloadMillisecondsToFrameAfterChange' : smallReloadData['hotReloadMillisecondsToFrame'][1],
// ignore: avoid_dynamic_calls
'hotReloadDevFSSyncMillisecondsAfterChange': smallReloadData['hotReloadDevFSSyncMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadFlutterReassembleMillisecondsAfterChange': smallReloadData['hotReloadFlutterReassembleMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadVMReloadMillisecondsAfterChange': smallReloadData['hotReloadVMReloadMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadInitialDevFSSyncAfterRelaunchMilliseconds' : freshRestartReloadsData['hotReloadInitialDevFSSyncMilliseconds'][0],
// ignore: avoid_dynamic_calls
'hotReloadMillisecondsToFrameAfterMediumChange' : mediumReloadData['hotReloadMillisecondsToFrame'][1],
// ignore: avoid_dynamic_calls
'hotReloadDevFSSyncMillisecondsAfterMediumChange': mediumReloadData['hotReloadDevFSSyncMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadFlutterReassembleMillisecondsAfterMediumChange': mediumReloadData['hotReloadFlutterReassembleMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadVMReloadMillisecondsAfterMediumChange': mediumReloadData['hotReloadVMReloadMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadMillisecondsToFrameAfterLargeChange' : largeReloadData['hotReloadMillisecondsToFrame'][1],
// ignore: avoid_dynamic_calls
'hotReloadDevFSSyncMillisecondsAfterLargeChange': largeReloadData['hotReloadDevFSSyncMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadFlutterReassembleMillisecondsAfterLargeChange': largeReloadData['hotReloadFlutterReassembleMilliseconds'][1],
// ignore: avoid_dynamic_calls
'hotReloadVMReloadMillisecondsAfterLargeChange': largeReloadData['hotReloadVMReloadMilliseconds'][1],
},
benchmarkScoreKeys: <String>[
@@ -421,13 +421,15 @@ TaskFunction createsScrollSmoothnessPerfTest() {
final Map<String, dynamic> result = <String, dynamic>{};
void addResult(dynamic data, String suffix) {
assert(data is Map<String, dynamic>);
const List<String> metricKeys = <String>[
'janky_count',
'average_abs_jerk',
'dropped_frame_count',
];
for (final String key in metricKeys) {
result[key+suffix] = data[key];
if (data is Map<String, dynamic>) {
const List<String> metricKeys = <String>[
'janky_count',
'average_abs_jerk',
'dropped_frame_count',
];
for (final String key in metricKeys) {
result[key + suffix] = data[key];
}
}
}
addResult(data['resample on with 90Hz input'], '_with_resampler_90Hz');
@@ -1472,15 +1474,15 @@ class DevToolsMemoryTest {
final Map<String, dynamic> data = json.decode(
file('$project/$_kJsonFileName').readAsStringSync(),
) as Map<String, dynamic>;
final List<dynamic> samples = data['samples']['data'] as List<dynamic>;
final List<Map<String, dynamic>> samples = (data['samples'] as Map<String, dynamic>)['data'] as List<Map<String, dynamic>>;
int maxRss = 0;
int maxAdbTotal = 0;
for (final dynamic sample in samples) {
for (final Map<String, dynamic> sample in samples) {
if (sample['rss'] != null) {
maxRss = math.max(maxRss, sample['rss'] as int);
}
if (sample['adb_memoryInfo'] != null) {
maxAdbTotal = math.max(maxAdbTotal, sample['adb_memoryInfo']['Total'] as int);
maxAdbTotal = math.max(maxAdbTotal, (sample['adb_memoryInfo'] as Map<String, dynamic>)['Total'] as int);
}
}

@@ -69,7 +69,7 @@ Future<TaskResult> runWebBenchmark({ @required bool useCanvasKit }) async {
final BlinkTraceSummary traceSummary = BlinkTraceSummary.fromJson(latestPerformanceTrace);
profile['totalUiFrame.average'] = traceSummary.averageTotalUIFrameTime.inMicroseconds;
profile['scoreKeys'] ??= <dynamic>[]; // using dynamic for consistency with JSON
profile['scoreKeys'].add('totalUiFrame.average');
(profile['scoreKeys'] as List<dynamic>).add('totalUiFrame.average');
latestPerformanceTrace = null;
}
collectedProfiles.add(profile);
@@ -46,7 +46,7 @@ class _ColorPickerSwatch extends StatelessWidget {

final Color color;
final bool selected;
final Function? onTap;
final VoidCallback? onTap;

@override
Widget build (BuildContext context) {
@@ -42,7 +42,7 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
frameStart = timestamp;
} else {
assert(phase == 'E');
final String routeName = startEvent['args']['to'] as String;
final String routeName = (startEvent['args'] as Map<String, dynamic>)['to'] as String;
durations[routeName] ??= <int>[];
durations[routeName]!.add(timestamp - frameStart!);
startEvent = null;
@@ -79,7 +79,7 @@ Future<void> saveDurationsHistogram(List<Map<String, dynamic>> events, String ou
continue;

final String routeName = eventName == 'Start Transition'
? eventIter.current['args']['to'] as String
? (eventIter.current['args'] as Map<String, dynamic>)['to'] as String
: '';

if (eventName == lastEventName && routeName == lastRouteName) {
@@ -440,18 +440,18 @@ class LogicalKeyEntry {
LogicalKeyEntry.fromJsonMapEntry(Map<String, dynamic> map)
: value = map['value'] as int,
name = map['name'] as String,
webNames = _toNonEmptyArray<String>(map['names']['web']),
macOSKeyCodeNames = _toNonEmptyArray<String>(map['names']['macos']),
macOSKeyCodeValues = _toNonEmptyArray<int>(map['values']?['macos']),
iOSKeyCodeNames = _toNonEmptyArray<String>(map['names']['ios']),
iOSKeyCodeValues = _toNonEmptyArray<int>(map['values']?['ios']),
gtkNames = _toNonEmptyArray<String>(map['names']['gtk']),
gtkValues = _toNonEmptyArray<int>(map['values']?['gtk']),
windowsNames = _toNonEmptyArray<String>(map['names']['windows']),
windowsValues = _toNonEmptyArray<int>(map['values']?['windows']),
androidNames = _toNonEmptyArray<String>(map['names']['android']),
androidValues = _toNonEmptyArray<int>(map['values']?['android']),
fuchsiaValues = _toNonEmptyArray<int>(map['values']?['fuchsia']),
webNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['web']),
macOSKeyCodeNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['macos']),
macOSKeyCodeValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['macos']),
iOSKeyCodeNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['ios']),
iOSKeyCodeValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['ios']),
gtkNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['gtk']),
gtkValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['gtk']),
windowsNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['windows']),
windowsValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['windows']),
androidNames = _toNonEmptyArray<String>((map['names'] as Map<String, dynamic>)['android']),
androidValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['android']),
fuchsiaValues = _toNonEmptyArray<int>((map['values'] as Map<String, dynamic>?)?['fuchsia']),
keyLabel = map['keyLabel'] as String?;

final int value;
@@ -275,17 +275,20 @@ class PhysicalKeyEntry {

/// Populates the key from a JSON map.
factory PhysicalKeyEntry.fromJsonMapEntry(Map<String, dynamic> map) {
final Map<String, dynamic> names = map['names'] as Map<String, dynamic>;
final Map<String, dynamic> scanCodes = map['scanCodes'] as Map<String, dynamic>;
final Map<String, dynamic>? keyCodes = map['keyCodes'] as Map<String, dynamic>?;
return PhysicalKeyEntry(
name: map['names']['name'] as String,
chromiumCode: map['names']['chromium'] as String?,
usbHidCode: map['scanCodes']['usb'] as int,
androidScanCodes: (map['scanCodes']['android'] as List<dynamic>?)?.cast<int>() ?? <int>[],
linuxScanCode: map['scanCodes']['linux'] as int?,
xKbScanCode: map['scanCodes']['xkb'] as int?,
windowsScanCode: map['scanCodes']['windows'] as int?,
macOSScanCode: map['scanCodes']['macos'] as int?,
iOSScanCode: map['scanCodes']['ios'] as int?,
glfwKeyCodes: (map['keyCodes']?['glfw'] as List<dynamic>?)?.cast<int>() ?? <int>[],
name: names['name'] as String,
chromiumCode: names['chromium'] as String?,
usbHidCode: scanCodes['usb'] as int,
androidScanCodes: (scanCodes['android'] as List<dynamic>?)?.cast<int>() ?? <int>[],
linuxScanCode: scanCodes['linux'] as int?,
xKbScanCode: scanCodes['xkb'] as int?,
windowsScanCode: scanCodes['windows'] as int?,
macOSScanCode: scanCodes['macos'] as int?,
iOSScanCode: scanCodes['ios'] as int?,
glfwKeyCodes: (keyCodes?['glfw'] as List<dynamic>?)?.cast<int>() ?? <int>[],
);
}

@@ -221,7 +221,7 @@ class _ChainedEvaluation<T> extends Animatable<T> {
/// If `T` is not nullable, then [begin] and [end] must both be set to
/// non-null values before using [lerp] or [transform], otherwise they
/// will throw.
class Tween<T extends dynamic> extends Animatable<T> {
class Tween<T extends Object?> extends Animatable<T> {
/// Creates a tween.
///
/// The [begin] and [end] properties must be non-null before the tween is
@@ -261,7 +261,8 @@ class Tween<T extends dynamic> extends Animatable<T> {
// that do not conform to the Tween requirements.
dynamic result;
try {
result = begin + (end - begin) * t;
// ignore: avoid_dynamic_calls
result = (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t;
result as T;
return true;
} on NoSuchMethodError {
@@ -301,7 +302,8 @@ class Tween<T extends dynamic> extends Animatable<T> {
]);
}
}());
return begin + (end - begin) * t as T;
// ignore: avoid_dynamic_calls
return (begin as dynamic) + ((end as dynamic) - (begin as dynamic)) * t as T;
}

/// Returns the interpolated value for the current value of the given animation.
@@ -330,7 +332,7 @@ class Tween<T extends dynamic> extends Animatable<T> {
}

/// A [Tween] that evaluates its [parent] in reverse.
class ReverseTween<T> extends Tween<T> {
class ReverseTween<T extends Object?> extends Tween<T> {
/// Construct a [Tween] that evaluates its [parent] in reverse.
ReverseTween(this.parent)
: assert(parent != null),

0 comments on commit 88f3811

Please sign in to comment.