From bf79e4604cd9da8bb2b7b3b2b44922cc81a92149 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Thu, 27 Jun 2019 19:34:05 +0000 Subject: [PATCH] Migration: Add support for synthetic constructors in generic class type aliases. Change-Id: I8eee88e4dd607623fe109143d01438a5271b3230 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107521 Reviewed-by: Konstantin Shcheglov Commit-Queue: Paul Berry --- .../lib/src/decorated_type.dart | 2 + pkg/nnbd_migration/lib/src/edge_builder.dart | 4 + .../test/edge_builder_test.dart | 83 +++++++++++++++++++ .../test/node_builder_test.dart | 28 +++++++ 4 files changed, 117 insertions(+) diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart index dbe45b3d68e..94faa871154 100644 --- a/pkg/nnbd_migration/lib/src/decorated_type.dart +++ b/pkg/nnbd_migration/lib/src/decorated_type.dart @@ -146,6 +146,8 @@ class DecoratedType { } else if (type is FunctionType) { return DecoratedType.forImplicitFunction( type, NullabilityNode.forInferredType(), graph); + } else if (type is TypeParameterType) { + return DecoratedType(type, NullabilityNode.forInferredType()); } // TODO(paulberry) throw UnimplementedError( diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart index 4235a3c2d2c..bde41e5d2a9 100644 --- a/pkg/nnbd_migration/lib/src/edge_builder.dart +++ b/pkg/nnbd_migration/lib/src/edge_builder.dart @@ -7,6 +7,7 @@ import 'package:analyzer/dart/ast/token.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; +import 'package:analyzer/src/dart/element/handle.dart'; import 'package:analyzer/src/dart/element/inheritance_manager2.dart'; import 'package:analyzer/src/dart/element/member.dart'; import 'package:analyzer/src/generated/resolver.dart'; @@ -287,6 +288,9 @@ class EdgeBuilder extends GeneralizingAstVisitor { var classElement = node.declaredElement; var supertype = classElement.supertype; var superElement = supertype.element; + if (superElement is ClassElementHandle) { + superElement = (superElement as ClassElementHandle).actualElement; + } for (var constructorElement in classElement.constructors) { assert(constructorElement.isSynthetic); var superConstructorElement = diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart index 6ce2d2a23c0..b259905234d 100644 --- a/pkg/nnbd_migration/test/edge_builder_test.dart +++ b/pkg/nnbd_migration/test/edge_builder_test.dart @@ -558,6 +558,21 @@ D f(MyList/*2*/ x) => D(x); decoratedTypeAnnotation('int>/*1*/').node); } + test_class_alias_synthetic_constructor_with_parameters_generic() async { + await analyze(''' +class C { + C(T t); +} +mixin M {} +class D = C with M; +'''); + var syntheticConstructor = findElement.unnamedConstructor('D'); + var constructorType = variables.decoratedElementType(syntheticConstructor); + var constructorParameterType = constructorType.positionalParameters[0]; + assertUnion( + constructorParameterType.node, decoratedTypeAnnotation('T t').node); + } + test_class_alias_synthetic_constructor_with_parameters_named() async { await analyze(''' class C { @@ -707,6 +722,74 @@ class C { // exception to be thrown. } + test_constructorDeclaration_returnType_generic() async { + await analyze(''' +class C { + C(); +} +'''); + var constructor = findElement.unnamedConstructor('C'); + var constructorDecoratedType = variables.decoratedElementType(constructor); + expect(constructorDecoratedType.type.toString(), 'C Function()'); + expect(constructorDecoratedType.node, same(never)); + expect(constructorDecoratedType.typeFormals, isEmpty); + expect(constructorDecoratedType.returnType.node, same(never)); + expect(constructorDecoratedType.returnType.type.toString(), 'C'); + var typeArguments = constructorDecoratedType.returnType.typeArguments; + expect(typeArguments, hasLength(2)); + expect(typeArguments[0].type.toString(), 'T'); + expect(typeArguments[0].node, same(never)); + expect(typeArguments[1].type.toString(), 'U'); + expect(typeArguments[1].node, same(never)); + } + + test_constructorDeclaration_returnType_generic_implicit() async { + await analyze(''' +class C {} +'''); + var constructor = findElement.unnamedConstructor('C'); + var constructorDecoratedType = variables.decoratedElementType(constructor); + expect(constructorDecoratedType.type.toString(), 'C Function()'); + expect(constructorDecoratedType.node, same(never)); + expect(constructorDecoratedType.typeFormals, isEmpty); + expect(constructorDecoratedType.returnType.node, same(never)); + expect(constructorDecoratedType.returnType.type.toString(), 'C'); + var typeArguments = constructorDecoratedType.returnType.typeArguments; + expect(typeArguments, hasLength(2)); + expect(typeArguments[0].type.toString(), 'T'); + expect(typeArguments[0].node, same(never)); + expect(typeArguments[1].type.toString(), 'U'); + expect(typeArguments[1].node, same(never)); + } + + test_constructorDeclaration_returnType_simple() async { + await analyze(''' +class C { + C(); +} +'''); + var constructorDecoratedType = + variables.decoratedElementType(findElement.unnamedConstructor('C')); + expect(constructorDecoratedType.type.toString(), 'C Function()'); + expect(constructorDecoratedType.node, same(never)); + expect(constructorDecoratedType.typeFormals, isEmpty); + expect(constructorDecoratedType.returnType.node, same(never)); + expect(constructorDecoratedType.returnType.typeArguments, isEmpty); + } + + test_constructorDeclaration_returnType_simple_implicit() async { + await analyze(''' +class C {} +'''); + var constructorDecoratedType = + variables.decoratedElementType(findElement.unnamedConstructor('C')); + expect(constructorDecoratedType.type.toString(), 'C Function()'); + expect(constructorDecoratedType.node, same(never)); + expect(constructorDecoratedType.typeFormals, isEmpty); + expect(constructorDecoratedType.returnType.node, same(never)); + expect(constructorDecoratedType.returnType.typeArguments, isEmpty); + } + test_doubleLiteral() async { await analyze(''' double f() { diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart index c5c55aae7b1..c5f35692613 100644 --- a/pkg/nnbd_migration/test/node_builder_test.dart +++ b/pkg/nnbd_migration/test/node_builder_test.dart @@ -127,6 +127,34 @@ class D = C with M; expect(dType.namedParameters, isEmpty); } + test_class_alias_synthetic_constructors_with_parameters_generic() async { + await analyze(''' +class C { + C(T t); +} +mixin M {} +class D = C with M; +'''); + var cConstructor = findElement.unnamedConstructor('C'); + var dConstructor = findElement.unnamedConstructor('D'); + var cConstructorType = variables.decoratedElementType(cConstructor); + var dConstructorType = variables.decoratedElementType(dConstructor); + expect(dConstructorType.type.toString(), 'D Function(U)'); + expect(dConstructorType.node, same(never)); + expect(dConstructorType.typeFormals, isEmpty); + expect(dConstructorType.returnType.type.toString(), 'D'); + expect(dConstructorType.returnType.node, same(never)); + var typeArguments = dConstructorType.returnType.typeArguments; + expect(typeArguments, hasLength(1)); + expect(typeArguments[0].type.toString(), 'U'); + expect(typeArguments[0].node, same(never)); + var cParams = cConstructorType.positionalParameters; + var dParams = dConstructorType.positionalParameters; + expect(dParams, hasLength(1)); + expect(dParams[0].type.toString(), 'U'); + expect(dParams[0].node, TypeMatcher()); + } + test_class_with_default_constructor() async { await analyze(''' class C {}