Version 2.13.0-169.0.dev
Merge commit 'a7b0f5108d2938f03eda39bdd72e05135f07d76f' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 9f0bf0b..8a5f7e9 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-03-24T12:15:31.538873",
+ "generated": "2021-03-24T13:42:28.071470",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -638,12 +638,6 @@
"languageVersion": "2.12"
},
{
- "name": "stagehand",
- "rootUri": "../third_party/pkg/stagehand",
- "packageUri": "lib/",
- "languageVersion": "2.10"
- },
- {
"name": "status_file",
"rootUri": "../pkg/status_file",
"packageUri": "lib/",
diff --git a/.packages b/.packages
index 5fc05a8..7646deb 100644
--- a/.packages
+++ b/.packages
@@ -95,7 +95,6 @@
source_span:third_party/pkg/source_span/lib
sse:third_party/pkg/sse/lib
stack_trace:third_party/pkg/stack_trace/lib
-stagehand:third_party/pkg/stagehand/lib
status_file:pkg/status_file/lib
stream_channel:third_party/pkg/stream_channel/lib
string_scanner:third_party/pkg/string_scanner/lib
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 143873c..f9bed69 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,18 @@
- new lint: `use_named_constants`.
- deprecation of `avoid_as`.
+### Other libraries
+
+#### `package:js`
+
+* **Breaking change:** It is no longer valid to use `String`s that match
+ an `@Native` annotation in an `@JS()` annotation for a non-anonymous JS
+ interop class. This led to erroneous behavior due to the way interceptors
+ work. If you need to work with a native class, prefer `dart:html`, an
+ `@anonymous` class, or `js_util`. See issue [#44211][] for more details.
+
+[#44211]: https://github.com/dart-lang/sdk/issues/44211
+
## 2.12.2 - 2021-03-17
This is a patch release that fixes crashes reported by Flutter 2 users (issue
diff --git a/DEPS b/DEPS
index 2948ee6..4ecf65b 100644
--- a/DEPS
+++ b/DEPS
@@ -152,7 +152,6 @@
"source_span_rev": "1be3c44045a06dff840d2ed3a13e6082d7a03a23",
"sse_tag": "5da8fedcdc56f306933d202e2d204753eecefd36",
"stack_trace_tag": "6788afc61875079b71b3d1c3e65aeaa6a25cbc2f",
- "stagehand_rev": "e64ac90cac508981011299c4ceb819149e71f1bd",
"stream_channel_tag": "d7251e61253ec389ee6e045ee1042311bced8f1d",
"string_scanner_rev": "1b63e6e5db5933d7be0a45da6e1129fe00262734",
"sync_http_rev": "b59c134f2e34d12acac110d4f17f83e5a7db4330",
@@ -430,8 +429,6 @@
Var("dart_git") + "sse.git" + "@" + Var("sse_tag"),
Var("dart_root") + "/third_party/pkg/stack_trace":
Var("dart_git") + "stack_trace.git" + "@" + Var("stack_trace_tag"),
- Var("dart_root") + "/third_party/pkg/stagehand":
- Var("dart_git") + "stagehand.git" + "@" + Var("stagehand_rev"),
Var("dart_root") + "/third_party/pkg/stream_channel":
Var("dart_git") + "stream_channel.git" +
"@" + Var("stream_channel_tag"),
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index 0efadbc..6668855 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -5,8 +5,8 @@
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
import 'package:test/test.dart';
+import '../mini_ast.dart';
import '../mini_types.dart';
-import 'flow_analysis_mini_ast.dart';
main() {
group('API', () {
@@ -42,8 +42,8 @@
test('assert_end joins previous and ifTrue states', () {
var h = Harness();
var x = Var('x', 'int?');
- var y = Var('x', 'int?');
- var z = Var('x', 'int?');
+ var y = Var('y', 'int?');
+ var z = Var('z', 'int?');
h.run([
x.read.as_('int').stmt,
z.read.as_('int').stmt,
@@ -519,13 +519,13 @@
});
test('equalityOp_end does not set reachability for `this`', () {
- var h = Harness()
+ var h = Harness(thisType: 'C')
..addSubtype('Null', 'C', false)
..addFactor('C', 'Null', 'C');
h.addSubtype('C', 'Object', true);
h.run([
- if_(this_('C').is_('Null'), [
- if_(this_('C').eq(nullLiteral), [
+ if_(this_.is_('Null'), [
+ if_(this_.eq(nullLiteral), [
checkReachable(true),
], [
checkReachable(true),
@@ -564,10 +564,10 @@
});
test('on explicit this', () {
- var h = Harness();
+ var h = Harness(thisType: 'C');
h.run([
- if_(this_('C').propertyGet('f').is_('Null'), [
- if_(this_('C').propertyGet('f').eq(nullLiteral), [
+ if_(this_.propertyGet('f').is_('Null'), [
+ if_(this_.propertyGet('f').eq(nullLiteral), [
checkReachable(true),
], [
checkReachable(true),
@@ -1464,11 +1464,11 @@
});
test('isExpression_end() does not set reachability for `this`', () {
- var h = Harness()
+ var h = Harness(thisType: 'C')
..addSubtype('Never', 'C', true)
..addFactor('C', 'Never', 'C');
h.run([
- if_(this_('C').is_('Never'), [
+ if_(this_.is_('Never'), [
checkReachable(true),
], [
checkReachable(true),
@@ -1502,9 +1502,9 @@
});
test('on explicit this', () {
- var h = Harness();
+ var h = Harness(thisType: 'C');
h.run([
- if_(this_('C').propertyGet('f').is_('Never'), [
+ if_(this_.propertyGet('f').is_('Never'), [
checkReachable(true),
], [
checkReachable(true),
@@ -2007,15 +2007,13 @@
declare(x, initialized: true),
declare(y, initialized: true),
y.read.as_('int').stmt,
- tryCatch([
+ try_([
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
checkPromoted(y, 'int'),
- ], [
- catch_(body: [
- checkNotPromoted(x),
- checkPromoted(y, 'int'),
- ])
+ ]).catch_(body: [
+ checkNotPromoted(x),
+ checkPromoted(y, 'int'),
]),
]);
});
@@ -2029,16 +2027,14 @@
declare(x, initialized: true),
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
- tryCatch([
+ try_([
x.write(expr('int?')).stmt,
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
getSsaNodes((nodes) => ssaAfterTry = nodes[x]!),
- ], [
- catch_(body: [
- checkNotPromoted(x),
- getSsaNodes((nodes) => expect(nodes[x], isNot(ssaAfterTry))),
- ]),
+ ]).catch_(body: [
+ checkNotPromoted(x),
+ getSsaNodes((nodes) => expect(nodes[x], isNot(ssaAfterTry))),
]),
]);
});
@@ -2053,16 +2049,14 @@
declare(x, initialized: true),
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
- tryCatch([
+ try_([
localFunction([
x.write(expr('int?')).stmt,
]),
return_(),
- ], [
- catch_(body: [
- x.read.as_('int').stmt,
- checkNotPromoted(x),
- ])
+ ]).catch_(body: [
+ x.read.as_('int').stmt,
+ checkNotPromoted(x),
]),
]);
});
@@ -2073,14 +2067,11 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- tryCatch([], [
- catch_(body: [
- x.read.as_('int').stmt,
- checkPromoted(x, 'int'),
- ]),
- catch_(body: [
- checkNotPromoted(x),
- ]),
+ try_([]).catch_(body: [
+ x.read.as_('int').stmt,
+ checkPromoted(x, 'int'),
+ ]).catch_(body: [
+ checkNotPromoted(x),
]),
]);
});
@@ -2090,11 +2081,9 @@
var e = Var('e', 'int');
var st = Var('st', 'StackTrace');
h.run([
- tryCatch([], [
- catch_(exception: e, stackTrace: st, body: [
- checkAssigned(e, true),
- checkAssigned(st, true),
- ]),
+ try_([]).catch_(exception: e, stackTrace: st, body: [
+ checkAssigned(e, true),
+ checkAssigned(st, true),
]),
]);
});
@@ -2108,14 +2097,12 @@
h.run([
declare(x, initialized: true), declare(y, initialized: true),
declare(z, initialized: true),
- tryCatch([
+ try_([
x.read.as_('int').stmt,
y.read.as_('int').stmt,
- ], [
- catch_(body: [
- x.read.as_('int').stmt,
- z.read.as_('int').stmt,
- ]),
+ ]).catch_(body: [
+ x.read.as_('int').stmt,
+ z.read.as_('int').stmt,
]),
// Only x should be promoted, because it's the only variable
// promoted in both the try body and the catch handler.
@@ -2131,17 +2118,14 @@
h.run([
declare(x, initialized: true), declare(y, initialized: true),
declare(z, initialized: true),
- tryCatch([
+ try_([
return_(),
- ], [
- catch_(body: [
- x.read.as_('int').stmt,
- y.read.as_('int').stmt,
- ]),
- catch_(body: [
- x.read.as_('int').stmt,
- z.read.as_('int').stmt,
- ]),
+ ]).catch_(body: [
+ x.read.as_('int').stmt,
+ y.read.as_('int').stmt,
+ ]).catch_(body: [
+ x.read.as_('int').stmt,
+ z.read.as_('int').stmt,
]),
// Only x should be promoted, because it's the only variable promoted
// in both catch handlers.
@@ -2157,11 +2141,11 @@
declare(x, initialized: true),
declare(y, initialized: true),
y.read.as_('int').stmt,
- tryFinally([
+ try_([
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
checkPromoted(y, 'int'),
- ], [
+ ]).finally_([
checkNotPromoted(x),
checkPromoted(y, 'int'),
]),
@@ -2179,13 +2163,13 @@
declare(x, initialized: true),
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
- tryFinally([
+ try_([
getSsaNodes((nodes) => ssaAtStartOfTry = nodes[x]!),
x.write(expr('int?')).stmt,
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
getSsaNodes((nodes) => ssaAfterTry = nodes[x]!),
- ], [
+ ]).finally_([
checkNotPromoted(x),
// The SSA node for X should be different from what it was at any time
// during the try block, because there is no telling at what point an
@@ -2207,12 +2191,12 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
localFunction([
x.write(expr('int?')).stmt,
]),
return_(),
- ], [
+ ]).finally_([
x.read.as_('int').stmt,
checkNotPromoted(x),
]),
@@ -2225,10 +2209,10 @@
var y = Var('y', 'int?');
h.run([
declare(x, initialized: true), declare(y, initialized: true),
- tryFinally([
+ try_([
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
- ], [
+ ]).finally_([
checkNotPromoted(x),
y.read.as_('int').stmt,
checkPromoted(y, 'int'),
@@ -2248,10 +2232,10 @@
late SsaNode<Var, Type> ySsaAtEndOfFinally;
h.run([
declare(x, initialized: true), declare(y, initialized: true),
- tryFinally([
+ try_([
x.read.as_('int').stmt,
checkPromoted(x, 'int'),
- ], [
+ ]).finally_([
checkNotPromoted(x),
x.write(expr('int?')).stmt,
y.write(expr('int?')).stmt,
@@ -2289,14 +2273,14 @@
late SsaNode<Var, Type> ySsaAtEndOfFinally;
h.run([
declare(x, initialized: true), declare(y, initialized: true),
- tryFinally([
+ try_([
x.write(expr('int?')).stmt,
y.write(expr('int?')).stmt,
getSsaNodes((nodes) {
xSsaAtEndOfTry = nodes[x]!;
ySsaAtEndOfTry = nodes[y]!;
}),
- ], [
+ ]).finally_([
if_(expr('bool'), [
x.write(expr('int?')).stmt,
]),
@@ -2329,10 +2313,10 @@
'unreachable', () {
var h = Harness();
h.run([
- tryFinally([
+ try_([
return_(),
checkReachable(false),
- ], [
+ ]).finally_([
checkReachable(true),
]),
checkReachable(false),
@@ -2344,9 +2328,9 @@
'unreachable', () {
var h = Harness();
h.run([
- tryFinally([
+ try_([
checkReachable(true),
- ], [
+ ]).finally_([
return_(),
checkReachable(false),
]),
@@ -2360,9 +2344,9 @@
var h = Harness();
var x = Var('x', 'int?');
h.run([
- tryFinally([
+ try_([
declare(x, initialized: true),
- ], []),
+ ]).finally_([]),
]);
});
@@ -2372,7 +2356,7 @@
var h = Harness();
var x = Var('x', 'int?');
h.run([
- tryFinally([], [
+ try_([]).finally_([
declare(x, initialized: true),
]),
]);
@@ -2385,11 +2369,11 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
localFunction([
x.write(expr('int?')).stmt,
]),
- ], []),
+ ]).finally_([]),
if_(x.read.notEq(nullLiteral), [
checkNotPromoted(x),
]),
@@ -2403,7 +2387,7 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- tryFinally([], [
+ try_([]).finally_([
localFunction([
x.write(expr('int?')).stmt,
]),
@@ -2421,12 +2405,12 @@
var x = Var('x', 'int?');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
if_(x.read.eq(nullLiteral), [
return_(),
]),
checkPromoted(x, 'int'),
- ], [
+ ]).finally_([
localFunction([
x.write(expr('int?')).stmt,
]),
@@ -2447,12 +2431,12 @@
var x = Var('x', 'Object');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
if_(x.read.is_('num', isInverted: true), [
return_(),
]),
checkPromoted(x, 'num'),
- ], [
+ ]).finally_([
if_(x.read.is_('int', isInverted: true), [
return_(),
]),
@@ -2471,12 +2455,12 @@
var x = Var('x', 'Object');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
if_(x.read.is_('String', isInverted: true), [
return_(),
]),
checkPromoted(x, 'String'),
- ], [
+ ]).finally_([
x.write(expr('Object')).stmt,
if_(x.read.is_('int', isInverted: true), [
return_(),
@@ -2493,10 +2477,10 @@
var x = Var('x', 'Object');
h.run([
declare(x, initialized: true),
- tryFinally([
+ try_([
if_(x.read.is_('String', isInverted: true), []),
checkNotPromoted(x),
- ], [
+ ]).finally_([
if_(x.read.is_('int', isInverted: true), []),
checkNotPromoted(x),
]),
@@ -2519,12 +2503,12 @@
h.run([
declare(x, initialized: false),
checkAssigned(x, false),
- tryFinally([
+ try_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
checkAssigned(x, false),
- ], [
+ ]).finally_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
@@ -2542,10 +2526,10 @@
h.run([
declare(x, initialized: false),
checkAssigned(x, false),
- tryFinally([
+ try_([
x.write(expr('Object')).stmt,
checkAssigned(x, true),
- ], [
+ ]).finally_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
@@ -2563,12 +2547,12 @@
h.run([
declare(x, initialized: false),
checkAssigned(x, false),
- tryFinally([
+ try_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
checkAssigned(x, false),
- ], [
+ ]).finally_([
x.write(expr('Object')).stmt,
checkAssigned(x, true),
]),
@@ -2584,9 +2568,9 @@
h.run([
declare(x, initialized: false),
checkUnassigned(x, true),
- tryFinally([
+ try_([
checkUnassigned(x, true),
- ], [
+ ]).finally_([
checkUnassigned(x, true),
]),
checkUnassigned(x, true),
@@ -2601,9 +2585,9 @@
h.run([
declare(x, initialized: false),
checkUnassigned(x, true),
- tryFinally([
+ try_([
checkUnassigned(x, true),
- ], [
+ ]).finally_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
@@ -2621,12 +2605,12 @@
h.run([
declare(x, initialized: false),
checkUnassigned(x, true),
- tryFinally([
+ try_([
if_(expr('bool'), [
x.write(expr('Object')).stmt,
]),
checkUnassigned(x, false),
- ], [
+ ]).finally_([
checkUnassigned(x, false),
]),
checkUnassigned(x, false),
@@ -5622,12 +5606,12 @@
group('because property', () {
test('via explicit this', () {
- var h = Harness();
+ var h = Harness(thisType: 'C');
h.run([
- if_(this_('C').propertyGet('field').eq(nullLiteral), [
+ if_(this_.propertyGet('field').eq(nullLiteral), [
return_(),
]),
- this_('C').propertyGet('field').whyNotPromoted((reasons) {
+ this_.propertyGet('field').whyNotPromoted((reasons) {
expect(reasons.keys, unorderedEquals([Type('Object')]));
var nonPromotionReason = reasons.values.single;
expect(nonPromotionReason, TypeMatcher<PropertyNotPromoted>());
@@ -5668,14 +5652,14 @@
group('because this', () {
test('explicit', () {
- var h = Harness()
+ var h = Harness(thisType: 'C')
..addSubtype('D', 'C', true)
..addFactor('C', 'D', 'C');
h.run([
- if_(this_('C').isNot('D'), [
+ if_(this_.isNot('D'), [
return_(),
]),
- this_('C').whyNotPromoted((reasons) {
+ this_.whyNotPromoted((reasons) {
expect(reasons.keys, unorderedEquals([Type('D')]));
var nonPromotionReason = reasons.values.single;
expect(nonPromotionReason, TypeMatcher<ThisNotPromoted>());
@@ -5684,11 +5668,11 @@
});
test('implicit', () {
- var h = Harness()
+ var h = Harness(thisType: 'C')
..addSubtype('D', 'C', true)
..addFactor('C', 'D', 'C');
h.run([
- if_(this_('C').isNot('D'), [
+ if_(this_.isNot('D'), [
return_(),
]),
implicitThis_whyNotPromoted('C', (reasons) {
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
index 8f705df..e83ebea 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/argument_type_not_assignable_nullability_error.dart
@@ -389,3 +389,15 @@
null: null
});
}
+
+class C26 {
+ int? bad;
+}
+
+compoundAssignmentRhs(C26 c) {
+ int i = 0;
+ if (c.bad == null) return;
+ i +=
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C26.bad, type: int?))*/ c
+ . /*cfe.notPromoted(propertyNotPromoted(target: member:C26.bad, type: int?))*/ bad;
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart
similarity index 95%
rename from pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
rename to pkg/_fe_analyzer_shared/test/mini_ast.dart
index d7fbe42..1d026cf 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart
@@ -9,10 +9,12 @@
import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
import 'package:test/test.dart';
-import '../mini_types.dart';
+import 'mini_types.dart';
Expression get nullLiteral => new _NullLiteral();
+Expression get this_ => new _This();
+
Statement assert_(Expression condition, [Expression? message]) =>
new _Assert(condition, message);
@@ -37,10 +39,6 @@
SwitchCase case_(List<Statement> body, {bool hasLabel = false}) =>
SwitchCase._(hasLabel, body);
-CatchClause catch_(
- {Var? exception, Var? stackTrace, required List<Statement> body}) =>
- CatchClause._(body, exception, stackTrace);
-
/// Creates a pseudo-statement whose function is to verify that flow analysis
/// considers [variable]'s assigned state to be [expectedAssignedState].
Statement checkAssigned(Var variable, bool expectedAssignedState) =>
@@ -160,18 +158,12 @@
{required bool isExhaustive}) =>
new _Switch(expression, cases, isExhaustive);
-Expression this_(String type) => new _This(Type(type));
-
Expression thisOrSuperPropertyGet(String name, {String type = 'Object?'}) =>
new _ThisOrSuperPropertyGet(name, Type(type));
Expression throw_(Expression operand) => new _Throw(operand);
-Statement tryCatch(List<Statement> body, List<CatchClause> catches) =>
- new _TryCatch(body, catches);
-
-Statement tryFinally(List<Statement> body, List<Statement> finally_) =>
- new _TryFinally(body, finally_);
+TryBuilder try_(List<Statement> body) => new _TryStatement(body, [], null);
Statement while_(Expression condition, List<Statement> body) =>
new _While(condition, body);
@@ -184,39 +176,6 @@
BranchTargetPlaceholder._();
}
-/// Representation of a single catch clause in a try/catch statement. Use
-/// [catch_] to create instances of this class.
-class CatchClause implements _Visitable<void> {
- final List<Statement> _body;
- final Var? _exception;
- final Var? _stackTrace;
-
- CatchClause._(this._body, this._exception, this._stackTrace);
-
- String toString() {
- String initialPart;
- if (_stackTrace != null) {
- initialPart = 'catch (${_exception!.name}, ${_stackTrace!.name})';
- } else if (_exception != null) {
- initialPart = 'catch (${_exception!.name})';
- } else {
- initialPart = 'on ...';
- }
- return '$initialPart ${block(_body)}';
- }
-
- void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- _body._preVisit(assignedVariables);
- }
-
- void _visit(
- Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.tryCatchStatement_catchBegin(_exception, _stackTrace);
- _body._visit(h, flow);
- flow.tryCatchStatement_catchEnd();
- }
-}
-
/// Representation of an expression in the pseudo-Dart language used for flow
/// analysis testing. Methods in this class may be used to create more complex
/// expressions based on this one.
@@ -427,6 +386,8 @@
final bool legacy;
+ final Type? thisType;
+
final Map<String, bool> _subtypes = Map.of(_coreSubtypes);
final Map<String, Type> _factorResults = Map.of(_coreFactors);
@@ -435,7 +396,8 @@
Map<String, Map<String, String>> _promotionExceptions = {};
- Harness({this.legacy = false});
+ Harness({this.legacy = false, String? thisType})
+ : thisType = thisType == null ? null : Type(thisType);
/// Updates the harness so that when a [factor] query is invoked on types
/// [from] and [what], [result] will be returned.
@@ -625,6 +587,17 @@
}
}
+abstract class TryBuilder {
+ TryStatement catch_(
+ {Var? exception, Var? stackTrace, required List<Statement> body});
+
+ Statement finally_(List<Statement> statements);
+}
+
+abstract class TryStatement extends Statement implements TryBuilder {
+ TryStatement._() : super._();
+}
+
/// Representation of a local variable in the pseudo-Dart language used for flow
/// analysis testing.
class Var {
@@ -757,6 +730,39 @@
}
}
+/// Representation of a single catch clause in a try/catch statement. Use
+/// [catch_] to create instances of this class.
+class _CatchClause implements _Visitable<void> {
+ final List<Statement> _body;
+ final Var? _exception;
+ final Var? _stackTrace;
+
+ _CatchClause(this._body, this._exception, this._stackTrace);
+
+ String toString() {
+ String initialPart;
+ if (_stackTrace != null) {
+ initialPart = 'catch (${_exception!.name}, ${_stackTrace!.name})';
+ } else if (_exception != null) {
+ initialPart = 'catch (${_exception!.name})';
+ } else {
+ initialPart = 'on ...';
+ }
+ return '$initialPart ${block(_body)}';
+ }
+
+ void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
+ _body._preVisit(assignedVariables);
+ }
+
+ void _visit(
+ Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
+ flow.tryCatchStatement_catchBegin(_exception, _stackTrace);
+ _body._visit(h, flow);
+ flow.tryCatchStatement_catchEnd();
+ }
+}
+
class _CheckAssigned extends Statement {
final Var variable;
final bool expectedAssignedState;
@@ -1515,10 +1521,6 @@
}
class _This extends Expression {
- final Type type;
-
- _This(this.type);
-
@override
String toString() => 'this';
@@ -1528,8 +1530,9 @@
@override
Type _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.thisOrSuper(this, type);
- return type;
+ var thisType = h.thisType!;
+ flow.thisOrSuper(this, thisType);
+ return thisType;
}
}
@@ -1573,60 +1576,68 @@
}
}
-class _TryCatch extends Statement {
- final List<Statement> body;
- final List<CatchClause> catches;
+class _TryStatement extends TryStatement {
+ final List<Statement> _body;
+ final List<_CatchClause> _catches;
+ final List<Statement>? _finally;
+ final _bodyNode = Node._();
- _TryCatch(this.body, this.catches) : super._();
+ _TryStatement(this._body, this._catches, this._finally) : super._();
@override
- String toString() => 'try ${block(body)} ${catches.join(' ')}';
-
- @override
- void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- assignedVariables.beginNode();
- body._preVisit(assignedVariables);
- assignedVariables.endNode(this);
- catches._preVisit(assignedVariables);
+ TryStatement catch_(
+ {Var? exception, Var? stackTrace, required List<Statement> body}) {
+ assert(_finally == null, 'catch after finally');
+ return _TryStatement(
+ _body, [..._catches, _CatchClause(body, exception, stackTrace)], null);
}
@override
- void _visit(
- Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.tryCatchStatement_bodyBegin();
- body._visit(h, flow);
- flow.tryCatchStatement_bodyEnd(this);
- catches._visit(h, flow);
- flow.tryCatchStatement_end();
+ Statement finally_(List<Statement> statements) {
+ assert(_finally == null, 'multiple finally clauses');
+ return _TryStatement(_body, _catches, statements);
}
-}
-
-class _TryFinally extends Statement {
- final List<Statement> body;
- final List<Statement> finally_;
- final Node _bodyNode = Node._();
-
- _TryFinally(this.body, this.finally_) : super._();
-
- @override
- String toString() => 'try ${block(body)} finally ${block(finally_)}';
@override
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
- assignedVariables.beginNode();
- body._preVisit(assignedVariables);
+ if (_finally != null) {
+ assignedVariables.beginNode();
+ }
+ if (_catches.isNotEmpty) {
+ assignedVariables.beginNode();
+ }
+ _body._preVisit(assignedVariables);
assignedVariables.endNode(_bodyNode);
- finally_._preVisit(assignedVariables);
+ _catches._preVisit(assignedVariables);
+ if (_finally != null) {
+ if (_catches.isNotEmpty) {
+ assignedVariables.endNode(this);
+ }
+ _finally!._preVisit(assignedVariables);
+ }
}
@override
void _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.tryFinallyStatement_bodyBegin();
- body._visit(h, flow);
- flow.tryFinallyStatement_finallyBegin(_bodyNode);
- finally_._visit(h, flow);
- flow.tryFinallyStatement_end();
+ if (_finally != null) {
+ flow.tryFinallyStatement_bodyBegin();
+ }
+ if (_catches.isNotEmpty) {
+ flow.tryCatchStatement_bodyBegin();
+ }
+ _body._visit(h, flow);
+ if (_catches.isNotEmpty) {
+ flow.tryCatchStatement_bodyEnd(_bodyNode);
+ _catches._visit(h, flow);
+ flow.tryCatchStatement_end();
+ }
+ if (_finally != null) {
+ flow.tryFinallyStatement_finallyBegin(
+ _catches.isNotEmpty ? this : _bodyNode);
+ _finally!._visit(h, flow);
+ flow.tryFinallyStatement_end();
+ }
}
}
diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
index 3ac8da4..92777a1 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart
@@ -35,6 +35,21 @@
assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
}
+ Future<void> test_ANNOTATION_hasTypeArguments_hasArguments() async {
+ addTestFile('''
+class AAA<T> {
+ const AAA(a, b, c);
+}
+
+@AAA<int>(1, 2, 3) void f() {}
+''');
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.ANNOTATION, '@AAA', '@AAA<int>('.length);
+ assertHasRegion(HighlightRegionType.ANNOTATION, ') void', ')'.length);
+ assertHasRegion(HighlightRegionType.CLASS, 'int>');
+ }
+
Future<void> test_ANNOTATION_noArguments() async {
addTestFile('''
const AAA = 42;
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index f7a70e9..8f42b24 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -197,6 +197,53 @@
assertHasRegionTarget('AAA aaa;', 'AAA {}');
}
+ Future<void> test_annotation_generic_typeArguments_class() async {
+ addTestFile('''
+class A<T> {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''');
+ await prepareNavigation();
+ assertHasRegion('int>()');
+ }
+
+ Future<void> test_annotationConstructor_generic_named() async {
+ addTestFile('''
+class A<T> {
+ const A.named(_);
+}
+
+@A<int>.named(0)
+void f() {}
+''');
+ await prepareNavigation();
+ {
+ assertHasRegion('A<int>.named(0)');
+ assertHasTarget('named(_);');
+ }
+ {
+ assertHasRegion('named(0)');
+ assertHasTarget('named(_);');
+ }
+ }
+
+ Future<void> test_annotationConstructor_generic_unnamed() async {
+ addTestFile('''
+class A<T> {
+ const A(_);
+}
+
+@A<int>(0)
+void f() {}
+''');
+ await prepareNavigation();
+ assertHasRegionString('A<int>(0)', 'A'.length);
+ assertHasTarget('A(_);', 0);
+ }
+
Future<void> test_annotationConstructor_implicit() async {
addTestFile('''
class A {
diff --git a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
index ecb0f00..f8b642b 100644
--- a/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/imported_reference_contributor_test.dart
@@ -32,6 +32,34 @@
@reflectiveTest
class ImportedReferenceContributorTest extends DartCompletionContributorTest
with ImportedReferenceContributorMixin {
+ Future<void> test_Annotation_typeArguments() async {
+ addSource('/home/test/lib/a.dart', '''
+class C {}
+typedef T1 = void Function();
+typedef T2 = List<int>;
+''');
+
+ addTestSource('''
+import 'a.dart';
+
+class A<T> {
+ const A();
+}
+
+@A<^>()
+void f() {}
+''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('C');
+ assertSuggestTypeAlias('T1',
+ aliasedType: 'void Function()', returnType: 'void');
+ assertSuggestTypeAlias('T2', aliasedType: 'List<int>');
+ assertNotSuggested('identical');
+ }
+
/// Sanity check. Permutations tested in local_ref_contributor.
Future<void> test_ArgDefaults_function_with_required_named() async {
writeTestPackageConfig(meta: true);
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 10488ef..0317cd7 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -164,6 +164,7 @@
CompileTimeErrorCode.EXTENDS_DEFERRED_CLASS,
CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
CompileTimeErrorCode.EXTENDS_NON_CLASS,
+ CompileTimeErrorCode.EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
CompileTimeErrorCode.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE,
CompileTimeErrorCode.EXTENSION_DECLARES_MEMBER_OF_OBJECT,
@@ -206,6 +207,7 @@
CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
CompileTimeErrorCode.IMPLEMENTS_REPEATED,
CompileTimeErrorCode.IMPLEMENTS_SUPER_CLASS,
+ CompileTimeErrorCode.IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
CompileTimeErrorCode.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER,
CompileTimeErrorCode.IMPORT_INTERNAL_LIBRARY,
CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY,
@@ -287,6 +289,8 @@
CompileTimeErrorCode.MIXIN_INSTANTIATE,
CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS,
CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
+ CompileTimeErrorCode.MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ CompileTimeErrorCode.MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DEFERRED_CLASS,
CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS,
CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_INTERFACE,
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 5fb5657..8989422 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -80,7 +80,7 @@
if (_lastClonedOffset <= token.offset) {
_cloneTokens(_nextToClone ?? token, token.offset);
}
- return _clonedTokens[token]!;
+ return _clonedTokens[token];
} else {
return token;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index 2ffd93d..d246ff1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -30,11 +30,11 @@
_definingLibrary.featureSet.isEnabled(Feature.generic_metadata);
void resolve(AnnotationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
AstNode parent = node.parent;
node.typeArguments?.accept(_resolver);
- _resolve(node, whyNotPromotedInfo);
+ _resolve(node, whyNotPromotedList);
var elementAnnotationImpl =
node.elementAnnotation as ElementAnnotationImpl?;
@@ -50,7 +50,7 @@
AnnotationImpl node,
ClassElement classElement,
SimpleIdentifierImpl? getterName,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
ExecutableElement? getter;
if (getterName != null) {
@@ -66,7 +66,7 @@
node.element = getter;
if (getterName != null && getter is PropertyAccessorElement) {
- _propertyAccessorElement(node, getterName, getter, whyNotPromotedInfo);
+ _propertyAccessorElement(node, getterName, getter, whyNotPromotedList);
_resolveAnnotationElementGetter(node, getter);
} else if (getter is! ConstructorElement) {
_errorReporter.reportErrorForNode(
@@ -75,7 +75,7 @@
);
}
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
}
void _constructorInvocation(
@@ -83,7 +83,7 @@
ClassElement classElement,
SimpleIdentifierImpl? constructorName,
ArgumentList argumentList,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
ConstructorElement? constructorElement;
if (constructorName != null) {
@@ -104,7 +104,7 @@
node,
);
_resolver.visitArgumentList(argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
return;
}
@@ -115,7 +115,7 @@
_resolveConstructorInvocationArguments(node);
InferenceContext.setType(argumentList, constructorElement.type);
_resolver.visitArgumentList(argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
return;
}
@@ -134,7 +134,7 @@
InferenceContext.setType(argumentList, constructorElement.type);
_resolver.visitArgumentList(argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
if (!_genericMetadataIsEnabled) {
@@ -164,7 +164,7 @@
}
_resolver.visitArgumentList(argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
var constructorRawType = _resolver.typeAnalyzer
.constructorToGenericFunctionType(constructorElement);
@@ -194,7 +194,7 @@
AnnotationImpl node,
ExtensionElement extensionElement,
SimpleIdentifierImpl? getterName,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
ExecutableElement? getter;
if (getterName != null) {
@@ -206,7 +206,7 @@
node.element = getter;
if (getterName != null && getter is PropertyAccessorElement) {
- _propertyAccessorElement(node, getterName, getter, whyNotPromotedInfo);
+ _propertyAccessorElement(node, getterName, getter, whyNotPromotedList);
_resolveAnnotationElementGetter(node, getter);
} else {
_errorReporter.reportErrorForNode(
@@ -215,25 +215,25 @@
);
}
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
}
void _propertyAccessorElement(
AnnotationImpl node,
SimpleIdentifierImpl name,
PropertyAccessorElement element,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
element = _resolver.toLegacyElement(element);
name.staticElement = element;
node.element = element;
_resolveAnnotationElementGetter(node, element);
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
}
void _resolve(AnnotationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
SimpleIdentifierImpl name1;
SimpleIdentifierImpl? name2;
SimpleIdentifierImpl? name3;
@@ -257,7 +257,7 @@
node,
[name1.name],
);
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
return;
}
@@ -265,16 +265,16 @@
if (element1 is ClassElement) {
if (argumentList != null) {
_constructorInvocation(
- node, element1, name2, argumentList, whyNotPromotedInfo);
+ node, element1, name2, argumentList, whyNotPromotedList);
} else {
- _classGetter(node, element1, name2, whyNotPromotedInfo);
+ _classGetter(node, element1, name2, whyNotPromotedList);
}
return;
}
// Extension.CONST
if (element1 is ExtensionElement) {
- _extensionGetter(node, element1, name2, whyNotPromotedInfo);
+ _extensionGetter(node, element1, name2, whyNotPromotedList);
return;
}
@@ -287,20 +287,20 @@
if (element2 is ClassElement) {
if (argumentList != null) {
_constructorInvocation(
- node, element2, name3, argumentList, whyNotPromotedInfo);
+ node, element2, name3, argumentList, whyNotPromotedList);
} else {
- _classGetter(node, element2, name3, whyNotPromotedInfo);
+ _classGetter(node, element2, name3, whyNotPromotedList);
}
return;
}
// prefix.Extension.CONST
if (element2 is ExtensionElement) {
- _extensionGetter(node, element2, name3, whyNotPromotedInfo);
+ _extensionGetter(node, element2, name3, whyNotPromotedList);
return;
}
// prefix.CONST
if (element2 is PropertyAccessorElement) {
- _propertyAccessorElement(node, name2, element2, whyNotPromotedInfo);
+ _propertyAccessorElement(node, name2, element2, whyNotPromotedList);
return;
}
// undefined
@@ -310,7 +310,7 @@
node,
[name2.name],
);
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
return;
}
}
@@ -318,7 +318,7 @@
// CONST
if (element1 is PropertyAccessorElement) {
- _propertyAccessorElement(node, name1, element1, whyNotPromotedInfo);
+ _propertyAccessorElement(node, name1, element1, whyNotPromotedList);
return;
}
@@ -332,7 +332,7 @@
node,
);
- _visitArguments(node, whyNotPromotedInfo);
+ _visitArguments(node, whyNotPromotedList);
}
void _resolveAnnotationElementGetter(
@@ -394,11 +394,11 @@
}
void _visitArguments(AnnotationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var arguments = node.arguments;
if (arguments != null) {
_resolver.visitArgumentList(arguments,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
}
}
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 a3a966c..4c05164 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -248,6 +248,11 @@
assignedType,
whyNotPromoted: operator == TokenType.EQ ? whyNotPromoted : null,
);
+ if (operator != TokenType.EQ &&
+ operator != TokenType.QUESTION_QUESTION_EQ) {
+ _resolver.checkForArgumentTypeNotAssignableForArgument(node.rightHandSide,
+ whyNotPromoted: whyNotPromoted);
+ }
}
void _setRhsContext(AssignmentExpressionImpl node, DartType leftType,
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 0fb7a3a..b6453e8 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -111,8 +111,7 @@
var right = node.rightOperand;
right.accept(_resolver);
right = node.rightOperand;
- var whyNotPromotedInfo =
- _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
+ var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
if (!leftExtensionOverride) {
flow?.equalityOp_end(node, right, right.typeOrThrow, notEqual: notEqual);
@@ -125,8 +124,7 @@
);
_resolveUserDefinableType(node);
_resolver.checkForArgumentTypeNotAssignableForArgument(node.rightOperand,
- promoteParameterToNullable: true,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ promoteParameterToNullable: true, whyNotPromoted: whyNotPromoted);
}
void _resolveIfNull(BinaryExpressionImpl node) {
@@ -275,12 +273,11 @@
right.accept(_resolver);
right = node.rightOperand;
- var whyNotPromotedInfo =
- _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
+ var whyNotPromoted = _resolver.flowAnalysis?.flow?.whyNotPromoted(right);
_resolveUserDefinableType(node);
_resolver.checkForArgumentTypeNotAssignableForArgument(right,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromoted: whyNotPromoted);
}
void _resolveUserDefinableElement(
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index a515061..9a099ed 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -37,11 +37,11 @@
_resolver.nullableDereferenceVerifier;
void resolve(FunctionExpressionInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var function = node.function;
if (function is ExtensionOverrideImpl) {
- _resolveReceiverExtensionOverride(node, function, whyNotPromotedInfo);
+ _resolveReceiverExtensionOverride(node, function, whyNotPromotedList);
return;
}
@@ -52,12 +52,12 @@
// `_resolveReceiverInterfaceType` calls `TypePropertyResolver.resolve`,
// which does the necessary null checking.
_resolveReceiverInterfaceType(
- node, function, receiverType, whyNotPromotedInfo);
+ node, function, receiverType, whyNotPromotedList);
return;
}
if (_checkForUseOfVoidResult(function, receiverType)) {
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedInfo);
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
return;
}
@@ -65,18 +65,18 @@
errorCode: CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE);
if (receiverType is FunctionType) {
- _resolve(node, receiverType, whyNotPromotedInfo);
+ _resolve(node, receiverType, whyNotPromotedList);
return;
}
if (identical(receiverType, NeverTypeImpl.instance)) {
_errorReporter.reportErrorForNode(
HintCode.RECEIVER_OF_TYPE_NEVER, function);
- _unresolved(node, NeverTypeImpl.instance, whyNotPromotedInfo);
+ _unresolved(node, NeverTypeImpl.instance, whyNotPromotedList);
return;
}
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedInfo);
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
}
/// Check for situations where the result of a method or function is used,
@@ -104,11 +104,11 @@
}
void _resolve(FunctionExpressionInvocationImpl node, FunctionType rawType,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_inferenceHelper.resolveFunctionExpressionInvocation(
node: node,
rawType: rawType,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
var returnType = _inferenceHelper.computeInvokeReturnType(
@@ -118,15 +118,15 @@
}
void _resolveArguments(FunctionExpressionInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_resolver.visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
void _resolveReceiverExtensionOverride(
FunctionExpressionInvocationImpl node,
ExtensionOverride function,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
var result = _extensionResolver.getOverrideMember(
function,
@@ -141,7 +141,7 @@
function,
[function.extensionName.name],
);
- return _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedInfo);
+ return _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
}
if (callElement.isStatic) {
@@ -152,14 +152,14 @@
}
var rawType = callElement.type;
- _resolve(node, rawType, whyNotPromotedInfo);
+ _resolve(node, rawType, whyNotPromotedList);
}
void _resolveReceiverInterfaceType(
FunctionExpressionInvocationImpl node,
Expression function,
InterfaceType receiverType,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
var result = _typePropertyResolver.resolve(
receiver: function,
@@ -177,7 +177,7 @@
function,
);
}
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedInfo);
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
return;
}
@@ -186,19 +186,19 @@
CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION,
function,
);
- _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedInfo);
+ _unresolved(node, DynamicTypeImpl.instance, whyNotPromotedList);
return;
}
node.staticElement = callElement;
var rawType = callElement.type;
- _resolve(node, rawType, whyNotPromotedInfo);
+ _resolve(node, rawType, whyNotPromotedList);
}
void _unresolved(FunctionExpressionInvocationImpl node, DartType type,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_setExplicitTypeArgumentTypes(node);
- _resolveArguments(node, whyNotPromotedInfo);
+ _resolveArguments(node, whyNotPromotedList);
node.staticInvokeType = DynamicTypeImpl.instance;
node.staticType = type;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 865c8dd..f7bef84 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -209,7 +209,7 @@
required FunctionExpressionInvocationImpl node,
required FunctionType rawType,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
_resolveInvocation(
rawType: rawType,
@@ -218,7 +218,7 @@
contextType: InferenceContext.getContext(node),
isConst: false,
errorNode: node.function,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
node.typeArgumentTypes = _typeArgumentTypes;
@@ -234,7 +234,7 @@
required MethodInvocationImpl node,
required FunctionType rawType,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
_resolveInvocation(
rawType: rawType,
@@ -243,7 +243,7 @@
contextType: InferenceContext.getContext(node),
isConst: false,
errorNode: node.function,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
node.typeArgumentTypes = _typeArgumentTypes;
@@ -333,10 +333,10 @@
}
void _resolveArguments(ArgumentList argumentList,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_resolver.visitArgumentList(argumentList,
isIdentical: _isCallToIdentical(argumentList.parent),
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
void _resolveInvocation({
@@ -347,14 +347,14 @@
required bool isConst,
required AstNode errorNode,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
if (typeArgumentList != null) {
_resolveInvocationWithTypeArguments(
rawType: rawType,
typeArgumentList: typeArgumentList,
argumentList: argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
} else {
_resolveInvocationWithoutTypeArguments(
@@ -363,7 +363,7 @@
argumentList: argumentList,
isConst: isConst,
errorNode: errorNode,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
_setCorrespondingParameters(argumentList, _invokeType!);
@@ -376,13 +376,13 @@
required bool isConst,
required AstNode errorNode,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
var typeParameters = rawType.typeFormals;
if (typeParameters.isEmpty) {
InferenceContext.setType(argumentList, rawType);
- _resolveArguments(argumentList, whyNotPromotedInfo);
+ _resolveArguments(argumentList, whyNotPromotedList);
_typeArgumentTypes = const <DartType>[];
_invokeType = rawType;
@@ -399,7 +399,7 @@
var downwardsInvokeType = rawType.instantiate(downwardsTypeArguments);
InferenceContext.setType(argumentList, downwardsInvokeType);
- _resolveArguments(argumentList, whyNotPromotedInfo);
+ _resolveArguments(argumentList, whyNotPromotedList);
_typeArgumentTypes = _inferUpwards(
rawType: rawType,
@@ -417,7 +417,7 @@
required TypeArgumentList typeArgumentList,
required ArgumentList argumentList,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
var typeParameters = rawType.typeFormals;
@@ -445,7 +445,7 @@
var invokeType = rawType.instantiate(typeArguments);
InferenceContext.setType(argumentList, invokeType);
- _resolveArguments(argumentList, whyNotPromotedInfo);
+ _resolveArguments(argumentList, whyNotPromotedList);
_typeArgumentTypes = typeArguments;
_invokeType = invokeType;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 7310f7e..c585b07 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -82,7 +82,7 @@
TypeSystemImpl get _typeSystem => _resolver.typeSystem;
void resolve(MethodInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_invocation = node;
var nameNode = node.methodName;
@@ -92,7 +92,7 @@
var receiver = node.realTarget;
if (receiver == null) {
- _resolveReceiverNull(node, nameNode, name, whyNotPromotedInfo);
+ _resolveReceiverNull(node, nameNode, name, whyNotPromotedList);
return;
}
@@ -100,7 +100,7 @@
var receiverElement = receiver.staticElement;
if (receiverElement is PrefixElement) {
_resolveReceiverPrefix(
- node, receiverElement, nameNode, name, whyNotPromotedInfo);
+ node, receiverElement, nameNode, name, whyNotPromotedList);
return;
}
}
@@ -109,19 +109,19 @@
var receiverElement = receiver.staticElement;
if (receiverElement is ExtensionElement) {
_resolveExtensionMember(node, receiver, receiverElement, nameNode, name,
- whyNotPromotedInfo);
+ whyNotPromotedList);
return;
}
}
if (receiver is SuperExpressionImpl) {
- _resolveReceiverSuper(node, receiver, nameNode, name, whyNotPromotedInfo);
+ _resolveReceiverSuper(node, receiver, nameNode, name, whyNotPromotedList);
return;
}
if (receiver is ExtensionOverrideImpl) {
_resolveExtensionOverride(
- node, receiver, nameNode, name, whyNotPromotedInfo);
+ node, receiver, nameNode, name, whyNotPromotedList);
return;
}
@@ -129,13 +129,13 @@
var element = receiver.staticElement;
if (element is ClassElement) {
_resolveReceiverTypeLiteral(
- node, element, nameNode, name, whyNotPromotedInfo);
+ node, element, nameNode, name, whyNotPromotedList);
return;
} else if (element is TypeAliasElement) {
var aliasedType = element.aliasedType;
if (aliasedType is InterfaceType) {
_resolveReceiverTypeLiteral(
- node, aliasedType.element, nameNode, name, whyNotPromotedInfo);
+ node, aliasedType.element, nameNode, name, whyNotPromotedList);
return;
}
}
@@ -144,17 +144,17 @@
DartType receiverType = receiver.typeOrThrow;
if (_typeSystem.isDynamicBounded(receiverType)) {
- _resolveReceiverDynamicBounded(node, whyNotPromotedInfo);
+ _resolveReceiverDynamicBounded(node, whyNotPromotedList);
return;
}
if (receiverType is NeverTypeImpl) {
- _resolveReceiverNever(node, receiver, receiverType, whyNotPromotedInfo);
+ _resolveReceiverNever(node, receiver, receiverType, whyNotPromotedList);
return;
}
if (receiverType is VoidType) {
- _reportUseOfVoidType(node, receiver, whyNotPromotedInfo);
+ _reportUseOfVoidType(node, receiver, whyNotPromotedList);
return;
}
@@ -165,7 +165,7 @@
if (_typeSystem.isFunctionBounded(receiverType)) {
_resolveReceiverFunctionBounded(
- node, receiver, receiverType, nameNode, name, whyNotPromotedInfo);
+ node, receiver, receiverType, nameNode, name, whyNotPromotedList);
return;
}
@@ -176,7 +176,7 @@
nameNode: nameNode,
name: name,
receiverErrorNode: receiver,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
@@ -217,9 +217,9 @@
}
void _reportInvocationOfNonFunction(MethodInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
_setDynamicResolution(node,
- setNameTypeToDynamic: false, whyNotPromotedInfo: whyNotPromotedInfo);
+ setNameTypeToDynamic: false, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION,
node.methodName,
@@ -251,9 +251,9 @@
required String? prefix,
required String name,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
if (nameScope.shouldIgnoreUndefined2(prefix: prefix, name: name)) {
return;
@@ -270,8 +270,8 @@
MethodInvocationImpl node,
String name,
ClassElement typeReference,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_METHOD,
node.methodName,
@@ -280,8 +280,8 @@
}
void _reportUseOfVoidType(MethodInvocationImpl node, AstNode errorNode,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.USE_OF_VOID_RESULT,
errorNode,
@@ -291,19 +291,19 @@
/// [InvocationExpression.staticInvokeType] has been set for the [node].
/// Use it to set context for arguments, and resolve them.
void _resolveArguments(MethodInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
// TODO(scheglov) This is bad, don't write raw type, carry it
_inferenceHelper.inferArgumentTypesForInvocation(
node,
node.methodName.staticType,
);
_resolver.visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
void _resolveArguments_finishInference(MethodInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
- _resolveArguments(node, whyNotPromotedInfo);
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
+ _resolveArguments(node, whyNotPromotedList);
// TODO(scheglov) This is bad, don't put / get raw FunctionType this way.
_inferenceHelper.inferGenericInvocationExpression(
@@ -341,7 +341,7 @@
ExtensionElement extension,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var getter = extension.getGetter(name);
if (getter != null) {
getter = _resolver.toLegacyElement(getter);
@@ -356,11 +356,11 @@
method = _resolver.toLegacyElement(method);
nameNode.staticElement = method;
_reportStaticAccessToInstanceMember(method, nameNode);
- _setResolution(node, method.type, whyNotPromotedInfo);
+ _setResolution(node, method.type, whyNotPromotedList);
return;
}
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD,
nameNode,
@@ -373,12 +373,12 @@
ExtensionOverride override,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var result = _extensionResolver.getOverrideMember(override, name);
var member = _resolver.toLegacyElement(result.getter);
if (member == null) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_EXTENSION_METHOD,
nameNode,
@@ -408,11 +408,11 @@
return _rewriteAsFunctionExpressionInvocation(node, member.returnType);
}
- _setResolution(node, member.type, whyNotPromotedInfo);
+ _setResolution(node, member.type, whyNotPromotedList);
}
void _resolveReceiverDynamicBounded(MethodInvocationImpl node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var nameNode = node.methodName;
var objectElement = _typeSystem.typeProvider.objectElement;
@@ -439,7 +439,7 @@
_setExplicitTypeArgumentTypes();
_resolver.visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
}
void _resolveReceiverFunctionBounded(
@@ -448,10 +448,10 @@
DartType receiverType,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
if (name == FunctionElement.CALL_METHOD_NAME) {
- _setResolution(node, receiverType, whyNotPromotedInfo);
+ _setResolution(node, receiverType, whyNotPromotedList);
// TODO(scheglov) Replace this with using FunctionType directly.
// Here was erase resolution that _setResolution() sets.
nameNode.staticElement = null;
@@ -466,7 +466,7 @@
nameNode: nameNode,
name: name,
receiverErrorNode: nameNode,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
@@ -474,7 +474,7 @@
MethodInvocationImpl node,
Expression receiver,
DartType receiverType,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
_setExplicitTypeArgumentTypes();
@@ -488,10 +488,10 @@
_setResolution(
node,
objectMember.type,
- whyNotPromotedInfo,
+ whyNotPromotedList,
);
} else {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.nullableDereferenceVerifier.report(receiver, receiverType,
errorCode: CompileTimeErrorCode
.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE);
@@ -504,7 +504,7 @@
node.staticInvokeType = _dynamicType;
node.staticType = NeverTypeImpl.instance;
- _resolveArguments(node, whyNotPromotedInfo);
+ _resolveArguments(node, whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
HintCode.RECEIVER_OF_TYPE_NEVER,
@@ -518,7 +518,7 @@
node.staticInvokeType = _dynamicType;
node.staticType = _dynamicType;
- _resolveArguments(node, whyNotPromotedInfo);
+ _resolveArguments(node, whyNotPromotedList);
return;
}
}
@@ -527,7 +527,7 @@
MethodInvocationImpl node,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var element = nameScope.lookup(name).getter;
if (element != null) {
element = _resolver.toLegacyElement(element);
@@ -540,7 +540,7 @@
return _rewriteAsFunctionExpressionInvocation(node, element.returnType);
}
if (element is ExecutableElement) {
- return _setResolution(node, element.type, whyNotPromotedInfo);
+ return _setResolution(node, element.type, whyNotPromotedList);
}
if (element is VariableElement) {
_resolver.checkReadOfNotAssignedLocalVariable(nameNode, element);
@@ -549,10 +549,10 @@
}
// TODO(scheglov) This is a questionable distinction.
if (element is PrefixElement) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
return _reportPrefixIdentifierNotFollowedByDot(nameNode);
}
- return _reportInvocationOfNonFunction(node, whyNotPromotedInfo);
+ return _reportInvocationOfNonFunction(node, whyNotPromotedList);
}
DartType receiverType;
@@ -565,7 +565,7 @@
node,
prefix: null,
name: node.methodName.name,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
@@ -576,7 +576,7 @@
nameNode: nameNode,
name: name,
receiverErrorNode: nameNode,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
@@ -585,7 +585,7 @@
PrefixElement prefix,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
// Note: prefix?.bar is reported as an error in ElementResolver.
if (name == FunctionElement.LOAD_LIBRARY_NAME) {
@@ -597,7 +597,7 @@
if (element is ExecutableElement) {
nameNode.staticElement = element;
return _setResolution(
- node, (element as ExecutableElement).type, whyNotPromotedInfo);
+ node, (element as ExecutableElement).type, whyNotPromotedList);
}
}
}
@@ -616,14 +616,14 @@
}
if (element is ExecutableElement) {
- return _setResolution(node, element.type, whyNotPromotedInfo);
+ return _setResolution(node, element.type, whyNotPromotedList);
}
_reportUndefinedFunction(
node,
prefix: prefix.name,
name: name,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromotedList: whyNotPromotedList,
);
}
@@ -632,10 +632,10 @@
SuperExpression receiver,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var enclosingClass = _resolver.enclosingClass;
if (SuperContext.of(receiver) != SuperContext.valid) {
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
return;
}
@@ -652,7 +652,7 @@
if (target is PropertyAccessorElement) {
return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
}
- _setResolution(node, target.type, whyNotPromotedInfo);
+ _setResolution(node, target.type, whyNotPromotedList);
return;
}
@@ -662,7 +662,7 @@
target = _inheritance.getInherited2(enclosingClass, _currentName!);
if (target != null) {
nameNode.staticElement = target;
- _setResolution(node, target.type, whyNotPromotedInfo);
+ _setResolution(node, target.type, whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
@@ -672,7 +672,7 @@
}
// Nothing help, there is no target at all.
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.UNDEFINED_SUPER_METHOD,
nameNode,
@@ -687,7 +687,7 @@
required String name,
required Expression receiverErrorNode,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo,
+ whyNotPromotedList,
}) {
var result = _resolver.typePropertyResolver.resolve(
receiver: receiver,
@@ -712,10 +712,10 @@
if (target is PropertyAccessorElement) {
return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
}
- return _setResolution(node, target.type, whyNotPromotedInfo);
+ return _setResolution(node, target.type, whyNotPromotedList);
}
- _setDynamicResolution(node, whyNotPromotedInfo: whyNotPromotedInfo);
+ _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
if (!result.needsGetterError) {
return;
@@ -742,7 +742,7 @@
ClassElement receiver,
SimpleIdentifierImpl nameNode,
String name,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
if (node.isCascaded) {
receiver = _typeType.element;
}
@@ -756,14 +756,14 @@
return _rewriteAsFunctionExpressionInvocation(
node, element.returnType);
}
- _setResolution(node, element.type, whyNotPromotedInfo);
+ _setResolution(node, element.type, whyNotPromotedList);
} else {
- _reportInvocationOfNonFunction(node, whyNotPromotedInfo);
+ _reportInvocationOfNonFunction(node, whyNotPromotedList);
}
return;
}
- _reportUndefinedMethod(node, name, receiver, whyNotPromotedInfo);
+ _reportUndefinedMethod(node, name, receiver, whyNotPromotedList);
}
/// If the given [type] is a type parameter, replace with its bound.
@@ -825,14 +825,14 @@
void _setDynamicResolution(MethodInvocationImpl node,
{bool setNameTypeToDynamic = true,
required List<Map<DartType, NonPromotionReason> Function()>
- whyNotPromotedInfo}) {
+ whyNotPromotedList}) {
if (setNameTypeToDynamic) {
node.methodName.staticType = _dynamicType;
}
node.staticInvokeType = _dynamicType;
node.staticType = _dynamicType;
_setExplicitTypeArgumentTypes();
- _resolveArguments_finishInference(node, whyNotPromotedInfo);
+ _resolveArguments_finishInference(node, whyNotPromotedList);
}
/// Set explicitly specified type argument types, or empty if not specified.
@@ -852,28 +852,28 @@
}
void _setResolution(MethodInvocationImpl node, DartType type,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
// TODO(scheglov) We need this for StaticTypeAnalyzer to run inference.
// But it seems weird. Do we need to know the raw type of a function?!
node.methodName.staticType = type;
if (type == _dynamicType || _isCoreFunction(type)) {
_setDynamicResolution(node,
- setNameTypeToDynamic: false, whyNotPromotedInfo: whyNotPromotedInfo);
+ setNameTypeToDynamic: false, whyNotPromotedList: whyNotPromotedList);
return;
}
if (type is FunctionType) {
_inferenceHelper.resolveMethodInvocation(
- node: node, rawType: type, whyNotPromotedInfo: whyNotPromotedInfo);
+ node: node, rawType: type, whyNotPromotedList: whyNotPromotedList);
return;
}
if (type is VoidType) {
- return _reportUseOfVoidType(node, node.methodName, whyNotPromotedInfo);
+ return _reportUseOfVoidType(node, node.methodName, whyNotPromotedList);
}
- _reportInvocationOfNonFunction(node, whyNotPromotedInfo);
+ _reportInvocationOfNonFunction(node, whyNotPromotedList);
}
/// Resolver visitor is separated from the elements resolver, which calls
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 666cce9..91d1ae7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -1193,6 +1193,10 @@
visitTypeName(typeName);
_typeNameResolver.classHierarchy_typeName = null;
+ if (_typeNameResolver.hasErrorReported) {
+ return;
+ }
+
DartType type = typeName.typeOrThrow;
if (type is InterfaceType) {
ClassElement element = type.element;
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
index c4c1dfe..4acea06 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_name_resolver.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -52,6 +53,9 @@
/// [ConstructorName]. Otherwise this field will be set `null`.
ConstructorName? rewriteResult;
+ /// If [resolveTypeName] reported an error, this flag is set to `true`.
+ bool hasErrorReported = false;
+
TypeNameResolver(this.typeSystem, TypeProvider typeProvider,
this.isNonNullableByDefault, this.errorReporter)
: dynamicType = typeProvider.dynamicType;
@@ -71,6 +75,7 @@
/// The client must set [nameScope] before calling [resolveTypeName].
void resolveTypeName(TypeNameImpl node) {
rewriteResult = null;
+ hasErrorReported = false;
var typeIdentifier = node.name;
if (typeIdentifier is PrefixedIdentifierImpl) {
@@ -386,11 +391,50 @@
TypeAliasElement element,
DartType type,
) {
+ // If a type alias that expands to a type parameter.
if (element.aliasedType is TypeParameterType) {
- var constructorName = node.parent;
- if (constructorName is ConstructorName) {
- _ErrorHelper(errorReporter)
- .reportTypeAliasExpandsToTypeParameter(constructorName, element);
+ var parent = node.parent;
+ if (parent is ConstructorName) {
+ var errorNode = _ErrorHelper._getErrorNode(node);
+ var constructorUsage = parent.parent;
+ if (constructorUsage is InstanceCreationExpression) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .INSTANTIATE_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ errorNode,
+ );
+ } else if (constructorUsage is ConstructorDeclaration &&
+ constructorUsage.redirectedConstructor == parent) {
+ errorReporter.reportErrorForNode(
+ CompileTimeErrorCode
+ .REDIRECT_TO_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ errorNode,
+ );
+ } else {
+ throw UnimplementedError('${constructorUsage.runtimeType}');
+ }
+ return dynamicType;
+ }
+
+ // Report if this type is used as a class in hierarchy.
+ ErrorCode? errorCode;
+ if (parent is ExtendsClause) {
+ errorCode =
+ CompileTimeErrorCode.EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER;
+ } else if (parent is ImplementsClause) {
+ errorCode = CompileTimeErrorCode
+ .IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER;
+ } else if (parent is OnClause) {
+ errorCode =
+ CompileTimeErrorCode.MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER;
+ } else if (parent is WithClause) {
+ errorCode =
+ CompileTimeErrorCode.MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER;
+ }
+ if (errorCode != null) {
+ var errorNode = _ErrorHelper._getErrorNode(node);
+ errorReporter.reportErrorForNode(errorCode, errorNode);
+ hasErrorReported = true;
return dynamicType;
}
}
@@ -550,28 +594,6 @@
);
}
- void reportTypeAliasExpandsToTypeParameter(
- ConstructorName constructorName,
- TypeAliasElement element,
- ) {
- var errorNode = _getErrorNode(constructorName.type);
- var constructorUsage = constructorName.parent;
- if (constructorUsage is InstanceCreationExpression) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INSTANTIATE_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
- errorNode,
- );
- } else if (constructorUsage is ConstructorDeclaration &&
- constructorUsage.redirectedConstructor == constructorName) {
- errorReporter.reportErrorForNode(
- CompileTimeErrorCode.REDIRECT_TO_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
- errorNode,
- );
- } else {
- throw UnimplementedError('${constructorUsage.runtimeType}');
- }
- }
-
/// Returns the simple identifier of the given (maybe prefixed) identifier.
static Identifier _getErrorNode(TypeName node) {
Identifier identifier = node.name;
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 05a61d7..6218be8 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -3384,6 +3384,15 @@
hasPublishedDocs: true,
isUnresolvedIdentifier: true);
+ static const CompileTimeErrorCode
+ EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER = CompileTimeErrorCode(
+ 'EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
+ "Type aliases that expand to a type parameter can't be used as "
+ "superclasses.",
+ correction:
+ "Try specifying a different superclass, or removing the extends "
+ "clause.");
+
/**
* Parameters:
* 0: the name of the extension
@@ -4913,6 +4922,12 @@
correction: "Try removing one of the occurrences.",
hasPublishedDocs: true);
+ static const CompileTimeErrorCode
+ IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER = CompileTimeErrorCode(
+ 'IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
+ "Type aliases that expand to a type parameter can't be implemented.",
+ correction: "Try specifying a class or mixin, or removing the list.");
+
/**
* Parameters:
* 0: the name of the instance member
@@ -7292,6 +7307,17 @@
'MIXIN_OF_NON_CLASS', "Classes can only mix in mixins and classes.",
hasPublishedDocs: true);
+ static const CompileTimeErrorCode
+ MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER = CompileTimeErrorCode(
+ 'MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
+ "Type aliases that expand to a type parameter can't be mixed in.");
+
+ static const CompileTimeErrorCode
+ MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER = CompileTimeErrorCode(
+ 'MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER',
+ "Type aliases that expand to a type parameter can't be used as"
+ "superclass constraints.");
+
/**
* No parameters.
*/
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 9b9b7af..a43c330 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -26,7 +26,6 @@
messageMissingAssignableSelector,
messageNativeClauseShouldBeAnnotation,
messageOperatorWithTypeParameters,
- messageTypedefNotFunction,
templateDuplicateLabelInSwitchStatement,
templateExpectedButGot,
templateExpectedIdentifier,
@@ -1549,7 +1548,15 @@
var metadata = pop() as List<Annotation>?;
var comment = _findComment(metadata, typedefKeyword);
if (type is! GenericFunctionType && !enableNonFunctionTypeAliases) {
- handleRecoverableError(messageTypedefNotFunction, equals, equals);
+ var feature = Feature.nonfunction_type_aliases;
+ handleRecoverableError(
+ templateExperimentNotEnabled.withArguments(
+ feature.enableString,
+ _versionAsString(ExperimentStatus.currentVersion),
+ ),
+ equals,
+ equals,
+ );
}
declarations.add(ast.genericTypeAlias(comment, metadata, typedefKeyword,
name, templateParameters, equals, type, semicolon));
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 423b5df..ed9e40f 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -397,10 +397,10 @@
@override
void visitMethodInvocation(MethodInvocation node,
{List<Map<DartType, NonPromotionReason> Function()>?
- whyNotPromotedInfo}) {
- whyNotPromotedInfo ??= [];
+ whyNotPromotedList}) {
+ whyNotPromotedList ??= [];
_methodInvocationResolver.resolve(
- node as MethodInvocationImpl, whyNotPromotedInfo);
+ node as MethodInvocationImpl, whyNotPromotedList);
}
@override
diff --git a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
index ff05271..350899c 100644
--- a/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
+++ b/pkg/analyzer/lib/src/generated/error_detection_helpers.dart
@@ -32,7 +32,7 @@
DartType? expectedStaticType,
DartType actualStaticType,
ErrorCode errorCode,
- {Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo}) {
+ {Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
// Warning case: test static type information
if (expectedStaticType != null) {
if (!expectedStaticType.isVoid && checkForUseOfVoidResult(expression)) {
@@ -41,7 +41,7 @@
_checkForAssignableExpressionAtType(
expression, actualStaticType, expectedStaticType, errorCode,
- whyNotPromoted: whyNotPromotedInfo);
+ whyNotPromoted: whyNotPromoted);
}
}
@@ -54,12 +54,12 @@
/// See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
void checkForArgumentTypeNotAssignableForArgument(Expression argument,
{bool promoteParameterToNullable = false,
- Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo}) {
+ Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
checkForArgumentTypeNotAssignableForArgument2(
argument: argument,
parameter: argument.staticParameterElement,
promoteParameterToNullable: promoteParameterToNullable,
- whyNotPromotedInfo: whyNotPromotedInfo,
+ whyNotPromoted: whyNotPromoted,
);
}
@@ -67,7 +67,7 @@
required Expression argument,
required ParameterElement? parameter,
required bool promoteParameterToNullable,
- Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo,
+ Map<DartType, NonPromotionReason> Function()? whyNotPromoted,
}) {
var staticParameterType = parameter?.type;
if (promoteParameterToNullable && staticParameterType != null) {
@@ -78,7 +78,7 @@
argument,
staticParameterType,
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
- whyNotPromotedInfo);
+ whyNotPromoted);
}
/// Verify that the given constructor field [initializer] has compatible field
@@ -247,10 +247,10 @@
Expression expression,
DartType? expectedStaticType,
ErrorCode errorCode,
- Map<DartType, NonPromotionReason> Function()? whyNotPromotedInfo) {
+ Map<DartType, NonPromotionReason> Function()? whyNotPromoted) {
checkForArgumentTypeNotAssignable(
expression, expectedStaticType, expression.typeOrThrow, errorCode,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromoted: whyNotPromoted);
}
bool _checkForAssignableExpression(
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index e8136ea..16387ea 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -345,12 +345,6 @@
void visitAssignmentExpression(AssignmentExpression node) {
TokenType operatorType = node.operator.type;
Expression lhs = node.leftHandSide;
- Expression rhs = node.rightHandSide;
- if (operatorType == TokenType.EQ ||
- operatorType == TokenType.QUESTION_QUESTION_EQ) {
- } else {
- checkForArgumentTypeNotAssignableForArgument(rhs);
- }
if (operatorType == TokenType.QUESTION_QUESTION_EQ) {
_checkForDeadNullCoalesce(node.readType as TypeImpl, node.rightHandSide);
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index e011889..5684e0e 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -428,12 +428,12 @@
///
/// See [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE].
void checkForArgumentTypesNotAssignableInList(ArgumentList argumentList,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo) {
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList) {
var arguments = argumentList.arguments;
for (int i = 0; i < arguments.length; i++) {
checkForArgumentTypeNotAssignableForArgument(arguments[i],
- whyNotPromotedInfo:
- flowAnalysis?.flow == null ? null : whyNotPromotedInfo[i]);
+ whyNotPromoted:
+ flowAnalysis?.flow == null ? null : whyNotPromotedList[i]);
}
}
@@ -882,25 +882,25 @@
@override
void visitAnnotation(covariant AnnotationImpl node) {
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
AstNode parent = node.parent;
if (identical(parent, _enclosingClassDeclaration) ||
identical(parent, _enclosingFunctionTypeAlias) ||
identical(parent, _enclosingMixinDeclaration)) {
return;
}
- AnnotationResolver(this).resolve(node, whyNotPromotedInfo);
+ AnnotationResolver(this).resolve(node, whyNotPromotedList);
var arguments = node.arguments;
if (arguments != null) {
- checkForArgumentTypesNotAssignableInList(arguments, whyNotPromotedInfo);
+ checkForArgumentTypesNotAssignableInList(arguments, whyNotPromotedList);
}
}
@override
void visitArgumentList(ArgumentList node,
{bool isIdentical = false,
- List<Map<DartType, NonPromotionReason> Function()>? whyNotPromotedInfo}) {
- whyNotPromotedInfo ??= [];
+ List<Map<DartType, NonPromotionReason> Function()>? whyNotPromotedList}) {
+ whyNotPromotedList ??= [];
var callerType = InferenceContext.getContext(node);
NodeList<Expression> arguments = node.arguments;
if (callerType is FunctionType) {
@@ -967,7 +967,7 @@
}
arguments[i].accept(this);
if (flow != null) {
- whyNotPromotedInfo.add(flow.whyNotPromoted(arguments[i]));
+ whyNotPromotedList.add(flow.whyNotPromoted(arguments[i]));
}
}
if (isIdentical && length > 1) {
@@ -1444,13 +1444,13 @@
@override
void visitExtensionOverride(ExtensionOverride node) {
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
node.extensionName.accept(this);
node.typeArguments?.accept(this);
ExtensionMemberResolver(this).setOverrideReceiverContextType(node);
visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -1567,13 +1567,13 @@
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
node.function.accept(this);
_functionExpressionInvocationResolver.resolve(
- node as FunctionExpressionInvocationImpl, whyNotPromotedInfo);
+ node as FunctionExpressionInvocationImpl, whyNotPromotedList);
nullShortingTermination(node);
checkForArgumentTypesNotAssignableInList(
- node.argumentList, whyNotPromotedInfo);
+ node.argumentList, whyNotPromotedList);
}
@override
@@ -1719,15 +1719,15 @@
@override
void visitInstanceCreationExpression(
covariant InstanceCreationExpressionImpl node) {
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
node.constructorName.accept(this);
_inferArgumentTypesForInstanceCreate(node);
visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
node.accept(elementResolver);
node.accept(typeAnalyzer);
checkForArgumentTypesNotAssignableInList(
- node.argumentList, whyNotPromotedInfo);
+ node.argumentList, whyNotPromotedList);
}
@override
@@ -1792,7 +1792,7 @@
@override
void visitMethodInvocation(covariant MethodInvocationImpl node) {
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
var target = node.target;
target?.accept(this);
@@ -1812,18 +1812,18 @@
node.typeArguments?.accept(this);
elementResolver.visitMethodInvocation(node,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
var functionRewrite = MethodInvocationResolver.getRewriteResult(node);
if (functionRewrite != null) {
nullShortingTermination(node, discardType: true);
_resolveRewrittenFunctionExpressionInvocation(
- functionRewrite, whyNotPromotedInfo);
+ functionRewrite, whyNotPromotedList);
} else {
nullShortingTermination(node);
}
checkForArgumentTypesNotAssignableInList(
- node.argumentList, whyNotPromotedInfo);
+ node.argumentList, whyNotPromotedList);
}
@override
@@ -1940,14 +1940,14 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
node.accept(elementResolver);
InferenceContext.setType(node.argumentList, node.staticElement?.type);
visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
node.accept(typeAnalyzer);
checkForArgumentTypesNotAssignableInList(
- node.argumentList, whyNotPromotedInfo);
+ node.argumentList, whyNotPromotedList);
}
@override
@@ -2001,14 +2001,14 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
- var whyNotPromotedInfo = <Map<DartType, NonPromotionReason> Function()>[];
+ var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
node.accept(elementResolver);
InferenceContext.setType(node.argumentList, node.staticElement?.type);
visitArgumentList(node.argumentList,
- whyNotPromotedInfo: whyNotPromotedInfo);
+ whyNotPromotedList: whyNotPromotedList);
node.accept(typeAnalyzer);
checkForArgumentTypesNotAssignableInList(
- node.argumentList, whyNotPromotedInfo);
+ node.argumentList, whyNotPromotedList);
}
@override
@@ -2316,7 +2316,7 @@
/// as for method invocations.
void _resolveRewrittenFunctionExpressionInvocation(
FunctionExpressionInvocation node,
- List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedInfo,
+ List<Map<DartType, NonPromotionReason> Function()> whyNotPromotedList,
) {
var function = node.function;
@@ -2334,7 +2334,7 @@
}
_functionExpressionInvocationResolver.resolve(
- node as FunctionExpressionInvocationImpl, whyNotPromotedInfo);
+ node as FunctionExpressionInvocationImpl, whyNotPromotedList);
nullShortingTermination(node);
}
diff --git a/pkg/analyzer/test/generated/error_parser_test.dart b/pkg/analyzer/test/generated/error_parser_test.dart
index c7b7232..9115cc0 100644
--- a/pkg/analyzer/test/generated/error_parser_test.dart
+++ b/pkg/analyzer/test/generated/error_parser_test.dart
@@ -1698,7 +1698,7 @@
errors: [
expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 7),
expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 7),
- expectedError(ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 10, 1),
+ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 10, 1),
]);
}
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index ceb6903..402d7cc 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -3311,7 +3311,7 @@
p is F;
}
''', [
- error(ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 10, 1),
+ error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 10, 1),
]);
}
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 080532a..8251b43 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -552,6 +552,20 @@
assertThat(element).isReferencedAt('A();', false);
}
+ test_isReferencedBy_ClassElement_inGenericAnnotation() async {
+ await _indexTestUnit('''
+class A<T> {
+ const A();
+}
+
+@A<A>()
+void f() {}
+''');
+ assertThat(findElement.class_('A'))
+ ..isReferencedAt('A<A', false)
+ ..isReferencedAt('A>()', false);
+ }
+
test_isReferencedBy_ClassElement_inTypeAlias() async {
await _indexTestUnit('''
class A<T> {}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index b053a6f..10ac334 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -303,6 +303,25 @@
await _verifyReferences(element, expected);
}
+ test_searchReferences_ClassElement_typeArgument_ofGenericAnnotation() async {
+ await resolveTestCode('''
+class A<T> {
+ const A();
+}
+
+class B {}
+
+@A<B>()
+void f() {}
+''');
+
+ var element = findElement.class_('B');
+ var f = findElement.topFunction('f');
+ await _verifyReferences(element, [
+ _expectId(f, SearchResultKind.REFERENCE, 'B>()'),
+ ]);
+ }
+
test_searchReferences_CompilationUnitElement() async {
newFile('$testPackageLibPath/foo.dart');
await resolveTestCode('''
diff --git a/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
new file mode 100644
index 0000000..07eeb68
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/experiment_not_enabled_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ExperimentNotEnabledTest);
+ });
+}
+
+@reflectiveTest
+class ExperimentNotEnabledTest extends PubPackageResolutionTest {
+ test_nonFunctionTypeAliases_disabled() async {
+ await assertErrorsInCode(r'''
+// @dart = 2.12
+typedef A = int;
+''', [
+ error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 26, 1),
+ ]);
+ }
+
+ test_nonFunctionTypeAliases_disabled_nullable() async {
+ await assertErrorsInCode(r'''
+// @dart = 2.12
+typedef A = int?;
+''', [
+ error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 26, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extends_non_class_test.dart b/pkg/analyzer/test/src/diagnostics/extends_non_class_test.dart
index 95db122..ab697b0 100644
--- a/pkg/analyzer/test/src/diagnostics/extends_non_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/extends_non_class_test.dart
@@ -10,13 +10,19 @@
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ExtendsNonClassTest);
- defineReflectiveTests(ExtendsNonClassWithNullSafetyTest);
});
}
@reflectiveTest
-class ExtendsNonClassTest extends PubPackageResolutionTest
- with WithoutNullSafetyMixin {
+class ExtendsNonClassTest extends PubPackageResolutionTest {
+ test_Never() async {
+ await assertErrorsInCode('''
+class A extends Never {}
+''', [
+ error(CompileTimeErrorCode.EXTENDS_NON_CLASS, 16, 5),
+ ]);
+ }
+
test_undefined() async {
await assertErrorsInCode(r'''
class C extends A {}
@@ -123,15 +129,3 @@
]);
}
}
-
-@reflectiveTest
-class ExtendsNonClassWithNullSafetyTest extends ExtendsNonClassTest
- with WithNullSafetyMixin {
- test_Never() async {
- await assertErrorsInCode('''
-class A extends Never {}
-''', [
- error(CompileTimeErrorCode.EXTENDS_NON_CLASS, 16, 5),
- ]);
- }
-}
diff --git a/pkg/analyzer/test/src/diagnostics/extends_type_alias_expands_to_type_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/extends_type_alias_expands_to_type_parameter_test.dart
new file mode 100644
index 0000000..9737d88
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/extends_type_alias_expands_to_type_parameter_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ExtendsTypeAliasExpandsToTypeParameterTest);
+ });
+}
+
+@reflectiveTest
+class ExtendsTypeAliasExpandsToTypeParameterTest
+ extends PubPackageResolutionTest {
+ test_class() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+typedef T = A;
+class B extends A {}
+''');
+ }
+
+ test_class_noTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B extends T {}
+''', [
+ error(CompileTimeErrorCode.EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 55, 1),
+ ]);
+ }
+
+ test_class_withTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B extends T<A> {}
+''', [
+ error(CompileTimeErrorCode.EXTENDS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 55, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/implements_type_alias_expands_to_type_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/implements_type_alias_expands_to_type_parameter_test.dart
new file mode 100644
index 0000000..2810170
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/implements_type_alias_expands_to_type_parameter_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ImplementsTypeAliasExpandsToTypeParameterTest);
+ });
+}
+
+@reflectiveTest
+class ImplementsTypeAliasExpandsToTypeParameterTest
+ extends PubPackageResolutionTest {
+ test_class() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+typedef T = A;
+class B implements T {}
+''');
+ }
+
+ test_class_typeParameter_noTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B implements T {}
+''', [
+ error(
+ CompileTimeErrorCode.IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 58,
+ 1),
+ ]);
+ }
+
+ test_class_typeParameter_withTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B implements T<A> {}
+''', [
+ error(
+ CompileTimeErrorCode.IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 58,
+ 1),
+ ]);
+ }
+
+ test_mixin_typeParameter_noTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+mixin M implements T {}
+''', [
+ error(
+ CompileTimeErrorCode.IMPLEMENTS_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 58,
+ 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_of_type_alias_expands_to_type_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_of_type_alias_expands_to_type_parameter_test.dart
new file mode 100644
index 0000000..558e767
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/mixin_of_type_alias_expands_to_type_parameter_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MixinOfTypeAliasExpandsToTypeParameterTest);
+ });
+}
+
+@reflectiveTest
+class MixinOfTypeAliasExpandsToTypeParameterTest
+ extends PubPackageResolutionTest {
+ test_class() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+typedef T = A;
+class B with A {}
+''');
+ }
+
+ test_class_noTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B with T {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 52, 1),
+ ]);
+ }
+
+ test_class_withTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+class B with T<A> {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_OF_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 52, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_on_type_alias_expands_to_type_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_on_type_alias_expands_to_type_parameter_test.dart
new file mode 100644
index 0000000..26be464
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/mixin_on_type_alias_expands_to_type_parameter_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(MixinOnTypeAliasExpandsToTypeParameterTest);
+ });
+}
+
+@reflectiveTest
+class MixinOnTypeAliasExpandsToTypeParameterTest
+ extends PubPackageResolutionTest {
+ test_class() async {
+ await assertNoErrorsInCode(r'''
+class A {}
+typedef T = A;
+mixin M on A {}
+''');
+ }
+
+ test_class_noTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+mixin M on T {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 50, 1),
+ ]);
+ }
+
+ test_class_withTypeArguments() async {
+ await assertErrorsInCode(r'''
+class A {}
+typedef T<X extends A> = X;
+mixin M on T<A> {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_ON_TYPE_ALIAS_EXPANDS_TO_TYPE_PARAMETER,
+ 50, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 02c71dc..a227e93 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -147,6 +147,7 @@
as expected_one_set_type_arguments;
import 'expected_two_map_type_arguments_test.dart'
as expected_two_map_type_arguments;
+import 'experiment_not_enabled_test.dart' as experiment_not_enabled;
import 'export_internal_library_test.dart' as export_internal_library;
import 'export_legacy_symbol_test.dart' as export_legacy_symbol;
import 'export_of_non_library_test.dart' as export_of_non_library;
@@ -154,6 +155,8 @@
import 'extends_deferred_class_test.dart' as extends_deferred_class;
import 'extends_disallowed_class_test.dart' as extends_disallowed_class;
import 'extends_non_class_test.dart' as extends_non_class;
+import 'extends_type_alias_expands_to_type_parameter_test.dart'
+ as extends_type_alias_expands_to_type_parameter;
import 'extension_as_expression_test.dart' as extension_as_expression;
import 'extension_conflicting_static_and_instance_test.dart'
as extension_conflicting_static_and_instance;
@@ -229,6 +232,8 @@
import 'implements_disallowed_class_test.dart' as implements_disallowed_class;
import 'implements_non_class_test.dart' as implements_non_class;
import 'implements_super_class_test.dart' as implements_super_class;
+import 'implements_type_alias_expands_to_type_parameter_test.dart'
+ as implements_type_alias_expands_to_type_parameter;
import 'implicit_this_reference_in_initializer_test.dart'
as implicit_this_reference_in_initializer;
import 'import_deferred_library_with_load_function_test.dart'
@@ -391,7 +396,11 @@
as mixin_inherits_from_not_object;
import 'mixin_of_disallowed_class_test.dart' as mixin_of_disallowed_class;
import 'mixin_of_non_class_test.dart' as mixin_of_non_class;
+import 'mixin_of_type_alias_expands_to_type_parameter_test.dart'
+ as mixin_of_type_alias_expands_to_type_parameter;
import 'mixin_on_sealed_class_test.dart' as mixin_on_sealed_class;
+import 'mixin_on_type_alias_expands_to_type_parameter_test.dart'
+ as mixin_on_type_alias_expands_to_type_parameter;
import 'mixin_super_class_constraint_non_interface_test.dart'
as mixin_super_class_constraint_non_interface;
import 'mixin_with_non_class_superclass_test.dart'
@@ -776,6 +785,7 @@
expected_one_list_type_arguments.main();
expected_one_set_type_arguments.main();
expected_two_map_type_arguments.main();
+ experiment_not_enabled.main();
export_internal_library.main();
export_legacy_symbol.main();
export_of_non_library.main();
@@ -783,6 +793,7 @@
extends_deferred_class.main();
extends_disallowed_class.main();
extends_non_class.main();
+ extends_type_alias_expands_to_type_parameter.main();
extension_as_expression.main();
extension_conflicting_static_and_instance.main();
extension_declares_abstract_method.main();
@@ -828,6 +839,7 @@
implements_disallowed_class.main();
implements_non_class.main();
implements_super_class.main();
+ implements_type_alias_expands_to_type_parameter.main();
implicit_this_reference_in_initializer.main();
import_deferred_library_with_load_function.main();
import_internal_library.main();
@@ -931,7 +943,9 @@
mixin_inherits_from_not_object.main();
mixin_of_disallowed_class.main();
mixin_of_non_class.main();
+ mixin_of_type_alias_expands_to_type_parameter.main();
mixin_on_sealed_class.main();
+ mixin_on_type_alias_expands_to_type_parameter.main();
mixin_super_class_constraint_non_interface.main();
mixin_with_non_class_superclass.main();
mixins_super_class.main();
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/typedef_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/typedef_test.dart
index fc7f670..bd6536c 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/typedef_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/typedef_test.dart
@@ -50,11 +50,11 @@
[
ParserErrorCode.EXPECTED_TYPE_NAME,
ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE
+ ParserErrorCode.EXPERIMENT_NOT_ENABLED
],
"typedef T = _s_;",
expectedErrorsInValidCode: [
- ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE
+ ParserErrorCode.EXPERIMENT_NOT_ENABLED
],
failing: ['functionVoid', 'functionNonVoid', 'getter', 'mixin']),
],
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 1a8fcb0..4134ed6 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -182,6 +182,8 @@
computer._addRegionForNode(name, element);
}
computer._addRegionForNode(node.constructorName, element);
+ // type arguments
+ node.typeArguments?.accept(this);
// arguments
node.arguments?.accept(this);
}
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 761427f..aff886a 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -652,7 +652,7 @@
}
var fragmentsToLoad =
- compiler.backendStrategy.emitterTask.emitter.fragmentsToLoad;
+ compiler.backendStrategy.emitterTask.emitter.finalizedFragmentsToLoad;
var fragmentMerger =
compiler.backendStrategy.emitterTask.emitter.fragmentMerger;
result.deferredFiles = fragmentMerger.computeDeferredMap(fragmentsToLoad);
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index 4815c6d..3b14775 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -21,7 +21,7 @@
import '../world.dart' show JClosedWorld;
import 'program_builder/program_builder.dart';
import 'startup_emitter/emitter.dart' as startup_js_emitter;
-import 'startup_emitter/fragment_merger.dart' as fragment_merger;
+import 'startup_emitter/fragment_merger.dart';
import 'metadata_collector.dart' show MetadataCollector;
import 'model.dart';
@@ -211,13 +211,13 @@
abstract class Emitter implements ModularEmitter {
Program get programForTesting;
- List<fragment_merger.PreFragment> get preDeferredFragmentsForTesting;
+ List<PreFragment> get preDeferredFragmentsForTesting;
/// A map of loadId to list of [FinalizedFragments].
- Map<String, List<fragment_merger.FinalizedFragment>> get fragmentsToLoad;
+ Map<String, List<FinalizedFragment>> get finalizedFragmentsToLoad;
/// The [FragmentMerger] itself.
- fragment_merger.FragmentMerger get fragmentMerger;
+ FragmentMerger get fragmentMerger;
/// Uses the [programBuilder] to generate a model of the program, emits
/// the program, and returns the size of the generated output.
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 5a878fb..17184dd 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -160,7 +160,7 @@
List<PreFragment> preDeferredFragmentsForTesting;
@override
- Map<String, List<FinalizedFragment>> fragmentsToLoad;
+ Map<String, List<FinalizedFragment>> finalizedFragmentsToLoad;
@override
FragmentMerger fragmentMerger;
@@ -206,9 +206,9 @@
}
return _task.measureSubtask('emit program', () {
var size = _emitter.emitProgram(program, codegenWorld);
- fragmentsToLoad = _emitter.fragmentsToLoad;
+ finalizedFragmentsToLoad = _emitter.finalizedFragmentsToLoad;
fragmentMerger = _emitter.fragmentMerger;
- fragmentsToLoad.values.forEach((fragments) {
+ finalizedFragmentsToLoad.values.forEach((fragments) {
_task.metrics.hunkListElements.add(fragments.length);
});
if (retainDataForTesting) {
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index f5f2d9a..83ccedd 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -713,8 +713,25 @@
var lazyInitializers = emitLazilyInitializedStatics(fragment);
// TODO(floitsch): only call emitNativeSupport if we need native.
var nativeSupport = emitNativeSupport(fragment);
- return PreFragment(
- fragment,
+ int size = 0;
+ if (estimateSize) {
+ var estimator = SizeEstimator();
+ estimator.visit(classPrototypes);
+ estimator.visit(closurePrototypes);
+ estimator.visit(inheritance);
+ estimator.visit(methodAliases);
+ estimator.visit(tearOffs);
+ estimator.visit(constants);
+ estimator.visit(typeRules);
+ estimator.visit(variances);
+ estimator.visit(staticNonFinalFields);
+ estimator.visit(lazyInitializers);
+ estimator.visit(nativeSupport);
+ size = estimator.charCount;
+ }
+ var emittedOutputUnit = EmittedOutputUnit(
+ fragment.outputUnit,
+ fragment.libraries,
classPrototypes,
closurePrototypes,
inheritance,
@@ -725,8 +742,8 @@
variances,
staticNonFinalFields,
lazyInitializers,
- nativeSupport,
- estimateSize);
+ nativeSupport);
+ return PreFragment(fragment.outputFileName, emittedOutputUnit, size);
}
js.Statement emitMainFragment(
@@ -832,8 +849,7 @@
return new js.Block(holderInits);
}
- js.Expression emitDeferredFragment(
- FinalizedFragment fragment, List<Holder> holders) {
+ js.Expression emitCodeFragment(CodeFragment fragment, List<Holder> holders) {
HolderCode holderCode =
emitHolders(holders, fragment.libraries, initializeEmptyHolders: false);
@@ -1876,10 +1892,11 @@
// array of hashes indexed by part.
// [deferredLoadHashes] may have missing entries to indicate empty parts.
void finalizeDeferredLoadingData(
- Map<String, List<FinalizedFragment>> fragmentsToLoad,
+ Map<String, List<CodeFragment>> codeFragmentsToLoad,
+ Map<CodeFragment, FinalizedFragment> codeFragmentMap,
Map<FinalizedFragment, String> deferredLoadHashes,
DeferredLoadingState deferredLoadingState) {
- if (fragmentsToLoad.isEmpty) return;
+ if (codeFragmentsToLoad.isEmpty) return;
Map<FinalizedFragment, int> fragmentIndexes = {};
List<String> fragmentUris = [];
@@ -1887,10 +1904,11 @@
List<js.Property> libraryPartsMapEntries = [];
- fragmentsToLoad
- .forEach((String loadId, List<FinalizedFragment> fragmentList) {
+ codeFragmentsToLoad
+ .forEach((String loadId, List<CodeFragment> codeFragments) {
List<js.Expression> indexes = [];
- for (FinalizedFragment fragment in fragmentList) {
+ for (var codeFragment in codeFragments) {
+ var fragment = codeFragmentMap[codeFragment];
String fragmentHash = deferredLoadHashes[fragment];
if (fragmentHash == null) continue;
int index = fragmentIndexes[fragment];
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
index 2a80113..8eefc10 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
@@ -9,85 +9,172 @@
import '../../elements/entities.dart';
import '../../deferred_load.dart' show OutputUnit;
import '../../js/js.dart' as js;
-import '../../js/size_estimator.dart';
import '../../options.dart';
import '../model.dart';
+/// This file contains a number of abstractions used by dart2js for emitting and
+/// merging deferred fragments.
+///
+/// The initial deferred loading algorithm breaks a program up into multiple
+/// [OutputUnits] where each [OutputUnit] represents part of the user's
+/// program. [OutputUnits] are represented by a unique intersection of imports
+/// known as an import set. Thus, each [OutputUnit] is a node in a deferred
+/// graph. Edges in this graph are dependencies between [OutputUnits].
+///
+/// [OutputUnits] have a notion of successors and predecessors, that is a
+/// successor to an [OutputUnit] is an [OutputUnit] that must be loaded first. A
+/// predecessor to an [OutputUnit] is an [OutputUnit] that must be loaded later.
+///
+/// To load some given deferred library, a list of [OutputUnits] must be loaded
+/// in the correct order, with their successors loaded first, then the given
+/// [OutputUnit], then the [OutputUnits] predecessors.
+///
+/// To give a concrete example, say our graph looks like:
+/// {a} {b} {c}
+///
+/// {a, b} {b, c}
+///
+/// {a, b, c}
+///
+/// Where each set above is the import set of an [OutputUnit]. We say that
+/// {a}, {b}, and {c} are root [OutputUnits], i.e. [OutputUnits] with no
+/// predecessors, and {a, b, c} is a leaf [OutputUnit], i.e. [OutputUnits]
+/// with no successors.
+///
+/// We then have three load lists:
+/// a: {a, b, c}, {a, b}, {a}
+/// b: {a, b, c}, {a, b}, {b, c}, {b}
+/// c: {a, b, c}, {b, c}, {c}
+///
+/// In all 3 load lists, {a, b, c} must be loaded first. All of the other
+/// [OutputUnits] are predecessors of {a, b, c}. {a, b, c} is a successor to all
+/// other [OutputUnits].
+///
+/// However, the dart2js deferred loading algorithm generates a very granular
+/// sparse graph of [OutputUnits] and in many cases it is desireable to coalesce
+/// smaller [OutputUnits] together into larger chunks of code to reduce the
+/// number of files which have to be sent to the client. To do this
+/// cleanly, we use various abstractions to merge [OutputUnits].
+///
+/// First, we emit the code for each [OutputUnit] into an [EmittedOutputUnit].
+/// An [EmittedOutputUnit] is the Javascript representation of an [OutputUnit].
+/// [EmittedOutputUnits] map 1:1 to [OutputUnits].
+///
+/// We wrap each [EmittedOutputUnit] in a [PreFragment], which is just a wrapper
+/// to facilitate merging of [EmittedOutputUnits]. Then, we run a merge
+/// algorithm on these [PreFragments], merging them together until some
+/// threshold.
+///
+/// Once we are finished merging [PreFragments], we must now decide on their
+/// final representation in Javascript.
+///
+/// Depending on the results of the merge, we chose one of two representations.
+/// For example, say we merge {a, b} and {a} into {a, b}+{a}. In this case our
+/// new load lists look like:
+///
+/// a: {a, b, c}, {a, b}+{a}
+/// b: {a, b, c}, {a, b}+{a}, {b, c}, {b}
+/// c: {a, b, c}, {b, c}, {c}
+///
+/// This adds a bit of extra code to the 'b' load list, but otherwise there are
+/// no problems. In this case, we will interleave [EmittedOutputUnits] into a
+/// single [CodeFragment], with a single top level initialization function. This
+/// approach results in lower overhead, because the runtime can initialize the
+/// {a, b}+{a} [CodeFragment] with a single invocation of a top level function.
+///
+/// Ideally we would interleave all [EmittedOutputUnits] in each [PreFragment]
+/// into a single [CodeFragment]. We would then write this single
+/// [CodeFragment] into a single [FinalizedFragment], where a
+/// [FinalizedFragment] is just an abstraction representing a single file on
+/// disk. Unfortunately this is not always possible to do efficiently.
+///
+/// Specifically, lets say we decide to merge {a} and {c} into {a}+{c}
+/// In this case, our load lists now look like:
+///
+/// a: {a, b, c}, {a, b}, {a}+{c}
+/// b: {a, b, c}, {a, b}, {b, c}, {b}
+/// c: {a, b, c}, {b, c}, {a}+{c}
+///
+/// Now, load lists 'a' and 'c' are invalid. Specifically, load list 'a' is
+/// missing {c}'s dependency {b, c} and load list 'c' is missing {a}'s
+/// dependency {a, b}. We could bloat both load lists with the necessary
+/// dependencies, but this would negate any performance benefit from
+/// interleaving.
+///
+/// Instead, when this happens we emit {a} and {c} into separate
+/// [CodeFragments], with separate top level initalization functions that are
+/// only called when the necessary dependencies for initialization are
+/// present. These [CodeFragments] end up in a single [FinalizedFragment].
+/// While this approach doesn't have the performance benefits of
+/// interleaving, it at least reduces the total number of files which need to be
+/// sent to the client.
+
+class EmittedOutputUnit {
+ final OutputUnit outputUnit;
+ final List<Library> libraries;
+ final js.Statement classPrototypes;
+ final js.Statement closurePrototypes;
+ final js.Statement inheritance;
+ final js.Statement methodAliases;
+ final js.Statement tearOffs;
+ final js.Statement constants;
+ final js.Statement typeRules;
+ final js.Statement variances;
+ final js.Statement staticNonFinalFields;
+ final js.Statement lazyInitializers;
+ final js.Statement nativeSupport;
+
+ EmittedOutputUnit(
+ this.outputUnit,
+ this.libraries,
+ this.classPrototypes,
+ this.closurePrototypes,
+ this.inheritance,
+ this.methodAliases,
+ this.tearOffs,
+ this.constants,
+ this.typeRules,
+ this.variances,
+ this.staticNonFinalFields,
+ this.lazyInitializers,
+ this.nativeSupport);
+
+ CodeFragment toCodeFragment(Program program) {
+ return CodeFragment(
+ [outputUnit],
+ libraries,
+ classPrototypes,
+ closurePrototypes,
+ inheritance,
+ methodAliases,
+ tearOffs,
+ constants,
+ typeRules,
+ variances,
+ staticNonFinalFields,
+ lazyInitializers,
+ nativeSupport,
+ program.metadataTypesForOutputUnit(outputUnit));
+ }
+}
+
class PreFragment {
- final List<DeferredFragment> fragments = [];
- final List<js.Statement> classPrototypes = [];
- final List<js.Statement> closurePrototypes = [];
- final List<js.Statement> inheritance = [];
- final List<js.Statement> methodAliases = [];
- final List<js.Statement> tearOffs = [];
- final List<js.Statement> constants = [];
- final List<js.Statement> typeRules = [];
- final List<js.Statement> variances = [];
- final List<js.Statement> staticNonFinalFields = [];
- final List<js.Statement> lazyInitializers = [];
- final List<js.Statement> nativeSupport = [];
+ final String outputFileName;
+ final List<EmittedOutputUnit> emittedOutputUnits = [];
final Set<PreFragment> successors = {};
final Set<PreFragment> predecessors = {};
FinalizedFragment finalizedFragment;
int size = 0;
+ bool shouldInterleave = true;
PreFragment(
- Fragment fragment,
- js.Statement classPrototypes,
- js.Statement closurePrototypes,
- js.Statement inheritance,
- js.Statement methodAliases,
- js.Statement tearOffs,
- js.Statement constants,
- js.Statement typeRules,
- js.Statement variances,
- js.Statement staticNonFinalFields,
- js.Statement lazyInitializers,
- js.Statement nativeSupport,
- bool estimateSize) {
- this.fragments.add(fragment);
- this.classPrototypes.add(classPrototypes);
- this.closurePrototypes.add(closurePrototypes);
- this.inheritance.add(inheritance);
- this.methodAliases.add(methodAliases);
- this.tearOffs.add(tearOffs);
- this.constants.add(constants);
- this.typeRules.add(typeRules);
- this.variances.add(variances);
- this.staticNonFinalFields.add(staticNonFinalFields);
- this.lazyInitializers.add(lazyInitializers);
- this.nativeSupport.add(nativeSupport);
- if (estimateSize) {
- var estimator = SizeEstimator();
- estimator.visit(classPrototypes);
- estimator.visit(closurePrototypes);
- estimator.visit(inheritance);
- estimator.visit(methodAliases);
- estimator.visit(tearOffs);
- estimator.visit(constants);
- estimator.visit(typeRules);
- estimator.visit(variances);
- estimator.visit(staticNonFinalFields);
- estimator.visit(lazyInitializers);
- estimator.visit(nativeSupport);
- size = estimator.charCount;
- }
+ this.outputFileName, EmittedOutputUnit emittedOutputUnit, this.size) {
+ emittedOutputUnits.add(emittedOutputUnit);
}
PreFragment mergeAfter(PreFragment that) {
assert(this != that);
- this.fragments.addAll(that.fragments);
- this.classPrototypes.addAll(that.classPrototypes);
- this.closurePrototypes.addAll(that.closurePrototypes);
- this.inheritance.addAll(that.inheritance);
- this.methodAliases.addAll(that.methodAliases);
- this.tearOffs.addAll(that.tearOffs);
- this.constants.addAll(that.constants);
- this.typeRules.addAll(that.typeRules);
- this.variances.addAll(that.variances);
- this.staticNonFinalFields.addAll(that.staticNonFinalFields);
- this.lazyInitializers.addAll(that.lazyInitializers);
- this.nativeSupport.addAll(that.nativeSupport);
+ this.emittedOutputUnits.addAll(that.emittedOutputUnits);
this.successors.remove(that);
this.predecessors.remove(that);
that.successors.forEach((fragment) {
@@ -107,46 +194,46 @@
return this;
}
- FinalizedFragment finalize(
- Program program, Map<OutputUnit, FinalizedFragment> outputUnitMap) {
- assert(finalizedFragment == null);
- var seedFragment = fragments.first;
- var seedOutputUnit = seedFragment.outputUnit;
-
- // If we only have a single fragment, then wen just finalize it by itself.
- // Otherwise, we finalize an entire group of fragments into a single
- // merged and finalized fragment.
- if (fragments.length == 1) {
- finalizedFragment = FinalizedFragment(
- seedFragment.outputFileName,
- [seedOutputUnit],
- seedFragment.libraries,
- classPrototypes.first,
- closurePrototypes.first,
- inheritance.first,
- methodAliases.first,
- tearOffs.first,
- constants.first,
- typeRules.first,
- variances.first,
- staticNonFinalFields.first,
- lazyInitializers.first,
- nativeSupport.first,
- program.metadataTypesForOutputUnit(seedOutputUnit));
- outputUnitMap[seedOutputUnit] = finalizedFragment;
+ /// Interleaves the [EmittedOutputUnits] into a single [CodeFragment].
+ CodeFragment interleaveEmittedOutputUnits(Program program) {
+ var seedEmittedOutputUnit = emittedOutputUnits.first;
+ if (emittedOutputUnits.length == 1) {
+ return seedEmittedOutputUnit.toCodeFragment(program);
} else {
- List<OutputUnit> outputUnits = [seedOutputUnit];
+ var seedOutputUnit = seedEmittedOutputUnit.outputUnit;
List<Library> libraries = [];
- for (var fragment in fragments) {
- var fragmentOutputUnit = fragment.outputUnit;
- if (seedOutputUnit != fragmentOutputUnit) {
- program.mergeOutputUnitMetadata(seedOutputUnit, fragmentOutputUnit);
- outputUnits.add(fragmentOutputUnit);
+ List<OutputUnit> outputUnits = [seedOutputUnit];
+ List<js.Statement> classPrototypes = [];
+ List<js.Statement> closurePrototypes = [];
+ List<js.Statement> inheritance = [];
+ List<js.Statement> methodAliases = [];
+ List<js.Statement> tearOffs = [];
+ List<js.Statement> constants = [];
+ List<js.Statement> typeRules = [];
+ List<js.Statement> variances = [];
+ List<js.Statement> staticNonFinalFields = [];
+ List<js.Statement> lazyInitializers = [];
+ List<js.Statement> nativeSupport = [];
+ for (var emittedOutputUnit in emittedOutputUnits) {
+ var thatOutputUnit = emittedOutputUnit.outputUnit;
+ if (seedOutputUnit != thatOutputUnit) {
+ program.mergeOutputUnitMetadata(seedOutputUnit, thatOutputUnit);
+ outputUnits.add(thatOutputUnit);
}
- libraries.addAll(fragment.libraries);
+ libraries.addAll(emittedOutputUnit.libraries);
+ classPrototypes.add(emittedOutputUnit.classPrototypes);
+ closurePrototypes.add(emittedOutputUnit.closurePrototypes);
+ inheritance.add(emittedOutputUnit.inheritance);
+ methodAliases.add(emittedOutputUnit.methodAliases);
+ tearOffs.add(emittedOutputUnit.tearOffs);
+ constants.add(emittedOutputUnit.constants);
+ typeRules.add(emittedOutputUnit.typeRules);
+ variances.add(emittedOutputUnit.variances);
+ staticNonFinalFields.add(emittedOutputUnit.staticNonFinalFields);
+ lazyInitializers.add(emittedOutputUnit.lazyInitializers);
+ nativeSupport.add(emittedOutputUnit.nativeSupport);
}
- finalizedFragment = FinalizedFragment(
- seedFragment.outputFileName,
+ return CodeFragment(
outputUnits,
libraries,
js.Block(classPrototypes),
@@ -161,10 +248,36 @@
js.Block(lazyInitializers),
js.Block(nativeSupport),
program.metadataTypesForOutputUnit(seedOutputUnit));
- for (var outputUnit in outputUnits) {
- outputUnitMap[outputUnit] = finalizedFragment;
- }
}
+ }
+
+ /// Bundles [EmittedOutputUnits] into multiple [CodeFragments].
+ List<CodeFragment> bundleEmittedOutputUnits(Program program) {
+ List<CodeFragment> codeFragments = [];
+ for (var emittedOutputUnit in emittedOutputUnits) {
+ codeFragments.add(emittedOutputUnit.toCodeFragment(program));
+ }
+ return codeFragments;
+ }
+
+ /// Finalizes this [PreFragment] into a single [FinalizedFragment] by either
+ /// interleaving [EmittedOutputUnits] into a single [CodeFragment] or by
+ /// bundling [EmittedOutputUnits] into multiple [CodeFragments].
+ FinalizedFragment finalize(
+ Program program,
+ Map<OutputUnit, CodeFragment> outputUnitMap,
+ Map<CodeFragment, FinalizedFragment> codeFragmentMap) {
+ assert(finalizedFragment == null);
+ List<CodeFragment> codeFragments = shouldInterleave
+ ? [interleaveEmittedOutputUnits(program)]
+ : bundleEmittedOutputUnits(program);
+ finalizedFragment = FinalizedFragment(outputFileName, codeFragments);
+ codeFragments.forEach((codeFragment) {
+ codeFragmentMap[codeFragment] = finalizedFragment;
+ codeFragment.outputUnits.forEach((outputUnit) {
+ outputUnitMap[outputUnit] = codeFragment;
+ });
+ });
return finalizedFragment;
}
@@ -181,13 +294,10 @@
}
String debugName() {
- List<String> names = [];
- this.fragments.forEach(
- (fragment) => names.add(fragment.outputUnit.imports.toString()));
var outputUnitStrings = [];
- for (var fragment in fragments) {
+ for (var emittedOutputUnit in emittedOutputUnits) {
var importString = [];
- for (var import in fragment.outputUnit.imports) {
+ for (var import in emittedOutputUnit.outputUnit.imports) {
importString.add(import.name);
}
outputUnitStrings.add('{${importString.join(', ')}}');
@@ -198,26 +308,14 @@
/// Clears all [PreFragment] data structure and zeros out the size. Should be
/// used only after merging to GC internal data structures.
void clearAll() {
- fragments.clear();
- classPrototypes.clear();
- closurePrototypes.clear();
- inheritance.clear();
- methodAliases.clear();
- tearOffs.clear();
- constants.clear();
- typeRules.clear();
- variances.clear();
- staticNonFinalFields.clear();
- lazyInitializers.clear();
- nativeSupport.clear();
+ emittedOutputUnits.clear();
successors.clear();
predecessors.clear();
size = 0;
}
}
-class FinalizedFragment {
- final String outputFileName;
+class CodeFragment {
final List<OutputUnit> outputUnits;
final List<Library> libraries;
final js.Statement classPrototypes;
@@ -233,8 +331,7 @@
final js.Statement nativeSupport;
final js.Expression deferredTypes;
- FinalizedFragment(
- this.outputFileName,
+ CodeFragment(
this.outputUnits,
this.libraries,
this.classPrototypes,
@@ -279,11 +376,40 @@
isEmptyStatement(nativeSupport);
}
+ @override
+ String toString() {
+ List<String> outputUnitStrings = [];
+ for (var outputUnit in outputUnits) {
+ List<String> importStrings = [];
+ for (var import in outputUnit.imports) {
+ importStrings.add(import.name);
+ }
+ outputUnitStrings.add('{${importStrings.join(', ')}}');
+ }
+ return outputUnitStrings.join('+');
+ }
+}
+
+class FinalizedFragment {
+ final String outputFileName;
+ final List<CodeFragment> codeFragments;
+
+ FinalizedFragment(this.outputFileName, this.codeFragments);
+
// The 'main' [OutputUnit] for this [FinalizedFragment].
// TODO(joshualitt): Refactor this to more clearly disambiguate between
// [OutputUnits](units of deferred merging), fragments(units of emitted code),
// and files.
- OutputUnit get canonicalOutputUnit => outputUnits.first;
+ OutputUnit get canonicalOutputUnit => codeFragments.first.outputUnits.first;
+
+ @override
+ String toString() {
+ List<String> strings = [];
+ for (var codeFragment in codeFragments) {
+ strings.add(codeFragment.toString());
+ }
+ return 'FinalizedFragment([${strings.join(', ')}])';
+ }
}
class _Partition {
@@ -305,26 +431,37 @@
FragmentMerger(this._options, this._elementEnvironment, this.outputUnitData);
- // Converts a map of (loadId, List<OutputUnit>) to a map of
- // (loadId, List<FinalizedFragment>).
- Map<String, List<FinalizedFragment>> computeFragmentsToLoad(
+ // Converts a map of (loadId, List<OutputUnit>) to two maps.
+ // The first is a map of (loadId, List<FinalizedFragment>), which is used to
+ // compute which files need to be loaded for a given loadId.
+ // The second is a map of (loadId, List<CodeFragment>) which is used to
+ // compute which CodeFragments need to be loaded for a given loadId.
+ void computeFragmentsToLoad(
Map<String, List<OutputUnit>> outputUnitsToLoad,
- Map<OutputUnit, FinalizedFragment> outputUnitMap,
- Set<OutputUnit> omittedOutputUnits) {
- Map<String, List<FinalizedFragment>> fragmentsToLoad = {};
+ Map<OutputUnit, CodeFragment> outputUnitMap,
+ Map<CodeFragment, FinalizedFragment> codeFragmentMap,
+ Set<OutputUnit> omittedOutputUnits,
+ Map<String, List<CodeFragment>> codeFragmentsToLoad,
+ Map<String, List<FinalizedFragment>> finalizedFragmentsToLoad) {
outputUnitsToLoad.forEach((loadId, outputUnits) {
- Set<FinalizedFragment> unique = {};
+ Set<CodeFragment> uniqueCodeFragments = {};
+ Set<FinalizedFragment> uniqueFinalizedFragments = {};
List<FinalizedFragment> finalizedFragments = [];
- fragmentsToLoad[loadId] = finalizedFragments;
+ List<CodeFragment> codeFragments = [];
for (var outputUnit in outputUnits) {
if (omittedOutputUnits.contains(outputUnit)) continue;
- var finalizedFragment = outputUnitMap[outputUnit];
- if (unique.add(finalizedFragment)) {
+ var codeFragment = outputUnitMap[outputUnit];
+ if (uniqueCodeFragments.add(codeFragment)) {
+ codeFragments.add(codeFragment);
+ }
+ var finalizedFragment = codeFragmentMap[codeFragment];
+ if (uniqueFinalizedFragments.add(finalizedFragment)) {
finalizedFragments.add(finalizedFragment);
}
}
+ codeFragmentsToLoad[loadId] = codeFragments;
+ finalizedFragmentsToLoad[loadId] = finalizedFragments;
});
- return fragmentsToLoad;
}
/// Given a list of OutputUnits sorted by their import entites,
@@ -364,24 +501,21 @@
/// Attachs predecessors and successors to each PreFragment.
/// Expects outputUnits to be sorted.
void attachDependencies(
- List<OutputUnit> outputUnits,
- Map<Fragment, PreFragment> fragmentMap,
- List<PreFragment> preDeferredFragments) {
+ List<OutputUnit> outputUnits, List<PreFragment> preDeferredFragments) {
// Create a map of OutputUnit to Fragment.
- Map<OutputUnit, Fragment> outputUnitMap = {};
+ Map<OutputUnit, PreFragment> outputUnitMap = {};
for (var preFragment in preDeferredFragments) {
- var fragment = preFragment.fragments.single;
- var outputUnit = fragment.outputUnit;
- outputUnitMap[outputUnit] = fragment;
+ var outputUnit = preFragment.emittedOutputUnits.single.outputUnit;
+ outputUnitMap[outputUnit] = preFragment;
totalSize += preFragment.size;
}
// Get a list of direct edges and then attach them to PreFragments.
var allEdges = createDirectEdges(outputUnits);
allEdges.forEach((outputUnit, edges) {
- var predecessor = fragmentMap[outputUnitMap[outputUnit]];
+ var predecessor = outputUnitMap[outputUnit];
for (var edge in edges) {
- var successor = fragmentMap[outputUnitMap[edge]];
+ var successor = outputUnitMap[edge];
predecessor.successors.add(successor);
successor.predecessors.add(predecessor);
}
@@ -411,8 +545,8 @@
// Sort the fragments in the component so they will be in a canonical
// order.
component.sort((a, b) {
- return a.fragments.single.outputUnit
- .compareTo(b.fragments.single.outputUnit);
+ return a.emittedOutputUnits.single.outputUnit
+ .compareTo(b.emittedOutputUnits.single.outputUnit);
});
components.add(component);
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index a7c42ad..97b7f0d 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -52,6 +52,7 @@
import '../../io/source_information.dart';
import '../../io/source_map_builder.dart' show SourceMapBuilder;
import '../../js/js.dart' as js;
+import '../../js/size_estimator.dart';
import '../../js_backend/js_backend.dart'
show Namer, ConstantEmitter, StringBackedName;
import '../../js_backend/js_interop_analysis.dart' as jsInteropAnalysis;
@@ -84,6 +85,13 @@
part 'fragment_emitter.dart';
+class EmittedCodeFragment {
+ final CodeFragment codeFragment;
+ final js.Expression code;
+
+ EmittedCodeFragment(this.codeFragment, this.code);
+}
+
class ModelEmitter {
final CompilerOptions _options;
final DiagnosticReporter _reporter;
@@ -114,7 +122,11 @@
/// [lib1]]} would mean that in order to load "lib1" first the hunk
/// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3
/// can be loaded in parallel. And fially lib1 can be loaded.
- Map<String, List<FinalizedFragment>> fragmentsToLoad;
+ final Map<String, List<FinalizedFragment>> finalizedFragmentsToLoad = {};
+
+ /// Similar to the above map, but more granular as each [FinalizedFragment]
+ /// may have multiple CodeFragments.
+ final Map<String, List<CodeFragment>> codeFragmentsToLoad = {};
/// For deferred loading we communicate the initializers via this global var.
static const String deferredInitializersGlobal =
@@ -226,12 +238,10 @@
// In order to get size estimates, we partially emit deferred fragments.
List<OutputUnit> outputUnits = [];
List<PreFragment> preDeferredFragments = [];
- Map<DeferredFragment, PreFragment> preFragmentMap = {};
_task.measureSubtask('emit prefragments', () {
for (var fragment in deferredFragments) {
var preFragment =
fragmentEmitter.emitPreFragment(fragment, shouldMergeFragments);
- preFragmentMap[fragment] = preFragment;
outputUnits.add(fragment.outputUnit);
preDeferredFragments.add(preFragment);
}
@@ -247,8 +257,7 @@
// and merge.
if (shouldMergeFragments) {
preDeferredFragments = _task.measureSubtask('merge fragments', () {
- fragmentMerger.attachDependencies(
- outputUnits, preFragmentMap, preDeferredFragments);
+ fragmentMerger.attachDependencies(outputUnits, preDeferredFragments);
return fragmentMerger.mergeFragments(preDeferredFragments);
});
}
@@ -259,33 +268,47 @@
}
// Finalize and emit fragments.
- Map<OutputUnit, FinalizedFragment> outputUnitMap = {};
- Map<FinalizedFragment, js.Expression> deferredFragmentsCode = {};
+ Map<OutputUnit, CodeFragment> outputUnitMap = {};
+ Map<CodeFragment, FinalizedFragment> codeFragmentMap = {};
+ Map<FinalizedFragment, EmittedCodeFragment> deferredFragmentsCode = {};
for (var preDeferredFragment in preDeferredFragments) {
var finalizedFragment =
- preDeferredFragment.finalize(program, outputUnitMap);
- js.Expression fragmentCode = fragmentEmitter.emitDeferredFragment(
- finalizedFragment, program.holders);
+ preDeferredFragment.finalize(program, outputUnitMap, codeFragmentMap);
+ // TODO(joshualitt): Support bundling.
+ assert(finalizedFragment.codeFragments.length == 1);
+ var codeFragment = finalizedFragment.codeFragments.single;
+ js.Expression fragmentCode =
+ fragmentEmitter.emitCodeFragment(codeFragment, program.holders);
if (fragmentCode != null) {
- deferredFragmentsCode[finalizedFragment] = fragmentCode;
+ deferredFragmentsCode[finalizedFragment] =
+ EmittedCodeFragment(codeFragment, fragmentCode);
} else {
- omittedOutputUnits.addAll(finalizedFragment.outputUnits);
+ finalizedFragment.codeFragments.forEach((codeFragment) {
+ omittedOutputUnits.addAll(codeFragment.outputUnits);
+ });
}
}
// With all deferred fragments finalized, we can now compute a map of
// loadId to the files(FinalizedFragments) which need to be loaded.
- fragmentsToLoad = fragmentMerger.computeFragmentsToLoad(
- outputUnitsToLoad, outputUnitMap, omittedOutputUnits);
+ fragmentMerger.computeFragmentsToLoad(
+ outputUnitsToLoad,
+ outputUnitMap,
+ codeFragmentMap,
+ omittedOutputUnits,
+ codeFragmentsToLoad,
+ finalizedFragmentsToLoad);
// Emit main Fragment.
var deferredLoadingState = new DeferredLoadingState();
js.Statement mainCode = fragmentEmitter.emitMainFragment(
- program, fragmentsToLoad, deferredLoadingState);
+ program, finalizedFragmentsToLoad, deferredLoadingState);
// Count tokens and run finalizers.
js.TokenCounter counter = new js.TokenCounter();
- deferredFragmentsCode.values.forEach(counter.countTokens);
+ deferredFragmentsCode.values.forEach((emittedCodeFragment) {
+ counter.countTokens(emittedCodeFragment.code);
+ });
counter.countTokens(mainCode);
program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
@@ -302,7 +325,7 @@
// Now that we have written the deferred hunks, we can create the deferred
// loading data.
fragmentEmitter.finalizeDeferredLoadingData(
- fragmentsToLoad, hunkHashes, deferredLoadingState);
+ codeFragmentsToLoad, codeFragmentMap, hunkHashes, deferredLoadingState);
_task.measureSubtask('write fragments', () {
writeMainFragment(mainFragment, mainCode,
@@ -346,11 +369,13 @@
///
/// Updates the shared [outputBuffers] field with the output.
Map<FinalizedFragment, String> writeDeferredFragments(
- Map<FinalizedFragment, js.Expression> fragmentsCode) {
+ Map<FinalizedFragment, EmittedCodeFragment> fragmentsCode) {
Map<FinalizedFragment, String> hunkHashes = {};
- fragmentsCode.forEach((FinalizedFragment fragment, js.Expression code) {
- hunkHashes[fragment] = writeDeferredFragment(fragment, code);
+ fragmentsCode.forEach(
+ (FinalizedFragment fragment, EmittedCodeFragment emittedCodeFragment) {
+ hunkHashes[fragment] =
+ writeDeferredFragment(fragment, emittedCodeFragment.code);
});
return hunkHashes;
@@ -523,7 +548,7 @@
// data.
mapping["_comment"] = "This mapping shows which compiled `.js` files are "
"needed for a given deferred library import.";
- mapping.addAll(fragmentMerger.computeDeferredMap(fragmentsToLoad));
+ mapping.addAll(fragmentMerger.computeDeferredMap(finalizedFragmentsToLoad));
_outputProvider.createOutputSink(
_options.deferredMapUri.path, '', OutputType.deferredMap)
..add(const JsonEncoder.withIndent(" ").convert(mapping))
diff --git a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
index 660e27b..823899f 100644
--- a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
+++ b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
@@ -18,7 +18,9 @@
List<OutputUnit> collectOutputUnits(List<FinalizedFragment> fragments) {
List<OutputUnit> outputUnits = [];
for (var fragment in fragments) {
- outputUnits.addAll(fragment.outputUnits);
+ for (var codeFragment in fragment.codeFragments) {
+ outputUnits.addAll(codeFragment.outputUnits);
+ }
}
return outputUnits;
}
@@ -68,7 +70,8 @@
// InputElement is native, so it should be in the mainOutputUnit.
Expect.equals(mainOutputUnit, outputUnitForClass(inputElement));
- var hunksToLoad = backendStrategy.emitterTask.emitter.fragmentsToLoad;
+ var hunksToLoad =
+ backendStrategy.emitterTask.emitter.finalizedFragmentsToLoad;
var hunksLib1 = collectOutputUnits(hunksToLoad["lib1"]);
var hunksLib2 = collectOutputUnits(hunksToLoad["lib2"]);
var hunksLib4_1 = collectOutputUnits(hunksToLoad["lib4_1"]);
diff --git a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
index 2e74934..374d091 100644
--- a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
+++ b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
@@ -155,7 +155,7 @@
List<PreFragment> preDeferredFragments = compiler
.backendStrategy.emitterTask.emitter.preDeferredFragmentsForTesting;
Map<String, List<FinalizedFragment>> fragmentsToLoad =
- compiler.backendStrategy.emitterTask.emitter.fragmentsToLoad;
+ compiler.backendStrategy.emitterTask.emitter.finalizedFragmentsToLoad;
Map<String, List<PreFragment>> preFragmentMap =
buildPreFragmentMap(fragmentsToLoad, preDeferredFragments);
PreFragmentsIrComputer(compiler.reporter, actualMap, preFragmentMap)
@@ -213,8 +213,8 @@
}
}
- for (var fragment in preFragment.fragments) {
- supplied.add(fragment.outputUnit);
+ for (var emittedOutputUnit in preFragment.emittedOutputUnits) {
+ supplied.add(emittedOutputUnit.outputUnit);
}
var suppliedString = '[${supplied.map(outputUnitString).join(', ')}]';
features.addElement(Tags.outputUnits,
diff --git a/pkg/dartdev/lib/src/commands/create.dart b/pkg/dartdev/lib/src/commands/create.dart
index 26d6576..58dbb4f 100644
--- a/pkg/dartdev/lib/src/commands/create.dart
+++ b/pkg/dartdev/lib/src/commands/create.dart
@@ -8,10 +8,10 @@
import 'dart:math' as math;
import 'package:path/path.dart' as p;
-import 'package:stagehand/stagehand.dart' as stagehand;
import '../core.dart';
import '../sdk.dart';
+import '../templates.dart';
/// A command to create a new project from a set of templates.
class CreateCommand extends DartdevCommand {
@@ -19,18 +19,8 @@
static String defaultTemplateId = 'console-simple';
- static List<String> legalTemplateIds = [
- 'console-simple',
- 'console-full',
- 'package-simple',
- 'web-simple'
- ];
-
- static Iterable<stagehand.Generator> get generators =>
- legalTemplateIds.map(retrieveTemplateGenerator);
-
- static stagehand.Generator retrieveTemplateGenerator(String templateId) =>
- stagehand.getGenerator(templateId);
+ static final List<String> legalTemplateIds =
+ generators.map((generator) => generator.id).toList();
CreateCommand({bool verbose = false})
: super(cmdName, 'Create a new Dart project.') {
@@ -91,8 +81,8 @@
);
log.stdout('');
- var generator = retrieveTemplateGenerator(templateId);
- await generator.generate(
+ var generator = getGenerator(templateId);
+ generator.generate(
p.basename(dir),
DirectoryGeneratorTarget(generator, io.Directory(dir)),
);
@@ -151,7 +141,7 @@
}
String _availableTemplatesJson() {
- var items = generators.map((stagehand.Generator generator) {
+ var items = generators.map((Generator generator) {
var m = {
'name': generator.id,
'label': generator.label,
@@ -171,8 +161,8 @@
}
}
-class DirectoryGeneratorTarget extends stagehand.GeneratorTarget {
- final stagehand.Generator generator;
+class DirectoryGeneratorTarget extends GeneratorTarget {
+ final Generator generator;
final io.Directory dir;
DirectoryGeneratorTarget(this.generator, this.dir) {
@@ -180,13 +170,13 @@
}
@override
- Future createFile(String path, List<int> contents) async {
+ void createFile(String path, List<int> contents) {
io.File file = io.File(p.join(dir.path, path));
String name = p.relative(file.path, from: dir.path);
log.stdout(' $name');
- await file.create(recursive: true);
- await file.writeAsBytes(contents);
+ file.createSync(recursive: true);
+ file.writeAsBytesSync(contents);
}
}
diff --git a/pkg/dartdev/lib/src/templates.dart b/pkg/dartdev/lib/src/templates.dart
new file mode 100644
index 0000000..0b5aa0d
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates.dart
@@ -0,0 +1,195 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show utf8;
+
+import 'package:meta/meta.dart';
+
+import 'templates/console_full.dart';
+import 'templates/console_simple.dart';
+import 'templates/package_simple.dart';
+import 'templates/server_simple.dart';
+import 'templates/web_simple.dart';
+
+final _substituteRegExp = RegExp(r'__([a-zA-Z]+)__');
+final _nonValidSubstituteRegExp = RegExp('[^a-zA-Z]');
+
+final List<Generator> generators = [
+ ConsoleSimpleGenerator(),
+ ConsoleFullGenerator(),
+ PackageSimpleGenerator(),
+ ServerSimpleGenerator(),
+ WebSimpleGenerator(),
+];
+
+Generator getGenerator(String id) =>
+ generators.firstWhere((g) => g.id == id, orElse: () => null);
+
+/// An abstract class which both defines a template generator and can generate a
+/// user project based on this template.
+abstract class Generator implements Comparable<Generator> {
+ final String id;
+ final String label;
+ final String description;
+ final List<String> categories;
+
+ final List<TemplateFile> files = [];
+ TemplateFile _entrypoint;
+
+ Generator(
+ this.id,
+ this.label,
+ this.description, {
+ this.categories = const [],
+ });
+
+ /// The entrypoint of the application; the main file for the project, which an
+ /// IDE might open after creating the project.
+ TemplateFile get entrypoint => _entrypoint;
+
+ TemplateFile addFile(String path, String contents) {
+ return addTemplateFile(TemplateFile(path, contents));
+ }
+
+ /// Add a new template file.
+ TemplateFile addTemplateFile(TemplateFile file) {
+ files.add(file);
+ return file;
+ }
+
+ /// Return the template file wih the given [path].
+ TemplateFile getFile(String path) =>
+ files.firstWhere((file) => file.path == path, orElse: () => null);
+
+ /// Set the main entrypoint of this template. This is the 'most important'
+ /// file of this template. An IDE might use this information to open this file
+ /// after the user's project is generated.
+ void setEntrypoint(TemplateFile entrypoint) {
+ if (_entrypoint != null) throw StateError('entrypoint already set');
+ if (entrypoint == null) throw StateError('entrypoint is null');
+ _entrypoint = entrypoint;
+ }
+
+ void generate(
+ String projectName,
+ GeneratorTarget target, {
+ Map<String, String> additionalVars,
+ }) {
+ final vars = {
+ 'projectName': projectName,
+ 'description': description,
+ 'year': DateTime.now().year.toString(),
+ 'author': '<your name>',
+ if (additionalVars != null) ...additionalVars,
+ };
+
+ for (TemplateFile file in files) {
+ final resultFile = file.runSubstitution(vars);
+ final filePath = resultFile.path;
+ target.createFile(filePath, resultFile.content);
+ }
+ }
+
+ int numFiles() => files.length;
+
+ @override
+ int compareTo(Generator other) =>
+ id.toLowerCase().compareTo(other.id.toLowerCase());
+
+ /// Return some user facing instructions about how to finish installation of
+ /// the template.
+ String getInstallInstructions() => '';
+
+ @override
+ String toString() => '[$id: $description]';
+}
+
+/// An abstract implementation of a [Generator].
+abstract class DefaultGenerator extends Generator {
+ DefaultGenerator(
+ String id,
+ String label,
+ String description, {
+ List<String> categories = const [],
+ }) : super(id, label, description, categories: categories);
+}
+
+/// A target for a [Generator]. This class knows how to create files given a
+/// path for the file (relative to the particular [GeneratorTarget] instance),
+/// and the binary content for the file.
+abstract class GeneratorTarget {
+ /// Create a file at the given path with the given contents.
+ void createFile(String path, List<int> contents);
+}
+
+/// This class represents a file in a generator template. The contents could
+/// either be binary or text. If text, the contents may contain mustache
+/// variables that can be substituted (`__myVar__`).
+class TemplateFile {
+ final String path;
+ final String content;
+
+ TemplateFile(this.path, this.content);
+
+ FileContents runSubstitution(Map<String, String> parameters) {
+ if (path == 'pubspec.yaml' && parameters['author'] == '<your name>') {
+ parameters = Map.from(parameters);
+ parameters['author'] = 'Your Name';
+ }
+
+ final newPath = substituteVars(path, parameters);
+ final newContents = _createContent(parameters);
+
+ return FileContents(newPath, newContents);
+ }
+
+ List<int> _createContent(Map<String, String> vars) {
+ return utf8.encode(substituteVars(content, vars));
+ }
+}
+
+class FileContents {
+ final String path;
+ final List<int> content;
+
+ FileContents(this.path, this.content);
+}
+
+/// Given a `String` [str] with mustache templates, and a [Map] of String key /
+/// value pairs, substitute all instances of `__key__` for `value`. I.e.,
+///
+/// ```
+/// Foo __projectName__ baz.
+/// ```
+///
+/// and
+///
+/// ```
+/// {'projectName': 'bar'}
+/// ```
+///
+/// becomes:
+///
+/// ```
+/// Foo bar baz.
+/// ```
+///
+/// A key value can only be an ASCII string made up of letters: A-Z, a-z.
+/// No whitespace, numbers, or other characters are allowed.
+@visibleForTesting
+String substituteVars(String str, Map<String, String> vars) {
+ if (vars.keys.any((element) => element.contains(_nonValidSubstituteRegExp))) {
+ throw ArgumentError('vars.keys can only contain letters.');
+ }
+
+ return str.replaceAllMapped(_substituteRegExp, (match) {
+ final item = vars[match[1]];
+
+ if (item == null) {
+ return match[0];
+ } else {
+ return item;
+ }
+ });
+}
diff --git a/pkg/dartdev/lib/src/templates/common.dart b/pkg/dartdev/lib/src/templates/common.dart
new file mode 100644
index 0000000..b849fdd
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/common.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+final String gitignore = '''
+# Files and directories created by pub.
+.dart_tool/
+.packages
+
+# Conventional directory for build output.
+build/
+''';
+
+final String analysisOptions = '''
+# Defines a default set of lint rules enforced for projects at Google. For
+# details and rationale, see
+# https://github.com/dart-lang/pedantic#enabled-lints.
+
+include: package:pedantic/analysis_options.yaml
+
+# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
+
+# Uncomment to specify additional rules.
+# linter:
+# rules:
+# - camel_case_types
+
+# analyzer:
+# exclude:
+# - path/to/excluded/files/**
+''';
+
+final String changelog = '''
+## 1.0.0
+
+- Initial version.
+''';
diff --git a/pkg/dartdev/lib/src/templates/console_full.dart b/pkg/dartdev/lib/src/templates/console_full.dart
new file mode 100644
index 0000000..78e1670
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/console_full.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../templates.dart';
+import 'common.dart' as common;
+
+/// A generator for a hello world command-line application.
+class ConsoleFullGenerator extends DefaultGenerator {
+ ConsoleFullGenerator()
+ : super('console-full', 'Console Application',
+ 'A command-line application sample.',
+ categories: const ['dart', 'console']) {
+ addFile('.gitignore', common.gitignore);
+ addFile('analysis_options.yaml', common.analysisOptions);
+ addFile('CHANGELOG.md', common.changelog);
+ addFile('pubspec.yaml', _pubspec);
+ addFile('README.md', _readme);
+ setEntrypoint(
+ addFile('bin/__projectName__.dart', _mainDart),
+ );
+ addFile('lib/__projectName__.dart', _libDart);
+ addFile('test/__projectName___test.dart', _testDart);
+ }
+
+ @override
+ String getInstallInstructions() => '${super.getInstallInstructions()}\n'
+ 'run your app using `dart ${entrypoint.path}`.';
+}
+
+final String _pubspec = '''
+name: __projectName__
+description: A sample command-line application.
+version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+
+# dependencies:
+# path: ^1.8.0
+
+dev_dependencies:
+ pedantic: ^1.10.0
+ test: ^1.16.0
+''';
+
+final String _readme = '''
+A sample command-line application with an entrypoint in `bin/`, library code
+in `lib/`, and example unit test in `test/`.
+''';
+
+final String _mainDart = r'''
+import 'package:__projectName__/__projectName__.dart' as __projectName__;
+
+void main(List<String> arguments) {
+ print('Hello world: ${__projectName__.calculate()}!');
+}
+''';
+
+final String _libDart = '''
+int calculate() {
+ return 6 * 7;
+}
+''';
+
+final String _testDart = '''
+import 'package:__projectName__/__projectName__.dart';
+import 'package:test/test.dart';
+
+void main() {
+ test('calculate', () {
+ expect(calculate(), 42);
+ });
+}
+''';
diff --git a/pkg/dartdev/lib/src/templates/console_simple.dart b/pkg/dartdev/lib/src/templates/console_simple.dart
new file mode 100644
index 0000000..15384c6
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/console_simple.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../templates.dart';
+import 'common.dart' as common;
+
+/// A generator for a simple command-line application.
+class ConsoleSimpleGenerator extends DefaultGenerator {
+ ConsoleSimpleGenerator()
+ : super('console-simple', 'Simple Console Application',
+ 'A simple command-line application.',
+ categories: const ['dart', 'console']) {
+ addFile('.gitignore', common.gitignore);
+ addFile('analysis_options.yaml', common.analysisOptions);
+ addFile('CHANGELOG.md', common.changelog);
+ addFile('pubspec.yaml', _pubspec);
+ addFile('README.md', _readme);
+ setEntrypoint(
+ addFile('bin/__projectName__.dart', main),
+ );
+ }
+
+ @override
+ String getInstallInstructions() => '${super.getInstallInstructions()}\n'
+ 'run your app using `dart ${entrypoint.path}`.';
+}
+
+final String _pubspec = '''
+name: __projectName__
+description: A simple command-line application.
+version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+
+# dependencies:
+# path: ^1.8.0
+
+dev_dependencies:
+ pedantic: ^1.10.0
+''';
+
+final String _readme = '''
+A simple command-line application.
+''';
+
+final String main = '''
+void main(List<String> arguments) {
+ print('Hello world!');
+}
+''';
diff --git a/pkg/dartdev/lib/src/templates/package_simple.dart b/pkg/dartdev/lib/src/templates/package_simple.dart
new file mode 100644
index 0000000..7d013fa
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/package_simple.dart
@@ -0,0 +1,130 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../templates.dart';
+import 'common.dart' as common;
+
+/// A generator for a simple command-line application.
+class PackageSimpleGenerator extends DefaultGenerator {
+ PackageSimpleGenerator()
+ : super('package-simple', 'Dart Package',
+ 'A starting point for Dart libraries or applications.',
+ categories: const ['dart']) {
+ addFile('.gitignore', _gitignore);
+ addFile('analysis_options.yaml', common.analysisOptions);
+ addFile('CHANGELOG.md', common.changelog);
+ addFile('pubspec.yaml', _pubspec);
+ addFile('README.md', _readme);
+ addFile('example/__projectName___example.dart', _exampleDart);
+ setEntrypoint(
+ addFile('lib/__projectName__.dart', _libDart),
+ );
+ addFile('lib/src/__projectName___base.dart', _libSrcDart);
+ addFile('test/__projectName___test.dart', _testDart);
+ }
+
+ @override
+ String getInstallInstructions() => '${super.getInstallInstructions()}\n'
+ 'run your app using `dart ${entrypoint.path}`.';
+}
+
+final String _gitignore = '''
+# Files and directories created by pub.
+.dart_tool/
+.packages
+
+# Conventional directory for build outputs.
+build/
+
+# Omit committing pubspec.lock for library packages; see
+# https://dart.dev/guides/libraries/private-files#pubspeclock.
+pubspec.lock
+''';
+
+final String _pubspec = '''
+name: __projectName__
+description: A starting point for Dart libraries or applications.
+version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+ sdk: '>=2.12.0 <3.0.0'
+
+# dependencies:
+# path: ^1.8.0
+
+dev_dependencies:
+ pedantic: ^1.10.0
+ test: ^1.16.0
+''';
+
+final String _readme = '''
+A library for Dart developers.
+
+## Usage
+
+A simple usage example:
+
+```dart
+import 'package:__projectName__/__projectName__.dart';
+
+main() {
+ var awesome = new Awesome();
+}
+```
+
+## Features and bugs
+
+Please file feature requests and bugs at the [issue tracker][tracker].
+
+[tracker]: http://example.com/issues/replaceme
+''';
+
+final String _exampleDart = r'''
+import 'package:__projectName__/__projectName__.dart';
+
+void main() {
+ var awesome = Awesome();
+ print('awesome: ${awesome.isAwesome}');
+}
+''';
+
+final String _libDart = '''
+/// Support for doing something awesome.
+///
+/// More dartdocs go here.
+library __projectName__;
+
+export 'src/__projectName___base.dart';
+
+// TODO: Export any libraries intended for clients of this package.
+''';
+
+final String _libSrcDart = '''
+// TODO: Put public facing types in this file.
+
+/// Checks if you are awesome. Spoiler: you are.
+class Awesome {
+ bool get isAwesome => true;
+}
+''';
+
+final String _testDart = '''
+import 'package:__projectName__/__projectName__.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('A group of tests', () {
+ final awesome = Awesome();
+
+ setUp(() {
+ // Additional setup goes here.
+ });
+
+ test('First Test', () {
+ expect(awesome.isAwesome, isTrue);
+ });
+ });
+}
+''';
diff --git a/pkg/dartdev/lib/src/templates/server_simple.dart b/pkg/dartdev/lib/src/templates/server_simple.dart
new file mode 100644
index 0000000..6688f23
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/server_simple.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../templates.dart';
+import 'common.dart' as common;
+
+/// A generator for a server app built on `package:shelf`.
+class ServerSimpleGenerator extends DefaultGenerator {
+ ServerSimpleGenerator()
+ : super('server-simple', 'Web Server',
+ 'A web server built using package:shelf.',
+ categories: const ['dart', 'server']) {
+ addFile('.gitignore', common.gitignore);
+ addFile('analysis_options.yaml', common.analysisOptions);
+ addFile('CHANGELOG.md', common.changelog);
+ addFile('pubspec.yaml', _pubspec);
+ addFile('README.md', _readme);
+ setEntrypoint(
+ addFile('bin/server.dart', _main),
+ );
+ }
+
+ @override
+ String getInstallInstructions() => '${super.getInstallInstructions()}\n'
+ 'run your app using `dart ${entrypoint.path}`.';
+}
+
+final String _pubspec = '''
+name: __projectName__
+description: A web server built using the shelf package.
+version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+ sdk: ">=2.12.0 <3.0.0"
+
+dependencies:
+ args: ^2.0.0
+ shelf: ^1.1.0
+
+dev_dependencies:
+ pedantic: ^1.10.0
+''';
+
+final String _readme = '''
+A web server built using [Shelf](https://pub.dev/packages/shelf).
+''';
+
+final String _main = r'''
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:shelf/shelf.dart' as shelf;
+import 'package:shelf/shelf_io.dart' as io;
+
+// For Google Cloud Run, set _hostname to '0.0.0.0'.
+const _hostname = 'localhost';
+
+void main(List<String> args) async {
+ var parser = ArgParser()..addOption('port', abbr: 'p');
+ var result = parser.parse(args);
+
+ // For Google Cloud Run, we respect the PORT environment variable
+ var portStr = result['port'] ?? Platform.environment['PORT'] ?? '8080';
+ var port = int.tryParse(portStr);
+
+ if (port == null) {
+ stdout.writeln('Could not parse port value "$portStr" into a number.');
+ // 64: command line usage error
+ exitCode = 64;
+ return;
+ }
+
+ var handler = const shelf.Pipeline()
+ .addMiddleware(shelf.logRequests())
+ .addHandler(_echoRequest);
+
+ var server = await io.serve(handler, _hostname, port);
+ print('Serving at http://${server.address.host}:${server.port}');
+}
+
+shelf.Response _echoRequest(shelf.Request request) =>
+ shelf.Response.ok('Request for "${request.url}"');
+''';
diff --git a/pkg/dartdev/lib/src/templates/web_simple.dart b/pkg/dartdev/lib/src/templates/web_simple.dart
new file mode 100644
index 0000000..0fd6c34
--- /dev/null
+++ b/pkg/dartdev/lib/src/templates/web_simple.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../templates.dart';
+import 'common.dart' as common;
+
+/// A generator for a uber-simple web application.
+class WebSimpleGenerator extends DefaultGenerator {
+ WebSimpleGenerator()
+ : super('web-simple', 'Bare-bones Web App',
+ 'A web app that uses only core Dart libraries.',
+ categories: const ['dart', 'web']) {
+ addFile('.gitignore', common.gitignore);
+ addFile('analysis_options.yaml', common.analysisOptions);
+ addFile('CHANGELOG.md', common.changelog);
+ addFile('pubspec.yaml', _pubspec);
+ addFile('README.md', _readme);
+ addFile('web/index.html', _index);
+ setEntrypoint(
+ addFile('web/main.dart', _main),
+ );
+ addFile('web/styles.css', _styles);
+ }
+}
+
+final String _pubspec = '''
+name: __projectName__
+description: An absolute bare-bones web app.
+version: 1.0.0
+# homepage: https://www.example.com
+
+environment:
+ sdk: '>=2.10.0 <3.0.0'
+
+# dependencies:
+# path: ^1.7.0
+
+dev_dependencies:
+ build_runner: ^1.10.0
+ build_web_compilers: ^2.11.0
+ pedantic: ^1.9.0
+''';
+
+final String _readme = '''
+An absolute bare-bones web app.
+''';
+
+final String _index = '''
+<!DOCTYPE html>
+
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="scaffolded-by" content="https://github.com/dart-lang/sdk">
+ <title>__projectName__</title>
+ <link rel="stylesheet" href="styles.css">
+ <script defer src="main.dart.js"></script>
+</head>
+
+<body>
+
+ <div id="output"></div>
+
+</body>
+</html>
+''';
+
+final String _main = '''
+import 'dart:html';
+
+void main() {
+ querySelector('#output').text = 'Your Dart app is running.';
+}
+''';
+
+final String _styles = '''
+@import url(https://fonts.googleapis.com/css?family=Roboto);
+
+html, body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ font-family: 'Roboto', sans-serif;
+}
+
+#output {
+ padding: 20px;
+ text-align: center;
+}
+''';
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index 5acc161..20071f4 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -27,7 +27,6 @@
path: ^1.0.0
pedantic: ^1.9.0
pub: any
- stagehand: any
telemetry:
path: ../telemetry
usage: ^3.4.0
diff --git a/pkg/dartdev/test/commands/create_integration_test.dart b/pkg/dartdev/test/commands/create_integration_test.dart
new file mode 100644
index 0000000..af112d1
--- /dev/null
+++ b/pkg/dartdev/test/commands/create_integration_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:dartdev/src/commands/create.dart';
+import 'package:test/test.dart';
+
+import '../utils.dart';
+
+void main() {
+ group('create integration', defineCreateTests, timeout: longTimeout);
+}
+
+void defineCreateTests() {
+ TestProject p;
+
+ setUp(() => p = null);
+
+ tearDown(() => p?.dispose());
+
+ // Create tests for each template.
+ for (String templateId in CreateCommand.legalTemplateIds) {
+ test(templateId, () {
+ p = project();
+
+ ProcessResult createResult = p.runSync([
+ 'create',
+ '--force',
+ '--template',
+ templateId,
+ p.dir.path,
+ ]);
+ expect(createResult.exitCode, 0, reason: createResult.stderr);
+
+ // Validate that the project analyzes cleanly.
+ // TODO: Should we use --fatal-infos here?
+ ProcessResult analyzeResult =
+ p.runSync(['analyze'], workingDir: p.dir.path);
+ expect(analyzeResult.exitCode, 0, reason: analyzeResult.stdout);
+
+ // Validate that the code is well formatted.
+ ProcessResult formatResult = p.runSync([
+ 'format',
+ '--output',
+ 'none',
+ '--set-exit-if-changed',
+ p.dir.path,
+ ]);
+ expect(formatResult.exitCode, 0, reason: formatResult.stdout);
+ });
+ }
+}
diff --git a/pkg/dartdev/test/commands/create_test.dart b/pkg/dartdev/test/commands/create_test.dart
index 7f5c846..5429b80 100644
--- a/pkg/dartdev/test/commands/create_test.dart
+++ b/pkg/dartdev/test/commands/create_test.dart
@@ -6,6 +6,7 @@
import 'dart:io';
import 'package:dartdev/src/commands/create.dart';
+import 'package:dartdev/src/templates.dart' as templates;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
@@ -77,14 +78,19 @@
test('create $templateId', () {
p = project();
- ProcessResult result = p
- .runSync(['create', '--force', '--template', templateId, p.dir.path]);
+ ProcessResult result = p.runSync([
+ 'create',
+ '--force',
+ '--no-pub',
+ '--template',
+ templateId,
+ p.dir.path,
+ ]);
expect(result.exitCode, 0);
String projectName = path.basename(p.dir.path);
- String entry =
- CreateCommand.retrieveTemplateGenerator(templateId).entrypoint.path;
+ String entry = templates.getGenerator(templateId).entrypoint.path;
entry = entry.replaceAll('__projectName__', projectName);
File entryFile = File(path.join(p.dir.path, entry));
diff --git a/pkg/dartdev/test/templates_test.dart b/pkg/dartdev/test/templates_test.dart
new file mode 100644
index 0000000..3b466c9
--- /dev/null
+++ b/pkg/dartdev/test/templates_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:dartdev/src/templates.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('templates', () {
+ group('substituteVars', () {
+ test('simple', () {
+ _expect('foo __bar__ baz', {'bar': 'baz'}, 'foo baz baz');
+ });
+
+ test('nosub', () {
+ _expect('foo __bar__ baz', {'aaa': 'bbb'}, 'foo __bar__ baz');
+ });
+
+ test('matching input', () {
+ _expect('foo __bar__ baz', {'bar': '__baz__', 'baz': 'foo'},
+ 'foo __baz__ baz');
+ });
+
+ test('vars must be alpha + numeric', () {
+ expect(() => substituteVars('str', {'with space': 'noop'}),
+ throwsArgumentError);
+ expect(() => substituteVars('str', {'with!symbols': 'noop'}),
+ throwsArgumentError);
+ expect(() => substituteVars('str', {'with1numbers': 'noop'}),
+ throwsArgumentError);
+ expect(() => substituteVars('str', {'with_under': 'noop'}),
+ throwsArgumentError);
+ });
+ });
+ });
+}
+
+void _expect(String original, Map<String, String> vars, String result) {
+ expect(substituteVars(original, vars), result);
+}
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index 1f3db17..5a64ced 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -7,7 +7,6 @@
import 'package:path/path.dart' as path;
import 'package:pub_semver/pub_semver.dart';
-
import 'package:test/test.dart';
/// A long [Timeout] is provided for tests that start a process on
@@ -54,7 +53,7 @@
this.name = _defaultProjectName,
this.logAnalytics = false,
this.sdkConstraint}) {
- dir = Directory.systemTemp.createTempSync(name);
+ dir = Directory.systemTemp.createTempSync('a');
file('pubspec.yaml', '''
name: $name
environment:
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
index ebc57c1f..95d2fb0 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_test.dart
@@ -256,6 +256,8 @@
/// Depends on SDK artifacts (such as the sound and unsound dart_sdk.js
/// files) generated from the 'dartdevc_test' target.
Future<void> initSource(SetupCompilerOptions setup, String source) async {
+ // Prepend Dart nullability comment.
+ source = '${setup.dartLangComment}\n\n$source';
this.setup = setup;
this.source = source;
testDir = await chromeDir.createTemp('ddc_eval_test');
@@ -460,10 +462,7 @@
returnByValue: false);
await debugger.removeBreakpoint(bp.breakpointId);
-
- var value = evalResult.type == 'function'
- ? evalResult.description
- : evalResult.value;
+ var value = await stringifyRemoteObject(evalResult);
expect(
result,
@@ -471,6 +470,41 @@
.having((_) => '$value', 'result', _matches(expectedResult)));
}
+ /// Generate simple string representation of a RemoteObject that closely
+ /// resembles Chrome's console output.
+ ///
+ /// Examples:
+ /// Class: t.C.new {Symbol(C.field): 5, Symbol(_field): 7}
+ /// Function: function main() {
+ /// return test.foo(1, {y: 2});
+ /// }
+ Future<String> stringifyRemoteObject(wip.RemoteObject obj) async {
+ String str;
+ switch (obj.type) {
+ case 'function':
+ str = obj.description;
+ break;
+ case 'object':
+ if (obj.subtype == 'null') {
+ return 'null';
+ }
+ var properties =
+ await connection.runtime.getProperties(obj, ownProperties: true);
+ var filteredProps = <String, String>{};
+ for (var prop in properties) {
+ if (prop.value != null && prop.name != '__proto__') {
+ filteredProps[prop.name] = await stringifyRemoteObject(prop.value);
+ }
+ }
+ str = '${obj.description} $filteredProps';
+ break;
+ default:
+ str = '${obj.value}';
+ break;
+ }
+ return str;
+ }
+
/// Collects local JS variables visible at a breakpoint during evaluation.
///
/// Adapted from webdev/dwds/lib/src/services/expression_evaluator.dart.
@@ -565,8 +599,6 @@
group('Expression compiler extension symbols tests', () {
var source = '''
- ${setup.dartLangComment}
-
main() {
List<int> list = [];
list.add(0);
@@ -597,9 +629,10 @@
group('Expression compiler scope collection tests', () {
var source = '''
- ${setup.dartLangComment}
-
class C {
+ static int staticField = 0;
+ int field;
+
C(this.field);
void methodFieldAccess(int x) {
@@ -611,9 +644,6 @@
}
var notInScope = 3;
}
-
- static int staticField = 0;
- int field;
}
int global = 42;
@@ -681,7 +711,6 @@
group('Expression compiler tests in extension method:', () {
var source = '''
- ${setup.dartLangComment}
extension NumberParsing on String {
int parseInt() {
var ret = int.parse(this);
@@ -725,7 +754,6 @@
group('Expression compiler tests in static function:', () {
var source = '''
- ${setup.dartLangComment}
int foo(int x, {int y}) {
int z = 3;
// Breakpoint: bp
@@ -773,6 +801,216 @@
}''');
});
});
+
+ group('Expression compiler tests in method:', () {
+ var source = '''
+ extension NumberParsing on String {
+ int parseInt() {
+ return int.parse(this) + 1;
+ }
+ }
+
+ class C {
+ static int staticField = 1;
+ static int _staticField = 2;
+ static int _unusedStaticField = 3;
+ int field;
+ int _field;
+ int _unusedField = 4;
+
+ C(this.field, this._field);
+
+ int methodFieldAccess(int x) {
+ // Breakpoint: bp
+ return x + _field + _staticField;
+ }
+ }
+
+ void entrypoint() {
+ var c = C(5, 7);
+ // Breakpoint: bp1
+ c.methodFieldAccess(10);
+ }
+
+ int global = 42;
+ main() => entrypoint();
+ ''';
+
+ setUpAll(() async {
+ await driver.initSource(setup, source);
+ });
+
+ tearDownAll(() {
+ driver.cleanupTest();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x', expectedResult: '10');
+ });
+
+ test('this', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'this',
+ expectedResult:
+ 'test.C.new {Symbol(_unusedField): 4, Symbol(C.field): 5,'
+ ' Symbol(_field): 7}');
+ });
+
+ test('expression using locals', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x + 1', expectedResult: '11');
+ });
+
+ test('expression using static fields', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'x + staticField',
+ expectedResult: '11');
+ });
+
+ test('expression using private static fields', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'x + _staticField',
+ expectedResult: '12');
+ });
+
+ test('expression using fields', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x + field', expectedResult: '15');
+ });
+
+ test('expression using private fields', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x + _field', expectedResult: '17');
+ });
+
+ test('expression using globals', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x + global', expectedResult: '52');
+ });
+
+ test('expression using fields not referred to in the original code',
+ () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: '_unusedField + _unusedStaticField',
+ expectedResult: '7');
+ });
+
+ test('method call', () async {
+ await driver.check(
+ breakpointId: 'bp1',
+ expression: 'c.methodFieldAccess(2)',
+ expectedResult: '11');
+ });
+
+ test('extension method call', () async {
+ await driver.check(
+ breakpointId: 'bp1',
+ expression: '"1234".parseInt()',
+ expectedResult: '1235');
+ });
+
+ test('private field modification', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: '() {_field = 2; return _field;}()',
+ expectedResult: '2');
+ });
+
+ test('field modification', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: '() {field = 3; return field;}()',
+ expectedResult: '3');
+ });
+
+ test('private static field modification', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: '() {_staticField = 4; return _staticField;}()',
+ expectedResult: '4');
+ });
+
+ test('static field modification', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: '() {staticField = 5; return staticField;}()',
+ expectedResult: '5');
+ });
+ });
+
+ group('Expression compiler tests in async method:', () {
+ var source = '''
+ class C {
+ static int staticField = 1;
+ static int _staticField = 2;
+ int _field;
+ int field;
+
+ C(this.field, this._field);
+ Future<int> asyncMethod(int x) async {
+ // Breakpoint: bp
+ return x + global + _field + field + staticField + _staticField;
+ }
+ }
+
+ void entrypoint() async {
+ var c = C(5, 7);
+ // Breakpoint: bp1
+ var nop;
+ await c.asyncMethod(1);
+ }
+
+ int global = 42;
+ main() async => await entrypoint();
+ ''';
+
+ setUpAll(() async {
+ await driver.initSource(setup, source);
+ });
+
+ tearDownAll(() {
+ driver.cleanupTest();
+ });
+
+ test('compilation error', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'typo',
+ expectedError: "The getter 'typo' isn't defined for the class 'C'");
+ });
+
+ test('local', () async {
+ await driver.check(
+ breakpointId: 'bp', expression: 'x', expectedResult: '1');
+ });
+
+ test('this', () async {
+ await driver.check(
+ breakpointId: 'bp',
+ expression: 'this',
+ expectedResult:
+ 'test.C.new {Symbol(C.field): 5, Symbol(_field): 7}');
+ });
+
+ test('async method call', () async {
+ await driver.check(
+ breakpointId: 'bp1',
+ expression: 'await c.asyncMethod(1)',
+ expectedResult: '58');
+ }, skip: "'await' is not yet supported in expression evaluation.");
+ });
});
group('Sound null safety:', () {
@@ -789,8 +1027,6 @@
group('Expression compiler extension symbols tests', () {
var source = '''
- ${setup.dartLangComment}
-
main() {
List<int> list = [];
list.add(0);
@@ -821,8 +1057,6 @@
group('Expression compiler scope collection tests', () {
var source = '''
- ${setup.dartLangComment}
-
class C {
C(this.field);
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 2f32e9a..8d2d698 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -682,7 +682,10 @@
TypeAliasBuilder aliasBuilder; // Non-null if a type alias is use.
if (decl is TypeAliasBuilder) {
aliasBuilder = decl;
- decl = aliasBuilder.unaliasDeclaration(superClassType.arguments);
+ decl = aliasBuilder.unaliasDeclaration(superClassType.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: supertypeBuilder.charOffset,
+ usedAsClassFileUri: superClassType.fileUri);
}
// TODO(eernst): Should gather 'restricted supertype' checks in one place,
// e.g., dynamic/int/String/Null and more are checked elsewhere.
@@ -708,7 +711,10 @@
TypeAliasBuilder aliasBuilder; // Non-null if a type alias is used.
if (typeDeclaration is TypeAliasBuilder) {
aliasBuilder = typeDeclaration;
- decl = aliasBuilder.unaliasDeclaration(type.arguments);
+ decl = aliasBuilder.unaliasDeclaration(type.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: type.charOffset,
+ usedAsClassFileUri: type.fileUri);
} else {
decl = typeDeclaration;
}
@@ -1149,7 +1155,10 @@
if (builder is ClassBuilder) return builder;
if (builder is TypeAliasBuilder) {
TypeDeclarationBuilder declarationBuilder =
- builder.unaliasDeclaration(supertype.arguments);
+ builder.unaliasDeclaration(supertype.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: supertype.charOffset,
+ usedAsClassFileUri: supertype.fileUri);
if (declarationBuilder is ClassBuilder) return declarationBuilder;
}
}
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index 86e27d1..1833d4f 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -244,8 +244,23 @@
}
}
- return declaration.buildType(
- library, nullabilityBuilder, arguments, notInstanceContext);
+ if (library is SourceLibraryBuilder) {
+ int uncheckedTypedefTypeCount = library.uncheckedTypedefTypes.length;
+ DartType builtType = declaration.buildType(
+ library, nullabilityBuilder, arguments, notInstanceContext);
+ // Set locations for new unchecked TypedefTypes for error reporting.
+ for (int i = uncheckedTypedefTypeCount;
+ i < library.uncheckedTypedefTypes.length;
+ ++i) {
+ library.uncheckedTypedefTypes[i]
+ ..fileUri ??= fileUri
+ ..offset ??= charOffset;
+ }
+ return builtType;
+ } else {
+ return declaration.buildType(
+ library, nullabilityBuilder, arguments, notInstanceContext);
+ }
}
Supertype buildSupertype(
diff --git a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
index 0ff9c8e..577265a 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
@@ -6,14 +6,7 @@
library fasta.function_type_alias_builder;
-import 'package:kernel/ast.dart'
- show
- DartType,
- DynamicType,
- InvalidType,
- Nullability,
- TypeParameter,
- Typedef;
+import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart' show substitute, uniteNullabilities;
@@ -28,11 +21,13 @@
messageTypedefTypeVariableNotConstructorCause;
import '../problems.dart' show unhandled;
+import '../source/source_library_builder.dart';
import '../util/helpers.dart';
import 'class_builder.dart';
import 'library_builder.dart';
import 'metadata_builder.dart';
+import 'function_type_builder.dart';
import 'named_type_builder.dart';
import 'nullability_builder.dart';
import 'type_builder.dart';
@@ -81,14 +76,14 @@
/// based on the given [typeArguments]. It expands type aliases repeatedly
/// until it encounters a builder which is not a [TypeAliasBuilder].
///
- /// If [isInvocation] is false: In this case it is required that
+ /// If [isUsedAsClass] is false: In this case it is required that
/// `typeArguments.length == typeVariables.length`. The [typeArguments] are
/// threaded through the expansion if needed, and the resulting declaration
/// is returned.
///
- /// If [isInvocation] is true: In this case [typeArguments] are ignored, but
- /// [invocationCharOffset] and [invocationFileUri] must be non-null. If `this`
- /// type alias expands in one or more steps to a builder which is not a
+ /// If [isUsedAsClass] is true: In this case [typeArguments] are ignored, but
+ /// [usedAsClassCharOffset] and [usedAsClassFileUri] must be non-null. If
+ /// `this` type alias expands in one or more steps to a builder which is not a
/// [TypeAliasBuilder] nor a [TypeVariableBuilder] then that builder is
/// returned. If this type alias is cyclic or expands to an invalid type or
/// a type that does not have a declaration (say, a function type) then `this`
@@ -97,9 +92,9 @@
/// [TypeVariableBuilder] then the type alias cannot be used in a constructor
/// invocation. Then an error is emitted and `this` is returned.
TypeDeclarationBuilder unaliasDeclaration(List<TypeBuilder> typeArguments,
- {bool isInvocation = false,
- int invocationCharOffset,
- Uri invocationFileUri});
+ {bool isUsedAsClass = false,
+ int usedAsClassCharOffset,
+ Uri usedAsClassFileUri});
/// Compute type arguments passed to [ClassBuilder] from unaliasDeclaration.
/// This method does not check for cycles and may only be called if an
@@ -146,6 +141,17 @@
for (int i = 0; i < typedef.typeParameters.length; i++) {
substitution[typedef.typeParameters[i]] = arguments[i];
}
+ // The following adds the built type to the list of unchecked typedef types
+ // of the client library. It is needed because the type is built unaliased,
+ // and at the time of the check it wouldn't be possible to see if the type
+ // arguments to the generic typedef conform to the bounds without preserving
+ // the TypedefType for the delayed check.
+ if (library is SourceLibraryBuilder &&
+ arguments.isNotEmpty &&
+ type is! FunctionTypeBuilder) {
+ library.uncheckedTypedefTypes.add(new UncheckedTypedefType(
+ new TypedefType(typedef, nullability, arguments)));
+ }
return substitute(result, substitution);
}
@@ -191,25 +197,32 @@
/// based on the given [typeArguments]. It expands type aliases repeatedly
/// until it encounters a builder which is not a [TypeAliasBuilder].
///
- /// If [isInvocation] is false: In this case it is required that
+ /// The parameter [isUsedAsClass] indicates whether the type alias is being
+ /// used as a class, e.g., as the class in an instance creation, as a
+ /// superinterface, in a redirecting factory constructor, or to invoke a
+ /// static member.
+ ///
+ /// If [isUsedAsClass] is false: In this case it is required that
/// `typeArguments.length == typeVariables.length`. The [typeArguments] are
/// threaded through the expansion if needed, and the resulting declaration
/// is returned.
///
- /// If [isInvocation] is true: In this case [typeArguments] are ignored, but
- /// [invocationCharOffset] and [invocationFileUri] must be non-null. If `this`
+ /// If [isUsedAsClass] is true: In this case [typeArguments] can be null, but
+ /// [usedAsClassCharOffset] and [usedAsClassFileUri] must be non-null. When
+ /// [typeArguments] is null, the returned [TypeDeclarationBuilder] indicates
+ /// which class the type alias denotes, without type arguments. If `this`
/// type alias expands in one or more steps to a builder which is not a
/// [TypeAliasBuilder] nor a [TypeVariableBuilder] then that builder is
/// returned. If this type alias is cyclic or expands to an invalid type or
/// a type that does not have a declaration (say, a function type) then `this`
/// is returned (when the type was invalid: with `thisType` set to
/// `const InvalidType()`). If `this` type alias expands to a
- /// [TypeVariableBuilder] then the type alias cannot be used in a constructor
- /// invocation. Then an error is emitted and `this` is returned.
+ /// [TypeVariableBuilder] then the type alias cannot be used as a class, in
+ /// which case an error is emitted and `this` is returned.
TypeDeclarationBuilder unaliasDeclaration(List<TypeBuilder> typeArguments,
- {bool isInvocation = false,
- int invocationCharOffset,
- Uri invocationFileUri}) {
+ {bool isUsedAsClass = false,
+ int usedAsClassCharOffset,
+ Uri usedAsClassFileUri}) {
if (_cachedUnaliasedDeclaration != null) return _cachedUnaliasedDeclaration;
Set<TypeDeclarationBuilder> builders = {this};
TypeDeclarationBuilder current = this;
@@ -241,15 +254,39 @@
// `_cachedUnaliasedDeclaration` because it changes from call to call
// with type aliases of this kind. Note that every `aliasBuilder.type`
// up to this point is a [NamedTypeBuilder], because only they can have
- // a non-null `type`. However, a constructor invocation is not admitted.
- if (isInvocation) {
- library.addProblem(messageTypedefTypeVariableNotConstructor,
- invocationCharOffset, noLength, invocationFileUri,
- context: [
- messageTypedefTypeVariableNotConstructorCause.withLocation(
- current.fileUri, current.charOffset, noLength),
- ]);
- return this;
+ // a non-null `type`. However, this type alias can not be used as a
+ // class.
+ if (isUsedAsClass) {
+ List<TypeBuilder> freshTypeArguments = [
+ if (typeVariables != null)
+ for (TypeVariableBuilder typeVariable in typeVariables)
+ new NamedTypeBuilder.fromTypeDeclarationBuilder(
+ typeVariable,
+ library.nonNullableBuilder,
+ const [],
+ fileUri,
+ charOffset,
+ ),
+ ];
+ TypeDeclarationBuilder typeDeclarationBuilder =
+ _unaliasDeclaration(freshTypeArguments);
+ bool found = false;
+ for (TypeBuilder typeBuilder in freshTypeArguments) {
+ if (typeBuilder.declaration == typeDeclarationBuilder) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ library.addProblem(messageTypedefTypeVariableNotConstructor,
+ usedAsClassCharOffset, noLength, usedAsClassFileUri,
+ context: [
+ messageTypedefTypeVariableNotConstructorCause.withLocation(
+ current.fileUri, current.charOffset, noLength),
+ ]);
+ return this;
+ }
+ if (typeArguments == null) return typeDeclarationBuilder;
}
return _unaliasDeclaration(typeArguments);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index c697bac..927f9e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -1081,6 +1081,7 @@
resolveRedirectingFactoryTargets();
finishVariableMetadata();
+ libraryBuilder.checkUncheckedTypedefTypes(typeEnvironment);
}
void checkAsyncReturnType(AsyncMarker asyncModifier, DartType returnType,
@@ -4530,9 +4531,9 @@
noLength));
}
type = aliasBuilder.unaliasDeclaration(null,
- isInvocation: true,
- invocationCharOffset: nameToken.charOffset,
- invocationFileUri: uri);
+ isUsedAsClass: true,
+ usedAsClassCharOffset: nameToken.charOffset,
+ usedAsClassFileUri: uri);
List<TypeBuilder> typeArgumentBuilders = [];
if (typeArguments != null) {
for (UnresolvedType unresolvedType in typeArguments) {
@@ -4620,6 +4621,23 @@
}
}
}
+
+ List<DartType> typeArgumentsToCheck = const <DartType>[];
+ if (typeArgumentBuilders != null && typeArgumentBuilders.isNotEmpty) {
+ typeArgumentsToCheck = new List.filled(
+ typeArgumentBuilders.length, const DynamicType(),
+ growable: false);
+ for (int i = 0; i < typeArgumentsToCheck.length; ++i) {
+ typeArgumentsToCheck[i] =
+ typeArgumentBuilders[i].build(libraryBuilder);
+ }
+ }
+ DartType typeToCheck = new TypedefType(
+ aliasBuilder.typedef, Nullability.nonNullable, typeArgumentsToCheck);
+ libraryBuilder.checkBoundsInType(
+ typeToCheck, typeEnvironment, uri, charOffset,
+ allowSuperBounded: false);
+
if (type is ClassBuilder) {
if (typeArguments != null) {
int numberOfTypeParameters = aliasBuilder.typeVariables?.length ?? 0;
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 25e0a70..38ee51c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -1374,7 +1374,10 @@
if (mixin is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = mixin;
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
- mixin = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ mixin = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
}
if (mixin is ClassBuilder) {
scope = mixin.scope.computeMixinScope();
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 0112d3f..8041794 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -3383,15 +3383,8 @@
if (condition is AbortConstant) {
return new AbortStatus(condition);
- } else if (condition is! BoolConstant) {
- return new AbortStatus(exprEvaluator.createErrorConstant(
- node.condition,
- templateConstEvalInvalidType.withArguments(
- condition,
- exprEvaluator.typeEnvironment.coreTypes.boolLegacyRawType,
- condition.getType(exprEvaluator._staticTypeContext),
- exprEvaluator.isNonNullableByDefault)));
}
+ assert(condition is BoolConstant);
return const ProceedStatus();
}
@@ -3399,23 +3392,13 @@
ExecutionStatus visitIfStatement(IfStatement node) {
Constant condition = evaluate(node.condition);
if (condition is AbortConstant) return new AbortStatus(condition);
- if (condition is BoolConstant) {
- if (condition.value) {
- return node.then.accept(this);
- } else if (node.otherwise != null) {
- return node.otherwise.accept(this);
- } else {
- return const ProceedStatus();
- }
- } else {
- return new AbortStatus(exprEvaluator.createErrorConstant(
- node.condition,
- templateConstEvalInvalidType.withArguments(
- condition,
- exprEvaluator.typeEnvironment.coreTypes.boolLegacyRawType,
- condition.getType(exprEvaluator._staticTypeContext),
- exprEvaluator.isNonNullableByDefault)));
+ assert(condition is BoolConstant);
+ if ((condition as BoolConstant).value) {
+ return node.then.accept(this);
+ } else if (node.otherwise != null) {
+ return node.otherwise.accept(this);
}
+ return const ProceedStatus();
}
@override
@@ -3446,6 +3429,7 @@
}
if (condition is AbortConstant) return new AbortStatus(condition);
+ assert(condition is BoolConstant);
return const ProceedStatus();
}
@@ -3486,6 +3470,7 @@
condition = evaluate(node.condition);
}
if (condition is AbortConstant) return new AbortStatus(condition);
+ assert(condition is BoolConstant);
return const ProceedStatus();
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 6f89031..a6e54b2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -3061,9 +3061,9 @@
if (declarationBuilder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declarationBuilder;
declarationBuilder = aliasBuilder.unaliasDeclaration(null,
- isInvocation: true,
- invocationCharOffset: this.fileOffset,
- invocationFileUri: _uri);
+ isUsedAsClass: true,
+ usedAsClassCharOffset: this.fileOffset,
+ usedAsClassFileUri: _uri);
}
if (declarationBuilder is DeclarationBuilder) {
DeclarationBuilder declaration = declarationBuilder;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 1bebec8..a178096 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -675,7 +675,10 @@
if (supertype is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = supertype;
NamedTypeBuilder namedBuilder = type;
- supertype = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ supertype = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
}
if (supertype is SourceClassBuilder && supertype.isMixinApplication) {
installForwardingConstructors(supertype);
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 3017856..bf02502 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -589,8 +589,11 @@
if (declarationBuilder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declarationBuilder;
NamedTypeBuilder namedBuilder = supertype;
- declarationBuilder =
- aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ declarationBuilder = aliasBuilder.unaliasDeclaration(
+ namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
result[declarationBuilder] = aliasBuilder;
} else {
result[declarationBuilder] = null;
@@ -606,8 +609,11 @@
if (declarationBuilder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declarationBuilder;
NamedTypeBuilder namedBuilder = interface;
- declarationBuilder =
- aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ declarationBuilder = aliasBuilder.unaliasDeclaration(
+ namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
result[declarationBuilder] = aliasBuilder;
} else {
result[declarationBuilder] = null;
@@ -621,8 +627,11 @@
if (declarationBuilder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = declarationBuilder;
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
- declarationBuilder =
- aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ declarationBuilder = aliasBuilder.unaliasDeclaration(
+ namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
result[declarationBuilder] = aliasBuilder;
} else {
result[declarationBuilder] = null;
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 51d4375..d13a474 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -188,6 +188,9 @@
final List<TypeVariableBuilder> boundlessTypeVariables =
<TypeVariableBuilder>[];
+ final List<UncheckedTypedefType> uncheckedTypedefTypes =
+ <UncheckedTypedefType>[];
+
// A list of alternating forwarders and the procedures they were generated
// for. Note that it may not include a forwarder-origin pair in cases when
// the former does not need to be updated after the body of the latter was
@@ -3778,6 +3781,7 @@
}
}
inferredTypes.clear();
+ checkUncheckedTypedefTypes(typeEnvironment);
}
void registerImplicitlyTypedField(FieldBuilder fieldBuilder) {
@@ -3829,6 +3833,21 @@
_pendingNullabilities
.add(new PendingNullability(fileUri, charOffset, type));
}
+
+ /// Performs delayed bounds checks on [TypedefType]s for the library
+ ///
+ /// As [TypedefType]s are built, they are eagerly unaliased, making it
+ /// impossible to perform the bounds checks on them at the time when the
+ /// checks can be done. To perform the checks, [TypedefType]s are added to
+ /// [uncheckedTypedefTypes] as they are built. This method performs the
+ /// checks and clears the list of the types for the delayed check.
+ void checkUncheckedTypedefTypes(TypeEnvironment typeEnvironment) {
+ for (UncheckedTypedefType uncheckedTypedefType in uncheckedTypedefTypes) {
+ checkBoundsInType(uncheckedTypedefType.typeToCheck, typeEnvironment,
+ uncheckedTypedefType.fileUri, uncheckedTypedefType.offset);
+ }
+ uncheckedTypedefTypes.clear();
+ }
}
// The kind of type parameter scope built by a [TypeParameterScopeBuilder]
@@ -4295,3 +4314,14 @@
PendingNullability(this.fileUri, this.charOffset, this.type);
}
+
+class UncheckedTypedefType {
+ final TypedefType typeToCheck;
+
+ // TODO(dmitryas): Make these fields nullable when the library is opted-in to
+ // NNBD.
+ int offset;
+ Uri fileUri;
+
+ UncheckedTypedefType(this.typeToCheck);
+}
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 1183386..eed0da7 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -907,7 +907,10 @@
if (builder is TypeAliasBuilder) {
TypeAliasBuilder aliasBuilder = builder;
NamedTypeBuilder namedBuilder = mixedInTypeBuilder;
- builder = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ builder = aliasBuilder.unaliasDeclaration(namedBuilder.arguments,
+ isUsedAsClass: true,
+ usedAsClassCharOffset: namedBuilder.charOffset,
+ usedAsClassFileUri: namedBuilder.fileUri);
if (builder is! ClassBuilder) {
cls.addProblem(
templateIllegalMixin.withArguments(builder.fullNameForErrors),
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index c8fbea5e..2d7a818 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -3425,12 +3425,12 @@
receiver = _hoist(receiver, receiverType, hoistedExpressions);
}
- Map<DartType, NonPromotionReason> Function() whyNotPromotedInfo;
+ Map<DartType, NonPromotionReason> Function() whyNotPromoted;
if (!isTopLevel && target.isNullable) {
// We won't report the error until later (after we have an
// invocationResult), but we need to gather "why not promoted" info now,
// before we tell flow analysis about the property get.
- whyNotPromotedInfo = flowAnalysis?.whyNotPromoted(receiver);
+ whyNotPromoted = flowAnalysis?.whyNotPromoted(receiver);
}
Name originalName = field.name;
@@ -3516,7 +3516,7 @@
// in this scenario?
List<LocatedMessage> context = getWhyNotPromotedContext(
receiver,
- whyNotPromotedInfo(),
+ whyNotPromoted(),
invocationResult.expression,
(type) => !type.isPotentiallyNullable);
invocationResult = wrapExpressionInferenceResultInProblem(
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 7d290ee..912054f 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -3155,6 +3155,7 @@
unbind
uncertain
unchanged
+unchecked
unclaimed
unclear
undeclared
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index f2aa65a..8050222 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -57,6 +57,12 @@
bail
bailing
bailout
+bar1a
+bar1b
+bar2a
+bar2b
+bar3a
+bar3b
barbar
bash
bat
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart
new file mode 100644
index 0000000..84f5324
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A<T> {}
+
+typedef B<X extends A<X>> = A<X>;
+
+foo() {
+ B<A<int>> x1;
+ A<B<A<int>>> x2;
+}
+
+B<A<int>> bar1a() => throw 42;
+A<B<A<int>>> bar1b() => throw 42;
+
+bar2a(B<A<int>> x) => throw 42;
+bar2b(A<B<A<int>>> x) => throw 42;
+
+bar3a<X extends B<A<int>>>() => throw 42;
+bar3b<X extends A<B<A<int>>>>() => throw 42;
+
+class Bar1<X extends B<A<int>>> {
+ B<A<int>> barBar11() => throw 42;
+ barBar12(B<A<int>> x) => throw 42;
+ barBar13<X extends B<A<int>>>() => throw 42;
+}
+
+class Bar2<X extends A<B<A<int>>>> {
+ A<B<A<int>>> barBar21() => throw 42;
+ barBar22(A<B<A<int>>> x) => throw 42;
+ barBar23<X extends A<B<A<int>>>>() => throw 42;
+}
+
+typedef Baz1 = B<A<int>>;
+typedef Baz2 = A<B<A<int>>>;
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.expect
new file mode 100644
index 0000000..7506643
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.expect
@@ -0,0 +1,216 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:20:17: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3a<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:21:19: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3b<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:23:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar1<X extends B<A<int>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:26:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar13<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:29:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar2<X extends A<B<A<int>>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:32:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar23<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:14:1: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> bar1a() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:15:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> bar1b() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:17:7: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2a(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:18:9: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2b(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:24:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> barBar11() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:25:12: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar12(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:30:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> barBar21() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:31:14: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar22(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:35:16: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz1 = B<A<int>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:36:18: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz2 = A<B<A<int>>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:10:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> x1;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:11:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> x2;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef Baz1 = self::A<self::A<core::int>>;
+typedef Baz2 = self::A<self::A<self::A<core::int>>>;
+class A<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T%>
+ : super core::Object::•()
+ ;
+}
+class Bar1<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>> extends core::Object {
+ synthetic constructor •() → self::Bar1<self::Bar1::X>
+ : super core::Object::•()
+ ;
+ method barBar11() → self::A<self::A<core::int>>
+ return throw 42;
+ method barBar12(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+ method barBar13<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+}
+class Bar2<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>> extends core::Object {
+ synthetic constructor •() → self::Bar2<self::Bar2::X>
+ : super core::Object::•()
+ ;
+ method barBar21() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+ method barBar22(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+ method barBar23<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+}
+static method foo() → dynamic {
+ self::A<self::A<core::int>> x1;
+ self::A<self::A<self::A<core::int>>> x2;
+}
+static method bar1a() → self::A<self::A<core::int>>
+ return throw 42;
+static method bar1b() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+static method bar2a(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+static method bar2b(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+static method bar3a<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+static method bar3b<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.transformed.expect
new file mode 100644
index 0000000..7506643
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.strong.transformed.expect
@@ -0,0 +1,216 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:20:17: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3a<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:21:19: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3b<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:23:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar1<X extends B<A<int>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:26:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar13<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:29:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar2<X extends A<B<A<int>>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:32:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar23<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:14:1: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> bar1a() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:15:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> bar1b() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:17:7: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2a(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:18:9: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2b(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:24:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> barBar11() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:25:12: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar12(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:30:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> barBar21() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:31:14: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar22(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:35:16: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz1 = B<A<int>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:36:18: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz2 = A<B<A<int>>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:10:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> x1;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:11:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> x2;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef Baz1 = self::A<self::A<core::int>>;
+typedef Baz2 = self::A<self::A<self::A<core::int>>>;
+class A<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T%>
+ : super core::Object::•()
+ ;
+}
+class Bar1<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>> extends core::Object {
+ synthetic constructor •() → self::Bar1<self::Bar1::X>
+ : super core::Object::•()
+ ;
+ method barBar11() → self::A<self::A<core::int>>
+ return throw 42;
+ method barBar12(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+ method barBar13<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+}
+class Bar2<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>> extends core::Object {
+ synthetic constructor •() → self::Bar2<self::Bar2::X>
+ : super core::Object::•()
+ ;
+ method barBar21() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+ method barBar22(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+ method barBar23<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+}
+static method foo() → dynamic {
+ self::A<self::A<core::int>> x1;
+ self::A<self::A<self::A<core::int>>> x2;
+}
+static method bar1a() → self::A<self::A<core::int>>
+ return throw 42;
+static method bar1b() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+static method bar2a(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+static method bar2b(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+static method bar3a<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+static method bar3b<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.textual_outline.expect
new file mode 100644
index 0000000..2836a16
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.textual_outline.expect
@@ -0,0 +1,22 @@
+class A<T> {}
+typedef B<X extends A<X>> = A<X>;
+foo() {}
+B<A<int>> bar1a() => throw 42;
+A<B<A<int>>> bar1b() => throw 42;
+bar2a(B<A<int>> x) => throw 42;
+bar2b(A<B<A<int>>> x) => throw 42;
+bar3a<X extends B<A<int>>>() => throw 42;
+bar3b<X extends A<B<A<int>>>>() => throw 42;
+class Bar1<X extends B<A<int>>> {
+ B<A<int>> barBar11() => throw 42;
+ barBar12(B<A<int>> x) => throw 42;
+ barBar13<X extends B<A<int>>>() => throw 42;
+}
+class Bar2<X extends A<B<A<int>>>> {
+ A<B<A<int>>> barBar21() => throw 42;
+ barBar22(A<B<A<int>>> x) => throw 42;
+ barBar23<X extends A<B<A<int>>>>() => throw 42;
+}
+typedef Baz1 = B<A<int>>;
+typedef Baz2 = A<B<A<int>>>;
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.expect
new file mode 100644
index 0000000..7506643
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.expect
@@ -0,0 +1,216 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:20:17: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3a<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:21:19: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3b<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:23:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar1<X extends B<A<int>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:26:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar13<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:29:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar2<X extends A<B<A<int>>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:32:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar23<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:14:1: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> bar1a() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:15:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> bar1b() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:17:7: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2a(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:18:9: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2b(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:24:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> barBar11() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:25:12: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar12(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:30:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> barBar21() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:31:14: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar22(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:35:16: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz1 = B<A<int>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:36:18: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz2 = A<B<A<int>>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:10:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> x1;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:11:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> x2;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef Baz1 = self::A<self::A<core::int>>;
+typedef Baz2 = self::A<self::A<self::A<core::int>>>;
+class A<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T%>
+ : super core::Object::•()
+ ;
+}
+class Bar1<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>> extends core::Object {
+ synthetic constructor •() → self::Bar1<self::Bar1::X>
+ : super core::Object::•()
+ ;
+ method barBar11() → self::A<self::A<core::int>>
+ return throw 42;
+ method barBar12(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+ method barBar13<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+}
+class Bar2<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>> extends core::Object {
+ synthetic constructor •() → self::Bar2<self::Bar2::X>
+ : super core::Object::•()
+ ;
+ method barBar21() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+ method barBar22(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+ method barBar23<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+}
+static method foo() → dynamic {
+ self::A<self::A<core::int>> x1;
+ self::A<self::A<self::A<core::int>>> x2;
+}
+static method bar1a() → self::A<self::A<core::int>>
+ return throw 42;
+static method bar1b() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+static method bar2a(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+static method bar2b(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+static method bar3a<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+static method bar3b<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.outline.expect
new file mode 100644
index 0000000..e66dde1
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.outline.expect
@@ -0,0 +1,194 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:20:17: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3a<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:21:19: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3b<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:23:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar1<X extends B<A<int>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:26:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar13<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:29:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar2<X extends A<B<A<int>>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:32:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar23<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:14:1: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> bar1a() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:15:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> bar1b() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:17:7: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2a(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:18:9: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2b(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:24:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> barBar11() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:25:12: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar12(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:30:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> barBar21() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:31:14: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar22(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:35:16: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz1 = B<A<int>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:36:18: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz2 = A<B<A<int>>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef Baz1 = self::A<self::A<core::int>>;
+typedef Baz2 = self::A<self::A<self::A<core::int>>>;
+class A<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T%>
+ ;
+}
+class Bar1<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>> extends core::Object {
+ synthetic constructor •() → self::Bar1<self::Bar1::X>
+ ;
+ method barBar11() → self::A<self::A<core::int>>
+ ;
+ method barBar12(self::A<self::A<core::int>> x) → dynamic
+ ;
+ method barBar13<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ ;
+}
+class Bar2<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>> extends core::Object {
+ synthetic constructor •() → self::Bar2<self::Bar2::X>
+ ;
+ method barBar21() → self::A<self::A<self::A<core::int>>>
+ ;
+ method barBar22(self::A<self::A<self::A<core::int>>> x) → dynamic
+ ;
+ method barBar23<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ ;
+}
+static method foo() → dynamic
+ ;
+static method bar1a() → self::A<self::A<core::int>>
+ ;
+static method bar1b() → self::A<self::A<self::A<core::int>>>
+ ;
+static method bar2a(self::A<self::A<core::int>> x) → dynamic
+ ;
+static method bar2b(self::A<self::A<self::A<core::int>>> x) → dynamic
+ ;
+static method bar3a<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ ;
+static method bar3b<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.transformed.expect
new file mode 100644
index 0000000..7506643
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart.weak.transformed.expect
@@ -0,0 +1,216 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:20:17: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3a<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:21:19: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar3b<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:23:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar1<X extends B<A<int>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:26:22: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar13<X extends B<A<int>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:29:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// class Bar2<X extends A<B<A<int>>>> {
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:32:24: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar23<X extends A<B<A<int>>>>() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:14:1: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> bar1a() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:15:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> bar1b() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:17:7: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2a(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:18:9: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// bar2b(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:24:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> barBar11() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:25:12: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar12(B<A<int>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:30:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> barBar21() => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:31:14: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// barBar22(A<B<A<int>>> x) => throw 42;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:35:16: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz1 = B<A<int>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:36:18: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef Baz2 = A<B<A<int>>>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:10:3: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// B<A<int>> x1;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:11:5: Error: Type argument 'A<int>' doesn't conform to the bound 'A<X>' of the type variable 'X' on 'B'.
+// - 'A' is from 'pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// A<B<A<int>>> x2;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends A<X>> = A<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef B<X extends self::A<X> = self::A<dynamic>> = self::A<X>;
+typedef Baz1 = self::A<self::A<core::int>>;
+typedef Baz2 = self::A<self::A<self::A<core::int>>>;
+class A<T extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::T%>
+ : super core::Object::•()
+ ;
+}
+class Bar1<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>> extends core::Object {
+ synthetic constructor •() → self::Bar1<self::Bar1::X>
+ : super core::Object::•()
+ ;
+ method barBar11() → self::A<self::A<core::int>>
+ return throw 42;
+ method barBar12(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+ method barBar13<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+}
+class Bar2<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>> extends core::Object {
+ synthetic constructor •() → self::Bar2<self::Bar2::X>
+ : super core::Object::•()
+ ;
+ method barBar21() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+ method barBar22(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+ method barBar23<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+}
+static method foo() → dynamic {
+ self::A<self::A<core::int>> x1;
+ self::A<self::A<self::A<core::int>>> x2;
+}
+static method bar1a() → self::A<self::A<core::int>>
+ return throw 42;
+static method bar1b() → self::A<self::A<self::A<core::int>>>
+ return throw 42;
+static method bar2a(self::A<self::A<core::int>> x) → dynamic
+ return throw 42;
+static method bar2b(self::A<self::A<self::A<core::int>>> x) → dynamic
+ return throw 42;
+static method bar3a<X extends self::A<self::A<core::int>> = self::A<self::A<core::int>>>() → dynamic
+ return throw 42;
+static method bar3b<X extends self::A<self::A<self::A<core::int>>> = self::A<self::A<self::A<core::int>>>>() → dynamic
+ return throw 42;
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart
new file mode 100644
index 0000000..1317c74
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo() {
+ A<String> a;
+}
+
+typedef A<X extends int> = B<String>;
+typedef B<X extends int> = C<String>;
+typedef C<X extends int> = X;
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.expect
new file mode 100644
index 0000000..2b7816b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'C'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef B<X extends int> = C<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:11:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends int> = X;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef A<X extends int> = B<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends int> = C<String>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:6:3: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// A<String> a;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends int> = B<String>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<unrelated X extends core::int = core::int> = core::String;
+typedef B<unrelated X extends core::int = core::int> = core::String;
+typedef C<X extends core::int = core::int> = X;
+static method foo() → dynamic {
+ core::String a;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.transformed.expect
new file mode 100644
index 0000000..2b7816b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.strong.transformed.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'C'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef B<X extends int> = C<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:11:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends int> = X;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef A<X extends int> = B<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends int> = C<String>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:6:3: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// A<String> a;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends int> = B<String>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<unrelated X extends core::int = core::int> = core::String;
+typedef B<unrelated X extends core::int = core::int> = core::String;
+typedef C<X extends core::int = core::int> = X;
+static method foo() → dynamic {
+ core::String a;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.textual_outline.expect
new file mode 100644
index 0000000..ebe8a0b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.textual_outline.expect
@@ -0,0 +1,5 @@
+foo() {}
+typedef A<X extends int> = B<String>;
+typedef B<X extends int> = C<String>;
+typedef C<X extends int> = X;
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.expect
new file mode 100644
index 0000000..2b7816b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'C'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef B<X extends int> = C<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:11:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends int> = X;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef A<X extends int> = B<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends int> = C<String>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:6:3: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// A<String> a;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends int> = B<String>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<unrelated X extends core::int = core::int> = core::String;
+typedef B<unrelated X extends core::int = core::int> = core::String;
+typedef C<X extends core::int = core::int> = X;
+static method foo() → dynamic {
+ core::String a;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.outline.expect
new file mode 100644
index 0000000..0649b07
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.outline.expect
@@ -0,0 +1,30 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'C'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef B<X extends int> = C<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:11:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends int> = X;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef A<X extends int> = B<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends int> = C<String>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<unrelated X extends core::int = core::int> = core::String;
+typedef B<unrelated X extends core::int = core::int> = core::String;
+typedef C<X extends core::int = core::int> = X;
+static method foo() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.transformed.expect
new file mode 100644
index 0000000..2b7816b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart.weak.transformed.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'C'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef B<X extends int> = C<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:11:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef C<X extends int> = X;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:28: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// typedef A<X extends int> = B<String>;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:10:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends int> = C<String>;
+// ^
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:6:3: Error: Type argument 'String' doesn't conform to the bound 'int' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// A<String> a;
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_in_typedef.dart:9:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends int> = B<String>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<unrelated X extends core::int = core::int> = core::String;
+typedef B<unrelated X extends core::int = core::int> = core::String;
+typedef C<X extends core::int = core::int> = X;
+static method foo() → dynamic {
+ core::String a;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart
new file mode 100644
index 0000000..e08489b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {}
+
+typedef B<X extends String> = A;
+
+class C<Y extends B<int>> {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart
new file mode 100644
index 0000000..0123a2a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import './aliased_checks_no_bodies_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.expect
new file mode 100644
index 0000000..381925d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///aliased_checks_no_bodies_lib.dart";
+
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:9:19: Error: Type argument 'int' doesn't conform to the bound 'String' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class C<Y extends B<int>> {}
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends String> = A;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::String = core::String> = self2::A;
+class A extends core::Object {
+ synthetic constructor •() → self2::A
+ : super core::Object::•()
+ ;
+}
+class C<Y extends self2::A = self2::A> extends core::Object {
+ synthetic constructor •() → self2::C<self2::C::Y>
+ : super core::Object::•()
+ ;
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.transformed.expect
new file mode 100644
index 0000000..381925d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.strong.transformed.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///aliased_checks_no_bodies_lib.dart";
+
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:9:19: Error: Type argument 'int' doesn't conform to the bound 'String' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class C<Y extends B<int>> {}
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends String> = A;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::String = core::String> = self2::A;
+class A extends core::Object {
+ synthetic constructor •() → self2::A
+ : super core::Object::•()
+ ;
+}
+class C<Y extends self2::A = self2::A> extends core::Object {
+ synthetic constructor •() → self2::C<self2::C::Y>
+ : super core::Object::•()
+ ;
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline.expect
new file mode 100644
index 0000000..ac7da8d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import './aliased_checks_no_bodies_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ac7da8d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import './aliased_checks_no_bodies_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.expect
new file mode 100644
index 0000000..381925d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///aliased_checks_no_bodies_lib.dart";
+
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:9:19: Error: Type argument 'int' doesn't conform to the bound 'String' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class C<Y extends B<int>> {}
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends String> = A;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::String = core::String> = self2::A;
+class A extends core::Object {
+ synthetic constructor •() → self2::A
+ : super core::Object::•()
+ ;
+}
+class C<Y extends self2::A = self2::A> extends core::Object {
+ synthetic constructor •() → self2::C<self2::C::Y>
+ : super core::Object::•()
+ ;
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.outline.expect
new file mode 100644
index 0000000..ecbd101
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.outline.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///aliased_checks_no_bodies_lib.dart";
+
+static method main() → dynamic
+ ;
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:9:19: Error: Type argument 'int' doesn't conform to the bound 'String' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class C<Y extends B<int>> {}
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends String> = A;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::String = core::String> = self2::A;
+class A extends core::Object {
+ synthetic constructor •() → self2::A
+ ;
+}
+class C<Y extends self2::A = self2::A> extends core::Object {
+ synthetic constructor •() → self2::C<self2::C::Y>
+ ;
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.transformed.expect
new file mode 100644
index 0000000..381925d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_main.dart.weak.transformed.expect
@@ -0,0 +1,33 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///aliased_checks_no_bodies_lib.dart";
+
+static method main() → dynamic {}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:9:19: Error: Type argument 'int' doesn't conform to the bound 'String' of the type variable 'X' on 'B'.
+// Try changing type arguments so that they conform to the bounds.
+// class C<Y extends B<int>> {}
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/aliased_checks_no_bodies_lib.dart:7:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef B<X extends String> = A;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+typedef B<unrelated X extends core::String = core::String> = self2::A;
+class A extends core::Object {
+ synthetic constructor •() → self2::A
+ : super core::Object::•()
+ ;
+}
+class C<Y extends self2::A = self2::A> extends core::Object {
+ synthetic constructor •() → self2::C<self2::C::Y>
+ : super core::Object::•()
+ ;
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart
new file mode 100644
index 0000000..2da162b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C<X> {}
+typedef A<X extends num, Y> = C<X>;
+
+foo() {
+ new A<dynamic, String>();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.expect
new file mode 100644
index 0000000..0c361f8
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:9:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:6:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new self::C::•<dynamic>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.transformed.expect
new file mode 100644
index 0000000..0c361f8
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.strong.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:9:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:6:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new self::C::•<dynamic>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.textual_outline.expect
new file mode 100644
index 0000000..1eab745
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+class C<X> {}
+typedef A<X extends num, Y> = C<X>;
+foo() {}
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.expect
new file mode 100644
index 0000000..0c361f8
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:9:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:6:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new self::C::•<dynamic>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.outline.expect
new file mode 100644
index 0000000..67117f8
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.outline.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%>
+ ;
+}
+static method foo() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.transformed.expect
new file mode 100644
index 0000000..0c361f8
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:9:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls.dart:6:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method foo() → dynamic {
+ new self::C::•<dynamic>();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart
new file mode 100644
index 0000000..c93b7d9
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib;
+
+part './unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart';
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart
new file mode 100644
index 0000000..9bf694a
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import './unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.expect
new file mode 100644
index 0000000..afdc55d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart";
+
+static method main() → dynamic {}
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:11:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:8:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+part ./unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart;
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self2::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object { // from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
+ synthetic constructor •() → self2::C<self2::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method /* from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart */ foo() → dynamic {
+ new self2::C::•<dynamic>();
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.transformed.expect
new file mode 100644
index 0000000..afdc55d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.strong.transformed.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart";
+
+static method main() → dynamic {}
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:11:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:8:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+part ./unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart;
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self2::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object { // from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
+ synthetic constructor •() → self2::C<self2::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method /* from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart */ foo() → dynamic {
+ new self2::C::•<dynamic>();
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline.expect
new file mode 100644
index 0000000..c76bce2
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import './unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c76bce2
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import './unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.expect
new file mode 100644
index 0000000..afdc55d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart";
+
+static method main() → dynamic {}
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:11:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:8:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+part ./unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart;
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self2::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object { // from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
+ synthetic constructor •() → self2::C<self2::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method /* from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart */ foo() → dynamic {
+ new self2::C::•<dynamic>();
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.outline.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.outline.expect
new file mode 100644
index 0000000..d3cc16c
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.outline.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart";
+
+static method main() → dynamic
+ ;
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib /*isNonNullableByDefault*/;
+import self as self2;
+import "dart:core" as core;
+
+part ./unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart;
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self2::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object { // from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
+ synthetic constructor •() → self2::C<self2::C::X%>
+ ;
+}
+static method /* from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart */ foo() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.transformed.expect b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.transformed.expect
new file mode 100644
index 0000000..afdc55d
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_main.dart.weak.transformed.expect
@@ -0,0 +1,32 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+import "org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_lib.dart";
+
+static method main() → dynamic {}
+
+library unaliased_bounds_checks_in_constructor_calls_with_parts_lib /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:11:7: Error: Type argument 'dynamic' doesn't conform to the bound 'num' of the type variable 'X' on 'A'.
+// Try changing type arguments so that they conform to the bounds.
+// new A<dynamic, String>();
+// ^
+// pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart:8:11: Context: This is the type variable whose bound isn't conformed to.
+// typedef A<X extends num, Y> = C<X>;
+// ^
+//
+import self as self2;
+import "dart:core" as core;
+
+part ./unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart;
+typedef A<X extends core::num = core::num, unrelated Y extends core::Object? = dynamic> = self2::C<X>;
+class C<X extends core::Object? = dynamic> extends core::Object { // from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
+ synthetic constructor •() → self2::C<self2::C::X%>
+ : super core::Object::•()
+ ;
+}
+static method /* from org-dartlang-testcase:///unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart */ foo() → dynamic {
+ new self2::C::•<dynamic>();
+}
diff --git a/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
new file mode 100644
index 0000000..3ccd59b
--- /dev/null
+++ b/pkg/front_end/testcases/nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls_with_parts_part_lib.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of unaliased_bounds_checks_in_constructor_calls_with_parts_lib;
+
+class C<X> {}
+typedef A<X extends num, Y> = C<X>;
+
+foo() {
+ new A<dynamic, String>();
+}
+
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index b703c23..1ca31da 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -124,9 +124,12 @@
nnbd_mixed/inheritance_from_opt_in: FormatterCrash
nnbd_mixed/issue41597: FormatterCrash
nnbd_mixed/null_safety_invalid_language_version: FormatterCrash
+nonfunction_type_aliases/aliased_checks: FormatterCrash
+nonfunction_type_aliases/aliased_checks_in_typedef: FormatterCrash
nonfunction_type_aliases/issue41501: FormatterCrash
nonfunction_type_aliases/issue42446: FormatterCrash
nonfunction_type_aliases/issue45051: FormatterCrash
+nonfunction_type_aliases/unaliased_bounds_checks_in_constructor_calls: FormatterCrash
rasta/bad_redirection: FormatterCrash
rasta/issue_000032: FormatterCrash
rasta/issue_000034: FormatterCrash
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 0362d62..68492a3 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -187,12 +187,6 @@
{})[uniqueIdentifierForSpan(node.offset, node.end)];
}
- /// If the given [node] is preceded by a `/*required*/` hint, returns the
- /// HintComment for it; otherwise returns `null`. See [recordRequiredHint].
- HintComment getRequiredHint(Source source, FormalParameter node) {
- return (_requiredHints[source] ?? {})[node.offset];
- }
-
/// If the given [expression] is followed by a null check hint (`/*!*/`),
/// returns the HintComment for it; otherwise returns `null`. See
/// [recordNullCheckHint].
@@ -201,6 +195,12 @@
{})[(uniqueIdentifierForSpan(expression.offset, expression.end))];
}
+ /// If the given [node] is preceded by a `/*required*/` hint, returns the
+ /// HintComment for it; otherwise returns `null`. See [recordRequiredHint].
+ HintComment getRequiredHint(Source source, FormalParameter node) {
+ return (_requiredHints[source] ?? {})[node.offset];
+ }
+
/// Records conditional discard information for the given AST node (which is
/// an `if` statement or a conditional (`?:`) expression).
void recordConditionalDiscard(
@@ -268,12 +268,6 @@
{})[uniqueIdentifierForSpan(node.offset, node.end)] = hintComment;
}
- /// Records that the given [node] was preceded by a `/*required*/` hint.
- void recordRequiredHint(
- Source source, FormalParameter node, HintComment hint) {
- (_requiredHints[source] ??= {})[node.offset] = hint;
- }
-
/// Records that the given [expression] is followed by a null check hint
/// (`/*!*/`), for later recall by [hasNullCheckHint].
void recordNullCheckHint(
@@ -283,6 +277,12 @@
hintComment;
}
+ /// Records that the given [node] was preceded by a `/*required*/` hint.
+ void recordRequiredHint(
+ Source source, FormalParameter node, HintComment hint) {
+ (_requiredHints[source] ??= {})[node.offset] = hint;
+ }
+
/// Records the fact that prior to migration, an unnecessary cast existed at
/// [node].
void recordUnnecessaryCast(Source source, AsExpression node) {
@@ -371,7 +371,8 @@
/// Creates a decorated type for the given [element], which should come from
/// an already-migrated library (or the SDK).
DecoratedType _createDecoratedElementType(Element element) {
- if (_graph.isBeingMigrated(element.library.source)) {
+ if (_graph.isBeingMigrated(element.library.source) &&
+ !_isLoadLibraryElement(element)) {
var description;
if (ElementTypeProvider.current is MigrationResolutionHooksImpl) {
// Don't attempt to call toString() on element, or we will overflow.
@@ -429,6 +430,12 @@
return result;
}
+ bool _isLoadLibraryElement(Element element) =>
+ element.isSynthetic &&
+ element is FunctionElement &&
+ element.enclosingElement is LibraryElement &&
+ element.name == 'loadLibrary';
+
/// Inverts the logic of [uniqueIdentifierForSpan], producing an (offset, end)
/// pair.
static OffsetEndPair spanForUniqueIdentifier(int span) {
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 97bac6d..ff70ada 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -4695,6 +4695,46 @@
await _checkSingleFileChanges(content, expected);
}
+ Future<void> test_loadLibrary_call() async {
+ var testPath = convertPath('$testsPath/lib/test.dart');
+ var otherPath = convertPath('$testsPath/lib/other.dart');
+ var content = {
+ testPath: '''
+import 'other.dart' deferred as other;
+Future<Object> f() => other.loadLibrary();
+''',
+ otherPath: ''
+ };
+ var expected = {
+ testPath: '''
+import 'other.dart' deferred as other;
+Future<Object?> f() => other.loadLibrary();
+''',
+ otherPath: ''
+ };
+ await _checkMultipleFileChanges(content, expected);
+ }
+
+ Future<void> test_loadLibrary_tearOff() async {
+ var testPath = convertPath('$testsPath/lib/test.dart');
+ var otherPath = convertPath('$testsPath/lib/other.dart');
+ var content = {
+ testPath: '''
+import 'other.dart' deferred as other;
+Future<Object> Function() f() => other.loadLibrary;
+''',
+ otherPath: ''
+ };
+ var expected = {
+ testPath: '''
+import 'other.dart' deferred as other;
+Future<Object?> Function() f() => other.loadLibrary;
+''',
+ otherPath: ''
+ };
+ await _checkMultipleFileChanges(content, expected);
+ }
+
Future<void> test_local_function() async {
var content = '''
int f(int i) {
diff --git a/pkg/scrape/example/null_aware.dart b/pkg/scrape/example/null_aware.dart
index 392798e..4437bd2 100644
--- a/pkg/scrape/example/null_aware.dart
+++ b/pkg/scrape/example/null_aware.dart
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
-
import 'package:scrape/scrape.dart';
void main(List<String> arguments) {
@@ -235,7 +234,7 @@
}
if (parent is BinaryExpression) {
- recordType('Uncategorized ${parent}');
+ recordType('Uncategorized $parent');
return;
}
diff --git a/pkg/vm/lib/transformations/pragma.dart b/pkg/vm/lib/transformations/pragma.dart
index d27f3d8..cde363a 100644
--- a/pkg/vm/lib/transformations/pragma.dart
+++ b/pkg/vm/lib/transformations/pragma.dart
@@ -13,6 +13,7 @@
const kResultTypeUsesPassedTypeArguments =
"result-type-uses-passed-type-arguments";
const kRecognizedPragmaName = "vm:recognized";
+const kDisableUnboxedParametetersPragmaName = "vm:disable-unboxed-parameters";
abstract class ParsedPragma {}
@@ -46,6 +47,10 @@
ParsedRecognized(this.type);
}
+class ParsedDisableUnboxedParameters extends ParsedPragma {
+ ParsedDisableUnboxedParameters();
+}
+
abstract class PragmaAnnotationParser {
/// May return 'null' if the annotation does not represent a recognized
/// @pragma.
@@ -142,6 +147,8 @@
"pragma: $options";
}
return new ParsedRecognized(type);
+ case kDisableUnboxedParametetersPragmaName:
+ return new ParsedDisableUnboxedParameters();
default:
return null;
}
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index 7375c51..e24408b 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -233,6 +233,19 @@
(expectedTypes == null || expectedTypes.contains(type));
}
+ bool hasDisableUnboxedParameters(Member member) {
+ for (var annotation in member.annotations) {
+ ParsedPragma pragma = _matcher.parsePragma(annotation);
+ if (pragma is ParsedDisableUnboxedParameters) {
+ if (member.enclosingLibrary.importUri.scheme != "dart") {
+ throw "ERROR: Cannot use @pragma(vm:disable-unboxed-parameters) outside core libraries.";
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
/// Simulate the execution of a native method by adding its entry points
/// using [entryPointsListener]. Returns result type of the native method.
TypeExpr handleNativeProcedure(
diff --git a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
index 792dc99..03f7ef2 100644
--- a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
+++ b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
@@ -203,7 +203,8 @@
_nativeCodeOracle.isRecognized(member, const [
PragmaRecognizedType.AsmIntrinsic,
PragmaRecognizedType.Other
- ]);
+ ]) ||
+ _nativeCodeOracle.hasDisableUnboxedParameters(member);
}
bool _isNative(Member member) => getExternalName(member) != null;
diff --git a/runtime/observatory/tests/service/service_kernel.status b/runtime/observatory/tests/service/service_kernel.status
index f729ce3..8608b32 100644
--- a/runtime/observatory/tests/service/service_kernel.status
+++ b/runtime/observatory/tests/service/service_kernel.status
@@ -31,6 +31,7 @@
pause_on_exceptions_test: SkipByDesign # No incremental compiler available.
rewind_optimized_out_test: SkipByDesign # No incremental compiler available.
rewind_test: SkipByDesign # No incremental compiler available.
+sigquit_starts_service_test: SkipByDesign # Spawns a secondary process using Platform.executable.
[ $compiler == dartk ]
bad_reload_test: RuntimeError # Issue 34025
diff --git a/runtime/observatory_2/tests/service_2/service_2_kernel.status b/runtime/observatory_2/tests/service_2/service_2_kernel.status
index f56c520..227cb0a 100644
--- a/runtime/observatory_2/tests/service_2/service_2_kernel.status
+++ b/runtime/observatory_2/tests/service_2/service_2_kernel.status
@@ -31,6 +31,7 @@
pause_on_exceptions_test: SkipByDesign # No incremental compiler available.
rewind_optimized_out_test: SkipByDesign # No incremental compiler available.
rewind_test: SkipByDesign # No incremental compiler available.
+sigquit_starts_service_test: SkipByDesign # Spawns a secondary process using Platform.executable.
[ $compiler == dartk ]
bad_reload_test: RuntimeError # Issue 34025
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index af137ed..8322ba6 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -16,7 +16,7 @@
// Version of DartFuzz. Increase this each time changes are made
// to preserve the property that a given version of DartFuzz yields
// the same fuzzed program for a deterministic random seed.
-const String version = '1.88';
+const String version = '1.89';
// Restriction on statements and expressions.
const int stmtDepth = 1;
@@ -792,6 +792,7 @@
emitLn('// Program generated as:');
emitLn('// dart dartfuzz.dart --seed $seed --${fp ? "" : "no-"}fp '
'--${ffi ? "" : "no-"}ffi --${flatTp ? "" : "no-"}flat');
+ emitLn('// @dart=2.7');
emitNewline();
emitImport('dart:async');
emitImport('dart:cli');
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index de299cd..49bbe05 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -224,33 +224,6 @@
return false;
}
-static bool HasLikelySmiOperand(InstanceCallInstr* instr) {
- ASSERT(instr->type_args_len() == 0);
-
- // If Smi is not assignable to the interface target of the call, the receiver
- // is definitely not a Smi.
- if (!instr->CanReceiverBeSmiBasedOnInterfaceTarget(
- Thread::Current()->zone())) {
- return false;
- }
-
- // Phis with at least one known smi are // guessed to be likely smi as well.
- for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) {
- PhiInstr* phi = instr->ArgumentAt(i)->AsPhi();
- if (phi != NULL) {
- for (intptr_t j = 0; j < phi->InputCount(); ++j) {
- if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true;
- }
- }
- }
- // If all of the inputs are known smis or the result of CheckedSmiOp,
- // we guess the operand to be likely smi.
- for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) {
- if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false;
- }
- return true;
-}
-
bool AotCallSpecializer::TryInlineFieldAccess(InstanceCallInstr* call) {
const Token::Kind op_kind = call->token_kind();
if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
@@ -798,53 +771,6 @@
}
}
- switch (instr->token_kind()) {
- case Token::kEQ:
- case Token::kNE:
- case Token::kLT:
- case Token::kLTE:
- case Token::kGT:
- case Token::kGTE: {
- if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
- HasLikelySmiOperand(instr)) {
- ASSERT(receiver_idx == 0);
- Definition* left = instr->ArgumentAt(0);
- Definition* right = instr->ArgumentAt(1);
- CheckedSmiComparisonInstr* smi_op = new (Z)
- CheckedSmiComparisonInstr(instr->token_kind(), new (Z) Value(left),
- new (Z) Value(right), instr);
- ReplaceCall(instr, smi_op);
- return;
- }
- break;
- }
- case Token::kSHL:
- case Token::kSHR:
- case Token::kUSHR:
- case Token::kBIT_OR:
- case Token::kBIT_XOR:
- case Token::kBIT_AND:
- case Token::kADD:
- case Token::kSUB:
- case Token::kMUL: {
- if (instr->BinaryFeedback().OperandsAre(kSmiCid) ||
- HasLikelySmiOperand(instr)) {
- ASSERT(receiver_idx == 0);
- Definition* left = instr->ArgumentAt(0);
- Definition* right = instr->ArgumentAt(1);
- CheckedSmiOpInstr* smi_op =
- new (Z) CheckedSmiOpInstr(instr->token_kind(), new (Z) Value(left),
- new (Z) Value(right), instr);
-
- ReplaceCall(instr, smi_op);
- return;
- }
- break;
- }
- default:
- break;
- }
-
// No IC data checks. Try resolve target using the propagated cid.
const intptr_t receiver_cid =
instr->ArgumentValueAt(receiver_idx)->Type()->ToCid();
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index 4dff2a2..101ea94 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -91,179 +91,6 @@
__ b(not_smi, NE);
}
-void AsmIntrinsifier::Integer_add(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // Checks two smis.
- __ adds(R0, R0, Operand(R1)); // Adds.
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, VC)); // Return if no overflow.
- // Otherwise fall through.
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_sub(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ subs(R0, R1, Operand(R0)); // Subtract.
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, VC)); // Return if no overflow.
- // Otherwise fall through.
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_mul(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // checks two smis
- __ SmiUntag(R0); // Untags R0. We only want result shifted by one.
- __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
- __ cmp(IP, Operand(R0, ASR, 31));
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, EQ));
- __ Bind(normal_ir_body); // Fall through on overflow.
-}
-
-// Optimizations:
-// - result is 0 if:
-// - left is 0
-// - left equals right
-// - result is left if
-// - left > 0 && left < right
-// R1: Tagged left (dividend).
-// R0: Tagged right (divisor).
-// Returns:
-// R1: Untagged fallthrough result (remainder to be adjusted), or
-// R0: Tagged return result (remainder).
-static void EmitRemainderOperation(Assembler* assembler) {
- Label modulo;
- const Register left = R1;
- const Register right = R0;
- const Register result = R1;
- const Register tmp = R2;
- ASSERT(left == result);
-
- // Check for quick zero results.
- __ cmp(left, Operand(0));
- __ mov(R0, Operand(0), EQ);
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, EQ)); // left is 0? Return 0.
- __ cmp(left, Operand(right));
- __ mov(R0, Operand(0), EQ);
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, EQ)); // left == right? Return 0.
-
- // Check if result should be left.
- __ cmp(left, Operand(0));
- __ b(&modulo, LT);
- // left is positive.
- __ cmp(left, Operand(right));
- // left is less than right, result is left.
- __ mov(R0, Operand(left), LT);
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, LT));
- __ Bind(&modulo);
- // result <- left - right * (left / right)
- __ SmiUntag(left);
- __ SmiUntag(right);
-
- __ IntegerDivide(tmp, left, right, D1, D0);
-
- __ mls(result, right, tmp, left); // result <- left - right * TMP
-}
-
-// Implementation:
-// res = left % right;
-// if (res < 0) {
-// if (right < 0) {
-// res = res - right;
-// } else {
-// res = res + right;
-// }
-// }
-void AsmIntrinsifier::Integer_mod(Assembler* assembler, Label* normal_ir_body) {
- if (!TargetCPUFeatures::can_divide()) {
- return;
- }
- // Check to see if we have integer division
- __ ldr(R0, Address(SP, +0 * target::kWordSize));
- __ ldr(R1, Address(SP, +1 * target::kWordSize));
- __ orr(TMP, R0, Operand(R1));
- __ tst(TMP, Operand(kSmiTagMask));
- __ b(normal_ir_body, NE);
- // R1: Tagged left (dividend).
- // R0: Tagged right (divisor).
- // Check if modulo by zero -> exception thrown in main function.
- __ cmp(R0, Operand(0));
- __ b(normal_ir_body, EQ);
- EmitRemainderOperation(assembler);
- // Untagged right in R0. Untagged remainder result in R1.
-
- __ cmp(R1, Operand(0));
- __ mov(R0, Operand(R1, LSL, 1), GE); // Tag and move result to R0.
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, GE));
- // Result is negative, adjust it.
- __ cmp(R0, Operand(0));
- __ sub(R0, R1, Operand(R0), LT);
- __ add(R0, R1, Operand(R0), GE);
- __ SmiTag(R0);
- __ Ret();
-
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_truncDivide(Assembler* assembler,
- Label* normal_ir_body) {
- if (!TargetCPUFeatures::can_divide()) {
- return;
- }
- // Check to see if we have integer division
-
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ cmp(R0, Operand(0));
- __ b(normal_ir_body, EQ); // If b is 0, fall through.
-
- __ SmiUntag(R0);
- __ SmiUntag(R1);
-
- __ IntegerDivide(R0, R1, R0, D1, D0);
-
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
- __ CompareImmediate(R0, 0x40000000);
- __ SmiTag(R0, NE); // Not equal. Okay to tag and return.
- READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_negate(Assembler* assembler,
- Label* normal_ir_body) {
- __ ldr(R0, Address(SP, +0 * target::kWordSize)); // Grab first argument.
- __ tst(R0, Operand(kSmiTagMask)); // Test for Smi.
- __ b(normal_ir_body, NE);
- __ rsbs(R0, R0, Operand(0)); // R0 is a Smi. R0 <- 0 - R0.
- READS_RETURN_ADDRESS_FROM_LR(__ bx(
- LR, VC)); // Return if there wasn't overflow, fall through otherwise.
- // R0 is not a Smi. Fall through.
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitAnd(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // checks two smis
- __ and_(R0, R0, Operand(R1));
-
- __ Ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitOr(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // checks two smis
- __ orr(R0, R0, Operand(R1));
-
- __ Ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitXor(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // checks two smis
- __ eor(R0, R0, Operand(R1));
-
- __ Ret();
- __ Bind(normal_ir_body);
-}
-
void AsmIntrinsifier::Integer_shl(Assembler* assembler, Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
ASSERT(kSmiTag == 0);
@@ -471,33 +298,6 @@
Integer_equalToInteger(assembler, normal_ir_body);
}
-void AsmIntrinsifier::Integer_sar(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // Shift amount in R0. Value to shift in R1.
-
- // Fall through if shift amount is negative.
- __ SmiUntag(R0);
- __ CompareImmediate(R0, 0);
- __ b(normal_ir_body, LT);
-
- // If shift amount is bigger than 31, set to 31.
- __ CompareImmediate(R0, 0x1F);
- __ LoadImmediate(R0, 0x1F, GT);
- __ SmiUntag(R1);
- __ mov(R0, Operand(R1, ASR, R0));
- __ SmiTag(R0);
- __ Ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Smi_bitNegate(Assembler* assembler,
- Label* normal_ir_body) {
- __ ldr(R0, Address(SP, 0 * target::kWordSize));
- __ mvn(R0, Operand(R0));
- __ bic(R0, R0, Operand(kSmiTagMask)); // Remove inverted smi-tag.
- __ Ret();
-}
-
void AsmIntrinsifier::Smi_bitLength(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index c3c64be..eede391 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -92,192 +92,6 @@
__ BranchIfNotSmi(TMP, not_smi);
}
-void AsmIntrinsifier::Integer_add(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // Checks two smis.
- __ adds(R0, R0, Operand(R1), kObjectBytes); // Add.
- __ b(normal_ir_body, VS); // Fall-through on overflow.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_sub(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ subs(R0, R1, Operand(R0), compiler::kObjectBytes); // Subtract.
- __ b(normal_ir_body, VS); // Fall-through on overflow.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_mul(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // checks two smis
- __ SmiUntag(R0); // Untags R6. We only want result shifted by one.
-
-#if !defined(DART_COMPRESSED_POINTERS)
- __ mul(TMP, R0, R1);
- __ smulh(TMP2, R0, R1);
- // TMP: result bits 64..127.
-#else
- __ smull(TMP, R0, R1);
- __ AsrImmediate(TMP2, TMP, 31);
- // TMP: result bits 32..63.
-#endif
- __ cmp(TMP2, Operand(TMP, ASR, 63));
- __ b(normal_ir_body, NE);
- __ mov(R0, TMP);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-// Optimizations:
-// - result is 0 if:
-// - left is 0
-// - left equals right
-// - result is left if
-// - left > 0 && left < right
-// R1: Tagged left (dividend).
-// R0: Tagged right (divisor).
-// Returns:
-// R1: Untagged fallthrough result (remainder to be adjusted), or
-// R0: Tagged return result (remainder).
-static void EmitRemainderOperation(Assembler* assembler) {
- Label return_zero, modulo;
- const Register left = R1;
- const Register right = R0;
- const Register result = R1;
- const Register tmp = R2;
- ASSERT(left == result);
-
- // Check for quick zero results.
- __ CompareObjectRegisters(left, ZR);
- __ b(&return_zero, EQ);
- __ CompareObjectRegisters(left, right);
- __ b(&return_zero, EQ);
-
- // Check if result should be left.
- __ CompareObjectRegisters(left, ZR);
- __ b(&modulo, LT);
- // left is positive.
- __ CompareObjectRegisters(left, right);
- // left is less than right, result is left.
- __ b(&modulo, GT);
- __ mov(R0, left);
- __ ret();
-
- __ Bind(&return_zero);
- __ mov(R0, ZR);
- __ ret();
-
- __ Bind(&modulo);
- // result <- left - right * (left / right)
- __ SmiUntag(left);
- __ SmiUntag(right);
-
- __ sdiv(tmp, left, right, kObjectBytes);
- __ msub(result, right, tmp, left,
- kObjectBytes); // result <- left - right * tmp
-}
-
-// Implementation:
-// res = left % right;
-// if (res < 0) {
-// if (right < 0) {
-// res = res - right;
-// } else {
-// res = res + right;
-// }
-// }
-void AsmIntrinsifier::Integer_mod(Assembler* assembler, Label* normal_ir_body) {
- // Check to see if we have integer division
- Label neg_remainder, fall_through;
- __ ldr(R0, Address(SP, +0 * target::kWordSize));
- __ ldr(R1, Address(SP, +1 * target::kWordSize));
- __ orr(TMP, R0, Operand(R1));
- __ BranchIfNotSmi(TMP, normal_ir_body);
- // R1: Tagged left (dividend).
- // R0: Tagged right (divisor).
- // Check if modulo by zero -> exception thrown in main function.
- __ CompareObjectRegisters(R0, ZR);
- __ b(normal_ir_body, EQ);
- EmitRemainderOperation(assembler);
- // Untagged right in R0. Untagged remainder result in R1.
-
- __ CompareObjectRegisters(R1, ZR);
- __ b(&neg_remainder, LT);
- __ SmiTag(R0, R1); // Tag and move result to R0.
- __ ret();
-
- __ Bind(&neg_remainder);
- // Result is negative, adjust it.
- __ CompareObjectRegisters(R0, ZR);
- __ sub(TMP, R1, Operand(R0), kObjectBytes);
- __ add(TMP2, R1, Operand(R0), kObjectBytes);
- __ csel(R0, TMP2, TMP, GE);
- __ SmiTag(R0);
- __ ret();
-
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_truncDivide(Assembler* assembler,
- Label* normal_ir_body) {
- // Check to see if we have integer division
-
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ CompareObjectRegisters(R0, ZR);
- __ b(normal_ir_body, EQ); // If b is 0, fall through.
-
- __ SmiUntag(R0);
- __ SmiUntag(R1);
-
- __ sdiv(R0, R1, R0, kObjectBytes);
-
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
-#if !defined(DART_COMPRESSED_POINTERS)
- __ CompareImmediate(R0, 0x4000000000000000);
-#else
- __ CompareImmediate(R0, 0x40000000, compiler::kFourBytes);
-#endif
- __ b(normal_ir_body, EQ);
- __ SmiTag(R0); // Not equal. Okay to tag and return.
- __ ret(); // Return.
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_negate(Assembler* assembler,
- Label* normal_ir_body) {
- __ ldr(R0, Address(SP, +0 * target::kWordSize)); // Grab first argument.
- __ BranchIfNotSmi(R0, normal_ir_body);
- __ negs(R0, R0, kObjectBytes);
- __ b(normal_ir_body, VS);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitAnd(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // Checks two smis.
- __ and_(R0, R0, Operand(R1));
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitOr(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // Checks two smis.
- __ orr(R0, R0, Operand(R1));
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitXor(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body); // Checks two smis.
- __ eor(R0, R0, Operand(R1));
- __ ret();
- __ Bind(normal_ir_body);
-}
-
void AsmIntrinsifier::Integer_shl(Assembler* assembler, Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
ASSERT(kSmiTag == 0);
@@ -396,38 +210,6 @@
Integer_equalToInteger(assembler, normal_ir_body);
}
-void AsmIntrinsifier::Integer_sar(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // Shift amount in R0. Value to shift in R1.
-
- // Fall through if shift amount is negative.
- __ SmiUntag(R0);
- __ CompareObjectRegisters(R0, ZR);
- __ b(normal_ir_body, LT);
-
- // If shift amount is bigger than 63/31, set to 63/31.
-#if !defined(DART_COMPRESSED_POINTERS)
- __ LoadImmediate(TMP, 0x3F);
-#else
- __ LoadImmediate(TMP, 0x1F);
-#endif
- __ CompareRegisters(R0, TMP);
- __ csel(R0, TMP, R0, GT);
- __ SmiUntag(R1);
- __ asrv(R0, R1, R0, kObjectBytes);
- __ SmiTag(R0);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Smi_bitNegate(Assembler* assembler,
- Label* normal_ir_body) {
- __ ldr(R0, Address(SP, 0 * target::kWordSize));
- __ mvn(R0, R0);
- __ andi(R0, R0, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
- __ ret();
-}
-
void AsmIntrinsifier::Smi_bitLength(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index a6d5e20..9cfe941 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -93,188 +93,6 @@
__ j(NOT_ZERO, not_smi, Assembler::kNearJump);
}
-void AsmIntrinsifier::Integer_add(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ addl(EAX, Address(ESP, +2 * target::kWordSize));
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_sub(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ movl(EBX, EAX);
- __ movl(EAX, Address(ESP, +2 * target::kWordSize));
- __ subl(EAX, EBX);
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_mul(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- ASSERT(kSmiTag == 0); // Adjust code below if not the case.
- __ SmiUntag(EAX);
- __ imull(EAX, Address(ESP, +2 * target::kWordSize));
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-// Optimizations:
-// - result is 0 if:
-// - left is 0
-// - left equals right
-// - result is left if
-// - left > 0 && left < right
-// EAX: Tagged left (dividend).
-// EBX: Tagged right (divisor).
-// Returns:
-// EDX: Untagged fallthrough result (remainder to be adjusted), or
-// EAX: Tagged return result (remainder).
-static void EmitRemainderOperation(Assembler* assembler) {
- Label return_zero, modulo;
- // Check for quick zero results.
- __ cmpl(EAX, Immediate(0));
- __ j(EQUAL, &return_zero, Assembler::kNearJump);
- __ cmpl(EAX, EBX);
- __ j(EQUAL, &return_zero, Assembler::kNearJump);
-
- // Check if result equals left.
- __ cmpl(EAX, Immediate(0));
- __ j(LESS, &modulo, Assembler::kNearJump);
- // left is positive.
- __ cmpl(EAX, EBX);
- __ j(GREATER, &modulo, Assembler::kNearJump);
- // left is less than right, result is left (EAX).
- __ ret();
-
- __ Bind(&return_zero);
- __ xorl(EAX, EAX);
- __ ret();
-
- __ Bind(&modulo);
- __ SmiUntag(EBX);
- __ SmiUntag(EAX);
- __ cdq();
- __ idivl(EBX);
-}
-
-// Implementation:
-// res = left % right;
-// if (res < 0) {
-// if (right < 0) {
-// res = res - right;
-// } else {
-// res = res + right;
-// }
-// }
-void AsmIntrinsifier::Integer_mod(Assembler* assembler, Label* normal_ir_body) {
- Label subtract;
- __ movl(EAX, Address(ESP, +2 * target::kWordSize));
- __ movl(EBX, Address(ESP, +1 * target::kWordSize));
- __ orl(EBX, EAX);
- __ testl(EBX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, normal_ir_body);
- __ movl(EBX, Address(ESP, +1 * target::kWordSize));
- // EAX: Tagged left (dividend).
- // EBX: Tagged right (divisor).
- // Check if modulo by zero -> exception thrown in main function.
- __ cmpl(EBX, Immediate(0));
- __ j(EQUAL, normal_ir_body, Assembler::kNearJump);
- EmitRemainderOperation(assembler);
- // Untagged remainder result in EDX.
- Label done;
- __ movl(EAX, EDX);
- __ cmpl(EAX, Immediate(0));
- __ j(GREATER_EQUAL, &done, Assembler::kNearJump);
- // Result is negative, adjust it.
- __ cmpl(EBX, Immediate(0));
- __ j(LESS, &subtract, Assembler::kNearJump);
- __ addl(EAX, EBX);
- __ SmiTag(EAX);
- __ ret();
-
- __ Bind(&subtract);
- __ subl(EAX, EBX);
-
- __ Bind(&done);
- // The remainder of two smis is always a smi, no overflow check needed.
- __ SmiTag(EAX);
- __ ret();
-
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_truncDivide(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // EAX: right argument (divisor)
- __ cmpl(EAX, Immediate(0));
- __ j(EQUAL, normal_ir_body, Assembler::kNearJump);
- __ movl(EBX, EAX);
- __ SmiUntag(EBX);
- __ movl(EAX,
- Address(ESP, +2 * target::kWordSize)); // Left argument (dividend).
- __ SmiUntag(EAX);
- __ pushl(EDX); // Preserve EDX in case of 'fall_through'.
- __ cdq();
- __ idivl(EBX);
- __ popl(EDX);
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
- __ cmpl(EAX, Immediate(0x40000000));
- __ j(EQUAL, normal_ir_body);
- __ SmiTag(EAX);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_negate(Assembler* assembler,
- Label* normal_ir_body) {
- __ movl(EAX, Address(ESP, +1 * target::kWordSize));
- __ testl(EAX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, normal_ir_body, Assembler::kNearJump); // Non-smi value.
- __ negl(EAX);
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitAnd(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ movl(EBX, Address(ESP, +2 * target::kWordSize));
- __ andl(EAX, EBX);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitOr(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ movl(EBX, Address(ESP, +2 * target::kWordSize));
- __ orl(EAX, EBX);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitXor(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- __ movl(EBX, Address(ESP, +2 * target::kWordSize));
- __ xorl(EAX, EBX);
- // Result is in EAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
void AsmIntrinsifier::Integer_shl(Assembler* assembler, Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
ASSERT(kSmiTag == 0);
@@ -483,40 +301,7 @@
Integer_equalToInteger(assembler, normal_ir_body);
}
-void AsmIntrinsifier::Integer_sar(Assembler* assembler, Label* normal_ir_body) {
- Label shift_count_ok;
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // Can destroy ECX since we are not falling through.
- const Immediate& count_limit = Immediate(0x1F);
- // Check that the count is not larger than what the hardware can handle.
- // For shifting right a Smi the result is the same for all numbers
- // >= count_limit.
- __ SmiUntag(EAX);
- // Negative counts throw exception.
- __ cmpl(EAX, Immediate(0));
- __ j(LESS, normal_ir_body, Assembler::kNearJump);
- __ cmpl(EAX, count_limit);
- __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump);
- __ movl(EAX, count_limit);
- __ Bind(&shift_count_ok);
- __ movl(ECX, EAX); // Shift amount must be in ECX.
- __ movl(EAX, Address(ESP, +2 * target::kWordSize)); // Value.
- __ SmiUntag(EAX); // Value.
- __ sarl(EAX, ECX);
- __ SmiTag(EAX);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
// Argument is Smi (receiver).
-void AsmIntrinsifier::Smi_bitNegate(Assembler* assembler,
- Label* normal_ir_body) {
- __ movl(EAX, Address(ESP, +1 * target::kWordSize)); // Receiver.
- __ notl(EAX);
- __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
- __ ret();
-}
-
void AsmIntrinsifier::Smi_bitLength(Assembler* assembler,
Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index 9cf721d..cf4fcb3 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -90,260 +90,6 @@
__ j(NOT_ZERO, not_smi);
}
-void AsmIntrinsifier::Integer_add(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX contains right argument.
- __ OBJ(add)(RAX, Address(RSP, +2 * target::kWordSize));
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_sub(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX contains right argument, which is the actual subtrahend of subtraction.
- __ movq(RCX, RAX);
- __ movq(RAX, Address(RSP, +2 * target::kWordSize));
- __ OBJ(sub)(RAX, RCX);
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_mul(Assembler* assembler, Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX is the right argument.
- ASSERT(kSmiTag == 0); // Adjust code below if not the case.
- __ SmiUntag(RAX);
- __ OBJ(imul)(RAX, Address(RSP, +2 * target::kWordSize));
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-// Optimizations:
-// - result is 0 if:
-// - left is 0
-// - left equals right
-// - result is left if
-// - left > 0 && left < right
-// RAX: Tagged left (dividend).
-// RCX: Tagged right (divisor).
-// Returns:
-// RAX: Untagged fallthrough result (remainder to be adjusted), or
-// RAX: Tagged return result (remainder).
-static void EmitRemainderOperation(Assembler* assembler) {
- Label return_zero, try_modulo, not_32bit, done;
- // Check for quick zero results.
- __ OBJ(cmp)(RAX, Immediate(0));
- __ j(EQUAL, &return_zero, Assembler::kNearJump);
- __ OBJ(cmp)(RAX, RCX);
- __ j(EQUAL, &return_zero, Assembler::kNearJump);
-
- // Check if result equals left.
- __ OBJ(cmp)(RAX, Immediate(0));
- __ j(LESS, &try_modulo, Assembler::kNearJump);
- // left is positive.
- __ OBJ(cmp)(RAX, RCX);
- __ j(GREATER, &try_modulo, Assembler::kNearJump);
- // left is less than right, result is left (RAX).
- __ ret();
-
- __ Bind(&return_zero);
- __ xorq(RAX, RAX);
- __ ret();
-
- __ Bind(&try_modulo);
-
-#if !defined(DART_COMPRESSED_POINTERS)
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency. We are checking
- // this before untagging them to avoid corner case dividing INT_MAX by -1 that
- // raises exception because quotient is too large for 32bit register.
- __ movsxd(RBX, RAX);
- __ cmpq(RBX, RAX);
- __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
- __ movsxd(RBX, RCX);
- __ cmpq(RBX, RCX);
- __ j(NOT_EQUAL, ¬_32bit, Assembler::kNearJump);
-#endif
-
- // Both operands are 31bit smis. Divide using 32bit idiv.
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ cdq();
- __ idivl(RCX);
- __ movsxd(RAX, RDX);
-#if !defined(DART_COMPRESSED_POINTERS)
- __ jmp(&done, Assembler::kNearJump);
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ cqo();
- __ idivq(RCX);
- __ movq(RAX, RDX);
- __ Bind(&done);
-#endif
-}
-
-// Implementation:
-// res = left % right;
-// if (res < 0) {
-// if (right < 0) {
-// res = res - right;
-// } else {
-// res = res + right;
-// }
-// }
-void AsmIntrinsifier::Integer_mod(Assembler* assembler, Label* normal_ir_body) {
- Label negative_result;
-
- __ movq(RAX, Address(RSP, +2 * target::kWordSize));
- __ movq(RCX, Address(RSP, +1 * target::kWordSize));
- __ orq(RCX, RAX);
- __ testq(RCX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, normal_ir_body);
- __ movq(RCX, Address(RSP, +1 * target::kWordSize));
- // RAX: Tagged left (dividend).
- // RCX: Tagged right (divisor).
- __ OBJ(cmp)(RCX, Immediate(0));
- __ j(EQUAL, normal_ir_body);
- EmitRemainderOperation(assembler);
- // Untagged remainder result in RAX.
- __ OBJ(cmp)(RAX, Immediate(0));
- __ j(LESS, &negative_result, Assembler::kNearJump);
- __ SmiTag(RAX);
- __ ret();
-
- __ Bind(&negative_result);
- Label subtract;
- // RAX: Untagged result.
- // RCX: Untagged right.
- __ OBJ(cmp)(RCX, Immediate(0));
- __ j(LESS, &subtract, Assembler::kNearJump);
- __ OBJ(add)(RAX, RCX);
- __ SmiTag(RAX);
- __ ret();
-
- __ Bind(&subtract);
- __ OBJ(sub)(RAX, RCX);
- __ SmiTag(RAX);
- __ ret();
-
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_truncDivide(Assembler* assembler,
- Label* normal_ir_body) {
- Label not_32bit;
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX: right argument (divisor)
- __ OBJ(cmp)(RAX, Immediate(0));
- __ j(EQUAL, normal_ir_body, Assembler::kNearJump);
- __ movq(RCX, RAX);
- __ movq(RAX,
- Address(RSP, +2 * target::kWordSize)); // Left argument (dividend).
-
-#if !defined(DART_COMPRESSED_POINTERS)
- // Check if both operands fit into 32bits as idiv with 64bit operands
- // requires twice as many cycles and has much higher latency. We are checking
- // this before untagging them to avoid corner case dividing INT_MAX by -1 that
- // raises exception because quotient is too large for 32bit register.
- __ movsxd(RBX, RAX);
- __ cmpq(RBX, RAX);
- __ j(NOT_EQUAL, ¬_32bit);
- __ movsxd(RBX, RCX);
- __ cmpq(RBX, RCX);
- __ j(NOT_EQUAL, ¬_32bit);
-
- // Both operands are 31bit smis. Divide using 32bit idiv.
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ cdq();
- __ idivl(RCX);
- __ movsxd(RAX, RAX);
- __ SmiTag(RAX); // Result is guaranteed to fit into a smi.
- __ ret();
-
- // Divide using 64bit idiv.
- __ Bind(¬_32bit);
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ pushq(RDX); // Preserve RDX in case of 'fall_through'.
- __ cqo();
- __ idivq(RCX);
- __ popq(RDX);
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
- __ cmpq(RAX, Immediate(0x4000000000000000));
- __ j(EQUAL, normal_ir_body);
- __ SmiTag(RAX);
- __ ret();
-#else
- // Check the corner case of dividing the 'MIN_SMI' with -1, in which case we
- // cannot tag the result.
- __ cmpq(RAX, Immediate(target::ToRawSmi(target::kSmiMin)));
- __ j(EQUAL, normal_ir_body);
-
- // Both operands are 31bit smis. Divide using 32bit idiv.
- __ SmiUntag(RAX);
- __ SmiUntag(RCX);
- __ cdq();
- __ idivl(RCX);
- __ SmiTag(RAX); // Result is guaranteed to fit into a smi.
- __ movsxd(RAX, RAX);
- __ ret();
-#endif
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_negate(Assembler* assembler,
- Label* normal_ir_body) {
- __ movq(RAX, Address(RSP, +1 * target::kWordSize));
- __ testq(RAX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, normal_ir_body, Assembler::kNearJump); // Non-smi value.
- __ OBJ(neg)(RAX);
- __ j(OVERFLOW, normal_ir_body, Assembler::kNearJump);
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitAnd(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX is the right argument.
- __ andq(RAX, Address(RSP, +2 * target::kWordSize));
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitOr(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX is the right argument.
- __ orq(RAX, Address(RSP, +2 * target::kWordSize));
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-void AsmIntrinsifier::Integer_bitXor(Assembler* assembler,
- Label* normal_ir_body) {
- TestBothArgumentsSmis(assembler, normal_ir_body);
- // RAX is the right argument.
- __ xorq(RAX, Address(RSP, +2 * target::kWordSize));
- // Result is in RAX.
- __ ret();
- __ Bind(normal_ir_body);
-}
-
void AsmIntrinsifier::Integer_shl(Assembler* assembler, Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
ASSERT(kSmiTag == 0);
@@ -471,43 +217,6 @@
Integer_equalToInteger(assembler, normal_ir_body);
}
-void AsmIntrinsifier::Integer_sar(Assembler* assembler, Label* normal_ir_body) {
- Label shift_count_ok;
- TestBothArgumentsSmis(assembler, normal_ir_body);
-#if !defined(DART_COMPRESSED_POINTERS)
- const Immediate& count_limit = Immediate(0x3F);
-#else
- const Immediate& count_limit = Immediate(0x1F);
-#endif
- // Check that the count is not larger than what the hardware can handle.
- // For shifting right a Smi the result is the same for all numbers
- // >= count_limit.
- __ SmiUntag(RAX);
- // Negative counts throw exception.
- __ OBJ(cmp)(RAX, Immediate(0));
- __ j(LESS, normal_ir_body, Assembler::kNearJump);
- __ OBJ(cmp)(RAX, count_limit);
- __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump);
- __ movq(RAX, count_limit);
- __ Bind(&shift_count_ok);
- __ movq(RCX, RAX); // Shift amount must be in RCX.
- __ movq(RAX, Address(RSP, +2 * target::kWordSize)); // Value.
- __ SmiUntag(RAX); // Value.
- __ OBJ(sar)(RAX, RCX);
- __ SmiTag(RAX);
- __ ret();
- __ Bind(normal_ir_body);
-}
-
-// Argument is Smi (receiver).
-void AsmIntrinsifier::Smi_bitNegate(Assembler* assembler,
- Label* normal_ir_body) {
- __ movq(RAX, Address(RSP, +1 * target::kWordSize)); // Index.
- __ OBJ(not )(RAX);
- __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
- __ ret();
-}
-
void AsmIntrinsifier::Smi_bitLength(Assembler* assembler,
Label* normal_ir_body) {
ASSERT(kSmiTagShift == 1);
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 53ca92a..4f8e3aa 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -3928,18 +3928,19 @@
intptr_t left_cid = this->left()->Type()->ToCid();
intptr_t right_cid = this->right()->Type()->ToCid();
bool combined_smi_check = false;
- if (this->left()->definition() == this->right()->definition()) {
- __ tst(left, compiler::Operand(kSmiTagMask));
+ if (FLAG_use_slow_path) {
+ __ b(slow_path->entry_label());
+ } else if (this->left()->definition() == this->right()->definition()) {
+ __ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
- __ tst(right, compiler::Operand(kSmiTagMask));
+ __ BranchIfNotSmi(right, slow_path->entry_label());
} else if (right_cid == kSmiCid) {
- __ tst(left, compiler::Operand(kSmiTagMask));
+ __ BranchIfNotSmi(left, slow_path->entry_label());
} else {
combined_smi_check = true;
__ orr(result, left, compiler::Operand(right));
- __ tst(result, compiler::Operand(kSmiTagMask));
+ __ BranchIfNotSmi(result, slow_path->entry_label());
}
- __ b(slow_path->entry_label(), NE);
switch (op_kind()) {
case Token::kADD:
__ adds(result, left, compiler::Operand(right));
@@ -4148,17 +4149,18 @@
Register temp = locs()->temp(0).reg(); \
intptr_t left_cid = this->left()->Type()->ToCid(); \
intptr_t right_cid = this->right()->Type()->ToCid(); \
- if (this->left()->definition() == this->right()->definition()) { \
- __ tst(left, compiler::Operand(kSmiTagMask)); \
+ if (FLAG_use_slow_path) { \
+ __ b(slow_path->entry_label()); \
+ } else if (this->left()->definition() == this->right()->definition()) { \
+ __ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
- __ tst(right, compiler::Operand(kSmiTagMask)); \
+ __ BranchIfNotSmi(right, slow_path->entry_label()); \
} else if (right_cid == kSmiCid) { \
- __ tst(left, compiler::Operand(kSmiTagMask)); \
+ __ BranchIfNotSmi(left, slow_path->entry_label()); \
} else { \
__ orr(temp, left, compiler::Operand(right)); \
- __ tst(temp, compiler::Operand(kSmiTagMask)); \
- } \
- __ b(slow_path->entry_label(), NE)
+ __ BranchIfNotSmi(temp, slow_path->entry_label()); \
+ }
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 8cae728..f8a5f78 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -3492,7 +3492,9 @@
intptr_t left_cid = this->left()->Type()->ToCid();
intptr_t right_cid = this->right()->Type()->ToCid();
bool combined_smi_check = false;
- if (this->left()->definition() == this->right()->definition()) {
+ if (FLAG_use_slow_path) {
+ __ b(slow_path->entry_label());
+ } else if (this->left()->definition() == this->right()->definition()) {
__ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
__ BranchIfNotSmi(right, slow_path->entry_label());
@@ -3672,7 +3674,9 @@
Register temp = locs()->temp(0).reg(); \
intptr_t left_cid = this->left()->Type()->ToCid(); \
intptr_t right_cid = this->right()->Type()->ToCid(); \
- if (this->left()->definition() == this->right()->definition()) { \
+ if (FLAG_use_slow_path) { \
+ __ b(slow_path->entry_label()); \
+ } else if (this->left()->definition() == this->right()->definition()) { \
__ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
__ BranchIfNotSmi(right, slow_path->entry_label()); \
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index d3264b1..55eaf32 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -3600,18 +3600,19 @@
intptr_t right_cid = right()->Type()->ToCid();
Register left = locs()->in(0).reg();
Register right = locs()->in(1).reg();
- if (this->left()->definition() == this->right()->definition()) {
- __ testq(left, compiler::Immediate(kSmiTagMask));
+ if (FLAG_use_slow_path) {
+ __ jmp(slow_path->entry_label());
+ } else if (this->left()->definition() == this->right()->definition()) {
+ __ BranchIfNotSmi(left, slow_path->entry_label());
} else if (left_cid == kSmiCid) {
- __ testq(right, compiler::Immediate(kSmiTagMask));
+ __ BranchIfNotSmi(right, slow_path->entry_label());
} else if (right_cid == kSmiCid) {
- __ testq(left, compiler::Immediate(kSmiTagMask));
+ __ BranchIfNotSmi(left, slow_path->entry_label());
} else {
__ movq(TMP, left);
__ orq(TMP, right);
- __ testq(TMP, compiler::Immediate(kSmiTagMask));
+ __ BranchIfNotSmi(TMP, slow_path->entry_label());
}
- __ j(NOT_ZERO, slow_path->entry_label());
Register result = locs()->out(0).reg();
switch (op_kind()) {
case Token::kADD:
@@ -3791,18 +3792,19 @@
intptr_t right_cid = right()->Type()->ToCid(); \
Register left = locs()->in(0).reg(); \
Register right = locs()->in(1).reg(); \
- if (this->left()->definition() == this->right()->definition()) { \
- __ testq(left, compiler::Immediate(kSmiTagMask)); \
+ if (FLAG_use_slow_path) { \
+ __ jmp(slow_path->entry_label()); \
+ } else if (this->left()->definition() == this->right()->definition()) { \
+ __ BranchIfNotSmi(left, slow_path->entry_label()); \
} else if (left_cid == kSmiCid) { \
- __ testq(right, compiler::Immediate(kSmiTagMask)); \
+ __ BranchIfNotSmi(right, slow_path->entry_label()); \
} else if (right_cid == kSmiCid) { \
- __ testq(left, compiler::Immediate(kSmiTagMask)); \
+ __ BranchIfNotSmi(left, slow_path->entry_label()); \
} else { \
__ movq(TMP, left); \
__ orq(TMP, right); \
- __ testq(TMP, compiler::Immediate(kSmiTagMask)); \
- } \
- __ j(NOT_ZERO, slow_path->entry_label())
+ __ BranchIfNotSmi(TMP, slow_path->entry_label()); \
+ }
void CheckedSmiComparisonInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
diff --git a/runtime/vm/compiler/backend/typed_data_aot_test.cc b/runtime/vm/compiler/backend/typed_data_aot_test.cc
index 68bca62..557139a 100644
--- a/runtime/vm/compiler/backend/typed_data_aot_test.cc
+++ b/runtime/vm/compiler/backend/typed_data_aot_test.cc
@@ -208,8 +208,6 @@
kMatchAndMoveLoadIndexed,
kMoveGlob,
// Store 1
- kMatchAndMoveGenericCheckBound,
- kMoveGlob,
kMoveParallelMoves,
kMatchAndMoveLoadUntagged,
kMoveParallelMoves,
@@ -253,8 +251,6 @@
kMatchAndMoveLoadIndexed,
kMoveGlob,
// Store 1
- kMatchAndMoveGenericCheckBound,
- kMoveGlob,
kMoveParallelMoves,
kMatchAndMoveLoadUntagged,
kMoveParallelMoves,
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index cb294e9..e33e569 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -111,16 +111,7 @@
}
const Token::Kind op_kind = call->token_kind();
- if (FLAG_guess_icdata_cid) {
- if (CompilerState::Current().is_aot()) {
- // In precompiler speculate that both sides of bitwise operation
- // are Smi-s.
- if (Token::IsBinaryBitwiseOperator(op_kind) &&
- call->CanReceiverBeSmiBasedOnInterfaceTarget(zone())) {
- class_ids[0] = kSmiCid;
- class_ids[1] = kSmiCid;
- }
- }
+ if (FLAG_guess_icdata_cid && !CompilerState::Current().is_aot()) {
if (Token::IsRelationalOperator(op_kind) ||
Token::IsEqualityOperator(op_kind) ||
Token::IsBinaryOperator(op_kind)) {
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index 5397c82..d0ca36b 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -920,6 +920,98 @@
return true;
}
+static bool BuildUnarySmiOp(FlowGraph* flow_graph, Token::Kind op_kind) {
+ ASSERT(!flow_graph->function().has_unboxed_return());
+ ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ auto normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+ Definition* left = builder.AddParameter(0, /*with_frame=*/false);
+ builder.AddInstruction(
+ new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
+ Definition* result = builder.AddDefinition(
+ new UnarySmiOpInstr(op_kind, new Value(left), DeoptId::kNone));
+ builder.AddReturn(new Value(result));
+ return true;
+}
+
+bool GraphIntrinsifier::Build_Smi_bitNegate(FlowGraph* flow_graph) {
+ return BuildUnarySmiOp(flow_graph, Token::kBIT_NOT);
+}
+
+bool GraphIntrinsifier::Build_Integer_negate(FlowGraph* flow_graph) {
+ return BuildUnarySmiOp(flow_graph, Token::kNEGATE);
+}
+
+static bool BuildBinarySmiOp(FlowGraph* flow_graph, Token::Kind op_kind) {
+ ASSERT(!flow_graph->function().has_unboxed_return());
+ ASSERT(!flow_graph->function().is_unboxed_parameter_at(0));
+ ASSERT(!flow_graph->function().is_unboxed_parameter_at(1));
+ GraphEntryInstr* graph_entry = flow_graph->graph_entry();
+ auto normal_entry = graph_entry->normal_entry();
+ BlockBuilder builder(flow_graph, normal_entry);
+ Definition* left = builder.AddParameter(0, /*with_frame=*/false);
+ Definition* right = builder.AddParameter(1, /*with_frame=*/false);
+ builder.AddInstruction(
+ new CheckSmiInstr(new Value(left), DeoptId::kNone, builder.Source()));
+ builder.AddInstruction(
+ new CheckSmiInstr(new Value(right), DeoptId::kNone, builder.Source()));
+ Definition* result = builder.AddDefinition(new BinarySmiOpInstr(
+ op_kind, new Value(left), new Value(right), DeoptId::kNone));
+ builder.AddReturn(new Value(result));
+ return true;
+}
+
+bool GraphIntrinsifier::Build_Integer_add(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kADD);
+}
+
+bool GraphIntrinsifier::Build_Integer_sub(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kSUB);
+}
+
+bool GraphIntrinsifier::Build_Integer_mul(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kMUL);
+}
+
+bool GraphIntrinsifier::Build_Integer_mod(FlowGraph* flow_graph) {
+#if defined(TARGET_ARCH_ARM)
+ if (!TargetCPUFeatures::can_divide()) {
+ return false;
+ }
+#endif
+ return BuildBinarySmiOp(flow_graph, Token::kMOD);
+}
+
+bool GraphIntrinsifier::Build_Integer_truncDivide(FlowGraph* flow_graph) {
+#if defined(TARGET_ARCH_ARM)
+ if (!TargetCPUFeatures::can_divide()) {
+ return false;
+ }
+#endif
+ return BuildBinarySmiOp(flow_graph, Token::kTRUNCDIV);
+}
+
+bool GraphIntrinsifier::Build_Integer_bitAnd(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kBIT_AND);
+}
+
+bool GraphIntrinsifier::Build_Integer_bitOr(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kBIT_OR);
+}
+
+bool GraphIntrinsifier::Build_Integer_bitXor(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kBIT_XOR);
+}
+
+bool GraphIntrinsifier::Build_Integer_sar(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kSHR);
+}
+
+bool GraphIntrinsifier::Build_Integer_shr(FlowGraph* flow_graph) {
+ return BuildBinarySmiOp(flow_graph, Token::kUSHR);
+}
+
static Definition* ConvertOrUnboxDoubleParameter(BlockBuilder* builder,
Definition* value,
intptr_t index,
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 4ee61c5..6c22c21 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -206,7 +206,6 @@
// List of intrinsics:
// (class-name, function-name, intrinsification method, fingerprint).
#define CORE_LIB_INTRINSIC_LIST(V) \
- V(_Smi, ~, Smi_bitNegate, 0x8254f51b) \
V(_Smi, get:bitLength, Smi_bitLength, 0x7ab50ceb) \
V(_BigIntImpl, _lsh, Bigint_lsh, 0x3f8b105e) \
V(_BigIntImpl, _rsh, Bigint_rsh, 0x117ed3f3) \
@@ -257,15 +256,6 @@
V(::, _setHash, Object_setHash, 0x8f2a5b0b) \
#define CORE_INTEGER_LIB_INTRINSIC_LIST(V) \
- V(_IntegerImplementation, +, Integer_add, 0xd561008f) \
- V(_IntegerImplementation, -, Integer_sub, 0xc96a0f80) \
- V(_IntegerImplementation, *, Integer_mul, 0xacd9641d) \
- V(_IntegerImplementation, %, Integer_mod, 0xfcf7cc13) \
- V(_IntegerImplementation, ~/, Integer_truncDivide, 0xdda49e7f) \
- V(_IntegerImplementation, unary-, Integer_negate, 0xf7a9a696) \
- V(_IntegerImplementation, &, Integer_bitAnd, 0x8b9d7c33) \
- V(_IntegerImplementation, |, Integer_bitOr, 0x8f47f5eb) \
- V(_IntegerImplementation, ^, Integer_bitXor, 0xd838bef2) \
V(_IntegerImplementation, >, Integer_greaterThan, 0x402b12df) \
V(_IntegerImplementation, ==, Integer_equal, 0x509c9146) \
V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, \
@@ -273,8 +263,7 @@
V(_IntegerImplementation, <, Integer_lessThan, 0x39643178) \
V(_IntegerImplementation, <=, Integer_lessEqualThan, 0x73d2a9f5) \
V(_IntegerImplementation, >=, Integer_greaterEqualThan, 0xbc280c13) \
- V(_IntegerImplementation, <<, Integer_shl, 0x766f00e5) \
- V(_IntegerImplementation, >>, Integer_sar, 0x931fbb8a) \
+ V(_IntegerImplementation, <<, Integer_shl, 0x766f04a6) \
V(_Double, toInt, DoubleToInteger, 0x676f1ce8) \
#define MATH_LIB_INTRINSIC_LIST(V) \
@@ -362,6 +351,18 @@
0x17f90910) \
V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt, \
0x17f90910) \
+ V(_Smi, ~, Smi_bitNegate, 0x8254f8dc) \
+ V(_IntegerImplementation, +, Integer_add, 0xd5610450) \
+ V(_IntegerImplementation, -, Integer_sub, 0xc96a1341) \
+ V(_IntegerImplementation, *, Integer_mul, 0xacd967de) \
+ V(_IntegerImplementation, %, Integer_mod, 0xfcf7cfd4) \
+ V(_IntegerImplementation, ~/, Integer_truncDivide, 0xdda4a240) \
+ V(_IntegerImplementation, unary-, Integer_negate, 0xf7a9aa57) \
+ V(_IntegerImplementation, &, Integer_bitAnd, 0x8b9d7ff4) \
+ V(_IntegerImplementation, |, Integer_bitOr, 0x8f47f9ac) \
+ V(_IntegerImplementation, ^, Integer_bitXor, 0xd838c2b3) \
+ V(_IntegerImplementation, >>, Integer_sar, 0x931fbf4b) \
+ V(_IntegerImplementation, >>>, Integer_shr, 0x7495fbad) \
V(_Double, unary-, DoubleFlipSignBit, 0x3d39082b) \
V(_Double, truncateToDouble, DoubleTruncate, 0x62d48298) \
V(_Double, roundToDouble, DoubleRound, 0x5649c63f) \
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 47dc4cd..eb95276 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -66,13 +66,13 @@
: debugger_(debugger),
script_(script.ptr()),
url_(script.url()),
+ line_number_(-1), // lazily computed
token_pos_(token_pos),
end_token_pos_(end_token_pos),
next_(NULL),
conditions_(NULL),
requested_line_number_(requested_line_number),
requested_column_number_(requested_column_number),
- function_(Function::null()),
code_token_pos_(TokenPosition::kNoSource) {
ASSERT(!script.IsNull());
ASSERT(token_pos_.IsReal());
@@ -92,7 +92,6 @@
conditions_(NULL),
requested_line_number_(requested_line_number),
requested_column_number_(requested_column_number),
- function_(Function::null()),
code_token_pos_(TokenPosition::kNoSource) {
ASSERT(requested_line_number_ >= 0);
}
@@ -116,7 +115,6 @@
ASSERT(func.script() == script_);
ASSERT(token_pos.IsWithin(func.token_pos(), func.end_token_pos()));
ASSERT(func.is_debuggable());
- function_ = func.ptr();
token_pos_ = token_pos;
end_token_pos_ = token_pos;
code_token_pos_ = token_pos;
@@ -146,7 +144,6 @@
void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) {
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&script_));
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&url_));
- visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&function_));
Breakpoint* bpt = conditions_;
while (bpt != NULL) {
@@ -177,6 +174,23 @@
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&saved_value_));
}
+const char* CodeBreakpoint::ToCString() const {
+ if (breakpoint_locations_.length() == 0) {
+ return "unlinked breakpoint";
+ }
+
+ char buffer[1024];
+ BufferFormatter f(buffer, sizeof(buffer));
+ // Pick the first, all other should have same script/line number.
+ BreakpointLocation* breakpoint_location = breakpoint_locations_.At(0);
+ Script& script = Script::Handle(breakpoint_location->script());
+ String& source_url = String::Handle(script.url());
+ intptr_t line_number = breakpoint_location->line_number();
+
+ f.Printf("breakpoint at %s:%" Pd, source_url.ToCString(), line_number);
+ return Thread::Current()->zone()->MakeCopyOfString(buffer);
+}
+
ActivationFrame::ActivationFrame(uword pc,
uword fp,
uword sp,
@@ -1448,21 +1462,20 @@
UntaggedPcDescriptors::kRuntimeCall;
CodeBreakpoint::CodeBreakpoint(const Code& code,
- TokenPosition token_pos,
+ BreakpointLocation* breakpoint_location,
uword pc,
UntaggedPcDescriptors::Kind kind)
: code_(code.ptr()),
- token_pos_(token_pos),
pc_(pc),
- line_number_(-1),
enabled_count_(0),
next_(NULL),
breakpoint_kind_(kind),
saved_value_(Code::null()) {
ASSERT(!code.IsNull());
- ASSERT(token_pos_.IsReal());
ASSERT(pc_ != 0);
ASSERT((breakpoint_kind_ & kSafepointKind) != 0);
+ AddBreakpointLocation(breakpoint_location);
+ ASSERT(breakpoint_location->token_pos().IsReal());
}
CodeBreakpoint::~CodeBreakpoint() {
@@ -1477,29 +1490,6 @@
#endif
}
-FunctionPtr CodeBreakpoint::function() const {
- return Code::Handle(code_).function();
-}
-
-ScriptPtr CodeBreakpoint::SourceCode() {
- const Function& func = Function::Handle(this->function());
- return func.script();
-}
-
-StringPtr CodeBreakpoint::SourceUrl() {
- const Script& script = Script::Handle(SourceCode());
- return script.url();
-}
-
-intptr_t CodeBreakpoint::LineNumber() {
- // Compute line number lazily since it causes scanning of the script.
- if (line_number_ < 0) {
- const Script& script = Script::Handle(SourceCode());
- script.GetTokenLocation(token_pos_, &line_number_);
- }
- return line_number_;
-}
-
void CodeBreakpoint::Enable() {
if (enabled_count_ == 0) {
PatchCode();
@@ -2486,6 +2476,45 @@
return TokenPosition::kNoSource;
}
+bool BreakpointLocation::EnsureIsResolved(const Function& target_function,
+ TokenPosition exact_token_pos) {
+ if (IsResolved()) {
+ return true;
+ }
+
+ // Resolve source breakpoint in the newly compiled function.
+ TokenPosition resolved_pos =
+ ResolveBreakpointPos(target_function, token_pos(), end_token_pos(),
+ requested_column_number(), exact_token_pos);
+ if (!resolved_pos.IsDebugPause()) {
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("Failed resolving breakpoint for function '%s'\n",
+ target_function.ToFullyQualifiedCString());
+ }
+ return false;
+ }
+ TokenPosition requested_pos = token_pos();
+ TokenPosition requested_end_pos = end_token_pos();
+ SetResolved(target_function, resolved_pos);
+ Breakpoint* breakpoint = breakpoints();
+ while (breakpoint != nullptr) {
+ if (FLAG_verbose_debug) {
+ OS::PrintErr("Resolved breakpoint %" Pd
+ " to pos %s, function '%s' (requested range %s-%s, "
+ "requested col %" Pd ")\n",
+ breakpoint->id(), token_pos().ToCString(),
+ target_function.ToFullyQualifiedCString(),
+ requested_pos.ToCString(), requested_end_pos.ToCString(),
+ requested_column_number());
+ }
+ debugger()->SendBreakpointEvent(ServiceEvent::kBreakpointResolved,
+ breakpoint);
+ breakpoint = breakpoint->next();
+ }
+
+ return true;
+}
+
void GroupDebugger::MakeCodeBreakpointAt(const Function& func,
BreakpointLocation* loc) {
ASSERT(loc->token_pos_.IsReal());
@@ -2514,8 +2543,7 @@
CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc);
if (code_bpt == nullptr) {
// No code breakpoint for this code exists; create one.
- code_bpt =
- new CodeBreakpoint(code, loc->token_pos_, lowest_pc, lowest_kind);
+ code_bpt = new CodeBreakpoint(code, loc, lowest_pc, lowest_kind);
if (FLAG_verbose_debug) {
OS::PrintErr("Setting code breakpoint at pos %s pc %#" Px
" offset %#" Px "\n",
@@ -2531,8 +2559,8 @@
loc->token_pos_.ToCString(), lowest_pc,
lowest_pc - code.PayloadStart());
}
+ code_bpt->AddBreakpointLocation(loc);
}
- code_bpt->AddBreakpointLocation(loc);
if (loc->AnyEnabled()) {
code_bpt->Enable();
}
@@ -2777,14 +2805,11 @@
TokenPosition breakpoint_pos = ResolveBreakpointPos(
function, token_pos, last_token_pos, requested_column, exact_token_pos);
if (!breakpoint_pos.IsReal()) {
- return NULL;
+ return nullptr;
}
- // Find an existing resolved breakpoint location.
BreakpointLocation* loc =
- GetBreakpointLocation(script, TokenPosition::kNoSource,
- /* requested_line = */ -1,
- /* requested_column = */ -1, breakpoint_pos);
- if (loc == NULL) {
+ GetResolvedBreakpointLocation(script, breakpoint_pos);
+ if (loc == nullptr) {
// Find an existing unresolved breakpoint location.
loc = GetBreakpointLocation(script, token_pos, requested_line,
requested_column);
@@ -3792,11 +3817,11 @@
// Hit a synthetic async breakpoint.
if (FLAG_verbose_debug) {
OS::PrintErr(
- ">>> hit synthetic breakpoint at %s:%" Pd
+ ">>> hit synthetic %s"
" (func %s token %s address %#" Px " offset %#" Px ")\n",
- String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(),
+ cbpt->ToCString(),
String::Handle(top_frame->QualifiedFunctionName()).ToCString(),
- cbpt->token_pos().ToCString(), top_frame->pc(),
+ bpt_location->token_pos().ToCString(), top_frame->pc(),
top_frame->pc() - top_frame->code().PayloadStart());
}
@@ -3815,12 +3840,12 @@
}
if (FLAG_verbose_debug) {
- OS::PrintErr(">>> hit breakpoint %" Pd " at %s:%" Pd
+ OS::PrintErr(">>> hit %" Pd
+ " %s"
" (func %s token %s address %#" Px " offset %#" Px ")\n",
- bpt_hit->id(), String::Handle(cbpt->SourceUrl()).ToCString(),
- cbpt->LineNumber(),
+ bpt_hit->id(), cbpt->ToCString(),
String::Handle(top_frame->QualifiedFunctionName()).ToCString(),
- cbpt->token_pos().ToCString(), top_frame->pc(),
+ bpt_location->token_pos().ToCString(), top_frame->pc(),
top_frame->pc() - top_frame->code().PayloadStart());
}
@@ -3993,37 +4018,10 @@
// There is no local function within func that contains the
// breakpoint token position. Resolve the breakpoint if necessary
// and set the code breakpoints.
- if (!loc->IsResolved()) {
- // Resolve source breakpoint in the newly compiled function.
- TokenPosition bp_pos =
- ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(),
- loc->requested_column_number(), token_pos);
- if (!bp_pos.IsDebugPause()) {
- if (FLAG_verbose_debug) {
- OS::PrintErr("Failed resolving breakpoint for function '%s'\n",
- func.ToFullyQualifiedCString());
- }
- continue;
- }
- TokenPosition requested_pos = loc->token_pos();
- TokenPosition requested_end_pos = loc->end_token_pos();
- loc->SetResolved(func, bp_pos);
- Breakpoint* bpt = loc->breakpoints();
- while (bpt != NULL) {
- if (FLAG_verbose_debug) {
- OS::PrintErr(
- "Resolved breakpoint %" Pd
- " to pos %s, function '%s' (requested range %s-%s, "
- "requested col %" Pd ")\n",
- bpt->id(), loc->token_pos().ToCString(),
- func.ToFullyQualifiedCString(), requested_pos.ToCString(),
- requested_end_pos.ToCString(), loc->requested_column_number());
- }
- SendBreakpointEvent(ServiceEvent::kBreakpointResolved, bpt);
- bpt = bpt->next();
- }
+ if (!loc->EnsureIsResolved(func, token_pos)) {
+ // Failed to resolve breakpoint location for some reason
+ continue;
}
- ASSERT(loc->IsResolved());
if (FLAG_verbose_debug) {
Breakpoint* bpt = loc->breakpoints();
while (bpt != NULL) {
@@ -4328,6 +4326,20 @@
needs_breakpoint_cleanup_ = false;
}
+BreakpointLocation* Debugger::GetResolvedBreakpointLocation(
+ const Script& script,
+ TokenPosition code_token_pos) {
+ BreakpointLocation* loc = breakpoint_locations_;
+ while (loc != nullptr) {
+ if (loc->script_ == script.ptr() &&
+ loc->code_token_pos_ == code_token_pos) {
+ return loc;
+ }
+ loc = loc->next();
+ }
+ return nullptr;
+}
+
BreakpointLocation* Debugger::GetBreakpointLocation(
const Script& script,
TokenPosition token_pos,
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index ff044ed..b1bf176 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -138,8 +138,14 @@
~BreakpointLocation();
- FunctionPtr function() const { return function_; }
TokenPosition token_pos() const { return token_pos_; }
+ intptr_t line_number() {
+ // Compute line number lazily since it causes scanning of the script.
+ if (line_number_ < 0) {
+ Script::Handle(script()).GetTokenLocation(token_pos(), &line_number_);
+ }
+ return line_number_;
+ }
TokenPosition end_token_pos() const { return end_token_pos_; }
ScriptPtr script() const { return script_; }
@@ -160,6 +166,9 @@
bool IsResolved() const { return code_token_pos_.IsReal(); }
bool IsLatent() const { return !token_pos_.IsReal(); }
+ bool EnsureIsResolved(const Function& target_function,
+ TokenPosition exact_token_pos);
+
Debugger* debugger() { return debugger_; }
private:
@@ -181,6 +190,7 @@
Debugger* debugger_;
ScriptPtr script_;
StringPtr url_;
+ intptr_t line_number_; // lazily computed for token_pos_
TokenPosition token_pos_;
TokenPosition end_token_pos_;
BreakpointLocation* next_;
@@ -189,7 +199,6 @@
intptr_t requested_column_number_;
// Valid for resolved breakpoints:
- FunctionPtr function_;
TokenPosition code_token_pos_;
friend class Debugger;
@@ -211,37 +220,50 @@
// is synchronized, guarded by mutexes.
class CodeBreakpoint {
public:
+ // Unless CodeBreakpoint is unlinked and is no longer used there should be at
+ // least one BreakpointLocation associated with CodeBreakpoint. If there are
+ // more BreakpointLocation added assumption is is that all of them point to
+ // the same source so have the same token pos.
CodeBreakpoint(const Code& code,
- TokenPosition token_pos,
+ BreakpointLocation* loc,
uword pc,
UntaggedPcDescriptors::Kind kind);
~CodeBreakpoint();
- FunctionPtr function() const;
+ // Used by GroupDebugger to find CodeBreakpoint associated with
+ // particular function.
+ FunctionPtr function() const { return Code::Handle(code_).function(); }
+
uword pc() const { return pc_; }
- TokenPosition token_pos() const { return token_pos_; }
bool HasBreakpointLocation(BreakpointLocation* breakpoint_location);
bool FindAndDeleteBreakpointLocation(BreakpointLocation* breakpoint_location);
bool HasNoBreakpointLocations() {
return breakpoint_locations_.length() == 0;
}
- ScriptPtr SourceCode();
- StringPtr SourceUrl();
- intptr_t LineNumber();
-
void Enable();
void Disable();
bool IsEnabled() const { return enabled_count_ > 0; }
CodePtr OrigStubAddress() const;
+ const char* ToCString() const;
+
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
+ // Finds right BreakpointLocation for a given Isolate's debugger.
BreakpointLocation* FindBreakpointForDebugger(Debugger* debugger);
- void AddBreakpointLocation(BreakpointLocation* value) {
- breakpoint_locations_.Add(value);
+ // Adds new BreakpointLocation for another isolate that wants to
+ // break at the same function/code location that this CodeBreakpoint
+ // represents.
+ void AddBreakpointLocation(BreakpointLocation* breakpoint_location) {
+ ASSERT(breakpoint_locations_.length() == 0 ||
+ (breakpoint_location->token_pos() ==
+ breakpoint_locations_.At(0)->token_pos() &&
+ breakpoint_location->script() ==
+ breakpoint_locations_.At(0)->script()));
+ breakpoint_locations_.Add(breakpoint_location);
}
void set_next(CodeBreakpoint* value) { next_ = value; }
@@ -251,9 +273,7 @@
void RestoreCode();
CodePtr code_;
- TokenPosition token_pos_;
uword pc_;
- intptr_t line_number_;
int enabled_count_; // incremented for every enabled breakpoint location
// Breakpoint locations from different debuggers/isolates that
@@ -716,6 +736,9 @@
intptr_t line,
intptr_t column);
void RegisterBreakpointLocation(BreakpointLocation* bpt);
+ BreakpointLocation* GetResolvedBreakpointLocation(
+ const Script& script,
+ TokenPosition code_token_pos);
BreakpointLocation* GetBreakpointLocation(
const Script& script,
TokenPosition token_pos,
diff --git a/sdk/lib/_internal/vm/lib/integers.dart b/sdk/lib/_internal/vm/lib/integers.dart
index 123c964..95e3826 100644
--- a/sdk/lib/_internal/vm/lib/integers.dart
+++ b/sdk/lib/_internal/vm/lib/integers.dart
@@ -5,22 +5,26 @@
// part of "core_patch.dart";
abstract class _IntegerImplementation implements int {
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
num operator +(num other) => other._addFromInteger(this);
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
num operator -(num other) => other._subFromInteger(this);
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
num operator *(num other) => other._mulFromInteger(this);
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator ~/(num other) {
if ((other is int) && (other == 0)) {
throw const IntegerDivisionByZeroException();
@@ -32,9 +36,10 @@
return this.toDouble() / other.toDouble();
}
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
num operator %(num other) {
if ((other is int) && (other == 0)) {
throw const IntegerDivisionByZeroException();
@@ -42,26 +47,30 @@
return other._moduloFromInteger(this);
}
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator -() {
// Issue(https://dartbug.com/39639): The analyzer incorrectly reports the
// result type as `num`.
return unsafeCast<int>(0 - this);
}
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator &(int other) => other._bitAndFromInteger(this);
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator |(int other) => other._bitOrFromInteger(this);
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator ^(int other) => other._bitXorFromInteger(this);
num remainder(num other) {
@@ -96,15 +105,20 @@
return unsafeCast<int>(other - (other ~/ this) * this);
}
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator >>(int other) => other._shrFromInteger(this);
+ @pragma("vm:recognized", "graph-intrinsic")
+ @pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator >>>(int other) => other._ushrFromInteger(this);
@pragma("vm:recognized", "asm-intrinsic")
@pragma("vm:non-nullable-result-type")
@pragma("vm:never-inline")
+ @pragma("vm:disable-unboxed-parameters")
int operator <<(int other) => other._shlFromInteger(this);
@pragma("vm:recognized", "asm-intrinsic")
@@ -540,8 +554,9 @@
int get hashCode => this;
int get _identityHashCode => this;
- @pragma("vm:recognized", "asm-intrinsic")
+ @pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:exact-result-type", "dart:core#_Smi")
+ @pragma("vm:disable-unboxed-parameters")
int operator ~() native "Smi_bitNegate";
@pragma("vm:recognized", "asm-intrinsic")
@pragma("vm:exact-result-type", "dart:core#_Smi")
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index d9e2540..6a3566a 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.dart
@@ -29,8 +29,8 @@
/// * such an identifier followed by "=" (a setter name),
/// * the name of a declarable operator
/// (one of "`+`", "`-`", "`*`", "`/`", "`%`", "`~/`", "`&`", "`|`",
- /// "`^`", "`~`", "`<<`", "`>>`", "`<`", "`<=`", "`>`", "`>=`", "`==`",
- /// "`[]`", "`[]=`", or "`unary-`"),
+ /// "`^`", "`~`", "`<<`", "`>>`", "`>>>`", "`<`", "`<=`", "`>`", "`>=`",
+ /// "`==`", "`[]`", "`[]=`", or "`unary-`"),
/// * any of the above preceded by any number of qualifiers,
/// where a qualifier is a non-private identifier followed by '`.`',
/// * or the empty string (the default name of a library with no library
diff --git a/sdk/lib/internal/symbol.dart b/sdk/lib/internal/symbol.dart
index bf48493..c65e5e8 100644
--- a/sdk/lib/internal/symbol.dart
+++ b/sdk/lib/internal/symbol.dart
@@ -50,7 +50,7 @@
* is "unary-".
*/
static const String operatorRE =
- r'(?:[\-+*/%&|^]|\[\]=?|==|~/?|<[<=]?|>[>=]?|unary-)';
+ r'(?:[\-+*/%&|^]|\[\]=?|==|~/?|<[<=]?|>(?:|=|>>?)|unary-)';
// Grammar if symbols:
// symbol ::= qualifiedName | <empty>
diff --git a/tests/language/const_functions/const_functions_do_statements_error_test.dart b/tests/language/const_functions/const_functions_do_statements_error_test.dart
index f48bab3..38a769f 100644
--- a/tests/language/const_functions/const_functions_do_statements_error_test.dart
+++ b/tests/language/const_functions/const_functions_do_statements_error_test.dart
@@ -33,3 +33,15 @@
} while (x as dynamic);
return 2;
}
+
+const var3 = fn3();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn3() {
+ dynamic x = 0;
+ do {
+ x++;
+ } while (x);
+ return 2;
+}
diff --git a/tests/language/const_functions/const_functions_for_statements_error_test.dart b/tests/language/const_functions/const_functions_for_statements_error_test.dart
new file mode 100644
index 0000000..86b9908
--- /dev/null
+++ b/tests/language/const_functions/const_functions_for_statements_error_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests erroneous for statements for const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = fn();
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() {
+ int val = 0;
+ for (; val;) {
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.NON_BOOL_CONDITION
+ // [cfe] A value of type 'int' can't be assigned to a variable of type 'bool'.
+ val += 1;
+ }
+ return val;
+}
+
+const var2 = fn2();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn2() {
+ int val = 0;
+ for (; val as dynamic;) {
+ val += 1;
+ }
+ return val;
+}
+
+const var3 = fn3();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn3() {
+ dynamic val = 0;
+ for (; val;) {
+ val += 1;
+ }
+ return val;
+}
diff --git a/tests/language/const_functions/const_functions_if_statements_error_test.dart b/tests/language/const_functions/const_functions_if_statements_error_test.dart
new file mode 100644
index 0000000..31a25d5
--- /dev/null
+++ b/tests/language/const_functions/const_functions_if_statements_error_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests erroneous if statements for const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = fn();
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() {
+ int val = 0;
+ if (val) {
+ //^^^
+ // [analyzer] COMPILE_TIME_ERROR.NON_BOOL_CONDITION
+ // [cfe] A value of type 'int' can't be assigned to a variable of type 'bool'.
+ val += 1;
+ }
+ return val;
+}
+
+const var2 = fn2();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn2() {
+ int val = 0;
+ if (val as dynamic) {
+ val += 1;
+ }
+ return val;
+}
+
+const var3 = fn3();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn3() {
+ dynamic val = 0;
+ if (val) {
+ val += 1;
+ }
+ return val;
+}
diff --git a/tests/language/const_functions/const_functions_while_statements_error_test.dart b/tests/language/const_functions/const_functions_while_statements_error_test.dart
new file mode 100644
index 0000000..1b7bc18
--- /dev/null
+++ b/tests/language/const_functions/const_functions_while_statements_error_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests erroneous while statements for const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = fn();
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() {
+ int val = 0;
+ while (val) {
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.NON_BOOL_CONDITION
+ // [cfe] A value of type 'int' can't be assigned to a variable of type 'bool'.
+ val += 1;
+ }
+ return val;
+}
+
+const var2 = fn2();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn2() {
+ int val = 0;
+ while (val as dynamic) {
+ val += 1;
+ }
+ return val;
+}
+
+const var3 = fn3();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// [cfe] Constant evaluation error:
+int fn3() {
+ dynamic val = 0;
+ while (val) {
+ val += 1;
+ }
+ return val;
+}
diff --git a/tests/language/generic/function_typedef2_test.dart b/tests/language/generic/function_typedef2_test.dart
index 0ad79c5..6d9c0ff 100644
--- a/tests/language/generic/function_typedef2_test.dart
+++ b/tests/language/generic/function_typedef2_test.dart
@@ -11,19 +11,19 @@
typedef G = F;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef H = int;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef I = A;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef J = List<int>;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef K = Function(Function<A>(A<int>));
// ^^^^^^
diff --git a/tests/language/nonfunction_type_aliases/generic_usage_type_variable_error_test.dart b/tests/language/nonfunction_type_aliases/generic_usage_type_variable_error_test.dart
index 80b22b7..a0ee00c 100644
--- a/tests/language/nonfunction_type_aliases/generic_usage_type_variable_error_test.dart
+++ b/tests/language/nonfunction_type_aliases/generic_usage_type_variable_error_test.dart
@@ -21,22 +21,45 @@
// [cfe] unspecified
}
-class D1<X> extends T<X> {}
-// ^
+class D {}
+mixin M {}
+
+abstract class D1<X> extends T<D> {}
+// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D2 extends C with T<int> {}
+abstract class D2 extends C with T<M> {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D3<X, Y> implements T<T> {}
+abstract class D3<X, Y> implements T<T<D>> {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D4 = C with T<void>;
+abstract class D4 = C with T<D>;
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class D5<X> extends T<X> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D6 extends C with T<int> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D7<X, Y> implements T<T> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D8 = C with T<void>;
// ^
// [analyzer] unspecified
// [cfe] unspecified
diff --git a/tests/language/nonfunction_type_aliases/generic_usage_type_variable_test.dart b/tests/language/nonfunction_type_aliases/generic_usage_type_variable_test.dart
index 291fc7d..a9cd0c2 100644
--- a/tests/language/nonfunction_type_aliases/generic_usage_type_variable_test.dart
+++ b/tests/language/nonfunction_type_aliases/generic_usage_type_variable_test.dart
@@ -45,12 +45,6 @@
}
class D {}
-mixin M {}
-
-abstract class D1<X> extends T<D> {}
-abstract class D2 extends C with T<M> {}
-abstract class D3<X, Y> implements T<T<D>> {}
-abstract class D4 = C with T<D>;
extension E on T<dynamic> {
T<dynamic> foo(T<dynamic> t) => t;
diff --git a/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_error_test.dart b/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_error_test.dart
index a398f3b..cad1f88 100644
--- a/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_error_test.dart
+++ b/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_error_test.dart
@@ -23,22 +23,45 @@
// [cfe] unspecified
}
-class D1<X> extends T<X> {}
-// ^
+class D {}
+mixin M {}
+
+abstract class D1<X> extends T<D> {}
+// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D2 extends C with T<int> {}
+abstract class D2 extends C with T<M> {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D3<X, Y> implements T<T> {}
+abstract class D3<X, Y> implements T<T<D>> {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
-abstract class D4 = C with T<void>;
+abstract class D4 = C with T<D>;
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class D5<X> extends T<X> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D6 extends C with T<int> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D7<X, Y> implements T<T> {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+abstract class D8 = C with T<void>;
// ^
// [analyzer] unspecified
// [cfe] unspecified
diff --git a/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_test.dart b/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_test.dart
index 6e8688f..52b2f4b 100644
--- a/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_test.dart
+++ b/tests/language/nonfunction_type_aliases/mixed/generic_usage_type_variable_test.dart
@@ -47,16 +47,6 @@
class D {}
-mixin M {}
-
-abstract class D1<X> extends T<D> {}
-
-abstract class D2 extends C with T<M> {}
-
-abstract class D3<X, Y> implements T<T<D>> {}
-
-abstract class D4 = C with T<D>;
-
extension E on T<dynamic> {
T<dynamic> foo(T<dynamic> t) => t;
}
diff --git a/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_error_test.dart b/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_error_test.dart
index 840809b..a544e21 100644
--- a/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_error_test.dart
+++ b/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_error_test.dart
@@ -22,16 +22,28 @@
// [cfe] unspecified
}
+class D1 extends T {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
abstract class D2 extends C with T {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
+abstract class D3 implements T {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
abstract class D4 = C with T;
// ^
// [analyzer] unspecified
// [cfe] unspecified
+X foo<X>(X x) => x;
+
main() {
var v14 = <Set<T>, Set<T>>{{}: {}};
v14[{}] = {T()};
diff --git a/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_test.dart b/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_test.dart
index d4212df..983f6a6 100644
--- a/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_test.dart
+++ b/tests/language/nonfunction_type_aliases/mixed/usage_type_variable_test.dart
@@ -45,10 +45,6 @@
noSuchMethod(Invocation invocation) => throw 0;
}
-class D1 extends T {}
-
-abstract class D3 implements T {}
-
extension E on T {
T foo(T t) => t;
}
@@ -60,7 +56,6 @@
main() {
var v13 = <T>[];
var v14 = <Set<T>, Set<T>>{{}: {}};
- v14[{}] = {D1()};
var v15 = {v13};
Set<List<T>> v16 = v15;
v15 = v16;
diff --git a/tests/language/nonfunction_type_aliases/near_expand_to_type_variable_test.dart b/tests/language/nonfunction_type_aliases/near_expand_to_type_variable_test.dart
new file mode 100644
index 0000000..27c816f
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/near_expand_to_type_variable_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+import 'package:expect/expect.dart';
+
+typedef TB<T extends C> = T;
+typedef AC = C; // Direct.
+typedef AEC = TB<C>; // Explicit C argument.
+typedef AIC = TB; // Implicit instantiate to bounds.
+
+class C {
+ static const c = 42;
+ static int s = 42;
+ final int y;
+ const C(this.y);
+ const C.name(this.y);
+}
+
+main() {
+ const c0 = AC.c;
+ const c1 = AEC.c;
+ const c2 = AIC.c;
+ Expect.equals(42, AC.s);
+ Expect.equals(42, AEC.s);
+ Expect.equals(42, AIC.s);
+ Expect.equals(0, AC(0).y);
+ Expect.equals(0, AEC(0).y);
+ Expect.equals(0, AIC(0).y);
+ Expect.equals(0, AC.name(0).y);
+ Expect.equals(0, AEC.name(0).y);
+ Expect.equals(0, AIC.name(0).y);
+}
diff --git a/tests/language/nonfunction_type_aliases/usage_type_variable_error_test.dart b/tests/language/nonfunction_type_aliases/usage_type_variable_error_test.dart
index b24e824..5a6ffb3 100644
--- a/tests/language/nonfunction_type_aliases/usage_type_variable_error_test.dart
+++ b/tests/language/nonfunction_type_aliases/usage_type_variable_error_test.dart
@@ -25,16 +25,29 @@
// [cfe] unspecified
}
+class D1 extends T {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
abstract class D2 extends C with T {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
+abstract class D3 implements T {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+
abstract class D4 = C with T;
// ^
// [analyzer] unspecified
// [cfe] unspecified
+X foo<X>(X x) => x;
+
main() {
var v14 = <Set<T>, Set<T>>{{}: {}};
v14[{}] = {T()};
diff --git a/tests/language/nonfunction_type_aliases/usage_type_variable_test.dart b/tests/language/nonfunction_type_aliases/usage_type_variable_test.dart
index 6c1b6c8..2c511b6 100644
--- a/tests/language/nonfunction_type_aliases/usage_type_variable_test.dart
+++ b/tests/language/nonfunction_type_aliases/usage_type_variable_test.dart
@@ -48,9 +48,6 @@
noSuchMethod(Invocation invocation) => throw 0;
}
-class D1 extends T {}
-abstract class D3 implements T {}
-
extension E on T {
T foo(T t) => t;
}
@@ -62,7 +59,6 @@
main() {
var v13 = <T>[];
var v14 = <Set<T>, Set<T>>{{}: {}};
- v14[{}] = {D1()};
var v15 = {v13};
Set<List<T>> v16 = v15;
v15 = v16;
diff --git a/tests/language/vm/checked_smi_comparison_test.dart b/tests/language/vm/checked_smi_comparison_test.dart
new file mode 100644
index 0000000..d22cb01
--- /dev/null
+++ b/tests/language/vm/checked_smi_comparison_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=
+// VMOptions=--use_slow_path
+
+import "package:expect/expect.dart";
+
+@pragma("vm:never-inline")
+dynamic hiddenSmi() {
+ try {
+ throw 42;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenMint() {
+ try {
+ throw 0x8000000000000000;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenDouble() {
+ try {
+ throw 3.0;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenCustom() {
+ try {
+ throw new Custom();
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+class Custom {
+ operator <(other) => "lt";
+ operator >(other) => "gt";
+ operator <=(other) => "le";
+ operator >=(other) => "ge";
+ operator ==(other) => false;
+}
+
+main() {
+ Expect.equals(false, hiddenSmi() < 2);
+ Expect.equals(true, hiddenSmi() > 2);
+ Expect.equals(false, hiddenSmi() <= 2);
+ Expect.equals(true, hiddenSmi() >= 2);
+ Expect.equals(false, hiddenSmi() == 2);
+ Expect.equals(true, hiddenSmi() != 2);
+
+ Expect.equals(true, hiddenMint() < 2);
+ Expect.equals(false, hiddenMint() > 2);
+ Expect.equals(true, hiddenMint() <= 2);
+ Expect.equals(false, hiddenMint() >= 2);
+ Expect.equals(false, hiddenMint() == 2);
+ Expect.equals(true, hiddenMint() != 2);
+
+ Expect.equals(false, hiddenDouble() < 2);
+ Expect.equals(true, hiddenDouble() > 2);
+ Expect.equals(false, hiddenDouble() <= 2);
+ Expect.equals(true, hiddenDouble() >= 2);
+ Expect.equals(false, hiddenDouble() == 2);
+ Expect.equals(true, hiddenDouble() != 2);
+
+ Expect.equals("lt", hiddenCustom() < 2);
+ Expect.equals("gt", hiddenCustom() > 2);
+ Expect.equals("le", hiddenCustom() <= 2);
+ Expect.equals("ge", hiddenCustom() >= 2);
+ Expect.equals(false, hiddenCustom() == 2);
+ Expect.equals(true, hiddenCustom() != 2);
+}
diff --git a/tests/language/vm/checked_smi_op_test.dart b/tests/language/vm/checked_smi_op_test.dart
new file mode 100644
index 0000000..f1ae4a6
--- /dev/null
+++ b/tests/language/vm/checked_smi_op_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=triple-shift
+// VMOptions=
+// VMOptions=--use_slow_path
+
+import "package:expect/expect.dart";
+
+@pragma("vm:never-inline")
+dynamic hiddenSmi() {
+ try {
+ throw 42;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenMint() {
+ try {
+ throw 0x8000000000000000;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenDouble() {
+ try {
+ throw 3.0;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenCustom() {
+ try {
+ throw new Custom();
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+class Custom {
+ operator +(other) => "add";
+ operator -(other) => "sub";
+ operator *(other) => "mul";
+ operator ~/(other) => "div";
+ operator %(other) => "mod";
+ operator &(other) => "and";
+ operator |(other) => "or";
+ operator ^(other) => "xor";
+ operator <<(other) => "sll";
+ operator >>(other) => "sra";
+ operator >>>(other) => "srl";
+}
+
+main() {
+ Expect.equals(44, hiddenSmi() + 2);
+ Expect.equals(40, hiddenSmi() - 2);
+ Expect.equals(84, hiddenSmi() * 2);
+ Expect.equals(21, hiddenSmi() ~/ 2);
+ Expect.equals(0, hiddenSmi() % 2);
+ Expect.equals(2, hiddenSmi() & 2);
+ Expect.equals(42, hiddenSmi() | 2);
+ Expect.equals(40, hiddenSmi() ^ 2);
+ Expect.equals(168, hiddenSmi() << 2);
+ Expect.equals(10, hiddenSmi() >> 2);
+ Expect.equals(10, hiddenSmi() >>> 2);
+
+ Expect.equals(-9223372036854775806, hiddenMint() + 2);
+ Expect.equals(9223372036854775806, hiddenMint() - 2);
+ Expect.equals(0, hiddenMint() * 2);
+ Expect.equals(-4611686018427387904, hiddenMint() ~/ 2);
+ Expect.equals(0, hiddenMint() % 2);
+ Expect.equals(0, hiddenMint() & 2);
+ Expect.equals(-9223372036854775806, hiddenMint() | 2);
+ Expect.equals(-9223372036854775806, hiddenMint() ^ 2);
+ Expect.equals(0, hiddenMint() << 2);
+ Expect.equals(-2305843009213693952, hiddenMint() >> 2);
+ Expect.equals(2305843009213693952, hiddenMint() >>> 2);
+
+ Expect.equals(5.0, hiddenDouble() + 2);
+ Expect.equals(1.0, hiddenDouble() - 2);
+ Expect.equals(6.0, hiddenDouble() * 2);
+ Expect.equals(1, hiddenDouble() ~/ 2);
+ Expect.equals(1.0, hiddenDouble() % 2);
+ Expect.throws(() => hiddenDouble() & 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() | 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() ^ 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() << 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() >> 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() >>> 2, (e) => e is NoSuchMethodError);
+
+ Expect.equals("add", hiddenCustom() + 2);
+ Expect.equals("sub", hiddenCustom() - 2);
+ Expect.equals("mul", hiddenCustom() * 2);
+ Expect.equals("div", hiddenCustom() ~/ 2);
+ Expect.equals("mod", hiddenCustom() % 2);
+ Expect.equals("and", hiddenCustom() & 2);
+ Expect.equals("or", hiddenCustom() | 2);
+ Expect.equals("xor", hiddenCustom() ^ 2);
+ Expect.equals("sll", hiddenCustom() << 2);
+ Expect.equals("sra", hiddenCustom() >> 2);
+ Expect.equals("srl", hiddenCustom() >>> 2);
+}
diff --git a/tests/language/vm/div_mod_test.dart b/tests/language/vm/div_mod_test.dart
index f534e67..ea22240 100755
--- a/tests/language/vm/div_mod_test.dart
+++ b/tests/language/vm/div_mod_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--deterministic
+// VMOptions=--deterministic --use_slow_path
// Unit tests on DIV and MOV operations by various constants.
diff --git a/tests/language/vm/modtruncdiv_int_test.dart b/tests/language/vm/modtruncdiv_int_test.dart
index f5a51ce..9fc5b53 100644
--- a/tests/language/vm/modtruncdiv_int_test.dart
+++ b/tests/language/vm/modtruncdiv_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language/vm/mult_int_test.dart b/tests/language/vm/mult_int_test.dart
index b13cbd5..16df391 100644
--- a/tests/language/vm/mult_int_test.dart
+++ b/tests/language/vm/mult_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language/vm/negate_int_test.dart b/tests/language/vm/negate_int_test.dart
index 8703aef..253756e 100644
--- a/tests/language/vm/negate_int_test.dart
+++ b/tests/language/vm/negate_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language/vm/shift_special_cases_test.dart b/tests/language/vm/shift_special_cases_test.dart
index 2cba918..b0fd2ed 100644
--- a/tests/language/vm/shift_special_cases_test.dart
+++ b/tests/language/vm/shift_special_cases_test.dart
@@ -1,7 +1,9 @@
// Copyright (c) 2018, 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.
+
// VMOptions=--optimization-counter-threshold=10 --no-background-compilation
+// VMOptions=--optimization-counter-threshold=10 --no-background-compilation --use_slow_path
// Test for special cases of << and >> integer operations with int64.
diff --git a/tests/language_2/generic/function_typedef2_test.dart b/tests/language_2/generic/function_typedef2_test.dart
index 704a824..b7ae03a 100644
--- a/tests/language_2/generic/function_typedef2_test.dart
+++ b/tests/language_2/generic/function_typedef2_test.dart
@@ -11,19 +11,19 @@
typedef G = F;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef H = int;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef I = A;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef J = List<int>;
// ^
-// [analyzer] SYNTACTIC_ERROR.INVALID_GENERIC_FUNCTION_TYPE
+// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] Can't create typedef from non-function type.
typedef K = Function(Function<A>(A<int>));
// ^^^^^^
diff --git a/tests/language_2/vm/checked_smi_comparison_test.dart b/tests/language_2/vm/checked_smi_comparison_test.dart
new file mode 100644
index 0000000..d22cb01
--- /dev/null
+++ b/tests/language_2/vm/checked_smi_comparison_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=
+// VMOptions=--use_slow_path
+
+import "package:expect/expect.dart";
+
+@pragma("vm:never-inline")
+dynamic hiddenSmi() {
+ try {
+ throw 42;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenMint() {
+ try {
+ throw 0x8000000000000000;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenDouble() {
+ try {
+ throw 3.0;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenCustom() {
+ try {
+ throw new Custom();
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+class Custom {
+ operator <(other) => "lt";
+ operator >(other) => "gt";
+ operator <=(other) => "le";
+ operator >=(other) => "ge";
+ operator ==(other) => false;
+}
+
+main() {
+ Expect.equals(false, hiddenSmi() < 2);
+ Expect.equals(true, hiddenSmi() > 2);
+ Expect.equals(false, hiddenSmi() <= 2);
+ Expect.equals(true, hiddenSmi() >= 2);
+ Expect.equals(false, hiddenSmi() == 2);
+ Expect.equals(true, hiddenSmi() != 2);
+
+ Expect.equals(true, hiddenMint() < 2);
+ Expect.equals(false, hiddenMint() > 2);
+ Expect.equals(true, hiddenMint() <= 2);
+ Expect.equals(false, hiddenMint() >= 2);
+ Expect.equals(false, hiddenMint() == 2);
+ Expect.equals(true, hiddenMint() != 2);
+
+ Expect.equals(false, hiddenDouble() < 2);
+ Expect.equals(true, hiddenDouble() > 2);
+ Expect.equals(false, hiddenDouble() <= 2);
+ Expect.equals(true, hiddenDouble() >= 2);
+ Expect.equals(false, hiddenDouble() == 2);
+ Expect.equals(true, hiddenDouble() != 2);
+
+ Expect.equals("lt", hiddenCustom() < 2);
+ Expect.equals("gt", hiddenCustom() > 2);
+ Expect.equals("le", hiddenCustom() <= 2);
+ Expect.equals("ge", hiddenCustom() >= 2);
+ Expect.equals(false, hiddenCustom() == 2);
+ Expect.equals(true, hiddenCustom() != 2);
+}
diff --git a/tests/language_2/vm/checked_smi_op_test.dart b/tests/language_2/vm/checked_smi_op_test.dart
new file mode 100644
index 0000000..f1ae4a6
--- /dev/null
+++ b/tests/language_2/vm/checked_smi_op_test.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=triple-shift
+// VMOptions=
+// VMOptions=--use_slow_path
+
+import "package:expect/expect.dart";
+
+@pragma("vm:never-inline")
+dynamic hiddenSmi() {
+ try {
+ throw 42;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenMint() {
+ try {
+ throw 0x8000000000000000;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenDouble() {
+ try {
+ throw 3.0;
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+@pragma("vm:never-inline")
+dynamic hiddenCustom() {
+ try {
+ throw new Custom();
+ } catch (e) {
+ return e;
+ }
+ return 0;
+}
+
+class Custom {
+ operator +(other) => "add";
+ operator -(other) => "sub";
+ operator *(other) => "mul";
+ operator ~/(other) => "div";
+ operator %(other) => "mod";
+ operator &(other) => "and";
+ operator |(other) => "or";
+ operator ^(other) => "xor";
+ operator <<(other) => "sll";
+ operator >>(other) => "sra";
+ operator >>>(other) => "srl";
+}
+
+main() {
+ Expect.equals(44, hiddenSmi() + 2);
+ Expect.equals(40, hiddenSmi() - 2);
+ Expect.equals(84, hiddenSmi() * 2);
+ Expect.equals(21, hiddenSmi() ~/ 2);
+ Expect.equals(0, hiddenSmi() % 2);
+ Expect.equals(2, hiddenSmi() & 2);
+ Expect.equals(42, hiddenSmi() | 2);
+ Expect.equals(40, hiddenSmi() ^ 2);
+ Expect.equals(168, hiddenSmi() << 2);
+ Expect.equals(10, hiddenSmi() >> 2);
+ Expect.equals(10, hiddenSmi() >>> 2);
+
+ Expect.equals(-9223372036854775806, hiddenMint() + 2);
+ Expect.equals(9223372036854775806, hiddenMint() - 2);
+ Expect.equals(0, hiddenMint() * 2);
+ Expect.equals(-4611686018427387904, hiddenMint() ~/ 2);
+ Expect.equals(0, hiddenMint() % 2);
+ Expect.equals(0, hiddenMint() & 2);
+ Expect.equals(-9223372036854775806, hiddenMint() | 2);
+ Expect.equals(-9223372036854775806, hiddenMint() ^ 2);
+ Expect.equals(0, hiddenMint() << 2);
+ Expect.equals(-2305843009213693952, hiddenMint() >> 2);
+ Expect.equals(2305843009213693952, hiddenMint() >>> 2);
+
+ Expect.equals(5.0, hiddenDouble() + 2);
+ Expect.equals(1.0, hiddenDouble() - 2);
+ Expect.equals(6.0, hiddenDouble() * 2);
+ Expect.equals(1, hiddenDouble() ~/ 2);
+ Expect.equals(1.0, hiddenDouble() % 2);
+ Expect.throws(() => hiddenDouble() & 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() | 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() ^ 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() << 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() >> 2, (e) => e is NoSuchMethodError);
+ Expect.throws(() => hiddenDouble() >>> 2, (e) => e is NoSuchMethodError);
+
+ Expect.equals("add", hiddenCustom() + 2);
+ Expect.equals("sub", hiddenCustom() - 2);
+ Expect.equals("mul", hiddenCustom() * 2);
+ Expect.equals("div", hiddenCustom() ~/ 2);
+ Expect.equals("mod", hiddenCustom() % 2);
+ Expect.equals("and", hiddenCustom() & 2);
+ Expect.equals("or", hiddenCustom() | 2);
+ Expect.equals("xor", hiddenCustom() ^ 2);
+ Expect.equals("sll", hiddenCustom() << 2);
+ Expect.equals("sra", hiddenCustom() >> 2);
+ Expect.equals("srl", hiddenCustom() >>> 2);
+}
diff --git a/tests/language_2/vm/div_mod_test.dart b/tests/language_2/vm/div_mod_test.dart
index 92fab4f..ff9a88c 100755
--- a/tests/language_2/vm/div_mod_test.dart
+++ b/tests/language_2/vm/div_mod_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--deterministic
+// VMOptions=--deterministic --use_slow_path
// Unit tests on DIV and MOV operations by various constants.
diff --git a/tests/language_2/vm/modtruncdiv_int_test.dart b/tests/language_2/vm/modtruncdiv_int_test.dart
index b838b15..018995e 100644
--- a/tests/language_2/vm/modtruncdiv_int_test.dart
+++ b/tests/language_2/vm/modtruncdiv_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language_2/vm/mult_int_test.dart b/tests/language_2/vm/mult_int_test.dart
index b13cbd5..16df391 100644
--- a/tests/language_2/vm/mult_int_test.dart
+++ b/tests/language_2/vm/mult_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language_2/vm/negate_int_test.dart b/tests/language_2/vm/negate_int_test.dart
index 8703aef..253756e 100644
--- a/tests/language_2/vm/negate_int_test.dart
+++ b/tests/language_2/vm/negate_int_test.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--no_background_compilation --optimization_counter_threshold=10
+// VMOptions=--no_background_compilation --optimization_counter_threshold=10 --use_slow_path
import "package:expect/expect.dart";
diff --git a/tests/language_2/vm/shift_special_cases_test.dart b/tests/language_2/vm/shift_special_cases_test.dart
index 604a0a3..f854461 100644
--- a/tests/language_2/vm/shift_special_cases_test.dart
+++ b/tests/language_2/vm/shift_special_cases_test.dart
@@ -1,7 +1,9 @@
// Copyright (c) 2018, 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.
+
// VMOptions=--optimization-counter-threshold=10 --no-background-compilation
+// VMOptions=--optimization-counter-threshold=10 --no-background-compilation --use_slow_path
// Test for special cases of << and >> integer operations with int64.
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 9069e5b..1c4e7ce 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -39,6 +39,7 @@
js/instanceof_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/async_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/jsify_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
+js/js_util/promise_reject_null_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/properties_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/method_call_on_object_test: SkipByDesign # Issue 42085.
js/mock_test/*: SkipByDesign # Issue 42085.
diff --git a/tests/lib_2/lib_2.status b/tests/lib_2/lib_2.status
index 5a1d63b..a6d093b 100644
--- a/tests/lib_2/lib_2.status
+++ b/tests/lib_2/lib_2.status
@@ -39,6 +39,7 @@
js/instanceof_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/async_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/jsify_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
+js/js_util/promise_reject_null_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/js_util/properties_test: SkipByDesign # Issue 42085. CSP policy disallows injected JS code
js/method_call_on_object_test: SkipByDesign # Issue 42085.
js/mock_test/*: SkipByDesign # Issue 42085.
diff --git a/tools/VERSION b/tools/VERSION
index 1d974fb..0d6a30e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 168
+PRERELEASE 169
PRERELEASE_PATCH 0
\ No newline at end of file