Additional language tests for parsing behaviors around type arguments.

Change-Id: I8ae5e800588ece4e08add7b0c7afe6587c01c478
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200200
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
Paul Berry 2021-05-18 14:06:13 +00:00 committed by commit-bot@chromium.org
parent e57a5d13f6
commit bb7dbc004e
8 changed files with 398 additions and 2 deletions

View file

@ -0,0 +1,50 @@
// 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.
// This test verifies that `f<T, U>(0)` is properly parsed as a generic
// invocation, for all type syntaxes that may appear as T and U.
// Note: it doesn't really matter what we import here; it's just a handy library
// that has declares a types so that we can refer a type via a prefix.
import 'dart:async' as prefix;
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object? x = absent, Object? y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
}
/// Helper function to work around the fact that not all types can be expressed
/// as type literals.
Type typeOf<T>() => T;
main() {
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[typeOf<C?>()] = 'C?';
SyntaxTracker.known[prefix.Zone] = 'prefix.Zone';
SyntaxTracker.known[typeOf<prefix.Zone?>()] = 'prefix.Zone?';
SyntaxTracker.known[dynamic] = 'dynamic';
SyntaxTracker.known[typeOf<List<C>>()] = 'List<C>';
SyntaxTracker.known[typeOf<List<C>?>()] = 'List<C>?';
SyntaxTracker.known[typeOf<void Function()>()] = 'void Function()';
SyntaxTracker.known[typeOf<void Function()?>()] = 'void Function()?';
checkSyntax(f(f<C, C>(0)), 'f(f<C, C>(0))');
checkSyntax(f(f<C?, C>(0)), 'f(f<C?, C>(0))');
checkSyntax(f(f<dynamic, C>(0)), 'f(f<dynamic, C>(0))');
checkSyntax(f(f<prefix.Zone, C>(0)), 'f(f<prefix.Zone, C>(0))');
checkSyntax(f(f<prefix.Zone?, C>(0)), 'f(f<prefix.Zone?, C>(0))');
checkSyntax(f(f<List<C>, C>(0)), 'f(f<List<C>, C>(0))');
checkSyntax(f(f<List<C>?, C>(0)), 'f(f<List<C>?, C>(0))');
checkSyntax(f(f<void Function(), C>(0)), 'f(f<void Function(), C>(0))');
checkSyntax(f(f<void Function()?, C>(0)), 'f(f<void Function()?, C>(0))');
checkSyntax(f(f<C, C?>(0)), 'f(f<C, C?>(0))');
checkSyntax(f(f<C, dynamic>(0)), 'f(f<C, dynamic>(0))');
checkSyntax(f(f<C, prefix.Zone>(0)), 'f(f<C, prefix.Zone>(0))');
checkSyntax(f(f<C, prefix.Zone?>(0)), 'f(f<C, prefix.Zone?>(0))');
checkSyntax(f(f<C, List<C>>(0)), 'f(f<C, List<C>>(0))');
checkSyntax(f(f<C, List<C>?>(0)), 'f(f<C, List<C>?>(0))');
checkSyntax(f(f<C, void Function()>(0)), 'f(f<C, void Function()>(0))');
checkSyntax(f(f<C, void Function()?>(0)), 'f(f<C, void Function()?>(0))');
}

View file

@ -0,0 +1,71 @@
// 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.
// This test verifies that `f<EXPR,b>(x)` is properly parsed as a pair of
// expressions separated by a `,`, for all types of expressions that may appear
// as EXPR that can't be parsed as types.
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object? x = absent, Object? y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
C.syntax(String s) : super(s);
}
class ThisTest extends C {
ThisTest() : super.syntax('this');
void test() {
checkSyntax(f(x < this, C > (x)), 'f((x < this), (C > x))');
// Note: SyntaxTracker can't see the parens around `this` in the line below
checkSyntax(f(x < (this), C > (x)), 'f((x < this), (C > x))');
}
}
main() {
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[#x] = '#x';
checkSyntax(
f(x < x.getter.getter, C > (x)), 'f((x < x.getter.getter), (C > x))');
checkSyntax(f(x < C(), C > (x)), 'f((x < new C()), (C > x))');
checkSyntax(f(x < new C(), C > (x)), 'f((x < new C()), (C > x))');
checkSyntax(f(x < f(), C > (x)), 'f((x < f()), (C > x))');
checkSyntax(f(x < x.method(), C > (x)), 'f((x < x.method()), (C > x))');
checkSyntax(f(x < x[0](), C > (x)), 'f((x < x[0]()), (C > x))');
checkSyntax(f(x < #x, C > (x)), 'f((x < #x), (C > x))');
checkSyntax(f(x < null, C > (x)), 'f((x < null), (C > x))');
checkSyntax(f(x < 0, C > (x)), 'f((x < 0), (C > x))');
checkSyntax(f(x < 0.5, C > (x)), 'f((x < 0.5), (C > x))');
checkSyntax(f(x < [], C > (x)), 'f((x < []), (C > x))');
checkSyntax(f(x < [0], C > (x)), 'f((x < [0]), (C > x))');
checkSyntax(f(x < {}, C > (x)), 'f((x < {}), (C > x))');
checkSyntax(f(x < {0}, C > (x)), 'f((x < {0}), (C > x))');
checkSyntax(f(x < {0: 0}, C > (x)), 'f((x < { 0: 0 }), (C > x))');
checkSyntax(f(x < true, C > (x)), 'f((x < true), (C > x))');
checkSyntax(f(x < "s", C > (x)), 'f((x < "s"), (C > x))');
checkSyntax(f(x < r"s", C > (x)), 'f((x < "s"), (C > x))');
checkSyntax(f(x < x[0], C > (x)), 'f((x < x[0]), (C > x))');
// Note: SyntaxTracker can't see the `!` in the line below
checkSyntax(f(x < x!, C > (x)), 'f((x < x), (C > x))');
// Note: SyntaxTracker can't see the parens around `x` in the line below
checkSyntax(f(x < (x), C > (x)), 'f((x < x), (C > x))');
checkSyntax(f(x < -x, C > (x)), 'f((x < (-x)), (C > x))');
checkSyntax(f(x < !true, C > (x)), 'f((x < false), (C > x))');
checkSyntax(f(x < !(true), C > (x)), 'f((x < false), (C > x))');
checkSyntax(f(x < ~x, C > (x)), 'f((x < (~x)), (C > x))');
checkSyntax(f(x < x * x, C > (x)), 'f((x < (x * x)), (C > x))');
checkSyntax(f(x < x / x, C > (x)), 'f((x < (x / x)), (C > x))');
checkSyntax(f(x < x ~/ x, C > (x)), 'f((x < (x ~/ x)), (C > x))');
checkSyntax(f(x < x % x, C > (x)), 'f((x < (x % x)), (C > x))');
checkSyntax(f(x < x + x, C > (x)), 'f((x < (x + x)), (C > x))');
checkSyntax(f(x < x - x, C > (x)), 'f((x < (x - x)), (C > x))');
checkSyntax(f(x < x << x, C > (x)), 'f((x < (x << x)), (C > x))');
checkSyntax(f(x < x >> x, C > (x)), 'f((x < (x >> x)), (C > x))');
checkSyntax(f(x < x & x, C > (x)), 'f((x < (x & x)), (C > x))');
checkSyntax(f(x < x ^ x, C > (x)), 'f((x < (x ^ x)), (C > x))');
checkSyntax(f(x < x | x, C > (x)), 'f((x < (x | x)), (C > x))');
ThisTest().test();
}

View file

@ -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.
// This test verifies that `f<a,EXPR>(x)` is properly parsed as a pair of
// expressions separated by a `,`, for all types of expressions that may appear
// as EXPR that can't be parsed as types.
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object? x = absent, Object? y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
C.syntax(String s) : super(s);
Object? operator >(Object? other) =>
SyntaxTracker('(${syntax(this)} > ${syntax(other)})');
}
class ThisTest extends C {
ThisTest() : super.syntax('this');
void test() {
checkSyntax(f(x < C, this > (x)), 'f((x < C), (this > x))');
// Note: SyntaxTracker can't see the parens around `this` in the line below
checkSyntax(f(x < C, (this) > (x)), 'f((x < C), (this > x))');
}
}
class SuperTest extends C {
SuperTest() : super.syntax('super');
void test() {
checkSyntax(f(x < C, super > (x)), 'f((x < C), (super > x))');
}
}
main() {
const y = 123;
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[#x] = '#x';
SyntaxTracker.known[y] = 'y';
checkSyntax(
f(x < C, x.getter.getter > (x)), 'f((x < C), (x.getter.getter > x))');
checkSyntax(f(x < C, C() > (x)), 'f((x < C), (new C() > x))');
checkSyntax(f(x < C, new C() > (x)), 'f((x < C), (new C() > x))');
checkSyntax(f(x < C, f() > (x)), 'f((x < C), (f() > x))');
checkSyntax(f(x < C, x.method() > (x)), 'f((x < C), (x.method() > x))');
checkSyntax(f(x < C, x[0]() > (x)), 'f((x < C), (x[0]() > x))');
checkSyntax(f(x < C, #x > (x)), 'f((x < C), (#x > x))');
checkSyntax(f(x < C, null > (x)), 'f((x < C), (null > x))');
checkSyntax(f(x < C, 0 > (y)), 'f((x < C), false)');
checkSyntax(f(x < C, 0.5 > (y)), 'f((x < C), false)');
checkSyntax(f(x < C, [] > (x)), 'f((x < C), ([] > x))');
checkSyntax(f(x < C, [0] > (x)), 'f((x < C), ([0] > x))');
checkSyntax(f(x < C, {} > (x)), 'f((x < C), ({} > x))');
checkSyntax(f(x < C, {0} > (x)), 'f((x < C), ({0} > x))');
checkSyntax(f(x < C, {0: 0} > (x)), 'f((x < C), ({ 0: 0 } > x))');
checkSyntax(f(x < C, true > (x)), 'f((x < C), (true > x))');
checkSyntax(f(x < C, "s" > (x)), 'f((x < C), ("s" > x))');
checkSyntax(f(x < C, r"s" > (x)), 'f((x < C), ("s" > x))');
checkSyntax(f(x < C, x[0] > (x)), 'f((x < C), (x[0] > x))');
// Note: SyntaxTracker can't see the `!` in the line below
checkSyntax(f(x < C, x! > (x)), 'f((x < C), (x > x))');
// Note: SyntaxTracker can't see the parens around `x` in the line below
checkSyntax(f(x < C, (x) > (x)), 'f((x < C), (x > x))');
checkSyntax(f(x < C, -x > (x)), 'f((x < C), ((-x) > x))');
checkSyntax(f(x < C, !true > (x)), 'f((x < C), (false > x))');
checkSyntax(f(x < C, !(true) > (x)), 'f((x < C), (false > x))');
checkSyntax(f(x < C, ~x > (x)), 'f((x < C), ((~x) > x))');
checkSyntax(f(x < C, x * x > (x)), 'f((x < C), ((x * x) > x))');
checkSyntax(f(x < C, x / x > (x)), 'f((x < C), ((x / x) > x))');
checkSyntax(f(x < C, x ~/ x > (x)), 'f((x < C), ((x ~/ x) > x))');
checkSyntax(f(x < C, x % x > (x)), 'f((x < C), ((x % x) > x))');
checkSyntax(f(x < C, x + x > (x)), 'f((x < C), ((x + x) > x))');
checkSyntax(f(x < C, x - x > (x)), 'f((x < C), ((x - x) > x))');
checkSyntax(f(x < C, x << x > (x)), 'f((x < C), ((x << x) > x))');
checkSyntax(f(x < C, x >> x > (x)), 'f((x < C), ((x >> x) > x))');
checkSyntax(f(x < C, x & x > (x)), 'f((x < C), ((x & x) > x))');
checkSyntax(f(x < C, x ^ x > (x)), 'f((x < C), ((x ^ x) > x))');
checkSyntax(f(x < C, x | x > (x)), 'f((x < C), ((x | x) > x))');
ThisTest().test();
SuperTest().test();
}

View file

@ -51,7 +51,7 @@ class SyntaxTracker {
'(${[x, y].where((v) => v is! Absent).join(', ')})';
static String typeArgs(Type T, Type U) =>
T.toString() == 'dynamic' ? '' : '<${syntax(T)}, ${syntax(U)}>';
T == dynamic && U == dynamic ? '' : '<${syntax(T)}, ${syntax(U)}>';
/// Simple objects with known syntactic representations. Tests can add to
/// this map.

View file

@ -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.
// This test verifies that `f<T, U>(0)` is properly parsed as a generic
// invocation, for all type syntaxes that may appear as T and U.
// Note: it doesn't really matter what we import here; it's just a handy library
// that has declares a types so that we can refer a type via a prefix.
import 'dart:async' as prefix;
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object x = absent, Object y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
}
/// Helper function to work around the fact that not all types can be expressed
/// as type literals.
Type typeOf<T>() => T;
main() {
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[prefix.Zone] = 'prefix.Zone';
SyntaxTracker.known[dynamic] = 'dynamic';
SyntaxTracker.known[typeOf<List<C>>()] = 'List<C>';
SyntaxTracker.known[typeOf<void Function()>()] = 'void Function()';
checkSyntax(f(f<C, C>(0)), 'f(f<C, C>(0))');
checkSyntax(f(f<dynamic, C>(0)), 'f(f<dynamic, C>(0))');
checkSyntax(f(f<prefix.Zone, C>(0)), 'f(f<prefix.Zone, C>(0))');
checkSyntax(f(f<List<C>, C>(0)), 'f(f<List<C>, C>(0))');
checkSyntax(f(f<void Function(), C>(0)), 'f(f<void Function(), C>(0))');
checkSyntax(f(f<C, dynamic>(0)), 'f(f<C, dynamic>(0))');
checkSyntax(f(f<C, prefix.Zone>(0)), 'f(f<C, prefix.Zone>(0))');
checkSyntax(f(f<C, List<C>>(0)), 'f(f<C, List<C>>(0))');
checkSyntax(f(f<C, void Function()>(0)), 'f(f<C, void Function()>(0))');
}

View file

@ -0,0 +1,69 @@
// 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.
// This test verifies that `f<EXPR,b>(x)` is properly parsed as a pair of
// expressions separated by a `,`, for all types of expressions that may appear
// as EXPR that can't be parsed as types.
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object x = absent, Object y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
C.syntax(String s) : super(s);
}
class ThisTest extends C {
ThisTest() : super.syntax('this');
void test() {
checkSyntax(f(x < this, C > (x)), 'f((x < this), (C > x))');
// Note: SyntaxTracker can't see the parens around `this` in the line below
checkSyntax(f(x < (this), C > (x)), 'f((x < this), (C > x))');
}
}
main() {
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[#x] = '#x';
checkSyntax(
f(x < x.getter.getter, C > (x)), 'f((x < x.getter.getter), (C > x))');
checkSyntax(f(x < C(), C > (x)), 'f((x < new C()), (C > x))');
checkSyntax(f(x < new C(), C > (x)), 'f((x < new C()), (C > x))');
checkSyntax(f(x < f(), C > (x)), 'f((x < f()), (C > x))');
checkSyntax(f(x < x.method(), C > (x)), 'f((x < x.method()), (C > x))');
checkSyntax(f(x < x[0](), C > (x)), 'f((x < x[0]()), (C > x))');
checkSyntax(f(x < #x, C > (x)), 'f((x < #x), (C > x))');
checkSyntax(f(x < null, C > (x)), 'f((x < null), (C > x))');
checkSyntax(f(x < 0, C > (x)), 'f((x < 0), (C > x))');
checkSyntax(f(x < 0.5, C > (x)), 'f((x < 0.5), (C > x))');
checkSyntax(f(x < [], C > (x)), 'f((x < []), (C > x))');
checkSyntax(f(x < [0], C > (x)), 'f((x < [0]), (C > x))');
checkSyntax(f(x < {}, C > (x)), 'f((x < {}), (C > x))');
checkSyntax(f(x < {0}, C > (x)), 'f((x < {0}), (C > x))');
checkSyntax(f(x < {0: 0}, C > (x)), 'f((x < { 0: 0 }), (C > x))');
checkSyntax(f(x < true, C > (x)), 'f((x < true), (C > x))');
checkSyntax(f(x < "s", C > (x)), 'f((x < "s"), (C > x))');
checkSyntax(f(x < r"s", C > (x)), 'f((x < "s"), (C > x))');
checkSyntax(f(x < x[0], C > (x)), 'f((x < x[0]), (C > x))');
// Note: SyntaxTracker can't see the parens around `x` in the line below
checkSyntax(f(x < (x), C > (x)), 'f((x < x), (C > x))');
checkSyntax(f(x < -x, C > (x)), 'f((x < (-x)), (C > x))');
checkSyntax(f(x < !true, C > (x)), 'f((x < false), (C > x))');
checkSyntax(f(x < !(true), C > (x)), 'f((x < false), (C > x))');
checkSyntax(f(x < ~x, C > (x)), 'f((x < (~x)), (C > x))');
checkSyntax(f(x < x * x, C > (x)), 'f((x < (x * x)), (C > x))');
checkSyntax(f(x < x / x, C > (x)), 'f((x < (x / x)), (C > x))');
checkSyntax(f(x < x ~/ x, C > (x)), 'f((x < (x ~/ x)), (C > x))');
checkSyntax(f(x < x % x, C > (x)), 'f((x < (x % x)), (C > x))');
checkSyntax(f(x < x + x, C > (x)), 'f((x < (x + x)), (C > x))');
checkSyntax(f(x < x - x, C > (x)), 'f((x < (x - x)), (C > x))');
checkSyntax(f(x < x << x, C > (x)), 'f((x < (x << x)), (C > x))');
checkSyntax(f(x < x >> x, C > (x)), 'f((x < (x >> x)), (C > x))');
checkSyntax(f(x < x & x, C > (x)), 'f((x < (x & x)), (C > x))');
checkSyntax(f(x < x ^ x, C > (x)), 'f((x < (x ^ x)), (C > x))');
checkSyntax(f(x < x | x, C > (x)), 'f((x < (x | x)), (C > x))');
ThisTest().test();
}

View file

@ -0,0 +1,83 @@
// 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.
// This test verifies that `f<a,EXPR>(x)` is properly parsed as a pair of
// expressions separated by a `,`, for all types of expressions that may appear
// as EXPR that can't be parsed as types.
import '../syntax_helper.dart';
class C extends SyntaxTracker {
C([Object x = absent, Object y = absent])
: super('new C${SyntaxTracker.args(x, y)}');
C.syntax(String s) : super(s);
Object operator >(Object other) =>
SyntaxTracker('(${syntax(this)} > ${syntax(other)})');
}
class ThisTest extends C {
ThisTest() : super.syntax('this');
void test() {
checkSyntax(f(x < C, this > (x)), 'f((x < C), (this > x))');
// Note: SyntaxTracker can't see the parens around `this` in the line below
checkSyntax(f(x < C, (this) > (x)), 'f((x < C), (this > x))');
}
}
class SuperTest extends C {
SuperTest() : super.syntax('super');
void test() {
checkSyntax(f(x < C, super > (x)), 'f((x < C), (super > x))');
}
}
main() {
const y = 123;
SyntaxTracker.known[C] = 'C';
SyntaxTracker.known[#x] = '#x';
SyntaxTracker.known[y] = 'y';
checkSyntax(
f(x < C, x.getter.getter > (x)), 'f((x < C), (x.getter.getter > x))');
checkSyntax(f(x < C, C() > (x)), 'f((x < C), (new C() > x))');
checkSyntax(f(x < C, new C() > (x)), 'f((x < C), (new C() > x))');
checkSyntax(f(x < C, f() > (x)), 'f((x < C), (f() > x))');
checkSyntax(f(x < C, x.method() > (x)), 'f((x < C), (x.method() > x))');
checkSyntax(f(x < C, x[0]() > (x)), 'f((x < C), (x[0]() > x))');
checkSyntax(f(x < C, #x > (x)), 'f((x < C), (#x > x))');
checkSyntax(f(x < C, null > (x)), 'f((x < C), (null > x))');
checkSyntax(f(x < C, 0 > (y)), 'f((x < C), false)');
checkSyntax(f(x < C, 0.5 > (y)), 'f((x < C), false)');
checkSyntax(f(x < C, [] > (x)), 'f((x < C), ([] > x))');
checkSyntax(f(x < C, [0] > (x)), 'f((x < C), ([0] > x))');
checkSyntax(f(x < C, {} > (x)), 'f((x < C), ({} > x))');
checkSyntax(f(x < C, {0} > (x)), 'f((x < C), ({0} > x))');
checkSyntax(f(x < C, {0: 0} > (x)), 'f((x < C), ({ 0: 0 } > x))');
checkSyntax(f(x < C, true > (x)), 'f((x < C), (true > x))');
checkSyntax(f(x < C, "s" > (x)), 'f((x < C), ("s" > x))');
checkSyntax(f(x < C, r"s" > (x)), 'f((x < C), ("s" > x))');
checkSyntax(f(x < C, x[0] > (x)), 'f((x < C), (x[0] > x))');
// Note: SyntaxTracker can't see the parens around `x` in the line below
checkSyntax(f(x < C, (x) > (x)), 'f((x < C), (x > x))');
checkSyntax(f(x < C, -x > (x)), 'f((x < C), ((-x) > x))');
checkSyntax(f(x < C, !true > (x)), 'f((x < C), (false > x))');
checkSyntax(f(x < C, !(true) > (x)), 'f((x < C), (false > x))');
checkSyntax(f(x < C, ~x > (x)), 'f((x < C), ((~x) > x))');
checkSyntax(f(x < C, x * x > (x)), 'f((x < C), ((x * x) > x))');
checkSyntax(f(x < C, x / x > (x)), 'f((x < C), ((x / x) > x))');
checkSyntax(f(x < C, x ~/ x > (x)), 'f((x < C), ((x ~/ x) > x))');
checkSyntax(f(x < C, x % x > (x)), 'f((x < C), ((x % x) > x))');
checkSyntax(f(x < C, x + x > (x)), 'f((x < C), ((x + x) > x))');
checkSyntax(f(x < C, x - x > (x)), 'f((x < C), ((x - x) > x))');
checkSyntax(f(x < C, x << x > (x)), 'f((x < C), ((x << x) > x))');
checkSyntax(f(x < C, x >> x > (x)), 'f((x < C), ((x >> x) > x))');
checkSyntax(f(x < C, x & x > (x)), 'f((x < C), ((x & x) > x))');
checkSyntax(f(x < C, x ^ x > (x)), 'f((x < C), ((x ^ x) > x))');
checkSyntax(f(x < C, x | x > (x)), 'f((x < C), ((x | x) > x))');
ThisTest().test();
SuperTest().test();
}

View file

@ -51,7 +51,7 @@ class SyntaxTracker {
'(${[x, y].where((v) => v is! Absent).join(', ')})';
static String typeArgs(Type T, Type U) =>
T.toString() == 'dynamic' ? '' : '<${syntax(T)}, ${syntax(U)}>';
T == dynamic && U == dynamic ? '' : '<${syntax(T)}, ${syntax(U)}>';
/// Simple objects with known syntactic representations. Tests can add to
/// this map.