blob: 6844abba0fdbc4bbf24f606147b36d5347863b97 [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);
compiler.diagnosticHandler = createHandler(compiler, source);
return compiler.runCompiler(uri).then((_) {
return compiler;
});
}
test(String source, {var errors, var warnings}) {
if (errors == null) errors = [];
if (errors is! List) errors = [errors];
if (warnings == null) warnings = [];
if (warnings is! List) warnings = [warnings];
asyncTest(() => compile(source).then((compiler) {
Expect.equals(!errors.isEmpty, compiler.compilationFailed);
Expect.equals(errors.length, compiler.errors.length,
'unexpected error count: ${compiler.errors.length} '
'expected ${errors.length}');
Expect.equals(warnings.length, compiler.warnings.length,
'unexpected warning count: ${compiler.warnings.length} '
'expected ${warnings.length}');
for (int i = 0 ; i < errors.length ; i++) {
Expect.equals(errors[i], compiler.errors[i].message.kind);
}
for (int i = 0 ; i < warnings.length ; i++) {
Expect.equals(warnings[i], compiler.warnings[i].message.kind);
}
}));
}
test1() {
asyncTest(() => compile(r"""
class A<T extends T> {}
void main() {
new A();
}
""").then((compiler) {
Expect.isFalse(compiler.compilationFailed);
Expect.isTrue(compiler.errors.isEmpty,
'unexpected errors: ${compiler.errors}');
Expect.equals(1, compiler.warnings.length,
'expected exactly one warning, but got ${compiler.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[0].message.kind);
Expect.equals("T", compiler.warnings[0].node.toString());
}));
}
test2() {
asyncTest(() => compile(r"""
class B<T extends S, S extends T> {}
void main() {
new B();
}
""").then((compiler) {
Expect.isFalse(compiler.compilationFailed);
print(compiler.errors);
Expect.isTrue(compiler.errors.isEmpty, 'unexpected errors');
Expect.equals(2, compiler.warnings.length,
'expected exactly one error, but got ${compiler.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[0].message.kind);
Expect.equals("T", compiler.warnings[0].node.toString());
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[1].message.kind);
Expect.equals("S", compiler.warnings[1].node.toString());
}));
}
test3() {
asyncTest(() => compile(r"""
class C<T extends S, S extends U, U extends T> {}
void main() {
new C();
}
""").then((compiler) {
Expect.isFalse(compiler.compilationFailed);
print(compiler.errors);
Expect.isTrue(compiler.errors.isEmpty, 'unexpected errors');
Expect.equals(3, compiler.warnings.length,
'expected exactly one error, but got ${compiler.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[0].message.kind);
Expect.equals("T", compiler.warnings[0].node.toString());
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[1].message.kind);
Expect.equals("S", compiler.warnings[1].node.toString());
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[2].message.kind);
Expect.equals("U", compiler.warnings[2].node.toString());
}));
}
test4() {
asyncTest(() => compile(r"""
class D<T extends S, S extends U, U extends S> {}
void main() {
new D();
}
""").then((compiler) {
Expect.isFalse(compiler.compilationFailed);
print(compiler.errors);
Expect.isTrue(compiler.errors.isEmpty, 'unexpected errors');
Expect.equals(2, compiler.warnings.length,
'expected exactly one error, but got ${compiler.warnings}');
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[0].message.kind);
Expect.equals("S", compiler.warnings[0].node.toString());
Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
compiler.warnings[1].message.kind);
Expect.equals("U", compiler.warnings[1].node.toString());
}));
}
test5() {
test(r"""
class A<T extends num> {}
void main() {
new A();
new A<num>();
new A<dynamic>();
new A<int>();
new A<double>();
}
""");
}
test6() {
test(r"""
class A<T extends num> {}
void main() {
new A<String>();
}
""", warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
}
test7() {
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);
}
test8() {
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();
}
""");
}
test9() {
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]);
}
main() {
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
}