From f65f71923348b61186780f441d65ab03d5e670ed Mon Sep 17 00:00:00 2001 From: pq Date: Tue, 22 Oct 2024 17:04:51 +0000 Subject: [PATCH] [element model] fix unsafe `ConstructorMember` cast See: b/374689139. https://dart-review.googlesource.com/c/sdk/+/390941 is blocking an SDK roll. Root cause: ``` Action threw an exception: type 'ConstructorMember' is not a subtype of type 'ConstructorFragment' in type cast #0 InterfaceTypeImpl.constructors2. (package:analyzer/src/dart/element/type.dart:569) #1 MappedListIterable.elementAt (dart:_internal/iterable.dart:435) #2 ListIterator.moveNext (dart:_internal/iterable.dart:364) #3 new _GrowableList._ofEfficientLengthIterable (dart:core-patch/growable_array.dart:189) #4 new _GrowableList.of (dart:core-patch/growable_array.dart:150) #5 new List.of (dart:core-patch/array_patch.dart:39) #6 ListIterable.toList (dart:_internal/iterable.dart:224) #7 InterfaceTypeImpl.constructors2 (package:analyzer/src/dart/element/type.dart:570) #8 _Visitor._hasConstConstructorInvocation (package:linter/src/rules/prefer_const_constructors_in_immutables.dart:110) #9 _Visitor.visitConstructorDeclaration (package:linter/src/rules/prefer_const_constructors_in_immutables.dart:58) ``` To verify the fix locally: ``` solo_test_X() async { await assertNoErrorsInCode(r''' class A {} '''); var A = findElement.class_('A').instantiate( typeArguments: [intType], nullabilitySuffix: NullabilitySuffix.none, ); A.constructors2; } ``` Bug: b/374689139 Change-Id: I70034d938d840dc0c3939db27e7116164e4617e9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391483 Reviewed-by: Konstantin Shcheglov Commit-Queue: Phil Quitslund --- pkg/analyzer/lib/src/dart/element/type.dart | 8 +++++++- ...fer_const_constructors_in_immutables_test.dart | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart index c71d5d9a45f1..b00d61fa9b65 100644 --- a/pkg/analyzer/lib/src/dart/element/type.dart +++ b/pkg/analyzer/lib/src/dart/element/type.dart @@ -554,7 +554,13 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType { @override List get constructors2 => constructors - .map((fragment) => (fragment as ConstructorFragment).element) + .map((fragment) => switch (fragment) { + ConstructorFragment(:var element) => element, + ConstructorMember() => fragment, + _ => throw StateError( + 'unexpected fragment type: ${fragment.runtimeType}', + ) + }) .toList(); @override diff --git a/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart b/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart index 232dc751f9ec..942acfe1ce5e 100644 --- a/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart +++ b/pkg/linter/test/rules/prefer_const_constructors_in_immutables_test.dart @@ -405,6 +405,21 @@ macro class M { ]); } + test_parameterizedType() async { + // Verify we aren't doing an unsafe cast to a `ConstructorFragment` in type.dart. + // b/374689139 + await assertNoDiagnostics(r''' +import 'package:meta/meta.dart'; + +class A {} + +@immutable +class C extends A { + C(); +} +'''); + } + test_returnOfInvalidType() async { await assertDiagnostics(r''' import 'package:meta/meta.dart';