| Index: pkg/analyzer/test/generated/strong_mode_test.dart
|
| diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
|
| index 893875624e32907fc8bf2b344cb1e8d82e467c3c..8eca7f8b8e8c1f8a363a15b59a92d03434533fc7 100644
|
| --- a/pkg/analyzer/test/generated/strong_mode_test.dart
|
| +++ b/pkg/analyzer/test/generated/strong_mode_test.dart
|
| @@ -14,6 +14,7 @@ import 'package:analyzer/src/dart/element/element.dart';
|
| import 'package:analyzer/src/error/codes.dart';
|
| import 'package:analyzer/src/generated/engine.dart';
|
| import 'package:analyzer/src/generated/source_io.dart';
|
| +import 'package:analyzer/src/task/strong/ast_properties.dart';
|
| import 'package:front_end/src/base/errors.dart';
|
| import 'package:test/test.dart';
|
| import 'package:test_reflective_loader/test_reflective_loader.dart';
|
| @@ -420,6 +421,300 @@ class StrongModeLocalInferenceTest extends ResolverTestCase {
|
| _isListOf(_isString)(exp.staticType);
|
| }
|
|
|
| + test_covarianceChecks() async {
|
| + var source = addSource(r'''
|
| +class C<T> {
|
| + add(T t) {}
|
| + forEach(void f(T t)) {}
|
| +}
|
| +class D extends C<int> {
|
| + add(int t) {}
|
| + forEach(void f(int t)) {}
|
| +}
|
| +class E extends C<int> {
|
| + add(Object t) {}
|
| + forEach(void f(Null t)) {}
|
| +}
|
| +''');
|
| + var unit = (await computeAnalysisResult(source)).unit;
|
| + assertNoErrors(source);
|
| + var cAdd = AstFinder.getMethodInClass(unit, "C", "add");
|
| + var covariantC = getClassCovariantParameters(AstFinder.getClass(unit, "C"));
|
| + expect(covariantC.toList(), [cAdd.element.parameters[0]]);
|
| +
|
| + var dAdd = AstFinder.getMethodInClass(unit, "D", "add");
|
| + var covariantD = getClassCovariantParameters(AstFinder.getClass(unit, "D"));
|
| + expect(covariantD.toList(), [dAdd.element.parameters[0]]);
|
| +
|
| + var covariantE = getClassCovariantParameters(AstFinder.getClass(unit, "E"));
|
| + expect(covariantE.toList(), []);
|
| + }
|
| +
|
| + test_covarianceChecks_genericMethods() async {
|
| + var source = addSource(r'''
|
| +class C<T> {
|
| + add<S>(T t) {}
|
| + forEach<S>(S f(T t)) {}
|
| +}
|
| +class D extends C<int> {
|
| + add<S>(int t) {}
|
| + forEach<S>(S f(int t)) {}
|
| +}
|
| +class E extends C<int> {
|
| + add<S>(Object t) {}
|
| + forEach<S>(S f(Null t)) {}
|
| +}
|
| +''');
|
| + var unit = (await computeAnalysisResult(source)).unit;
|
| + assertNoErrors(source);
|
| +
|
| + var cAdd = AstFinder.getMethodInClass(unit, "C", "add");
|
| + var covariantC = getClassCovariantParameters(AstFinder.getClass(unit, "C"));
|
| + expect(covariantC.toList(), [cAdd.element.parameters[0]]);
|
| +
|
| + var dAdd = AstFinder.getMethodInClass(unit, "D", "add");
|
| + var covariantD = getClassCovariantParameters(AstFinder.getClass(unit, "D"));
|
| + expect(covariantD.toList(), [dAdd.element.parameters[0]]);
|
| +
|
| + var covariantE = getClassCovariantParameters(AstFinder.getClass(unit, "E"));
|
| + expect(covariantE.toList(), []);
|
| + }
|
| +
|
| + test_covarianceChecks_superclass() async {
|
| + var source = addSource(r'''
|
| +class C<T> {
|
| + add(T t) {}
|
| + forEach(void f(T t)) {}
|
| +}
|
| +class D {
|
| + add(int t) {}
|
| + forEach(void f(int t)) {}
|
| +}
|
| +class E extends D implements C<int> {}
|
| +''');
|
| + var unit = (await computeAnalysisResult(source)).unit;
|
| + assertNoErrors(source);
|
| + var cAdd = AstFinder.getMethodInClass(unit, "C", "add");
|
| + var covariantC = getClassCovariantParameters(AstFinder.getClass(unit, "C"));
|
| + expect(covariantC.toList(), [cAdd.element.parameters[0]]);
|
| +
|
| + var dAdd = AstFinder.getMethodInClass(unit, "D", "add");
|
| + var covariantD = getClassCovariantParameters(AstFinder.getClass(unit, "D"));
|
| + expect(covariantD, null);
|
| +
|
| + var classE = AstFinder.getClass(unit, "E");
|
| + var covariantE = getClassCovariantParameters(classE);
|
| + var superCovariantE = getSuperclassCovariantParameters(classE);
|
| + expect(covariantE.toList(), []);
|
| + expect(superCovariantE.toList(), [dAdd.element.parameters[0]]);
|
| + }
|
| +
|
| + @soloTest
|
| + test_covarianceChecks_returnFunction() async {
|
| + var source = addSource(r'''
|
| +typedef F<T>(T t);
|
| +typedef T R<T>();
|
| +class C<T> {
|
| + F<T> f;
|
| +
|
| + C();
|
| + factory C.fact() => new C<Null>();
|
| +
|
| + F<T> get g => null;
|
| + F<T> m1() => null;
|
| + R<F<T>> m2() => null;
|
| +
|
| + casts(C<T> other, T t) {
|
| + other.f;
|
| + other.g(t);
|
| + other.m1();
|
| + other.m2;
|
| +
|
| + new C<T>.fact().f(t);
|
| + new C<int>.fact().g;
|
| + new C<int>.fact().m1;
|
| + new C<T>.fact().m2();
|
| +
|
| + new C<Object>.fact().f(42);
|
| + new C<Object>.fact().g;
|
| + new C<Object>.fact().m1;
|
| + new C<Object>.fact().m2();
|
| + }
|
| +
|
| + noCasts(T t) {
|
| + f;
|
| + g;
|
| + m1();
|
| + m2();
|
| +
|
| + f(t);
|
| + g(t);
|
| + (f)(t);
|
| + (g)(t);
|
| + m1;
|
| + m2;
|
| +
|
| + this.f;
|
| + this.g;
|
| + this.m1();
|
| + this.m2();
|
| + this.m1;
|
| + this.m2;
|
| + (this.m1)();
|
| + (this.m2)();
|
| + this.f(t);
|
| + this.g(t);
|
| + (this.f)(t);
|
| + (this.g)(t);
|
| +
|
| + new C<int>().f;
|
| + new C<T>().g;
|
| + new C<int>().m1();
|
| + new C().m2();
|
| +
|
| + new D().f;
|
| + new D().g;
|
| + new D().m1();
|
| + new D().m2();
|
| +
|
| + // fuzzy arrows are currently checked at the call, they skip this cast.
|
| + new C.fact().f(42);
|
| + new C.fact().g;
|
| + new C.fact().m1;
|
| + new C.fact().m2();
|
| + }
|
| +}
|
| +class D extends C<num> {
|
| + noCasts(t) {
|
| + f;
|
| + this.g;
|
| + this.m1();
|
| + m2;
|
| +
|
| + super.f;
|
| + super.g;
|
| + super.m1;
|
| + super.m2();
|
| + }
|
| +}
|
| +
|
| +D d;
|
| +C<Object> c;
|
| +C cD;
|
| +C<Null> cN;
|
| +F<Object> f;
|
| +F<Null> fN;
|
| +R<F<Object>> rf;
|
| +R<F<Null>> rfN;
|
| +R<R<F<Object>>> rrf;
|
| +R<R<F<Null>>> rrfN;
|
| +Object obj;
|
| +F<int> fi;
|
| +R<F<int>> rfi;
|
| +R<R<F<int>>> rrfi;
|
| +
|
| +casts() {
|
| + c.f;
|
| + c.g;
|
| + c.m1;
|
| + c.m1();
|
| + c.m2();
|
| +
|
| + fN = c.f;
|
| + fN = c.g;
|
| + rfN = c.m1;
|
| + rrfN = c.m2;
|
| + fN = c.m1();
|
| + rfN = c.m2();
|
| +
|
| + f = c.f;
|
| + f = c.g;
|
| + rf = c.m1;
|
| + rrf = c.m2;
|
| + f = c.m1();
|
| + rf = c.m2();
|
| + c.m2()();
|
| +
|
| + c.f(obj);
|
| + c.g(obj);
|
| + (c.f)(obj);
|
| + (c.g)(obj);
|
| + (c.m1)();
|
| + c.m1()(obj);
|
| + (c.m2)();
|
| +}
|
| +
|
| +noCasts() {
|
| + fi = d.f;
|
| + fi = d.g;
|
| + rfi = d.m1;
|
| + fi = d.m1();
|
| + rrfi = d.m2;
|
| + rfi = d.m2();
|
| + d.f(42);
|
| + d.g(42);
|
| + (d.f)(42);
|
| + (d.g)(42);
|
| + d.m1()(42);
|
| + d.m2()()(42);
|
| +
|
| + cN.f;
|
| + cN.g;
|
| + cN.m1;
|
| + cN.m1();
|
| + cN.m2();
|
| +
|
| + // fuzzy arrows are currently checked at the call, they skip this cast.
|
| + cD.f;
|
| + cD.g;
|
| + cD.m1;
|
| + cD.m1();
|
| + cD.m2();
|
| +}
|
| +''');
|
| + var unit = (await computeAnalysisResult(source)).unit;
|
| + assertNoErrors(source);
|
| +
|
| + void expectCast(Statement statement, bool hasCast) {
|
| + var value = (statement as ExpressionStatement).expression;
|
| + if (value is AssignmentExpression) {
|
| + value = (value as AssignmentExpression).rightHandSide;
|
| + }
|
| + while (value is FunctionExpressionInvocation) {
|
| + value = (value as FunctionExpressionInvocation).function;
|
| + }
|
| + while (value is ParenthesizedExpression) {
|
| + value = (value as ParenthesizedExpression).expression;
|
| + }
|
| + var isCallingGetter =
|
| + value is MethodInvocation && !value.methodName.name.startsWith('m');
|
| + var cast = isCallingGetter
|
| + ? getImplicitOperationCast(value)
|
| + : getImplicitCast(value);
|
| + var castKind = isCallingGetter ? 'special cast' : 'cast';
|
| + expect(cast, hasCast ? isNotNull : isNull,
|
| + reason: '`$statement` should ' +
|
| + (hasCast ? '' : 'not ') +
|
| + 'have a $castKind on `$value`.');
|
| + }
|
| +
|
| + for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'noCasts')) {
|
| + expectCast(s, false);
|
| + }
|
| + for (var s in AstFinder.getStatementsInMethod(unit, 'C', 'casts')) {
|
| + expectCast(s, true);
|
| + }
|
| + for (var s in AstFinder.getStatementsInMethod(unit, 'D', 'noCasts')) {
|
| + expectCast(s, false);
|
| + }
|
| + for (var s in AstFinder.getStatementsInTopLevelFunction(unit, 'noCasts')) {
|
| + expectCast(s, false);
|
| + }
|
| + for (var s in AstFinder.getStatementsInTopLevelFunction(unit, 'casts')) {
|
| + expectCast(s, true);
|
| + }
|
| + }
|
| +
|
| test_factoryConstructor_propagation() async {
|
| String code = r'''
|
| class A<T> {
|
|
|