Version 2.10.0-118.0.dev
Merge commit 'dfc411cb90910835ae14a1d3abc99e539c42433d' into 'dev'
diff --git a/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
new file mode 100644
index 0000000..4261b2b
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
@@ -0,0 +1,35 @@
+// 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.
+
+import 'dart:isolate';
+
+import 'json_benchmark.dart';
+import 'latency.dart';
+
+main() async {
+ // Start GC pressure from helper isolate.
+ final exitPort = ReceivePort();
+ final exitFuture = exitPort.first;
+ final isolate =
+ await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+
+ // Measure event loop latency.
+ const tickDuration = const Duration(milliseconds: 1);
+ const numberOfTicks = 8 * 1000; // min 8 seconds.
+ final EventLoopLatencyStats stats =
+ await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+ // Kill isolate & wait until it's dead.
+ isolate.kill(priority: Isolate.immediate);
+ await exitFuture;
+
+ // Report event loop latency statistics.
+ stats.report('EventLoopLatencyJson');
+}
+
+void runSplay(dynamic msg) async {
+ while (true) {
+ JsonRoundTripBenchmark().run();
+ }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart b/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart
new file mode 100644
index 0000000..c29a5b5
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart
@@ -0,0 +1,47 @@
+// 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.
+
+import 'dart:math';
+import 'dart:convert';
+
+class JsonRoundTripBenchmark {
+ void run() {
+ final res = json.decode(jsonData);
+ final out = json.encode(res);
+ if (out[0] != jsonData[0]) {
+ throw 'json conversion error';
+ }
+ }
+}
+
+// Builds around 4.5 MB of json data - big enough so the decoded object graph
+// does not fit into new space.
+final String jsonData = () {
+ final rnd = Random(42);
+ dynamic buildTree(int depth) {
+ final int coin = rnd.nextInt(1000);
+ if (depth == 0) {
+ if (coin % 2 == 0) return coin;
+ return 'foo-$coin';
+ }
+
+ if (coin % 2 == 0) {
+ final map = <String, dynamic>{};
+ final int length = rnd.nextInt(18);
+ for (int i = 0; i < length; ++i) {
+ map['bar-$i'] = buildTree(depth - 1);
+ }
+ return map;
+ } else {
+ final list = <dynamic>[];
+ final int length = rnd.nextInt(18);
+ for (int i = 0; i < length; ++i) {
+ list.add(buildTree(depth - 1));
+ }
+ return list;
+ }
+ }
+
+ return json.encode({'data': buildTree(6)});
+}();
diff --git a/benchmarks/EventLoopLatencyJson/dart/latency.dart b/benchmarks/EventLoopLatencyJson/dart/latency.dart
new file mode 100644
index 0000000..c368802
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/latency.dart
@@ -0,0 +1,135 @@
+// 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.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+/// Measures event loop responsiveness.
+///
+/// Schedules new timer events, [tickDuration] in the future, and measures how
+/// long it takes for these events to actually arrive.
+///
+/// Runs [numberOfTicks] times before completing with [EventLoopLatencyStats].
+Future<EventLoopLatencyStats> measureEventLoopLatency(
+ Duration tickDuration, int numberOfTicks) {
+ final completer = Completer<EventLoopLatencyStats>();
+
+ final tickDurationInUs = tickDuration.inMicroseconds;
+ final buffer = _TickLatencies(numberOfTicks);
+ final sw = Stopwatch()..start();
+ int lastTimestamp = 0;
+
+ void trigger() {
+ final int currentTimestamp = sw.elapsedMicroseconds;
+
+ // Every tick we missed to schedule we'll add with difference to when we
+ // would've scheduled it and when we became responsive again.
+ bool done = false;
+ while (!done && lastTimestamp < (currentTimestamp - tickDurationInUs)) {
+ done = !buffer.add(currentTimestamp - lastTimestamp - tickDurationInUs);
+ lastTimestamp += tickDurationInUs;
+ }
+
+ if (!done) {
+ lastTimestamp = currentTimestamp;
+ Timer(tickDuration, trigger);
+ } else {
+ completer.complete(buffer.makeStats());
+ }
+ }
+
+ Timer(tickDuration, trigger);
+
+ return completer.future;
+}
+
+/// Result of the event loop latency measurement.
+class EventLoopLatencyStats {
+ /// Minimum latency between scheduling a tick and it's arrival (in ms).
+ final double minLatency;
+
+ /// Average latency between scheduling a tick and it's arrival (in ms).
+ final double avgLatency;
+
+ /// Maximum latency between scheduling a tick and it's arrival (in ms).
+ final double maxLatency;
+
+ /// The 50th percentile (median) (in ms).
+ final double percentile50th;
+
+ /// The 90th percentile (in ms).
+ final double percentile90th;
+
+ /// The 95th percentile (in ms).
+ final double percentile95th;
+
+ /// The 99th percentile (in ms).
+ final double percentile99th;
+
+ /// The maximum RSS of the process.
+ final int maxRss;
+
+ EventLoopLatencyStats(
+ this.minLatency,
+ this.avgLatency,
+ this.maxLatency,
+ this.percentile50th,
+ this.percentile90th,
+ this.percentile95th,
+ this.percentile99th,
+ this.maxRss);
+
+ void report(String name) {
+ print('$name.Min(RunTime): $minLatency ms.');
+ print('$name.Avg(RunTime): $avgLatency ms.');
+ print('$name.Percentile50(RunTime): $percentile50th ms.');
+ print('$name.Percentile90(RunTime): $percentile90th ms.');
+ print('$name.Percentile95(RunTime): $percentile95th ms.');
+ print('$name.Percentile99(RunTime): $percentile99th ms.');
+ print('$name.Max(RunTime): $maxLatency ms.');
+ print('$name.MaxRss(MemoryUse): $maxRss');
+ }
+}
+
+/// Accumulates tick latencies and makes statistics for it.
+class _TickLatencies {
+ final Uint64List _timestamps;
+ int _index = 0;
+
+ _TickLatencies(int numberOfTicks) : _timestamps = Uint64List(numberOfTicks);
+
+ /// Returns `true` while the buffer has not been filled yet.
+ bool add(int latencyInUs) {
+ _timestamps[_index++] = latencyInUs;
+ return _index < _timestamps.length;
+ }
+
+ EventLoopLatencyStats makeStats() {
+ if (_index != _timestamps.length) {
+ throw 'Buffer has not been fully filled yet.';
+ }
+
+ _timestamps.sort();
+ final length = _timestamps.length;
+ final double avg = _timestamps.fold(0, (int a, int b) => a + b) / length;
+ final int min = _timestamps.fold(0x7fffffffffffffff, math.min);
+ final int max = _timestamps.fold(0, math.max);
+ final percentile50th = _timestamps[50 * length ~/ 100];
+ final percentile90th = _timestamps[90 * length ~/ 100];
+ final percentile95th = _timestamps[95 * length ~/ 100];
+ final percentile99th = _timestamps[99 * length ~/ 100];
+
+ return EventLoopLatencyStats(
+ min / 1000,
+ avg / 1000,
+ max / 1000,
+ percentile50th / 1000,
+ percentile90th / 1000,
+ percentile95th / 1000,
+ percentile99th / 1000,
+ ProcessInfo.maxRss);
+ }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
new file mode 100644
index 0000000..4261b2b
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
@@ -0,0 +1,35 @@
+// 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.
+
+import 'dart:isolate';
+
+import 'json_benchmark.dart';
+import 'latency.dart';
+
+main() async {
+ // Start GC pressure from helper isolate.
+ final exitPort = ReceivePort();
+ final exitFuture = exitPort.first;
+ final isolate =
+ await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+
+ // Measure event loop latency.
+ const tickDuration = const Duration(milliseconds: 1);
+ const numberOfTicks = 8 * 1000; // min 8 seconds.
+ final EventLoopLatencyStats stats =
+ await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+ // Kill isolate & wait until it's dead.
+ isolate.kill(priority: Isolate.immediate);
+ await exitFuture;
+
+ // Report event loop latency statistics.
+ stats.report('EventLoopLatencyJson');
+}
+
+void runSplay(dynamic msg) async {
+ while (true) {
+ JsonRoundTripBenchmark().run();
+ }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart b/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart
new file mode 100644
index 0000000..c29a5b5
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart
@@ -0,0 +1,47 @@
+// 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.
+
+import 'dart:math';
+import 'dart:convert';
+
+class JsonRoundTripBenchmark {
+ void run() {
+ final res = json.decode(jsonData);
+ final out = json.encode(res);
+ if (out[0] != jsonData[0]) {
+ throw 'json conversion error';
+ }
+ }
+}
+
+// Builds around 4.5 MB of json data - big enough so the decoded object graph
+// does not fit into new space.
+final String jsonData = () {
+ final rnd = Random(42);
+ dynamic buildTree(int depth) {
+ final int coin = rnd.nextInt(1000);
+ if (depth == 0) {
+ if (coin % 2 == 0) return coin;
+ return 'foo-$coin';
+ }
+
+ if (coin % 2 == 0) {
+ final map = <String, dynamic>{};
+ final int length = rnd.nextInt(18);
+ for (int i = 0; i < length; ++i) {
+ map['bar-$i'] = buildTree(depth - 1);
+ }
+ return map;
+ } else {
+ final list = <dynamic>[];
+ final int length = rnd.nextInt(18);
+ for (int i = 0; i < length; ++i) {
+ list.add(buildTree(depth - 1));
+ }
+ return list;
+ }
+ }
+
+ return json.encode({'data': buildTree(6)});
+}();
diff --git a/benchmarks/EventLoopLatencyJson/dart2/latency.dart b/benchmarks/EventLoopLatencyJson/dart2/latency.dart
new file mode 100644
index 0000000..c368802
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/latency.dart
@@ -0,0 +1,135 @@
+// 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.
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+/// Measures event loop responsiveness.
+///
+/// Schedules new timer events, [tickDuration] in the future, and measures how
+/// long it takes for these events to actually arrive.
+///
+/// Runs [numberOfTicks] times before completing with [EventLoopLatencyStats].
+Future<EventLoopLatencyStats> measureEventLoopLatency(
+ Duration tickDuration, int numberOfTicks) {
+ final completer = Completer<EventLoopLatencyStats>();
+
+ final tickDurationInUs = tickDuration.inMicroseconds;
+ final buffer = _TickLatencies(numberOfTicks);
+ final sw = Stopwatch()..start();
+ int lastTimestamp = 0;
+
+ void trigger() {
+ final int currentTimestamp = sw.elapsedMicroseconds;
+
+ // Every tick we missed to schedule we'll add with difference to when we
+ // would've scheduled it and when we became responsive again.
+ bool done = false;
+ while (!done && lastTimestamp < (currentTimestamp - tickDurationInUs)) {
+ done = !buffer.add(currentTimestamp - lastTimestamp - tickDurationInUs);
+ lastTimestamp += tickDurationInUs;
+ }
+
+ if (!done) {
+ lastTimestamp = currentTimestamp;
+ Timer(tickDuration, trigger);
+ } else {
+ completer.complete(buffer.makeStats());
+ }
+ }
+
+ Timer(tickDuration, trigger);
+
+ return completer.future;
+}
+
+/// Result of the event loop latency measurement.
+class EventLoopLatencyStats {
+ /// Minimum latency between scheduling a tick and it's arrival (in ms).
+ final double minLatency;
+
+ /// Average latency between scheduling a tick and it's arrival (in ms).
+ final double avgLatency;
+
+ /// Maximum latency between scheduling a tick and it's arrival (in ms).
+ final double maxLatency;
+
+ /// The 50th percentile (median) (in ms).
+ final double percentile50th;
+
+ /// The 90th percentile (in ms).
+ final double percentile90th;
+
+ /// The 95th percentile (in ms).
+ final double percentile95th;
+
+ /// The 99th percentile (in ms).
+ final double percentile99th;
+
+ /// The maximum RSS of the process.
+ final int maxRss;
+
+ EventLoopLatencyStats(
+ this.minLatency,
+ this.avgLatency,
+ this.maxLatency,
+ this.percentile50th,
+ this.percentile90th,
+ this.percentile95th,
+ this.percentile99th,
+ this.maxRss);
+
+ void report(String name) {
+ print('$name.Min(RunTime): $minLatency ms.');
+ print('$name.Avg(RunTime): $avgLatency ms.');
+ print('$name.Percentile50(RunTime): $percentile50th ms.');
+ print('$name.Percentile90(RunTime): $percentile90th ms.');
+ print('$name.Percentile95(RunTime): $percentile95th ms.');
+ print('$name.Percentile99(RunTime): $percentile99th ms.');
+ print('$name.Max(RunTime): $maxLatency ms.');
+ print('$name.MaxRss(MemoryUse): $maxRss');
+ }
+}
+
+/// Accumulates tick latencies and makes statistics for it.
+class _TickLatencies {
+ final Uint64List _timestamps;
+ int _index = 0;
+
+ _TickLatencies(int numberOfTicks) : _timestamps = Uint64List(numberOfTicks);
+
+ /// Returns `true` while the buffer has not been filled yet.
+ bool add(int latencyInUs) {
+ _timestamps[_index++] = latencyInUs;
+ return _index < _timestamps.length;
+ }
+
+ EventLoopLatencyStats makeStats() {
+ if (_index != _timestamps.length) {
+ throw 'Buffer has not been fully filled yet.';
+ }
+
+ _timestamps.sort();
+ final length = _timestamps.length;
+ final double avg = _timestamps.fold(0, (int a, int b) => a + b) / length;
+ final int min = _timestamps.fold(0x7fffffffffffffff, math.min);
+ final int max = _timestamps.fold(0, math.max);
+ final percentile50th = _timestamps[50 * length ~/ 100];
+ final percentile90th = _timestamps[90 * length ~/ 100];
+ final percentile95th = _timestamps[95 * length ~/ 100];
+ final percentile99th = _timestamps[99 * length ~/ 100];
+
+ return EventLoopLatencyStats(
+ min / 1000,
+ avg / 1000,
+ max / 1000,
+ percentile50th / 1000,
+ percentile90th / 1000,
+ percentile95th / 1000,
+ percentile99th / 1000,
+ ProcessInfo.maxRss);
+ }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
index 6e6309a..152ba37 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
@@ -126,7 +126,7 @@
);
server.onOverlayCreated(path, doc.text);
- final driver = server.contextManager.getDriverFor(path);
+ final driver = server.getAnalysisDriver(path);
// If the file did not exist, and is "overlay only", it still should be
// analyzed. Add it to driver to which it should have been added.
diff --git a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
index 3b42924..95e11f4 100644
--- a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
+++ b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
@@ -192,6 +192,43 @@
);
}
+ Future<void> test_changeWorkspaceFolders_openFileOutsideRoot() async {
+ // When a file is opened that is outside of the analysis roots, the first
+ // analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver]).
+ // This means as long as there is already an analysis root, the implicit root
+ // will be the original root and not the path of the opened file.
+ // For example, Go-to-Definition into a file in PubCache must *not* result in
+ // the pub cache folder being added as an analysis root, it should be analyzed
+ // by the existing project's driver.
+ final workspace1FilePath = join(workspaceFolder1Path, 'test.dart');
+ await newFile(workspace1FilePath);
+ final workspace2FilePath = join(workspaceFolder2Path, 'test.dart');
+ final workspace2FileUri = Uri.file(workspace2FilePath);
+ await newFile(workspace2FilePath);
+
+ await initialize(workspaceFolders: [workspaceFolder1Uri]);
+
+ // Expect explicit root for the workspace folder.
+ expect(
+ server.contextManager.includedPaths,
+ unorderedEquals([workspaceFolder1Path]),
+ );
+
+ // Open a file in workspaceFolder2 (which is not in the analysis roots).
+ await openFile(workspace2FileUri, '');
+ expect(
+ server.contextManager.includedPaths,
+ unorderedEquals([workspaceFolder1Path]),
+ );
+
+ // Closing the file should not result in the project being removed.
+ await closeFile(workspace2FileUri);
+ expect(
+ server.contextManager.includedPaths,
+ unorderedEquals([workspaceFolder1Path]),
+ );
+ }
+
Future<void> test_changeWorkspaceFolders_remove() async {
await initialize(
workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 0dfd4db..9e26d98 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6967,21 +6967,7 @@
}
@override
- DartType get returnTypeInternal {
- var returnType = variable.type;
-
- // While performing inference during linking, the first step is to collect
- // dependencies. During this step we resolve the expression, but we might
- // reference elements that don't have their types inferred yet. So, here
- // we give some type. A better solution would be to infer recursively, but
- // we are not doing this yet.
- if (returnType == null) {
- assert(linkedContext.isLinking);
- return DynamicTypeImpl.instance;
- }
-
- return returnType;
- }
+ DartType get returnTypeInternal => variable.type;
@override
FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
@@ -7138,7 +7124,19 @@
DartType get typeInternal {
if (linkedNode != null) {
if (_type != null) return _type;
- return _type = linkedContext.getType(linkedNode);
+ _type = linkedContext.getType(linkedNode);
+
+ // While performing inference during linking, the first step is to collect
+ // dependencies. During this step we resolve the expression, but we might
+ // reference elements that don't have their types inferred yet. So, here
+ // we give some type. A better solution would be to infer recursively, but
+ // we are not doing this yet.
+ if (_type == null) {
+ assert(linkedContext.isLinking);
+ return DynamicTypeImpl.instance;
+ }
+
+ return _type;
}
if (isSynthetic && _type == null) {
if (getter != null) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 4fd07d6..1a4c879 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -15,13 +15,13 @@
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
+import 'package:analyzer/src/error/assignment_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
import 'package:analyzer/src/generated/migration.dart';
import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/task/strong/checker.dart';
import 'package:meta/meta.dart';
/// Helper for resolving [AssignmentExpression]s.
@@ -52,9 +52,6 @@
return _resolver.migrationResolutionHooks;
}
- NullableDereferenceVerifier get _nullableDereferenceVerifier =>
- _resolver.nullableDereferenceVerifier;
-
TypeProvider get _typeProvider => _resolver.typeProvider;
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
@@ -63,6 +60,11 @@
var left = node.leftHandSide;
var right = node.rightHandSide;
+ if (left is PropertyAccess) {
+ _resolve_PropertyAccess(node, left);
+ return;
+ }
+
if (left is SimpleIdentifier) {
_resolve_SimpleIdentifier(node, left);
return;
@@ -81,23 +83,7 @@
_resolver.setWriteElement(left, null);
}
- _resolve1(node, getReadType(left));
-
- _setRhsContext(node, left.staticType, operator, right);
-
- _flowAnalysis?.assignmentExpression(node);
-
- if (operator != TokenType.EQ &&
- operator != TokenType.QUESTION_QUESTION_EQ) {
- _nullableDereferenceVerifier.expression(left);
- }
-
- right?.accept(_resolver);
- right = node.rightHandSide;
-
- _resolve2(node);
-
- _flowAnalysis?.assignmentExpression_afterRight(node);
+ _resolve3(node, left, operator, right);
}
void _checkForInvalidAssignment(
@@ -175,90 +161,6 @@
}
}
- void _reportNotSetter(
- Expression left,
- Element requested,
- Element recovery,
- ) {
- if (requested != null) {
- if (requested is VariableElement) {
- if (requested.isConst) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
- left,
- );
- } else if (requested.isFinal) {
- if (_isNonNullableByDefault) {
- // Handled during resolution, with flow analysis.
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
- left,
- [requested.name],
- );
- }
- }
- }
- return;
- }
-
- if (recovery is ClassElement ||
- recovery is DynamicElementImpl ||
- recovery is FunctionTypeAliasElement ||
- recovery is TypeParameterElement) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
- left,
- );
- } else if (recovery is FunctionElement) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FUNCTION,
- left,
- );
- } else if (recovery is MethodElement) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
- left,
- );
- } else if (recovery is PrefixElement) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
- left,
- [recovery.name],
- );
- } else if (recovery is PropertyAccessorElement && recovery.isGetter) {
- var variable = recovery.variable;
- if (variable.isConst) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
- left,
- );
- } else if (variable is FieldElement && variable.isSynthetic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
- left,
- [variable.name, variable.enclosingElement.displayName],
- );
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
- left,
- [variable.name],
- );
- }
- } else if (recovery is MultiplyDefinedElementImpl) {
- // Will be reported in ErrorVerifier.
- } else {
- if (left is SimpleIdentifier && !left.isSynthetic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
- left,
- [left.name],
- );
- }
- }
- }
-
void _resolve1(AssignmentExpressionImpl node, DartType leftType) {
Token operator = node.operator;
TokenType operatorType = operator.type;
@@ -310,7 +212,9 @@
}
}
- void _resolve2(AssignmentExpressionImpl node) {
+ /// TODO(scheglov) Replace [leftWriteType] with `node.writeType`
+ void _resolve2(AssignmentExpressionImpl node, DartType leftWriteType,
+ {@required bool doNullShortingTermination}) {
TokenType operator = node.operator.type;
if (operator == TokenType.EQ) {
var rightType = node.rightHandSide.staticType;
@@ -333,7 +237,7 @@
} else {
var rightType = node.rightHandSide.staticType;
- var leftReadType = getReadType(node.leftHandSide);
+ var leftReadType = node.readType;
if (identical(leftReadType, NeverTypeImpl.instance)) {
_inferenceHelper.recordStaticType(node, rightType);
return;
@@ -350,7 +254,6 @@
);
_inferenceHelper.recordStaticType(node, type);
- var leftWriteType = _getWriteType(node.leftHandSide);
if (!_typeSystem.isAssignableTo2(type, leftWriteType)) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVALID_ASSIGNMENT,
@@ -359,50 +262,14 @@
);
}
}
- _resolver.nullShortingTermination(node);
+
+ if (doNullShortingTermination) {
+ _resolver.nullShortingTermination(node);
+ }
}
- void _resolve_SimpleIdentifier(
- AssignmentExpressionImpl node,
- SimpleIdentifier left,
- ) {
- var right = node.rightHandSide;
- var operator = node.operator.type;
-
- if (operator != TokenType.EQ) {
- var readLookup = _resolver.lexicalLookup(node: left, setter: false);
- var readElement = readLookup.requested;
- _resolver.setReadElement(left, readElement);
- }
-
- var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
- var writeElement = writeLookup.requested ?? writeLookup.recovery;
- _resolver.setWriteElement(left, writeElement);
- _reportNotSetter(left, writeLookup.requested, writeLookup.recovery);
-
- // TODO(scheglov) This is mostly necessary for backward compatibility.
- // Although we also use `staticElement` for `getType(left)` below.
- {
- if (operator != TokenType.EQ) {
- var readElement = node.readElement;
- if (readElement is PropertyAccessorElement) {
- left.auxiliaryElements = AuxiliaryElements(readElement);
- }
- }
- left.staticElement = node.writeElement;
- if (node.readElement is VariableElement) {
- var leftType = _resolver.localVariableTypeProvider.getType(left);
- _recordStaticType(left, leftType);
- } else {
- _recordStaticType(left, node.writeType);
- }
- }
-
- if (operator != TokenType.EQ) {
- // TODO(scheglov) Change this method to work with elements.
- _resolver.checkReadOfNotAssignedLocalVariable(left);
- }
-
+ void _resolve3(AssignmentExpressionImpl node, Expression left,
+ TokenType operator, Expression right) {
_resolve1(node, node.readType);
{
@@ -421,7 +288,7 @@
right?.accept(_resolver);
right = node.rightHandSide;
- _resolve2(node);
+ _resolve2(node, node.writeType, doNullShortingTermination: false);
// TODO(scheglov) inline into resolve2().
DartType assignedType;
@@ -433,9 +300,11 @@
}
_checkForInvalidAssignment(node.writeType, right, assignedType);
+ _resolver.nullShortingTermination(node);
+
if (flow != null) {
- if (writeElement is VariableElement) {
- flow.write(writeElement, node.staticType);
+ if (node.writeElement is VariableElement) {
+ flow.write(node.writeElement, node.staticType);
}
if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
flow.ifNullExpression_end();
@@ -443,6 +312,107 @@
}
}
+ void _resolve_PropertyAccess(
+ AssignmentExpressionImpl node,
+ PropertyAccess left,
+ ) {
+ left.target?.accept(_resolver);
+
+ var propertyName = left.propertyName;
+ var operator = node.operator.type;
+ var hasRead = operator != TokenType.EQ;
+
+ _resolver.startNullAwarePropertyAccess(left);
+
+ ExecutableElement readElement;
+ ExecutableElement writeElement;
+
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePropertyAccess(
+ node: left,
+ hasRead: hasRead,
+ hasWrite: true,
+ );
+
+ readElement = result.readElement;
+ writeElement = result.writeElement;
+
+ if (hasRead) {
+ _resolver.setReadElement(left, readElement);
+ }
+
+ // var writeElement = result.setter ?? result.getter;
+ _resolver.setWriteElement(left, writeElement);
+
+ _setBackwardCompatibility(node, propertyName);
+
+ var right = node.rightHandSide;
+ _resolve3(node, left, operator, right);
+ }
+
+ void _resolve_SimpleIdentifier(
+ AssignmentExpressionImpl node,
+ SimpleIdentifier left,
+ ) {
+ var right = node.rightHandSide;
+ var operator = node.operator.type;
+
+ if (operator != TokenType.EQ) {
+ var readLookup = _resolver.lexicalLookup(node: left, setter: false);
+ var readElement = readLookup.requested;
+ _resolver.setReadElement(left, readElement);
+ }
+
+ var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
+ var writeElement = writeLookup.requested ?? writeLookup.recovery;
+ _resolver.setWriteElement(left, writeElement);
+
+ AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
+ node: left,
+ requested: writeLookup.requested,
+ recovery: writeLookup.recovery,
+ receiverTypeObject: null,
+ );
+
+ _setBackwardCompatibility(node, left);
+
+ if (operator != TokenType.EQ) {
+ // TODO(scheglov) Change this method to work with elements.
+ _resolver.checkReadOfNotAssignedLocalVariable(left);
+ }
+
+ _resolve3(node, left, operator, right);
+ }
+
+ /// TODO(scheglov) This is mostly necessary for backward compatibility.
+ /// Although we also use `staticElement` for `getType(left)` below.
+ void _setBackwardCompatibility(
+ AssignmentExpressionImpl node,
+ SimpleIdentifier left,
+ ) {
+ var operator = node.operator.type;
+
+ if (operator != TokenType.EQ) {
+ var readElement = node.readElement;
+ if (readElement is PropertyAccessorElement) {
+ left.auxiliaryElements = AuxiliaryElements(readElement);
+ }
+ }
+
+ left.staticElement = node.writeElement;
+ if (node.readElement is VariableElement) {
+ var leftType = _resolver.localVariableTypeProvider.getType(left);
+ _recordStaticType(left, leftType);
+ } else {
+ _recordStaticType(left, node.writeType);
+ }
+
+ var parent = left.parent;
+ if (parent is PropertyAccess && parent.propertyName == left) {
+ _recordStaticType(parent, node.writeType);
+ }
+ }
+
void _setRhsContext(AssignmentExpressionImpl node, DartType leftType,
TokenType operator, Expression right) {
switch (operator) {
@@ -482,19 +452,6 @@
}
return false;
}
-
- /// The type of the RHS assigned to [left] must be subtype of the return.
- static DartType _getWriteType(Expression left) {
- // We are writing, so ignore promotions.
- if (left is SimpleIdentifier) {
- var element = left.staticElement;
- if (element is PromotableElement) {
- return element.type;
- }
- }
-
- return left.staticType;
- }
}
class AssignmentExpressionShared {
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
new file mode 100644
index 0000000..70dcfbf
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -0,0 +1,503 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
+import 'package:analyzer/src/error/assignment_verifier.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/super_context.dart';
+import 'package:meta/meta.dart';
+
+class PropertyElementResolver {
+ final ResolverVisitor _resolver;
+
+ PropertyElementResolver(this._resolver);
+
+ LibraryElement get _definingLibrary => _resolver.definingLibrary;
+
+ ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+ ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver;
+
+ PropertyElementResolverResult resolve2({
+ @required Expression target,
+ @required bool isCascaded,
+ @required bool isNullAware,
+ @required SimpleIdentifier propertyName,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ if (target is ExtensionOverride) {
+ return _resolveTargetExtensionOverride(
+ target: target,
+ propertyName: propertyName,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+
+ //
+ // If this property access is of the form 'C.m' where 'C' is a class,
+ // then we don't call resolveProperty(...) which walks up the class
+ // hierarchy, instead we just look for the member in the type only. This
+ // does not apply to conditional property accesses (i.e. 'C?.m').
+ //
+ if (target is Identifier) {
+ var targetElement = target.staticElement;
+ if (targetElement is ClassElement) {
+ if (isCascaded) {
+ targetElement = _resolver.typeProvider.typeType.element;
+ }
+ return _resolveTargetClassElement(
+ typeReference: targetElement,
+ propertyName: propertyName,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+ }
+
+ //
+ // If this property access is of the form 'E.m' where 'E' is an extension,
+ // then look for the member in the extension. This does not apply to
+ // conditional property accesses (i.e. 'C?.m').
+ //
+ if (target is Identifier) {
+ var targetElement = target.staticElement;
+ if (targetElement is ExtensionElement) {
+ return _resolveTargetExtensionElement(
+ extension: targetElement,
+ propertyName: propertyName,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+ }
+
+ if (target is SuperExpression) {
+ return _resolveTargetSuperExpression(
+ target: target,
+ propertyName: propertyName,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+
+ var targetType = target.staticType;
+ targetType = _resolveTypeParameter(targetType);
+
+ if (targetType.isVoid) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.USE_OF_VOID_RESULT,
+ propertyName,
+ );
+ return PropertyElementResolverResult();
+ }
+
+ if (isNullAware) {
+ targetType = _resolver.typeSystem.promoteToNonNull(targetType);
+ }
+
+ var result = _resolver.typePropertyResolver.resolve(
+ receiver: target,
+ receiverType: targetType,
+ name: propertyName.name,
+ receiverErrorNode: target,
+ nameErrorNode: propertyName,
+ );
+
+ if (targetType is DynamicTypeImpl || targetType is NeverTypeImpl) {
+ // OK
+ } else {
+ // TODO(scheglov) It is not nice that we check for `call` here.
+ // We can find `call` in these types, is should be `single`, but `null`.
+ if (hasRead && result.getter == null && !result.isAmbiguous) {
+ if (targetType is FunctionType &&
+ propertyName.name == FunctionElement.CALL_METHOD_NAME) {
+ // Referencing `.call` on a FunctionType is OK.
+ } else if (targetType is InterfaceType &&
+ targetType.isDartCoreFunction &&
+ propertyName.name == FunctionElement.CALL_METHOD_NAME) {
+ // Referencing `.call` on a `Function` type is OK.
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_GETTER,
+ propertyName,
+ [propertyName.name, targetType],
+ );
+ }
+ }
+
+ if (hasWrite && result.setter == null && !result.isAmbiguous) {
+ AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+ node: propertyName,
+ requested: null,
+ recovery: result.getter,
+ receiverTypeObject: targetType,
+ );
+ }
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: result.getter,
+ readElementRecovery: result.setter,
+ writeElementRequested: result.setter,
+ writeElementRecovery: result.getter,
+ );
+ }
+
+ PropertyElementResolverResult resolvePrefixedIdentifier({
+ @required PrefixedIdentifier node,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ return resolve2(
+ target: node.prefix,
+ isCascaded: false,
+ isNullAware: false,
+ propertyName: node.identifier,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+
+ PropertyElementResolverResult resolvePropertyAccess({
+ @required PropertyAccess node,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ return resolve2(
+ target: node.realTarget,
+ isCascaded: node.target == null,
+ isNullAware: node.isNullAware,
+ propertyName: node.propertyName,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+ }
+
+ void _checkExtensionOverrideStaticMember(
+ SimpleIdentifier propertyName,
+ ExecutableElement element,
+ ) {
+ if (element != null && element.isStatic) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+ propertyName,
+ );
+ }
+ }
+
+ /// If the [element] is not static, report the error on the [identifier].
+ void _checkForStaticAccessToInstanceMember(
+ SimpleIdentifier identifier,
+ ExecutableElement element,
+ ) {
+ if (element.isStatic) return;
+
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
+ identifier,
+ [identifier.name],
+ );
+ }
+
+ bool _isAccessible(ExecutableElement element) {
+ return element.isAccessibleIn(_definingLibrary);
+ }
+
+ PropertyElementResolverResult _resolveTargetClassElement({
+ @required ClassElement typeReference,
+ @required SimpleIdentifier propertyName,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ ExecutableElement readElement;
+ if (hasRead) {
+ readElement = typeReference.getGetter(propertyName.name);
+ if (readElement != null && !_isAccessible(readElement)) {
+ readElement = null;
+ }
+
+ if (readElement == null) {
+ readElement = typeReference.getMethod(propertyName.name);
+ if (readElement != null && !_isAccessible(readElement)) {
+ readElement = null;
+ }
+ }
+
+ if (readElement != null) {
+ readElement = _resolver.toLegacyElement(readElement);
+ _checkForStaticAccessToInstanceMember(propertyName, readElement);
+ } else {
+ var code = typeReference.isEnum
+ ? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
+ : CompileTimeErrorCode.UNDEFINED_GETTER;
+ _errorReporter.reportErrorForNode(
+ code,
+ propertyName,
+ [propertyName.name, typeReference.name],
+ );
+ }
+ }
+
+ ExecutableElement writeElement;
+ ExecutableElement writeElementRecovery;
+ if (hasWrite) {
+ writeElement = typeReference.getSetter(propertyName.name);
+ if (writeElement != null) {
+ writeElement = _resolver.toLegacyElement(writeElement);
+ if (!_isAccessible(writeElement)) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.PRIVATE_SETTER,
+ propertyName,
+ [propertyName.name, typeReference.name],
+ );
+ }
+ _checkForStaticAccessToInstanceMember(propertyName, writeElement);
+ } else {
+ // Recovery, try to use getter.
+ writeElementRecovery = typeReference.getGetter(propertyName.name);
+ AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+ node: propertyName,
+ requested: null,
+ recovery: writeElementRecovery,
+ receiverTypeObject: typeReference.displayName,
+ );
+ }
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElement,
+ writeElementRequested: writeElement,
+ writeElementRecovery: writeElementRecovery,
+ );
+ }
+
+ PropertyElementResolverResult _resolveTargetExtensionElement({
+ @required ExtensionElement extension,
+ @required SimpleIdentifier propertyName,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ var memberName = propertyName.name;
+
+ ExecutableElement readElement;
+ if (hasRead) {
+ readElement ??= extension.getGetter(memberName);
+ readElement ??= extension.getMethod(memberName);
+
+ if (readElement == null) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
+ propertyName,
+ [memberName, extension.name],
+ );
+ } else {
+ readElement = _resolver.toLegacyElement(readElement);
+ _checkForStaticAccessToInstanceMember(propertyName, readElement);
+ }
+ }
+
+ ExecutableElement writeElement;
+ if (hasWrite) {
+ writeElement = extension.getSetter(memberName);
+
+ if (writeElement == null) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
+ propertyName,
+ [memberName, extension.name],
+ );
+ } else {
+ writeElement = _resolver.toLegacyElement(writeElement);
+ _checkForStaticAccessToInstanceMember(propertyName, writeElement);
+ }
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElement,
+ writeElementRequested: writeElement,
+ );
+ }
+
+ PropertyElementResolverResult _resolveTargetExtensionOverride({
+ @required ExtensionOverride target,
+ @required SimpleIdentifier propertyName,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ if (target.parent is CascadeExpression) {
+ // Report this error and recover by treating it like a non-cascade.
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
+ target.extensionName,
+ );
+ }
+
+ ExtensionElement element = target.extensionName.staticElement;
+ String memberName = propertyName.name;
+
+ var result = _extensionResolver.getOverrideMember(target, memberName);
+
+ ExecutableElement readElement;
+ if (hasRead) {
+ readElement = result.getter;
+ if (readElement == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
+ propertyName,
+ [memberName, element.name],
+ );
+ }
+ _checkExtensionOverrideStaticMember(propertyName, readElement);
+ }
+
+ ExecutableElement writeElement;
+ if (hasWrite) {
+ writeElement = result.setter;
+ if (writeElement == null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
+ propertyName,
+ [memberName, element.name],
+ );
+ }
+ _checkExtensionOverrideStaticMember(propertyName, writeElement);
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElement,
+ writeElementRequested: writeElement,
+ );
+ }
+
+ PropertyElementResolverResult _resolveTargetSuperExpression({
+ @required SuperExpression target,
+ @required SimpleIdentifier propertyName,
+ @required bool hasRead,
+ @required bool hasWrite,
+ }) {
+ if (SuperContext.of(target) != SuperContext.valid) {
+ return PropertyElementResolverResult();
+ }
+ var targetType = target.staticType;
+
+ ExecutableElement readElement;
+ ExecutableElement writeElement;
+
+ if (targetType is InterfaceTypeImpl) {
+ if (hasRead) {
+ var name = Name(_definingLibrary.source.uri, propertyName.name);
+ readElement = _resolver.inheritance
+ .getMember2(targetType.element, name, forSuper: true);
+
+ if (readElement != null) {
+ readElement = _resolver.toLegacyElement(readElement);
+ } else {
+ // We were not able to find the concrete dispatch target.
+ // But we would like to give the user at least some resolution.
+ // So, we retry simply looking for an inherited member.
+ readElement =
+ _resolver.inheritance.getInherited2(targetType.element, name);
+ if (readElement != null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
+ propertyName,
+ [readElement.kind.displayName, propertyName.name],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
+ propertyName,
+ [propertyName.name, targetType],
+ );
+ }
+ }
+ }
+
+ if (hasWrite) {
+ writeElement = targetType.lookUpSetter2(
+ propertyName.name,
+ _definingLibrary,
+ concrete: true,
+ inherited: true,
+ );
+
+ if (writeElement != null) {
+ writeElement = _resolver.toLegacyElement(writeElement);
+ } else {
+ // We were not able to find the concrete dispatch target.
+ // But we would like to give the user at least some resolution.
+ // So, we retry without the "concrete" requirement.
+ writeElement = targetType.lookUpSetter2(
+ propertyName.name,
+ _definingLibrary,
+ inherited: true,
+ );
+ if (writeElement != null) {
+ ClassElementImpl receiverSuperClass =
+ targetType.element.supertype.element;
+ if (!receiverSuperClass.hasNoSuchMethod) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
+ propertyName,
+ [writeElement.kind.displayName, propertyName.name],
+ );
+ }
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_SUPER_SETTER,
+ propertyName,
+ [propertyName.name, targetType],
+ );
+ }
+ }
+ }
+ }
+
+ return PropertyElementResolverResult(
+ readElementRequested: readElement,
+ writeElementRequested: writeElement,
+ );
+ }
+
+ /// If the given [type] is a type parameter, replace with its bound.
+ /// Otherwise, return the original type.
+ DartType _resolveTypeParameter(DartType type) {
+ if (type is TypeParameterType) {
+ return type.resolveToBound(_resolver.typeProvider.objectType);
+ }
+ return type;
+ }
+}
+
+class PropertyElementResolverResult {
+ final ExecutableElement readElementRequested;
+ final ExecutableElement readElementRecovery;
+ final ExecutableElement writeElementRequested;
+ final ExecutableElement writeElementRecovery;
+
+ PropertyElementResolverResult({
+ this.readElementRequested,
+ this.readElementRecovery,
+ this.writeElementRequested,
+ this.writeElementRecovery,
+ });
+
+ ExecutableElement get readElement {
+ return readElementRequested ?? readElementRecovery;
+ }
+
+ ExecutableElement get writeElement {
+ return writeElementRequested ?? writeElementRecovery;
+ }
+}
diff --git a/pkg/analyzer/lib/src/error/assignment_verifier.dart b/pkg/analyzer/lib/src/error/assignment_verifier.dart
new file mode 100644
index 0000000..54f0b21
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/assignment_verifier.dart
@@ -0,0 +1,125 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:meta/meta.dart';
+
+/// Helper for verifying resolution of assignments, in form of explicit
+/// an [AssignmentExpression], or a [PrefixExpression] or [PostfixExpression]
+/// when the operator is an increment operator.
+class AssignmentVerifier {
+ final LibraryElement _definingLibrary;
+ final ErrorReporter _errorReporter;
+
+ AssignmentVerifier(this._definingLibrary, this._errorReporter);
+
+ /// We resolved [node] and found that it references the [requested] element.
+ /// Verify that this element is actually writable.
+ ///
+ /// If the [requested] element is `null`, we might have the [recovery]
+ /// element, which is definitely not a valid write target. We want to report
+ /// a good error about this.
+ ///
+ /// The [receiverTypeObject] might be a [DartType] or [String], and when
+ /// it is not `null`, we report [CompileTimeErrorCode.UNDEFINED_SETTER]
+ /// instead of a more generic [CompileTimeErrorCode.UNDEFINED_IDENTIFIER].
+ void verify({
+ @required SimpleIdentifier node,
+ @required Element requested,
+ @required Element recovery,
+ @required Object receiverTypeObject,
+ }) {
+ if (requested != null) {
+ if (requested is VariableElement) {
+ if (requested.isConst) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
+ node,
+ );
+ } else if (requested.isFinal) {
+ if (_definingLibrary.isNonNullableByDefault) {
+ // Handled during resolution, with flow analysis.
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
+ node,
+ [requested.name],
+ );
+ }
+ }
+ }
+ return;
+ }
+
+ if (recovery is ClassElement ||
+ recovery is DynamicElementImpl ||
+ recovery is FunctionTypeAliasElement ||
+ recovery is TypeParameterElement) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
+ node,
+ );
+ } else if (recovery is FunctionElement) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FUNCTION,
+ node,
+ );
+ } else if (recovery is MethodElement) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
+ node,
+ );
+ } else if (recovery is PrefixElement) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+ node,
+ [recovery.name],
+ );
+ } else if (recovery is PropertyAccessorElement && recovery.isGetter) {
+ var variable = recovery.variable;
+ if (variable.isConst) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
+ node,
+ );
+ } else if (variable is FieldElement && variable.isSynthetic) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
+ node,
+ [variable.name, variable.enclosingElement.displayName],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
+ node,
+ [variable.name],
+ );
+ }
+ } else if (recovery is MultiplyDefinedElementImpl) {
+ // Will be reported in ErrorVerifier.
+ } else if (node is SimpleIdentifier) {
+ if (node.isSynthetic) {
+ return;
+ }
+ if (receiverTypeObject != null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_SETTER,
+ node,
+ [node.name, receiverTypeObject],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+ node,
+ [node.name],
+ );
+ }
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 0ae3509..469a0ce 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -9,12 +9,12 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
@@ -23,7 +23,6 @@
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/super_context.dart';
import 'package:analyzer/src/task/strong/checker.dart';
-import 'package:meta/meta.dart';
/// An object used by instances of [ResolverVisitor] to resolve references
/// within the AST structure to the elements being referenced. The requirements
@@ -91,9 +90,6 @@
/// The type representing the type 'dynamic'.
DartType _dynamicType;
- /// The type representing the type 'Type'.
- InterfaceType _typeType;
-
/// Whether constant evaluation errors should be reported during resolution.
@Deprecated('This field is no longer used')
final bool reportConstEvaluationErrors;
@@ -116,7 +112,6 @@
_extensionResolver = _resolver.extensionResolver,
_typePropertyResolver = _resolver.typePropertyResolver {
_dynamicType = _typeProvider.dynamicType;
- _typeType = _typeProvider.typeType;
_methodInvocationResolver = MethodInvocationResolver(
_resolver,
migratableAstInfoProvider,
@@ -577,81 +572,69 @@
// Otherwise, the prefix is really an expression that happens to be a simple
// identifier and this is really equivalent to a property access node.
//
- _resolvePropertyAccess(
- node,
- prefix,
- identifier,
- isCascaded: false,
- isNullAware: false,
- );
+ {
+ var hasRead = identifier.inGetterContext();
+ var hasWrite = identifier.inSetterContext();
+
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePrefixedIdentifier(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+
+ if (hasRead) {
+ _resolver.setReadElement(node, result.readElement);
+ }
+
+ if (hasWrite) {
+ _resolver.setWriteElement(node, result.writeElement);
+ }
+
+ if (hasWrite) {
+ identifier.staticElement = result.writeElement;
+ if (hasRead) {
+ identifier.auxiliaryElements = AuxiliaryElements(
+ result.readElement,
+ );
+ }
+ } else if (hasRead) {
+ identifier.staticElement = result.readElement;
+ }
+ }
}
@override
void visitPropertyAccess(PropertyAccess node) {
- Expression target = node.realTarget;
- if (target is SuperExpression &&
- SuperContext.of(target) != SuperContext.valid) {
- return;
- } else if (target is ExtensionOverride) {
- if (target.parent is CascadeExpression) {
- // Report this error and recover by treating it like a non-cascade.
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
- target.extensionName,
+ var propertyName = node.propertyName;
+ var hasRead = propertyName.inGetterContext();
+ var hasWrite = propertyName.inSetterContext();
+
+ var resolver = PropertyElementResolver(_resolver);
+ var result = resolver.resolvePropertyAccess(
+ node: node,
+ hasRead: hasRead,
+ hasWrite: hasWrite,
+ );
+
+ if (hasRead) {
+ _resolver.setReadElement(node, result.readElement);
+ }
+
+ if (hasWrite) {
+ _resolver.setWriteElement(node, result.writeElement);
+ }
+
+ if (hasWrite) {
+ propertyName.staticElement = result.writeElement;
+ if (hasRead) {
+ propertyName.auxiliaryElements = AuxiliaryElements(
+ result.readElement,
);
}
- ExtensionElement element = target.extensionName.staticElement;
- SimpleIdentifier propertyName = node.propertyName;
- String memberName = propertyName.name;
- ExecutableElement member;
- var result = _extensionResolver.getOverrideMember(target, memberName);
- if (propertyName.inSetterContext()) {
- _resolver.setWriteElement(node, result.setter);
- member = result.setter;
- if (member == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
- propertyName,
- [memberName, element.name]);
- }
- if (propertyName.inGetterContext()) {
- _resolver.setReadElement(node, result.getter);
- ExecutableElement getter = result.getter;
- if (getter == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
- propertyName,
- [memberName, element.name]);
- }
- propertyName.auxiliaryElements = AuxiliaryElements(getter);
- }
- } else if (propertyName.inGetterContext()) {
- _resolver.setReadElement(node, result.getter);
- member = result.getter;
- if (member == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
- propertyName,
- [memberName, element.name]);
- }
- }
- if (member != null && member.isStatic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
- propertyName);
- }
-
- propertyName.staticElement = member;
- return;
+ } else if (hasRead) {
+ propertyName.staticElement = result.readElement;
}
- SimpleIdentifier propertyName = node.propertyName;
- _resolvePropertyAccess(
- node,
- target,
- propertyName,
- isCascaded: node.isCascaded,
- isNullAware: node.isNullAware,
- );
}
@override
@@ -886,20 +869,6 @@
_resolveAnnotations(node.metadata);
}
- /// If the [element] is not static, report the error on the [identifier].
- void _checkForStaticAccessToInstanceMember(
- SimpleIdentifier identifier,
- ExecutableElement element,
- ) {
- if (element.isStatic) return;
-
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
- identifier,
- [identifier.name],
- );
- }
-
/// Check that the given index [expression] was resolved, otherwise a
/// [CompileTimeErrorCode.UNDEFINED_OPERATOR] is generated. The [target] is
/// the target of the expression. The [methodName] is the name of the operator
@@ -1283,311 +1252,6 @@
_resolveAnnotations(node.metadata);
}
- void _resolvePropertyAccess(
- Expression node,
- Expression target,
- SimpleIdentifier propertyName, {
- @required bool isCascaded,
- @required bool isNullAware,
- }) {
- DartType staticType = _getStaticType(target);
-
- //
- // If this property access is of the form 'E.m' where 'E' is an extension,
- // then look for the member in the extension. This does not apply to
- // conditional property accesses (i.e. 'C?.m').
- //
- if (target is Identifier && target.staticElement is ExtensionElement) {
- ExtensionElement extension = target.staticElement;
- String memberName = propertyName.name;
-
- if (propertyName.inGetterContext()) {
- ExecutableElement element;
- element ??= extension.getGetter(memberName);
- element ??= extension.getMethod(memberName);
- if (element != null) {
- element = _resolver.toLegacyElement(element);
- propertyName.staticElement = element;
- _checkForStaticAccessToInstanceMember(propertyName, element);
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
- propertyName,
- [memberName, extension.name],
- );
- }
- }
-
- if (propertyName.inSetterContext()) {
- var element = extension.getSetter(memberName);
- if (element != null) {
- element = _resolver.toLegacyElement(element);
- propertyName.staticElement = element;
- _checkForStaticAccessToInstanceMember(propertyName, element);
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
- propertyName,
- [memberName, extension.name],
- );
- }
- }
-
- return;
- }
-
- //
- // If this property access is of the form 'C.m' where 'C' is a class,
- // then we don't call resolveProperty(...) which walks up the class
- // hierarchy, instead we just look for the member in the type only. This
- // does not apply to conditional property accesses (i.e. 'C?.m').
- //
- ClassElement typeReference = getTypeReference(target);
- if (typeReference != null) {
- if (isCascaded) {
- typeReference = _typeType.element;
- }
-
- if (propertyName.inGetterContext()) {
- ExecutableElement element;
-
- if (element == null) {
- var getter = typeReference.getGetter(propertyName.name);
- if (getter != null && getter.isAccessibleIn(_definingLibrary)) {
- element = getter;
- }
- }
-
- if (element == null) {
- var method = typeReference.getMethod(propertyName.name);
- if (method != null && method.isAccessibleIn(_definingLibrary)) {
- element = method;
- }
- }
-
- element = _resolver.toLegacyElement(element);
- _resolver.setReadElement(node, element);
-
- if (element != null) {
- propertyName.staticElement = element;
- _checkForStaticAccessToInstanceMember(propertyName, element);
- } else {
- var code = typeReference.isEnum
- ? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
- : CompileTimeErrorCode.UNDEFINED_GETTER;
- _errorReporter.reportErrorForNode(
- code,
- propertyName,
- [propertyName.name, typeReference.name],
- );
- }
- }
-
- if (propertyName.inSetterContext()) {
- ExecutableElement element;
-
- var setter = typeReference.getSetter(propertyName.name);
- setter = _resolver.toLegacyElement(setter);
-
- _resolver.setWriteElement(node, setter);
-
- if (setter != null) {
- element = setter;
- if (!setter.isAccessibleIn(_definingLibrary)) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.PRIVATE_SETTER,
- propertyName,
- [propertyName.name, typeReference.name],
- );
- }
- }
-
- if (element != null) {
- propertyName.staticElement = element;
- _checkForStaticAccessToInstanceMember(propertyName, element);
- } else {
- var getter = typeReference.getGetter(propertyName.name);
- if (getter != null) {
- propertyName.staticElement = getter;
- _resolver.setWriteElement(node, getter);
- // The error will be reported in ErrorVerifier.
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_SETTER,
- propertyName,
- [propertyName.name, typeReference.name],
- );
- }
- }
- }
-
- return;
- }
-
- if (target is SuperExpression) {
- if (staticType is InterfaceTypeImpl) {
- if (propertyName.inGetterContext()) {
- var name = Name(_definingLibrary.source.uri, propertyName.name);
- var element = _resolver.inheritance
- .getMember2(staticType.element, name, forSuper: true);
- _resolver.setReadElement(node, element);
-
- if (element != null) {
- element = _resolver.toLegacyElement(element);
- propertyName.staticElement = element;
- } else {
- // We were not able to find the concrete dispatch target.
- // But we would like to give the user at least some resolution.
- // So, we retry simply looking for an inherited member.
- var element =
- _resolver.inheritance.getInherited2(staticType.element, name);
- if (element != null) {
- propertyName.staticElement = element;
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
- propertyName,
- [element.kind.displayName, propertyName.name],
- );
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
- propertyName,
- [propertyName.name, staticType],
- );
- }
- }
- }
-
- if (propertyName.inSetterContext()) {
- var element = staticType.lookUpSetter2(
- propertyName.name,
- _definingLibrary,
- concrete: true,
- inherited: true,
- );
- _resolver.setWriteElement(node, element);
-
- if (element != null) {
- element = _resolver.toLegacyElement(element);
- propertyName.staticElement = element;
- } else {
- // We were not able to find the concrete dispatch target.
- // But we would like to give the user at least some resolution.
- // So, we retry without the "concrete" requirement.
- var element = staticType.lookUpSetter2(
- propertyName.name,
- _definingLibrary,
- inherited: true,
- );
- if (element != null) {
- propertyName.staticElement = element;
- ClassElementImpl receiverSuperClass =
- staticType.element.supertype.element;
- if (!receiverSuperClass.hasNoSuchMethod) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
- propertyName,
- [element.kind.displayName, propertyName.name],
- );
- }
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_SUPER_SETTER,
- propertyName,
- [propertyName.name, staticType],
- );
- }
- }
- }
- }
-
- return;
- }
-
- if (staticType == null || staticType.isDynamic) {
- return;
- }
-
- if (isNullAware) {
- staticType = _typeSystem.promoteToNonNull(staticType);
- }
-
- if (staticType.isVoid) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.USE_OF_VOID_RESULT,
- propertyName,
- );
- return;
- }
-
- var result = _typePropertyResolver.resolve(
- receiver: target,
- receiverType: staticType,
- name: propertyName.name,
- receiverErrorNode: target,
- nameErrorNode: propertyName,
- );
-
- if (propertyName.inGetterContext()) {
- _resolver.setReadElement(node, result.getter);
- var shouldReportUndefinedGetter = false;
- if (result.isSingle) {
- var getter = result.getter;
- if (getter != null) {
- propertyName.staticElement = getter;
- } else {
- shouldReportUndefinedGetter = true;
- }
- } else if (result.isNone) {
- if (staticType is FunctionType &&
- propertyName.name == FunctionElement.CALL_METHOD_NAME) {
- // Referencing `.call` on a `Function` type is OK.
- } else if (staticType is InterfaceType &&
- staticType.isDartCoreFunction &&
- propertyName.name == FunctionElement.CALL_METHOD_NAME) {
- // Referencing `.call` on a `Function` type is OK.
- } else if (staticType is NeverTypeImpl) {
- shouldReportUndefinedGetter = false;
- } else {
- shouldReportUndefinedGetter = true;
- }
- }
- if (shouldReportUndefinedGetter) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_GETTER,
- propertyName,
- [propertyName.name, staticType],
- );
- }
- }
-
- if (propertyName.inSetterContext()) {
- _resolver.setWriteElement(node, result.setter);
- if (result.isSingle) {
- var setter = result.setter;
- if (setter != null) {
- propertyName.staticElement = setter;
- propertyName.auxiliaryElements = AuxiliaryElements(result.getter);
- } else {
- var getter = result.getter;
- propertyName.staticElement = getter;
- _resolver.setWriteElement(node, getter);
- // A more specific error will be reported in ErrorVerifier.
- }
- } else if (result.isNone) {
- if (staticType is NeverTypeImpl) {
- // OK
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.UNDEFINED_SETTER,
- propertyName,
- [propertyName.name, staticType],
- );
- }
- }
- }
- }
-
/// Resolve the given simple [identifier] if possible. Return the element to
/// which it could be resolved, or `null` if it could not be resolved. This
/// does not record the results of the resolution.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 8abc401..75fcfb7 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1628,6 +1628,9 @@
/// [StaticWarningCode.ASSIGNMENT_TO_FINAL], and
/// [StaticWarningCode.ASSIGNMENT_TO_METHOD].
void _checkForAssignmentToFinal(Expression expression) {
+ // TODO(scheglov) Check SimpleIdentifier(s) as all other nodes.
+ if (expression is! SimpleIdentifier) return;
+
// Already handled in the assignment resolver.
if (expression is SimpleIdentifier &&
expression.parent is AssignmentExpression) {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d1fedd3..43d1494 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -664,6 +664,22 @@
}
}
+ void startNullAwarePropertyAccess(
+ PropertyAccess node,
+ ) {
+ if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
+ _isNonNullableByDefault) {
+ var target = node.target;
+ if (target is SimpleIdentifier && target.staticElement is ClassElement) {
+ // `?.` to access static methods is equivalent to `.`, so do nothing.
+ } else {
+ _flowAnalysis.flow.nullAwareAccess_rightBegin(
+ target, node.realTarget.staticType ?? typeProvider.dynamicType);
+ _unfinishedNullShorts.add(node.nullShortingTermination);
+ }
+ }
+ }
+
/// If in a legacy library, return the legacy view on the [element].
/// Otherwise, return the original element.
T toLegacyElement<T extends Element>(T element) {
@@ -1642,16 +1658,7 @@
//
var target = node.target;
target?.accept(this);
- if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
- _isNonNullableByDefault) {
- if (target is SimpleIdentifier && target.staticElement is ClassElement) {
- // `?.` to access static methods is equivalent to `.`, so do nothing.
- } else {
- _flowAnalysis.flow.nullAwareAccess_rightBegin(
- target, node.realTarget.staticType ?? typeProvider.dynamicType);
- _unfinishedNullShorts.add(node.nullShortingTermination);
- }
- }
+ startNullAwarePropertyAccess(node);
node.accept(elementResolver);
node.accept(typeAnalyzer);
}
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index f219504..7f232fc 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -3495,36 +3495,36 @@
}
test_instantiateToBounds_class_error_recursion() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class C<T0 extends List<T1>, T1 extends List<T0>> {}
C c;
-''', []);
+''');
_assertTopVarType('c', 'C<List<dynamic>, List<dynamic>>');
}
test_instantiateToBounds_class_error_recursion_self() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class C<T extends C<T>> {}
C c;
-''', []);
+''');
_assertTopVarType('c', 'C<C<dynamic>>');
}
test_instantiateToBounds_class_error_recursion_self2() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class A<E> {}
class C<T extends A<T>> {}
C c;
-''', []);
+''');
_assertTopVarType('c', 'C<A<dynamic>>');
}
test_instantiateToBounds_class_error_typedef() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
typedef T F<T>(T x);
class C<T extends F<T>> {}
C c;
-''', []);
+''');
_assertTopVarType('c', 'C<dynamic Function(dynamic)>');
}
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index d8b9392..0c06671 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -352,7 +352,6 @@
''', [
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 35, 5),
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 35, 5),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 44, 1),
]);
var assignment = findNode.assignment('= c');
@@ -362,11 +361,8 @@
readType: 'dynamic',
writeElement: null,
writeType: 'dynamic',
- operatorElement: elementMatcher(
- numElement.getMethod('+'),
- isLegacy: isNullSafetySdkAndLegacyLibrary,
- ),
- type: 'double',
+ operatorElement: null,
+ type: 'dynamic',
);
assertElement(findNode.simple('a +'), findElement.parameter('a'));
@@ -382,7 +378,6 @@
''', [
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 35, 7),
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 35, 7),
- error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 46, 1),
]);
var assignment = findNode.assignment('= c');
@@ -392,11 +387,8 @@
readType: 'dynamic',
writeElement: null,
writeType: 'dynamic',
- operatorElement: elementMatcher(
- numElement.getMethod('+'),
- isLegacy: isNullSafetySdkAndLegacyLibrary,
- ),
- type: 'double',
+ operatorElement: null,
+ type: 'dynamic',
);
}
@@ -461,11 +453,8 @@
readType: 'dynamic',
writeElement: null,
writeType: 'dynamic',
- operatorElement: elementMatcher(
- numElement.getMethod('+'),
- isLegacy: isNullSafetySdkAndLegacyLibrary,
- ),
- type: 'num',
+ operatorElement: null,
+ type: 'dynamic',
);
assertSimpleIdentifier(
@@ -555,11 +544,8 @@
readType: 'dynamic',
writeElement: null,
writeType: 'dynamic',
- operatorElement: elementMatcher(
- numElement.getMethod('+'),
- isLegacy: isNullSafetySdkAndLegacyLibrary,
- ),
- type: 'num',
+ operatorElement: null,
+ type: 'dynamic',
);
assertSimpleIdentifier(
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index 38ca656..d35a83b 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -776,11 +776,11 @@
}
test_plus_int_never() async {
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
f(int a, Never b) {
a + b;
}
-''', []);
+''');
assertBinaryExpression(findNode.binary('a + b'),
element: numElement.getMethod('+'), type: 'num');
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
index c4da4a8..9a30b49 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
@@ -24,7 +24,7 @@
f() {
A.v = 1;
}''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 42, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 44, 1),
]);
}
@@ -36,7 +36,7 @@
f() {
A.v += 1;
}''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 42, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 44, 1),
]);
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
index 3d229b4..60d039d 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
@@ -25,23 +25,57 @@
void set foo(int _) {}
}
-f(C c) {
+void f(C c) {
c.foo = 0;
+ c.foo += 1;
+ c.foo++;
+ --c.foo;
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 87, 5),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 94, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 107, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 121, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 134, 3),
]);
}
- test_method() async {
+ test_prefixedIdentifier_instanceMethod() async {
await assertErrorsInCode('''
class A {
- m() {}
+ void foo() {}
}
-f(A a) {
- a.m = () {};
-}''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 32, 3),
+
+void f(A a) {
+ a.foo = 0;
+ a.foo += 1;
+ a.foo++;
+ ++a.foo;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 47, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 60, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 74, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 87, 3),
+ ]);
+ }
+
+ test_propertyAccess_instanceMethod() async {
+ await assertErrorsInCode('''
+class A {
+ void foo() {}
+}
+
+void f(A a) {
+ (a).foo = 0;
+ (a).foo += 1;
+ (a).foo++;
+ ++(a).foo;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 49, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 64, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 80, 3),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 95, 3),
]);
}
@@ -59,7 +93,7 @@
}
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 86, 8),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 91, 3),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart b/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
index a669585..e5abe38 100644
--- a/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
@@ -26,11 +26,11 @@
}
test_using_and_no_error() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
f(var x, var y) {
return x & y;
}
-''', []);
+''');
}
test_using_or() async {
@@ -44,11 +44,11 @@
}
test_using_or_no_error() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
f(var x, var y) {
return x | y;
}
-''', []);
+''');
}
test_using_shl() async {
@@ -62,11 +62,11 @@
}
test_using_shl_no_error() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
f(var x) {
return x << 2;
}
-''', []);
+''');
}
test_using_shr() async {
@@ -80,11 +80,11 @@
}
test_using_shr_no_error() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
f(var x) {
return x >> 2;
}
-''', []);
+''');
}
test_using_xor() async {
@@ -98,10 +98,10 @@
}
test_using_xor_no_error() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
f(var x, var y) {
return x ^ y;
}
-''', []);
+''');
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index a5edc42..207edcb 100644
--- a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -446,7 +446,7 @@
writeElement: null,
writeType: 'dynamic',
operatorElement: null,
- type: 'int',
+ type: 'dynamic',
);
}
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index a668a46..35eb115 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -123,11 +123,11 @@
// Referencing `.call` on a `Function` type works similarly to referencing
// it on `dynamic`--the reference is accepted at compile time, and all type
// checking is deferred until runtime.
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
f(Function f) {
return f.call;
}
-''', []);
+''');
}
test_ifElement_inList_notPromoted() async {
@@ -263,6 +263,26 @@
]);
}
+ test_propertyAccess_functionClass_call() async {
+ await assertNoErrorsInCode('''
+void f(Function a) {
+ return (a).call;
+}
+''');
+ }
+
+ test_propertyAccess_functionType_call() async {
+ await assertNoErrorsInCode('''
+class A {
+ void staticMethod() {}
+}
+
+void f(A a) {
+ return a.staticMethod.call;
+}
+''');
+ }
+
test_proxy_annotation_fakeProxy() async {
await assertErrorsInCode(r'''
library L;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 2a30b09..826a082 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -10335,6 +10335,20 @@
''');
}
+ test_type_inference_assignmentExpression_references_onTopLevelVariable() async {
+ var library = await checkLibrary('''
+var a = () {
+ b += 0;
+ return 0;
+};
+var b = 0;
+''');
+ checkElementText(library, '''
+int Function() a;
+int b;
+''');
+ }
+
test_type_inference_based_on_loadLibrary() async {
addLibrarySource('/a.dart', '');
var library = await checkLibrary('''
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 41ea625..b71fb4b 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -418,7 +418,7 @@
test_constantGenericTypeArg_infer() async {
// Regression test for https://github.com/dart-lang/sdk/issues/26141
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
abstract class Equality<Q> {}
abstract class EqualityBase<R> implements Equality<R> {
final C<R> c = const C();
@@ -439,7 +439,7 @@
main() {
const SetEquality<String>();
}
-''', []);
+''');
}
test_constructorInvalid() async {
@@ -2298,7 +2298,7 @@
}
test_genericMethodOverride() async {
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
class Future<T> {
S then<S>(S onValue(T t)) => null;
}
@@ -2318,7 +2318,7 @@
class DerivedFuture4<A> extends Future<A> {
B then<B>(Object onValue(A a)) => null;
}
-''', []);
+''');
}
test_genericMethodSuper() async {
@@ -2348,7 +2348,7 @@
}
test_genericMethodSuperSubstitute() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class Cloneable<T> {}
class G<T> {
create<A extends Cloneable<T>, B extends Iterable<A>>() => null;
@@ -2356,7 +2356,7 @@
class H extends G<num> {
create2() => super.create<Cloneable<int>, List<Cloneable<int>>>();
}
-''', []);
+''');
}
test_getterGetterOverride() async {
@@ -3103,7 +3103,7 @@
test_implicitDynamic_static() async {
_disableTestPackageImplicitDynamic();
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class C {
static void test(int body()) {}
}
@@ -3113,7 +3113,7 @@
return 42;
});
}
-''', []);
+''');
}
test_implicitDynamic_type() async {
@@ -3223,7 +3223,7 @@
test_interfacesFromMixinsOnlyConsiderMostDerivedMember() {
// Regression test for dart2js interface pattern in strong mode.
- return assertErrorsInCode(r'''
+ return assertNoErrorsInCode(r'''
abstract class I1 { num get x; }
abstract class I2 extends I1 { int get x; }
@@ -3234,7 +3234,7 @@
class Child extends Base with M2 implements I2 {}
class C extends Object with M1, M2 implements I1, I2 {}
-''', []);
+''');
}
test_interfacesFromMixinsUsedTwiceAreChecked() {
@@ -3548,7 +3548,7 @@
// This is a regression test for a bug in an earlier implementation were
// names were hiding errors if the first mixin override looked correct,
// but subsequent ones did not.
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
class A {}
class B {}
@@ -3571,7 +3571,7 @@
class T1 extends Base with M1, M2, M3 {}
class U1 = Base with M1, M2, M3;
-''', []);
+''');
}
test_invalidOverrides_noErrorsIfSubclassCorrectlyOverrideBaseAndInterface() async {
@@ -3785,14 +3785,14 @@
test_methodTearoffStrictArrow() async {
// Regression test for https://github.com/dart-lang/sdk/issues/26393
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
class A {
void foo(dynamic x) {}
void test(void f(int x)) {
test(foo);
}
}
-''', []);
+''');
}
test_mixinApplicationIsConcrete() {
@@ -4092,7 +4092,7 @@
}
test_nullCoalescingOperator() async {
- await assertErrorsInCode('''
+ await assertNoErrorsInCode('''
class A {}
class C<T> {}
main() {
@@ -4105,11 +4105,11 @@
c ??= new C();
d = d ?? new C();
}
-''', []);
+''');
}
test_nullCoalescingStrictArrow() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
bool _alwaysTrue(x) => true;
typedef bool TakesA<T>(T t);
class C<T> {
@@ -4118,7 +4118,7 @@
: g = f ?? _alwaysTrue;
C.a() : g = _alwaysTrue;
}
-''', []);
+''');
}
test_optionalParams() async {
@@ -4155,13 +4155,13 @@
test_overrideNarrowsType_legalWithChecked() async {
// Regression test for https://github.com/dart-lang/sdk/issues/25232
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
abstract class A { void test(A arg) { } }
abstract class B extends A { void test(covariant B arg) { } }
abstract class X implements A { }
class C extends B with X { }
class D extends B implements A { }
-''', []);
+''');
}
test_overrideNarrowsType_noDuplicateError() {
@@ -4643,7 +4643,7 @@
}
test_tearOffTreatedConsistentlyAsStrictArrow() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
void foo(void f(String x)) {}
class A {
@@ -4666,11 +4666,11 @@
foo(baz2);
foo(baz3);
}
-''', []);
+''');
}
test_tearOffTreatedConsistentlyAsStrictArrowNamedParam() async {
- await assertErrorsInCode(r'''
+ await assertNoErrorsInCode(r'''
typedef void Handler(String x);
void foo({Handler f}) {}
@@ -4694,7 +4694,7 @@
foo(f: baz2);
foo(f: baz3);
}
-''', []);
+''');
}
test_ternaryOperator() async {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 4aa804c..365500e 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -1502,7 +1502,20 @@
}
@override
- AbstractValue computeType(InferrerEngine inferrer) => safeType(inferrer);
+ AbstractValue computeType(InferrerEngine inferrer) {
+ AbstractValueDomain abstractValueDomain = inferrer.abstractValueDomain;
+ AbstractValue closureType = closure.type;
+ // We are not tracking closure calls, but if the receiver is not callable,
+ // the call will fail. The abstract value domain does not have a convenient
+ // method for detecting callable types, but we know `null` and unreachable
+ // code have no result type. This is helpful for propagating
+ // unreachability, i.e. tree-shaking.
+ if (abstractValueDomain.isEmpty(closureType).isDefinitelyTrue ||
+ abstractValueDomain.isNull(closureType).isDefinitelyTrue) {
+ return abstractValueDomain.emptyType;
+ }
+ return safeType(inferrer);
+ }
@override
Iterable<MemberEntity> get callees {
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index 25305e4..bafd5cc3 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -310,22 +310,29 @@
@override
AbstractValue resultTypeOfSelector(
Selector selector, AbstractValue receiver) {
- // Bailout for closure calls. We're not tracking types of
- // closures.
- if (selector.isClosureCall)
- return closedWorld.abstractValueDomain.dynamicType;
+ AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
+
+ // Bailout for closure calls. We're not tracking types of closures.
+ if (selector.isClosureCall) {
+ // But if the receiver is not callable, the call will fail.
+ if (abstractValueDomain.isEmpty(receiver).isDefinitelyTrue ||
+ abstractValueDomain.isNull(receiver).isDefinitelyTrue) {
+ return abstractValueDomain.emptyType;
+ }
+ return abstractValueDomain.dynamicType;
+ }
if (selector.isSetter || selector.isIndexSet) {
- return closedWorld.abstractValueDomain.dynamicType;
+ return abstractValueDomain.dynamicType;
}
if (returnsListElementType(selector, receiver)) {
- return closedWorld.abstractValueDomain.getContainerElementType(receiver);
+ return abstractValueDomain.getContainerElementType(receiver);
}
if (returnsMapValueType(selector, receiver)) {
- return closedWorld.abstractValueDomain.getMapValueType(receiver);
+ return abstractValueDomain.getMapValueType(receiver);
}
if (closedWorld.includesClosureCall(selector, receiver)) {
- return closedWorld.abstractValueDomain.dynamicType;
+ return abstractValueDomain.dynamicType;
} else {
Iterable<MemberEntity> elements =
closedWorld.locateMembers(selector, receiver);
@@ -334,7 +341,7 @@
AbstractValue type = typeOfMemberWithSelector(element, selector);
types.add(type);
}
- return closedWorld.abstractValueDomain.unionOfMany(types);
+ return abstractValueDomain.unionOfMany(types);
}
}
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 8a3c266..e0dd7a2 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -239,9 +239,9 @@
}
break;
case VariableUseKind.localReturnType:
- // SSA requires the element type of generators.
if (usage.localFunction.function.asyncMarker !=
ir.AsyncMarker.Sync) {
+ // The Future/Iterator/Stream implementation requires the type.
return true;
}
if (rtiNeed.localFunctionNeedsSignature(usage.localFunction)) {
diff --git a/pkg/compiler/test/inference/data/static.dart b/pkg/compiler/test/inference/data/static.dart
index f641d1a..d34d4fc 100644
--- a/pkg/compiler/test/inference/data/static.dart
+++ b/pkg/compiler/test/inference/data/static.dart
@@ -181,7 +181,7 @@
/*member: _field1:[null]*/
dynamic _field1;
-/*member: invokeStaticFieldUninitialized:[null|subclass=Object]*/
+/*member: invokeStaticFieldUninitialized:[empty]*/
invokeStaticFieldUninitialized() => _field1();
////////////////////////////////////////////////////////////////////////////////
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,15 +11,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::EmptyClass;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,15 +11,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::EmptyClass;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,15 +11,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::EmptyClass;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,15 +11,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::EmptyClass;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
index 9fe3384..c465cf0 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -37,15 +40,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::F;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
index fa46235..93db2ab 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -32,6 +35,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class F extends self::B implements self::C /*isEliminatedMixin*/ {
synthetic constructor •() → self::F
@@ -39,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::F;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
index 9fe3384..c465cf0 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -37,15 +40,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::F;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
index fa46235..93db2ab 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -32,6 +35,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
}
class F extends self::B implements self::C /*isEliminatedMixin*/ {
synthetic constructor •() → self::F
@@ -39,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::F;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
@@ -8,6 +8,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -18,15 +19,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
@@ -8,6 +8,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -18,15 +19,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
@@ -8,6 +8,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -18,15 +19,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
@@ -8,6 +8,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -18,15 +19,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
@@ -9,6 +9,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -19,6 +20,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends self::Animal {
synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
@@ -9,6 +9,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -19,6 +20,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends self::Animal {
synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
@@ -9,6 +9,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -19,6 +20,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends self::Animal {
synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
@@ -9,6 +9,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -19,6 +20,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends self::Animal {
synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
@@ -14,6 +14,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -24,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends core::Object implements self::Animal {
final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
@@ -14,6 +14,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -24,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends core::Object implements self::Animal {
final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
@@ -14,6 +14,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -24,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends core::Object implements self::Animal {
final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
@@ -14,6 +14,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -24,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
class Cat extends core::Object implements self::Animal {
final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
index eb9f0d0..218ec9f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -40,6 +41,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
index ea02301..9845aaa 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -40,6 +41,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
index eb9f0d0..218ec9f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -40,6 +41,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
index ea02301..9845aaa 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -40,6 +41,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
index aa94e2f..d3224ed 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -46,6 +47,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
index 0a9d8aa..bf869ee 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -46,6 +47,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
index aa94e2f..d3224ed 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -46,6 +47,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
index 0a9d8aa..bf869ee 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
@@ -30,6 +30,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -46,6 +47,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
@@ -13,6 +13,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -28,6 +29,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
}
class Animal2 extends core::Object {
final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
@@ -13,6 +13,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -28,6 +29,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
}
class Animal2 extends core::Object {
final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
@@ -13,6 +13,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -28,6 +29,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
}
class Animal2 extends core::Object {
final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
@@ -13,6 +13,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -28,6 +29,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
}
class Animal2 extends core::Object {
final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
}
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
index 28a8793..a0f49ac 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
@@ -71,6 +71,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
abstract class Animal2 extends core::Object {
synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self3::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
index 4a66e5d..e412416 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
@@ -71,6 +71,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
abstract class Animal2 extends core::Object {
synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self3::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
index 21d4e29..7ff4c88 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
@@ -71,6 +71,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
abstract class Animal2 extends core::Object {
synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self3::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
index 39979d6..939015f 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
@@ -71,6 +71,7 @@
//
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
}
abstract class Animal2 extends core::Object {
synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
}
static method main() → dynamic {
self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
}
library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self3::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
index 18d691c..7e226a5 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -39,11 +42,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
index 338f201..6ae17d2 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -22,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class C extends self::_C&B&A {
synthetic constructor •() → self::C
@@ -41,11 +46,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
index 18d691c..7e226a5 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -39,11 +42,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
index 338f201..6ae17d2 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -10,6 +11,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class B extends core::Object {
synthetic constructor •() → self::B
@@ -22,6 +25,8 @@
;
operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
return other is self::A;
+ get /*isNullableByDefault*/ hashCode() → core::int
+ return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
}
class C extends self::_C&B&A {
synthetic constructor •() → self::C
@@ -41,11 +46,11 @@
static method main() → dynamic {}
library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
import "dart:core" as core;
class JenkinsSmiHash extends core::Object {
- synthetic constructor •() → self2::JenkinsSmiHash
+ synthetic constructor •() → val::JenkinsSmiHash
: super core::Object::•()
;
static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/kernel/lib/transformations/scanner.dart b/pkg/kernel/lib/transformations/scanner.dart
index 5083fa6..6d4a690 100644
--- a/pkg/kernel/lib/transformations/scanner.dart
+++ b/pkg/kernel/lib/transformations/scanner.dart
@@ -27,25 +27,136 @@
ScanResult<Class, Y> scan(TreeNode node) {
ScanResult<Class, Y> result = new ScanResult();
result.targets = new Map();
+
if (node is Class) {
if (predicate(node)) {
result.targets[node] = next?.scan(node);
}
} else if (node is Library) {
- for (Class cls in node.classes) {
- if (predicate(cls)) {
- result.targets[cls] = next?.scan(cls);
- }
- }
+ _scanLibrary(node, result);
} else if (node is Component) {
- for (Library library in node.libraries) {
- for (Class cls in library.classes) {
- if (predicate(cls)) {
- result.targets[cls] = next?.scan(cls);
- }
- }
+ _scanComponent(node, result);
+ }
+
+ return result;
+ }
+
+ void _scanLibrary(Library library, ScanResult<Class, Y> result) {
+ for (Class cls in library.classes) {
+ if (predicate(cls)) {
+ result.targets[cls] = next?.scan(cls);
}
}
+ }
+
+ void _scanComponent(Component component, ScanResult<Class, Y> result) {
+ for (Library library in component.libraries) {
+ _scanLibrary(library, result);
+ }
+ }
+}
+
+abstract class FieldScanner<Y extends TreeNode> implements Scanner<Field, Y> {
+ final Scanner<Y, TreeNode> next;
+
+ FieldScanner(this.next);
+
+ bool predicate(Field node);
+
+ ScanResult<Field, Y> scan(TreeNode node) {
+ ScanResult<Field, Y> result = new ScanResult();
+ result.targets = new Map();
+
+ if (node is Field) {
+ if (predicate(node)) {
+ result.targets[node] = next?.scan(node);
+ }
+ } else if (node is Class) {
+ _scanClass(node, result);
+ } else if (node is Library) {
+ _scanLibrary(node, result);
+ } else if (node is Component) {
+ _scanComponent(node, result);
+ }
+
return result;
}
+
+ void _scanClass(Class cls, ScanResult<Field, Y> result) {
+ for (Field field in cls.fields) {
+ if (predicate(field)) {
+ result.targets[field] = next?.scan(field);
+ }
+ }
+ }
+
+ void _scanLibrary(Library library, ScanResult<Field, Y> result) {
+ for (Class cls in library.classes) {
+ _scanClass(cls, result);
+ }
+ for (Field field in library.fields) {
+ if (predicate(field)) {
+ result.targets[field] = next?.scan(field);
+ }
+ }
+ }
+
+ void _scanComponent(Component component, ScanResult<Field, Y> result) {
+ for (Library library in component.libraries) {
+ _scanLibrary(library, result);
+ }
+ }
+}
+
+abstract class ProcedureScanner<Y extends TreeNode>
+ implements Scanner<Procedure, Y> {
+ final Scanner<Y, TreeNode> next;
+
+ ProcedureScanner(this.next);
+
+ bool predicate(Procedure node);
+
+ ScanResult<Procedure, Y> scan(TreeNode node) {
+ ScanResult<Procedure, Y> result = new ScanResult();
+ result.targets = new Map();
+
+ if (node is Procedure) {
+ if (predicate(node)) {
+ result.targets[node] = next?.scan(node);
+ }
+ } else if (node is Class) {
+ _scanClass(node, result);
+ } else if (node is Library) {
+ _scanLibrary(node, result);
+ } else if (node is Component) {
+ _scanComponent(node, result);
+ }
+
+ return result;
+ }
+
+ void _scanClass(Class cls, ScanResult<Procedure, Y> result) {
+ for (Procedure procedure in cls.procedures) {
+ if (predicate(procedure)) {
+ result.targets[procedure] = next?.scan(procedure);
+ }
+ }
+ }
+
+ void _scanLibrary(Library library, ScanResult<Procedure, Y> result) {
+ for (Class cls in library.classes) {
+ _scanClass(cls, result);
+ }
+ for (Procedure procedure in library.procedures) {
+ if (predicate(procedure)) {
+ result.targets[procedure] = next?.scan(procedure);
+ }
+ }
+ }
+
+ void _scanComponent(Component component, ScanResult<Procedure, Y> result) {
+ for (Library library in component.libraries) {
+ _scanLibrary(library, result);
+ }
+ }
}
diff --git a/pkg/kernel/lib/transformations/value_class.dart b/pkg/kernel/lib/transformations/value_class.dart
index 9e38786..dc2d71a 100644
--- a/pkg/kernel/lib/transformations/value_class.dart
+++ b/pkg/kernel/lib/transformations/value_class.dart
@@ -27,6 +27,22 @@
}
}
+class JenkinsClassScanner extends ClassScanner<Procedure> {
+ JenkinsClassScanner(Scanner<Procedure, TreeNode> next) : super(next);
+
+ bool predicate(Class node) {
+ return node.name == "JenkinsSmiHash";
+ }
+}
+
+class HashCombineMethodsScanner extends ProcedureScanner<Null> {
+ HashCombineMethodsScanner() : super(null);
+
+ bool predicate(Procedure node) {
+ return node.name.name == "combine" || node.name.name == "finish";
+ }
+}
+
void transformComponent(
Component node, CoreTypes coreTypes, ClassHierarchy hierarchy) {
ValueClassScanner scanner = new ValueClassScanner();
@@ -40,7 +56,7 @@
Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
addConstructor(cls, coreTypes);
addEqualsOperator(cls, coreTypes, hierarchy);
- // addHashCode(cls, coreTypes);
+ addHashCode(cls, coreTypes, hierarchy);
// addCopyWith(cls);
}
@@ -170,34 +186,90 @@
cls.addMember(equalsOperator);
}
-/*
-void addHashCode(Class cls, CoreTypes coreTypes) {
- Map<String, VariableDeclaration> environment = Map.fromIterable(cls.fields,
- key: (f) => f.name.name,
- value: (f) => VariableDeclaration(f.name.name, type: f.type));
+void addHashCode(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
+ for (Procedure procedure in cls.procedures) {
+ if (procedure.kind == ProcedureKind.Getter &&
+ procedure.name.name == "hashCode") {
+ // hashCode getter is already implemented, spec is to do nothing
+ return;
+ }
+ }
+ DartType returnType = cls.enclosingLibrary.isNonNullableByDefault
+ ? coreTypes.intNonNullableRawType
+ : coreTypes.intLegacyRawType;
- VariableDeclaration other = VariableDeclaration("other");
+ Constructor superConstructor = null;
+ for (Constructor constructor in cls.superclass.constructors) {
+ if (constructor.name.name == "") {
+ superConstructor = constructor;
+ }
+ }
- var returnType = cls.enclosingLibrary.isNonNullableByDefault
- ? coreTypes.boolNonNullableRawType
- : coreTypes.boolLegacyRawType;
+ Procedure hashCombine, hashFinish;
+ HashCombineMethodsScanner hashCombineMethodsScanner =
+ new HashCombineMethodsScanner();
+ JenkinsClassScanner jenkinsScanner =
+ new JenkinsClassScanner(hashCombineMethodsScanner);
+ ScanResult<Class, Procedure> hashMethodsResult =
+ jenkinsScanner.scan(cls.enclosingLibrary.enclosingComponent);
+ for (Class clazz in hashMethodsResult.targets.keys) {
+ for (Procedure procedure in hashMethodsResult.targets[clazz].targets.keys) {
+ if (procedure.name.name == "combine") hashCombine = procedure;
+ if (procedure.name.name == "finish") hashFinish = procedure;
+ }
+ }
+ List<VariableDeclaration> allVariables = superConstructor
+ .function.namedParameters
+ .map<VariableDeclaration>(
+ (f) => VariableDeclaration(f.name, type: f.type))
+ .toList()
+ ..addAll(cls.fields.map<VariableDeclaration>(
+ (f) => VariableDeclaration(f.name.name, type: f.type)));
+
+ Map<VariableDeclaration, Member> targetsHashcode = new Map();
+ Map<VariableDeclaration, Member> targets = new Map();
+ for (VariableDeclaration variable in allVariables) {
+ Member target = coreTypes.objectEquals;
+ Member targetHashcode = coreTypes.objectEquals;
+ DartType fieldsType = variable.type;
+ if (fieldsType is InterfaceType) {
+ targetHashcode =
+ hierarchy.getInterfaceMember(fieldsType.classNode, Name("hashCode"));
+ target = hierarchy.getInterfaceMember(cls, Name(variable.name));
+ }
+ targetsHashcode[variable] = targetHashcode;
+ targets[variable] = target;
+ }
cls.addMember(Procedure(
Name("hashCode"),
ProcedureKind.Getter,
- FunctionNode(ReturnStatement(cls.fields
- .map((f) => DirectPropertyGet(
- VariableGet(environment[f.name.name]),
- Procedure(Name("hashCode"), ProcedureKind.Getter,
- null) // TODO(jlcontreras): Add ref to the real hashCode getter, dont create a new one
- ))
- .toList()
- .fold(
- IntLiteral(0),
- (previousValue, element) => MethodInvocation(
- previousValue, Name("*"), Arguments([element])))))));
+ FunctionNode(
+ ReturnStatement(StaticInvocation(
+ hashFinish,
+ Arguments([
+ allVariables
+ .map((f) => (PropertyGet(
+ PropertyGet(ThisExpression(), Name(f.name), targets[f]),
+ Name("hashCode"),
+ targetsHashcode[f])))
+ .fold(
+ PropertyGet(
+ StringLiteral(
+ cls.enclosingLibrary.importUri.toString() +
+ cls.name),
+ Name("hashCode"),
+ hierarchy.getInterfaceMember(
+ coreTypes.stringClass, Name("hashCode"))),
+ (previousValue, element) => StaticInvocation(
+ hashCombine, Arguments([previousValue, element])))
+ ]))),
+ returnType: returnType),
+ fileUri: cls.fileUri)
+ ..fileOffset = cls.fileOffset);
}
+/*
void addCopyWith(Class cls) {
Map<String, VariableDeclaration> environment = Map.fromIterable(cls.fields,
key: (f) => f.name.name,
@@ -228,16 +300,3 @@
cls.fields.map((f) => environment[f.name.name]).toList())));
}
*/
-
-bool isValueClass(Class cls) {
- for (Expression annotation in cls.annotations) {
- if (annotation is ConstantExpression &&
- annotation.constant is StringConstant) {
- StringConstant constant = annotation.constant;
- if (constant.value == 'valueClass') {
- return true;
- }
- }
- }
- return false;
-}
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 60a36ec..d901ed9 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -186,11 +186,6 @@
return Utils::StrDup("VM already initialized or flags not initialized.");
}
- if (FLAG_causal_async_stacks && FLAG_lazy_async_stacks) {
- return Utils::StrDup(
- "To use --lazy-async-stacks, please disable --causal-async-stacks!");
- }
-
const Snapshot* snapshot = nullptr;
if (vm_isolate_snapshot != nullptr) {
snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
@@ -210,6 +205,10 @@
return error;
}
}
+ if (FLAG_causal_async_stacks && FLAG_lazy_async_stacks) {
+ return Utils::StrDup(
+ "To use --lazy-async-stacks, please disable --causal-async-stacks!");
+ }
FrameLayout::Init();
diff --git a/tests/dart2js/sync_star_element_rti_need_test.dart b/tests/dart2js/sync_star_element_rti_need_test.dart
new file mode 100644
index 0000000..d82ee28
--- /dev/null
+++ b/tests/dart2js/sync_star_element_rti_need_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+main() {
+ var x = [1, 2, 3];
+ Expect.listEquals(x, nop(x).toList());
+}
+
+Iterable<T> nop<T>(Iterable<T> values) {
+ Iterable<T> inner() sync* {
+ yield* values;
+ return;
+ }
+
+ return inner();
+}
diff --git a/tests/dart2js_2/sync_star_element_rti_need_test.dart b/tests/dart2js_2/sync_star_element_rti_need_test.dart
new file mode 100644
index 0000000..d82ee28
--- /dev/null
+++ b/tests/dart2js_2/sync_star_element_rti_need_test.dart
@@ -0,0 +1,19 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+main() {
+ var x = [1, 2, 3];
+ Expect.listEquals(x, nop(x).toList());
+}
+
+Iterable<T> nop<T>(Iterable<T> values) {
+ Iterable<T> inner() sync* {
+ yield* values;
+ return;
+ }
+
+ return inner();
+}
diff --git a/tests/language/static/final_field2_test.dart b/tests/language/static/final_field2_test.dart
index 6430471..da8ea37 100644
--- a/tests/language/static/final_field2_test.dart
+++ b/tests/language/static/final_field2_test.dart
@@ -19,9 +19,8 @@
main() {
A.x = 2;
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
// ^
+// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
// [cfe] Setter not found: 'x'.
new B();
print(B.b);
diff --git a/tests/language_2/static/final_field2_test.dart b/tests/language_2/static/final_field2_test.dart
index 6430471..da8ea37 100644
--- a/tests/language_2/static/final_field2_test.dart
+++ b/tests/language_2/static/final_field2_test.dart
@@ -19,9 +19,8 @@
main() {
A.x = 2;
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
// ^
+// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
// [cfe] Setter not found: 'x'.
new B();
print(B.b);
diff --git a/tools/VERSION b/tools/VERSION
index 06eb9dd..1813698 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 117
+PRERELEASE 118
PRERELEASE_PATCH 0
\ No newline at end of file