blob: ed2d150c631e44973e78a8a4cd22c0616069f230 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import "package:async_helper/async_helper.dart";
import 'compiler_helper.dart';
import "package:expect/expect.dart";
Future compile(String source) {
Uri uri = Uri.parse('test:code');
var compiler =
compilerFor(source, uri, analyzeOnly: true, enableTypeAssertions: true);
compiler.diagnosticHandler = createHandler(compiler, source);
return compiler.run(uri).then((_) {
return compiler;
});
}
Future test(String source, {var errors, var warnings}) async {
if (errors == null) errors = [];
if (errors is! List) errors = [errors];
if (warnings == null) warnings = [];
if (warnings is! List) warnings = [warnings];
var compiler = await compile(source);
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.equals(!errors.isEmpty, compiler.compilationFailed);
Expect.equals(
errors.length,
collector.errors.length,
'unexpected error count: ${collector.errors.length} '
'expected ${errors.length}');
Expect.equals(
warnings.length,
collector.warnings.length,
'unexpected warning count: ${collector.warnings.length} '
'expected ${warnings.length}');
for (int i = 0; i < errors.length; i++) {
Expect.equals(errors[i], collector.errors.elementAt(i).message.kind);
}
for (int i = 0; i < warnings.length; i++) {
Expect.equals(warnings[i], collector.warnings.elementAt(i).message.kind);
}
}
Future test1() async {
var compiler = await compile(r"""
class A<T extends T> {}
void main() {
new A();
}
""");
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isFalse(compiler.compilationFailed);
Expect.isTrue(
collector.errors.isEmpty, 'unexpected errors: ${collector.errors}');
Expect.equals(1, collector.warnings.length,
'expected exactly one warning, but got ${collector.warnings}');
print(collector.warnings.elementAt(0));
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(0).message.kind);
Expect.equals("T",
collector.warnings.elementAt(0).message.arguments['typeVariableName']);
}
Future test2() async {
var compiler = await compile(r"""
class B<T extends S, S extends T> {}
void main() {
new B();
}
""");
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isFalse(compiler.compilationFailed);
print(collector.errors);
Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
Expect.equals(2, collector.warnings.length,
'expected exactly two errors, but got ${collector.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(0).message.kind);
Expect.equals("T",
collector.warnings.elementAt(0).message.arguments['typeVariableName']);
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(1).message.kind);
Expect.equals("S",
collector.warnings.elementAt(1).message.arguments['typeVariableName']);
}
Future test3() async {
var compiler = await compile(r"""
class C<T extends S, S extends U, U extends T> {}
void main() {
new C();
}
""");
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isFalse(compiler.compilationFailed);
print(collector.errors);
Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
Expect.equals(3, collector.warnings.length,
'expected exactly one error, but got ${collector.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(0).message.kind);
Expect.equals("T",
collector.warnings.elementAt(0).message.arguments['typeVariableName']);
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(1).message.kind);
Expect.equals("S",
collector.warnings.elementAt(1).message.arguments['typeVariableName']);
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(2).message.kind);
Expect.equals("U",
collector.warnings.elementAt(2).message.arguments['typeVariableName']);
}
Future test4() async {
var compiler = await compile(r"""
class D<T extends S, S extends U, U extends S> {}
void main() {
new D();
}
""");
DiagnosticCollector collector = compiler.diagnosticCollector;
Expect.isFalse(compiler.compilationFailed);
print(collector.errors);
Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
Expect.equals(2, collector.warnings.length,
'expected exactly one error, but got ${collector.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(0).message.kind);
Expect.equals("S",
collector.warnings.elementAt(0).message.arguments['typeVariableName']);
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
collector.warnings.elementAt(1).message.kind);
Expect.equals("U",
collector.warnings.elementAt(1).message.arguments['typeVariableName']);
}
Future test5() {
return test(r"""
class A<T extends num> {}
void main() {
new A();
new A<num>();
new A<dynamic>();
new A<int>();
new A<double>();
}
""");
}
Future test6() {
return test(
r"""
class A<T extends num> {}
void main() {
new A<String>();
}
""",
warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
}
Future test7() {
return test(
r"""
class A<T extends num> {}
class B<T> extends A<T> {} // Warning produced here.
void main() {
new B(); // No warning produced here.
new B<String>(); // No warning produced here.
}
""",
warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
}
Future test8() {
return test(r"""
class B<T extends B<T>> {}
class C<T extends B<T>> extends B<T> {}
class D<T extends C<T>> extends C<T> {}
class E<T extends E<T>> extends D<T> {}
class F extends E<F> {}
void main() {
new B();
new B<dynamic>();
new B<F>();
new B<B<F>>();
new C();
new C<dynamic>();
new C<B<F>>();
new D();
new D<dynamic>();
new D<C<F>>();
new E();
new E<dynamic>();
new E<E<F>>();
new F();
}
""");
}
Future test9() {
return test(
r"""
class B<T extends B<T>> {}
class C<T extends B<T>> extends B<T> {}
class D<T extends C<T>> extends C<T> {}
class E<T extends E<T>> extends D<T> {}
class F extends E<F> {}
void main() {
new D<B<F>>(); // Warning: B<F> is not a subtype of C<T>.
new E<D<F>>(); // Warning: E<F> is not a subtype of E<T>.
}
""",
warnings: [
MessageKind.INVALID_TYPE_VARIABLE_BOUND,
MessageKind.INVALID_TYPE_VARIABLE_BOUND
]);
}
Future test10() {
return test(r"""
class A {
const A();
}
class Test<T extends A> {
final T x = const A();
const Test();
}
main() {
print(const Test<A>());
}
""");
}
// TODO(het): The error is reported twice because both the Dart and JS constant
// compilers are run on the const constructor, investigate why.
Future test11() {
return test(
r"""
class A {
const A();
}
class B extends A {
const B();
}
class Test<T extends A> {
final T x = const A();
const Test();
}
main() {
print(const Test<B>());
}
""",
errors: [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
}
main() {
asyncTest(() async {
await test1();
await test2();
await test3();
await test4();
await test5();
await test6();
await test7();
await test8();
await test9();
await test10();
await test11();
});
}