analyzer: Tidy up 'proper rename' support

Change-Id: I5edaaa168c17b9c55f1dc942797373c983d70bcc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218781
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Sam Rawlins 2021-11-01 17:29:02 +00:00 committed by commit-bot@chromium.org
parent 5e990591b9
commit 67ab9b22e5
3 changed files with 54 additions and 33 deletions

View file

@ -643,7 +643,7 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
TypeAliasElement? viaTypeAlias;
if (typeElement is TypeAliasElementImpl) {
if (constructorFunctionType.typeFormals.isNotEmpty &&
!typeElement.isProperRename()) {
!typeElement.isProperRename) {
// The type alias is not a proper rename of the aliased class, so
// the constructor tear-off is distinct from the associated
// constructor function of the aliased class.

View file

@ -5482,6 +5482,34 @@ class TypeAliasElementImpl extends _ExistingElementImpl
CompilationUnitElement get enclosingElement =>
super.enclosingElement as CompilationUnitElement;
/// Returns whether this alias is a "proper rename" of [aliasedClass], as
/// defined in the constructor-tearoffs specification.
bool get isProperRename {
var aliasedType_ = aliasedType;
if (aliasedType_ is! InterfaceType) {
return false;
}
var aliasedClass = aliasedType_.element;
var typeArguments = aliasedType_.typeArguments;
var typeParameterCount = typeParameters.length;
if (typeParameterCount != aliasedClass.typeParameters.length) {
return false;
}
for (var i = 0; i < typeParameterCount; i++) {
var bound = typeParameters[i].bound ?? library.typeProvider.dynamicType;
var aliasedBound = aliasedClass.typeParameters[i].bound ??
library.typeProvider.dynamicType;
if (!library.typeSystem.isSubtypeOf(bound, aliasedBound) ||
!library.typeSystem.isSubtypeOf(aliasedBound, bound)) {
return false;
}
if (typeParameters[i] != typeArguments[i].element) {
return false;
}
}
return true;
}
@override
ElementKind get kind {
if (isNonFunctionTypeAliasesEnabled) {
@ -5582,37 +5610,6 @@ class TypeAliasElementImpl extends _ExistingElementImpl
}
}
/// Returns whether this alias is a "proper rename" of [aliasedClass], as
/// defined in the constructor-tearoffs specification.
bool isProperRename() {
var aliasedType_ = aliasedType;
if (aliasedType_ is! InterfaceType) {
return false;
}
var aliasedClass = aliasedType_.element;
var typeArguments = aliasedType_.typeArguments;
var typeParameterCount = typeParameters.length;
if (typeParameterCount != aliasedClass.typeParameters.length) {
return false;
}
if (typeParameterCount != typeArguments.length) {
return false;
}
for (var i = 0; i < typeParameterCount; i++) {
var bound = typeParameters[i].bound ?? library.typeProvider.dynamicType;
var aliasedBound = aliasedClass.typeParameters[i].bound ??
library.typeProvider.dynamicType;
if (!library.typeSystem.isSubtypeOf(bound, aliasedBound) ||
!library.typeSystem.isSubtypeOf(aliasedBound, bound)) {
return false;
}
if (typeParameters[i] != typeArguments[i].element) {
return false;
}
}
return true;
}
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;

View file

@ -64,6 +64,18 @@ const a = identical(MyC.new, C.new);
);
}
test_identical_constructorReference_aliasIsNotProperRename_differentCount2() async {
await resolveTestCode('''
class C<T, U> {}
typedef MyC<T> = C;
const a = identical(MyC.new, C.new);
''');
expect(
_evaluateConstant('a'),
_boolValue(false),
);
}
test_identical_constructorReference_aliasIsNotProperRename_differentOrder() async {
await resolveTestCode('''
class C<T, U> {}
@ -124,7 +136,7 @@ const a = identical(MyC<int>.new, (MyC.new)<int>);
);
}
test_identical_constructorReference_aliasIsProperRename_mutualSubtypes() async {
test_identical_constructorReference_aliasIsProperRename_mutualSubtypes_dynamic() async {
await resolveTestCode('''
class C<T> {}
typedef MyC<T extends Object?> = C<T>;
@ -136,6 +148,18 @@ const a = identical(MyC<int>.new, MyC<int>.new);
);
}
test_identical_constructorReference_aliasIsProperRename_mutualSubtypes_futureOr() async {
await resolveTestCode('''
class C<T extends num> {}
typedef MyC<T extends FutureOr<num>> = C<T>;
const a = identical(MyC<int>.new, MyC<int>.new);
''');
expect(
_evaluateConstant('a'),
_boolValue(true),
);
}
test_identical_constructorReference_aliasIsProperRename_uninstantiated() async {
await resolveTestCode('''
class C<T> {}