mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 14:43:32 +00:00
Implement 'covariant' modifier for dart2js.
Also adds some tests. Fixes #28165 BUG= http://dartbug.com/28165 R=sigmund@google.com Review-Url: https://codereview.chromium.org/2626843003 .
This commit is contained in:
parent
e5a45ffb5c
commit
71ec2f0297
|
@ -426,6 +426,15 @@ class Parser {
|
|||
Token parseFormalParameter(Token token, FormalParameterType type) {
|
||||
token = parseMetadataStar(token, forParameter: true);
|
||||
listener.beginFormalParameter(token);
|
||||
|
||||
// Skip over `covariant` token, if the next token is an identifier or
|
||||
// modifier.
|
||||
// This enables the case where `covariant` is the name of the parameter:
|
||||
// void foo(covariant);
|
||||
if (identical(token.stringValue, 'covariant') &&
|
||||
token.next.isIdentifier() || isModifier(token.next)) {
|
||||
token = token.next;
|
||||
}
|
||||
token = parseModifiers(token);
|
||||
// TODO(ahe): Validate that there are formal parameters if void.
|
||||
token = parseReturnTypeOpt(token);
|
||||
|
@ -988,9 +997,29 @@ class Parser {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Removes the optional `covariant` token from the modifiers, if there
|
||||
/// is no `static` in the list, and `covariant` is the first modifier.
|
||||
Link<Token> removeOptCovariantTokenIfNotStatic(Link<Token> modifiers) {
|
||||
if (modifiers.isEmpty ||
|
||||
!identical(modifiers.first.stringValue, 'covariant')) {
|
||||
return modifiers;
|
||||
}
|
||||
for (Token modifier in modifiers.tail) {
|
||||
if (identical(modifier.stringValue, 'static')) {
|
||||
return modifiers;
|
||||
}
|
||||
}
|
||||
return modifiers.tail;
|
||||
}
|
||||
|
||||
Token parseFields(Token start, Link<Token> modifiers, Token type,
|
||||
Token getOrSet, Token name, bool isTopLevel) {
|
||||
bool hasType = type != null;
|
||||
|
||||
if (getOrSet == null && !isTopLevel) {
|
||||
modifiers = removeOptCovariantTokenIfNotStatic(modifiers);
|
||||
}
|
||||
|
||||
Token varFinalOrConst =
|
||||
expectVarFinalOrConst(modifiers, hasType, !isTopLevel);
|
||||
bool isVar = false;
|
||||
|
|
|
@ -53,6 +53,7 @@ class Keyword {
|
|||
|
||||
const Keyword("abstract", isBuiltIn: true),
|
||||
const Keyword("as", info: Precedence.AS_INFO, isBuiltIn: true),
|
||||
const Keyword("covariant", isBuiltIn: true),
|
||||
const Keyword("dynamic", isBuiltIn: true),
|
||||
const Keyword("export", isBuiltIn: true),
|
||||
const Keyword("external", isBuiltIn: true),
|
||||
|
@ -77,7 +78,7 @@ class Keyword {
|
|||
const Keyword("async", isPseudo: true),
|
||||
const Keyword("sync", isPseudo: true),
|
||||
const Keyword("await", isPseudo: true),
|
||||
const Keyword("yield", isPseudo: true)
|
||||
const Keyword("yield", isPseudo: true),
|
||||
];
|
||||
|
||||
final String syntax;
|
||||
|
|
92
tests/language/covariant_override_test.dart
Normal file
92
tests/language/covariant_override_test.dart
Normal file
|
@ -0,0 +1,92 @@
|
|||
|
||||
// Copyright (c) 2017, 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 covariant_override_test;
|
||||
|
||||
// This test contains cases where `covariant` is used as intended.
|
||||
|
||||
abstract class A {
|
||||
A(this.f1, this.f2, this.f3);
|
||||
|
||||
// Normal usage, "by design": superclass requests covariance.
|
||||
void m1(covariant Object o);
|
||||
|
||||
// Normal usage, "ad hoc": subclass requests covariance.
|
||||
void m2(Object o);
|
||||
|
||||
// Syntactic special case: omit the type in subclass.
|
||||
void m3(Object o);
|
||||
|
||||
// Positional optional arguments.
|
||||
void m4([covariant Object o]);
|
||||
void m5([Object o]);
|
||||
void m6([Object o]);
|
||||
|
||||
// Named arguments.
|
||||
void m7({covariant Object arg});
|
||||
void m8({Object arg});
|
||||
void m9({Object arg});
|
||||
|
||||
// Normal usage on field, "by design": superclass requests covariance.
|
||||
covariant Object f1;
|
||||
|
||||
// Normal usage on field, "ad hoc": subclass requests covariance.
|
||||
Object f2;
|
||||
|
||||
// Syntactic special case.
|
||||
Object f3;
|
||||
}
|
||||
|
||||
abstract class B extends A {
|
||||
B(num f1, num f2, num f3): super(f1, f2, f3);
|
||||
|
||||
void m1(num n);
|
||||
void m2(covariant num n);
|
||||
void m3(covariant n);
|
||||
void m4([num n]);
|
||||
void m5([covariant num n]);
|
||||
void m6([covariant n]);
|
||||
void m7({num arg});
|
||||
void m8({covariant num arg});
|
||||
void m9({covariant arg});
|
||||
void set f1(num n);
|
||||
void set f2(covariant num n);
|
||||
void set f3(covariant n);
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
C(int f1, int f2, int f3): super(f1, f2, f3);
|
||||
|
||||
void m1(int i) {}
|
||||
void m2(int i) {}
|
||||
void m3(int i) {}
|
||||
void m4([int i]) {}
|
||||
void m5([int i]) {}
|
||||
void m6([int i]) {}
|
||||
void m7({int arg}) {}
|
||||
void m8({int arg}) {}
|
||||
void m9({int arg}) {}
|
||||
void set f1(int i) {}
|
||||
void set f2(int i) {}
|
||||
void set f3(int i) {}
|
||||
}
|
||||
|
||||
main() {
|
||||
// For Dart 1.x, `covariant` has no runtime semantics; we just ensure
|
||||
// that the code is not unused, such that we know it will be parsed.
|
||||
A a = new C(39, 40, 41);
|
||||
a.m1(42);
|
||||
a.m2(42);
|
||||
a.m3(42);
|
||||
a.m4(42);
|
||||
a.m5(42);
|
||||
a.m6(42);
|
||||
a.m7(arg: 42);
|
||||
a.m8(arg: 42);
|
||||
a.m9(arg: 42);
|
||||
a.f1 = 42;
|
||||
a.f2 = 42;
|
||||
a.f3 = 42;
|
||||
}
|
378
tests/language/covariant_test.dart
Normal file
378
tests/language/covariant_test.dart
Normal file
|
@ -0,0 +1,378 @@
|
|||
// Copyright (c) 2017, 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.
|
||||
|
||||
// Test that `covariant` can be parsed (and ignored) by
|
||||
// dart2js and the VM.
|
||||
// This test only checks for non-strong mode behavior.
|
||||
//
|
||||
// Generally, `covariant` should be ignored, when it is used in the right
|
||||
// places.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
// Top level field may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
covariant /// 00: compile-time error
|
||||
int x0;
|
||||
|
||||
// Getters may never have `covariant`. (Neither on the top-level nor as members)
|
||||
covariant /// 01: compile-time error
|
||||
int get x1 => 499;
|
||||
|
||||
// Top level setters may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
void set x2(
|
||||
covariant /// 02: compile-time error
|
||||
int val) {}
|
||||
|
||||
// Same as above, but with `covariant` in different positions.
|
||||
// The `covariant` is just wrong there.
|
||||
|
||||
int
|
||||
covariant /// 03: compile-time error
|
||||
x3;
|
||||
|
||||
int
|
||||
covariant /// 04: compile-time error
|
||||
get x4 => 499;
|
||||
|
||||
void set x5(
|
||||
int
|
||||
covariant /// 05: compile-time error
|
||||
val) {}
|
||||
|
||||
|
||||
// Same without types.
|
||||
|
||||
// Since `covariant` is a built-in identifier, it is not allowed here.
|
||||
covariant x6; /// 06: compile-time error
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
covariant /// 07: compile-time error
|
||||
get x7 => 499;
|
||||
|
||||
// Top level setters may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
void set x8(
|
||||
covariant /// 08: compile-time error
|
||||
val) {}
|
||||
|
||||
// If there is no type, then `covariant` is simply the parameter name:
|
||||
void set x9(covariant) {}
|
||||
|
||||
// Covariant won't work on return types.
|
||||
covariant /// 10: compile-time error
|
||||
int f10() => 499;
|
||||
|
||||
// Covariant won't work as a return type.
|
||||
covariant /// 11: compile-time error
|
||||
f11() => 499;
|
||||
|
||||
// Covariant should not work on top-level methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
int f12(
|
||||
covariant /// 12: compile-time error
|
||||
int x) => 499;
|
||||
|
||||
// `Covariant` must be in front of the types.
|
||||
int f13(
|
||||
int
|
||||
covariant /// 13: compile-time error
|
||||
x) => 499;
|
||||
|
||||
// Covariant should not work on top-level methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
int f14(
|
||||
covariant /// 14: compile-time error
|
||||
final
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
int f15(
|
||||
final
|
||||
covariant /// 15: compile-time error
|
||||
x) => 499;
|
||||
|
||||
// Covariant should not work on top-level methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
int f16(
|
||||
covariant /// 16: compile-time error
|
||||
final
|
||||
int
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
int f17(
|
||||
final
|
||||
covariant /// 17: compile-time error
|
||||
int
|
||||
x) => 499;
|
||||
|
||||
// On its own, `covariant` is just a parameter name.
|
||||
int f18(covariant) => covariant;
|
||||
|
||||
// All of the above as statics in a class.
|
||||
class A {
|
||||
// Static fields may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
static
|
||||
covariant /// 20: compile-time error
|
||||
int x20;
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
static
|
||||
covariant /// 21: compile-time error
|
||||
int get x21 => 499;
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
covariant /// 21b: compile-time error
|
||||
static
|
||||
int get x21b => 499;
|
||||
|
||||
// Static setters may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
static void set x22(
|
||||
covariant /// 22: compile-time error
|
||||
int val) {}
|
||||
|
||||
// Same as above, but with `covariant` in different positions.
|
||||
// The `covariant` is just wrong there.
|
||||
|
||||
static int
|
||||
covariant /// 23: compile-time error
|
||||
x23;
|
||||
|
||||
static int
|
||||
covariant /// 24: compile-time error
|
||||
get x24 => 499;
|
||||
|
||||
static void set x25(
|
||||
int
|
||||
covariant /// 25: compile-time error
|
||||
val) {}
|
||||
|
||||
// Since `covariant` is a built-in identifier, it is not allowed here.
|
||||
static covariant x26; /// 26: compile-time error
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
static
|
||||
covariant /// 27: compile-time error
|
||||
get x27 => 499;
|
||||
|
||||
covariant /// 27b: compile-time error
|
||||
static
|
||||
get x27b => 499;
|
||||
|
||||
// Static setters may not have a covariant.
|
||||
// Would be considered a minor (acceptable) bug, if it was accepted here too.
|
||||
static void set x28(
|
||||
covariant /// 28: compile-time error
|
||||
val) {}
|
||||
|
||||
// If there is no type, then `covariant` is simply the parameter name:
|
||||
static void set x29(covariant) {}
|
||||
|
||||
// Covariant won't work on return types.
|
||||
static
|
||||
covariant /// 30: compile-time error
|
||||
int f30() => 499;
|
||||
|
||||
covariant /// 30b: compile-time error
|
||||
static
|
||||
int f30b() => 499;
|
||||
|
||||
// Covariant won't work as a return type.
|
||||
static
|
||||
covariant /// 31: compile-time error
|
||||
f31() => 499;
|
||||
|
||||
covariant /// 31b: compile-time error
|
||||
static
|
||||
f31b() => 499;
|
||||
|
||||
// Covariant should not work on static methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
static int f32(
|
||||
covariant /// 32: compile-time error
|
||||
int x) => 499;
|
||||
|
||||
// `Covariant` must be in front of the types.
|
||||
static int f33(
|
||||
int
|
||||
covariant /// 33: compile-time error
|
||||
x) => 499;
|
||||
|
||||
// Covariant should not work on top-level methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
static int f34(
|
||||
covariant /// 34: compile-time error
|
||||
final
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
static int f35(
|
||||
final
|
||||
covariant /// 35: compile-time error
|
||||
x) => 499;
|
||||
|
||||
// Covariant should not work on top-level methods.
|
||||
// It's a minor (acceptable) bug to not error out here.
|
||||
static int f36(
|
||||
covariant /// 36: compile-time error
|
||||
final
|
||||
int
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
static int f37(
|
||||
final
|
||||
covariant /// 37: compile-time error
|
||||
int
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` on its own is just a parameter name.
|
||||
static int f38(covariant) => covariant;
|
||||
}
|
||||
|
||||
// All of the above as instance members in a class.
|
||||
class B {
|
||||
covariant int x40;
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
covariant /// 41: compile-time error
|
||||
int get x41 => 499;
|
||||
|
||||
void set x42(covariant int val) {}
|
||||
|
||||
// `covariant` in the wrong position.
|
||||
int
|
||||
covariant /// 43: compile-time error
|
||||
x43;
|
||||
|
||||
// `covariant` in the wrong position.
|
||||
int
|
||||
covariant /// 44: compile-time error
|
||||
get x44 => 499;
|
||||
|
||||
void set x45(
|
||||
int
|
||||
covariant /// 45: compile-time error
|
||||
val) {}
|
||||
|
||||
// Since `covariant` is a built-in identifier, it is not allowed here.
|
||||
covariant x46; /// 46: compile-time error
|
||||
|
||||
// Getters may never have `covariant`.
|
||||
covariant /// 47: compile-time error
|
||||
get x47 => 499;
|
||||
|
||||
void set x48(covariant val) {}
|
||||
|
||||
// If there is no type, then `covariant` is simply the parameter name:
|
||||
void set x49(covariant) {}
|
||||
|
||||
// Covariant won't work on return types.
|
||||
covariant /// 50: compile-time error
|
||||
int f50() => 499;
|
||||
|
||||
// Covariant won't work as a return type.
|
||||
covariant /// 51: compile-time error
|
||||
f51() => 499;
|
||||
|
||||
int f52(covariant int x) => 499;
|
||||
|
||||
// `Covariant` must be in front of the types.
|
||||
int f53(
|
||||
int
|
||||
covariant /// 53: compile-time error
|
||||
x) => 499;
|
||||
|
||||
int f54(covariant final x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
int f55(
|
||||
final
|
||||
covariant /// 55: compile-time error
|
||||
x) => 499;
|
||||
|
||||
int f56(covariant final int x) => 499;
|
||||
|
||||
// `Covariant` must be in front of modifiers.
|
||||
int f57(
|
||||
final
|
||||
covariant /// 57: compile-time error
|
||||
int
|
||||
x) => 499;
|
||||
|
||||
// `Covariant` on its own is just a parameter name.
|
||||
int f58(covariant) => covariant;
|
||||
}
|
||||
|
||||
void use(x) {}
|
||||
|
||||
main() {
|
||||
x0 = 0;
|
||||
use(x1);
|
||||
x2 = 499;
|
||||
use(x3);
|
||||
use(x4);
|
||||
x5 = 42;
|
||||
x6 = 0; /// 06: continued
|
||||
use(x7);
|
||||
x8 = 11;
|
||||
x9 = 12;
|
||||
use(f10());
|
||||
use(f11());
|
||||
use(f12(2));
|
||||
use(f13(3));
|
||||
use(f14(3));
|
||||
use(f15(3));
|
||||
use(f16(3));
|
||||
use(f17(3));
|
||||
Expect.equals(123, f18(123));
|
||||
|
||||
A.x20 = 0;
|
||||
use(A.x21);
|
||||
use(A.x21b);
|
||||
A.x22 = 499;
|
||||
use(A.x23);
|
||||
use(A.x24);
|
||||
A.x25 = 42;
|
||||
A.x26 = 0; /// 26: continued
|
||||
use(A.x27);
|
||||
use(A.x27b);
|
||||
A.x28 = 11;
|
||||
A.x29 = 12;
|
||||
use(A.f30());
|
||||
use(A.f31());
|
||||
use(A.f31b());
|
||||
use(A.f32(2));
|
||||
use(A.f33(3));
|
||||
use(A.f34(3));
|
||||
use(A.f35(3));
|
||||
use(A.f36(3));
|
||||
use(A.f37(3));
|
||||
Expect.equals(1234, A.f38(1234));
|
||||
|
||||
var b = new B();
|
||||
b.x40 = 0;
|
||||
use(b.x41);
|
||||
b.x42 = 499;
|
||||
use(b.x43);
|
||||
use(b.x44);
|
||||
b.x45 = 42;
|
||||
b.x46 = 0; /// 46: continued
|
||||
use(b.x47);
|
||||
b.x48 = 11;
|
||||
b.x49 = 12;
|
||||
use(b.f50());
|
||||
use(b.f51());
|
||||
use(b.f52(2));
|
||||
use(b.f53(2));
|
||||
use(b.f54(3));
|
||||
use(b.f55(3));
|
||||
use(b.f56(3));
|
||||
use(b.f57(3));
|
||||
Expect.equals(12345, b.f58(12345));
|
||||
}
|
|
@ -51,6 +51,10 @@ async_star_cancel_while_paused_test: RuntimeError
|
|||
# Fails because `as T` is an error rather than being treated like `as dynamic`.
|
||||
generic_methods_type_expression_test: RuntimeError # Issue 27460
|
||||
|
||||
# Doesn't yet implement `covariant` keyword.
|
||||
covariant_test/none: CompileTimeError # Issue 28166
|
||||
covariant_override_test: CompileTimeError # Issue 28166
|
||||
|
||||
[ ($compiler == none || $compiler == precompiler || $compiler == app_jit) && $checked ]
|
||||
# These generic functions tests pass for the wrong reason in checked mode,
|
||||
# because the parsed type parameters are mapped to dynamic type.
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
regress_26668_test: Fail # Issue 26678
|
||||
regress_27617_test/1: MissingCompileTimeError
|
||||
|
||||
# Doesn't yet implement `covariant` keyword.
|
||||
covariant_test/none: CompileTimeError # Issue 28167
|
||||
covariant_override_test: CompileTimeError # Issue 28167
|
||||
|
||||
# Runtime negative test. No static errors or warnings.
|
||||
closure_call_wrong_argument_count_negative_test: skip
|
||||
|
||||
|
|
|
@ -39,6 +39,17 @@ duplicate_part_test/01: MissingCompileTimeError # Issue 27517
|
|||
|
||||
bad_typedef_test/00: Crash # Issue 28214
|
||||
|
||||
covariant_test/02: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/08: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/12: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/14: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/16: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/22: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/28: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/32: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/34: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
covariant_test/36: MissingCompileTimeError, OK # Accepts `covariant` for statics/top-level.
|
||||
|
||||
[ $compiler == dart2js && $fast_startup ]
|
||||
const_evaluation_test/*: Fail # mirrors not supported
|
||||
deferred_constraints_constants_test/none: Fail # mirrors not supported
|
||||
|
|
|
@ -89,6 +89,8 @@ vm/debug_break_enabled_vm_test/none: DartkCompileTimeError
|
|||
vm/reflect_core_vm_test: DartkCompileTimeError
|
||||
vm/regress_27201_test: DartkCompileTimeError
|
||||
vm/regress_28325_test: RuntimeError # Issue 28055.
|
||||
covariant_test/none: CompileTimeError # Issue 28166
|
||||
covariant_override_test: Crash # Issue 28166
|
||||
|
||||
# dartk: JIT failures
|
||||
[ $compiler == dartk && $runtime == vm ]
|
||||
|
|
Loading…
Reference in a new issue