mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:43:57 +00:00
[cfe] Handle A extends FutureOr<B> <: FutureOr<B>
Change-Id: Ib5580328f006b033b2c004083b575a2cf5aed551 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/141541 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
80ae6ed91d
commit
a7f1a5e677
|
@ -56,6 +56,8 @@ import 'package:kernel/type_algebra.dart' show Substitution, substitute;
|
|||
import 'package:kernel/type_environment.dart'
|
||||
show SubtypeCheckMode, TypeEnvironment;
|
||||
|
||||
import 'package:kernel/src/types.dart' show Types;
|
||||
|
||||
import '../dill/dill_member_builder.dart' show DillMemberBuilder;
|
||||
|
||||
import '../fasta_codes.dart';
|
||||
|
@ -64,8 +66,6 @@ import '../kernel/redirecting_factory_body.dart' show getRedirectingFactoryBody;
|
|||
|
||||
import '../kernel/kernel_target.dart' show KernelTarget;
|
||||
|
||||
import '../kernel/types.dart' show Types;
|
||||
|
||||
import '../loader.dart';
|
||||
|
||||
import '../modifier.dart';
|
||||
|
@ -1025,8 +1025,9 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
// When a parameter is covariant we have to check that we also
|
||||
// override the same member in all parents.
|
||||
for (Supertype supertype in interfaceMember.enclosingClass.supers) {
|
||||
Member m = types.hierarchy.getInterfaceMemberKernel(
|
||||
supertype.classNode, interfaceMember.name, isSetter);
|
||||
Member m = types.hierarchy.getInterfaceMember(
|
||||
supertype.classNode, interfaceMember.name,
|
||||
setter: isSetter);
|
||||
if (m != null) {
|
||||
callback(declaredMember, m, isSetter);
|
||||
}
|
||||
|
@ -1160,7 +1161,7 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
interfaceSubstitution = Substitution.fromPairs(
|
||||
enclosingClass.typeParameters,
|
||||
types.hierarchy
|
||||
.getKernelTypeArgumentsAsInstanceOf(thisType, enclosingClass));
|
||||
.getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
|
||||
}
|
||||
|
||||
if (declaredFunction?.typeParameters?.length !=
|
||||
|
@ -1204,7 +1205,8 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
}
|
||||
DartType computedBound = substitution.substituteType(interfaceBound);
|
||||
if (!types
|
||||
.isSameTypeKernel(declaredBound, computedBound)
|
||||
.performNullabilityAwareMutualSubtypesCheck(
|
||||
declaredBound, computedBound)
|
||||
.isSubtypeWhenUsingNullabilities()) {
|
||||
reportInvalidOverride(
|
||||
isInterfaceCheck,
|
||||
|
@ -1243,7 +1245,7 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
declaredSubstitution = Substitution.fromPairs(
|
||||
enclosingClass.typeParameters,
|
||||
types.hierarchy
|
||||
.getKernelTypeArgumentsAsInstanceOf(thisType, enclosingClass));
|
||||
.getTypeArgumentsAsInstanceOf(thisType, enclosingClass));
|
||||
}
|
||||
return declaredSubstitution;
|
||||
}
|
||||
|
@ -1276,11 +1278,11 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
DartType subtype = inParameter ? interfaceType : declaredType;
|
||||
DartType supertype = inParameter ? declaredType : interfaceType;
|
||||
|
||||
if (types.isSubtypeOfKernel(
|
||||
if (types.isSubtypeOf(
|
||||
subtype, supertype, SubtypeCheckMode.withNullabilities)) {
|
||||
// No problem--the proper subtyping relation is satisfied.
|
||||
} else if (isCovariant &&
|
||||
types.isSubtypeOfKernel(
|
||||
types.isSubtypeOf(
|
||||
supertype, subtype, SubtypeCheckMode.withNullabilities)) {
|
||||
// No problem--the overriding parameter is marked "covariant" and has
|
||||
// a type which is a subtype of the parameter it overrides.
|
||||
|
@ -1289,10 +1291,10 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl
|
|||
// been reported.
|
||||
} else {
|
||||
// Report an error.
|
||||
bool isErrorInNnbdOptedOutMode = !types.isSubtypeOfKernel(
|
||||
bool isErrorInNnbdOptedOutMode = !types.isSubtypeOf(
|
||||
subtype, supertype, SubtypeCheckMode.ignoringNullabilities) &&
|
||||
(!isCovariant ||
|
||||
!types.isSubtypeOfKernel(
|
||||
!types.isSubtypeOf(
|
||||
supertype, subtype, SubtypeCheckMode.ignoringNullabilities));
|
||||
if (isErrorInNnbdOptedOutMode || library.isNonNullableByDefault) {
|
||||
String declaredMemberName = '${declaredMember.enclosingClass.name}'
|
||||
|
|
|
@ -6,7 +6,8 @@ library fasta.class_hierarchy_builder;
|
|||
|
||||
import 'package:kernel/ast.dart' hide MapEntry;
|
||||
|
||||
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
|
||||
import 'package:kernel/class_hierarchy.dart'
|
||||
show ClassHierarchy, ClassHierarchyBase;
|
||||
|
||||
import 'package:kernel/core_types.dart' show CoreTypes;
|
||||
|
||||
|
@ -17,6 +18,7 @@ import 'package:kernel/src/future_or.dart';
|
|||
import 'package:kernel/src/legacy_erasure.dart';
|
||||
import 'package:kernel/src/nnbd_top_merge.dart';
|
||||
import 'package:kernel/src/norm.dart';
|
||||
import 'package:kernel/src/types.dart' show Types;
|
||||
|
||||
import '../../testing/id_testing_utils.dart' show typeToText;
|
||||
|
||||
|
@ -81,8 +83,6 @@ import 'forwarding_node.dart' show ForwardingNode;
|
|||
|
||||
import 'kernel_builder.dart' show ImplicitFieldType;
|
||||
|
||||
import 'types.dart' show Types;
|
||||
|
||||
const bool useConsolidated = true;
|
||||
|
||||
const DebugLogger debug =
|
||||
|
@ -309,7 +309,7 @@ bool hasSameSignature(FunctionNode a, FunctionNode b) {
|
|||
return aReturnType == bReturnType;
|
||||
}
|
||||
|
||||
class ClassHierarchyBuilder {
|
||||
class ClassHierarchyBuilder implements ClassHierarchyBase {
|
||||
final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
|
||||
|
||||
final Map<ClassBuilder, Map<Class, Substitution>> substitutions =
|
||||
|
@ -473,8 +473,8 @@ class ClassHierarchyBuilder {
|
|||
return null;
|
||||
}
|
||||
|
||||
InterfaceType getKernelTypeAsInstanceOf(
|
||||
InterfaceType type, Class superclass, Library clientLibrary) {
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes) {
|
||||
Class kernelClass = type.classNode;
|
||||
if (kernelClass == superclass) return type;
|
||||
if (kernelClass == nullClass) {
|
||||
|
@ -495,7 +495,7 @@ class ClassHierarchyBuilder {
|
|||
.withNullability(type.nullability);
|
||||
}
|
||||
|
||||
List<DartType> getKernelTypeArgumentsAsInstanceOf(
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass) {
|
||||
Class kernelClass = type.classNode;
|
||||
if (kernelClass == superclass) return type.typeArguments;
|
||||
|
@ -534,10 +534,10 @@ class ClassHierarchyBuilder {
|
|||
ClassHierarchyNode node = nodes2[i];
|
||||
if (node == null) continue;
|
||||
if (nodes1.contains(node)) {
|
||||
DartType candidate1 = getKernelTypeAsInstanceOf(
|
||||
type1, node.classBuilder.cls, clientLibrary);
|
||||
DartType candidate2 = getKernelTypeAsInstanceOf(
|
||||
type2, node.classBuilder.cls, clientLibrary);
|
||||
DartType candidate1 = getTypeAsInstanceOf(
|
||||
type1, node.classBuilder.cls, clientLibrary, coreTypes);
|
||||
DartType candidate2 = getTypeAsInstanceOf(
|
||||
type2, node.classBuilder.cls, clientLibrary, coreTypes);
|
||||
if (candidate1 == candidate2) {
|
||||
common.add(node);
|
||||
}
|
||||
|
@ -553,8 +553,8 @@ class ClassHierarchyBuilder {
|
|||
for (int i = 0; i < common.length - 1; i++) {
|
||||
ClassHierarchyNode node = common[i];
|
||||
if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
|
||||
return getKernelTypeAsInstanceOf(
|
||||
type1, node.classBuilder.cls, clientLibrary)
|
||||
return getTypeAsInstanceOf(
|
||||
type1, node.classBuilder.cls, clientLibrary, coreTypes)
|
||||
.withNullability(
|
||||
uniteNullabilities(type1.nullability, type2.nullability));
|
||||
} else {
|
||||
|
@ -567,9 +567,9 @@ class ClassHierarchyBuilder {
|
|||
uniteNullabilities(type1.nullability, type2.nullability));
|
||||
}
|
||||
|
||||
Member getInterfaceMemberKernel(Class cls, Name name, bool isSetter) {
|
||||
Member getInterfaceMember(Class cls, Name name, {bool setter: false}) {
|
||||
return getNodeFromClass(cls)
|
||||
.getInterfaceMember(name, isSetter)
|
||||
.getInterfaceMember(name, setter)
|
||||
?.getMember(this);
|
||||
}
|
||||
|
||||
|
@ -744,7 +744,8 @@ class ClassHierarchyNodeBuilder {
|
|||
DartType overriddenBound = methodSubstitution
|
||||
.substituteType(overriddenTypeParameters[i].bound);
|
||||
if (!hierarchy.types
|
||||
.isSameTypeKernel(declaredBound, overriddenBound)
|
||||
.performNullabilityAwareMutualSubtypesCheck(
|
||||
declaredBound, overriddenBound)
|
||||
.isSubtypeWhenUsingNullabilities()) {
|
||||
debug?.log("Giving up 3");
|
||||
continue;
|
||||
|
@ -2565,13 +2566,14 @@ class TypeBuilderConstraintGatherer extends TypeConstraintGatherer
|
|||
@override
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes) {
|
||||
return hierarchy.getKernelTypeAsInstanceOf(type, superclass, clientLibrary);
|
||||
return hierarchy.getTypeAsInstanceOf(
|
||||
type, superclass, clientLibrary, coreTypes);
|
||||
}
|
||||
|
||||
@override
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass) {
|
||||
return hierarchy.getKernelTypeArgumentsAsInstanceOf(type, superclass);
|
||||
return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2583,7 +2585,7 @@ class TypeBuilderConstraintGatherer extends TypeConstraintGatherer
|
|||
@override
|
||||
bool isSubtypeOf(
|
||||
DartType subtype, DartType supertype, SubtypeCheckMode mode) {
|
||||
return hierarchy.types.isSubtypeOfKernel(subtype, supertype, mode);
|
||||
return hierarchy.types.isSubtypeOf(subtype, supertype, mode);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -2945,8 +2947,11 @@ class InterfaceConflict extends DelayedMember {
|
|||
unhandled("${member.runtimeType}", "$member", classBuilder.charOffset,
|
||||
classBuilder.fileUri);
|
||||
}
|
||||
InterfaceType instance = hierarchy.getKernelTypeAsInstanceOf(
|
||||
thisType, member.enclosingClass, classBuilder.library.library);
|
||||
InterfaceType instance = hierarchy.getTypeAsInstanceOf(
|
||||
thisType,
|
||||
member.enclosingClass,
|
||||
classBuilder.library.library,
|
||||
hierarchy.coreTypes);
|
||||
assert(
|
||||
instance != null,
|
||||
"No instance of $thisType as ${member.enclosingClass} found for "
|
||||
|
@ -2957,10 +2962,10 @@ class InterfaceConflict extends DelayedMember {
|
|||
bool isMoreSpecific(ClassHierarchyBuilder hierarchy, DartType a, DartType b) {
|
||||
if (isSetter) {
|
||||
return hierarchy.types
|
||||
.isSubtypeOfKernel(b, a, SubtypeCheckMode.withNullabilities);
|
||||
.isSubtypeOf(b, a, SubtypeCheckMode.withNullabilities);
|
||||
} else {
|
||||
return hierarchy.types
|
||||
.isSubtypeOfKernel(a, b, SubtypeCheckMode.withNullabilities);
|
||||
.isSubtypeOf(a, b, SubtypeCheckMode.withNullabilities);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -537,11 +537,12 @@ class ForwardingNode {
|
|||
Substitution _substitutionFor(
|
||||
List<TypeParameter> stubTypeParameters, Member candidate, Class class_) {
|
||||
Substitution substitution = Substitution.fromInterfaceType(
|
||||
hierarchy.getKernelTypeAsInstanceOf(
|
||||
hierarchy.getTypeAsInstanceOf(
|
||||
hierarchy.coreTypes
|
||||
.thisInterfaceType(class_, class_.enclosingLibrary.nonNullable),
|
||||
candidate.enclosingClass,
|
||||
class_.enclosingLibrary));
|
||||
class_.enclosingLibrary,
|
||||
hierarchy.coreTypes));
|
||||
if (stubTypeParameters != null) {
|
||||
// If the stub is generic ensure that type parameters are alpha renamed
|
||||
// to the [stubTypeParameters].
|
||||
|
|
|
@ -94,7 +94,7 @@ class UnknownType extends DartType {
|
|||
|
||||
@override
|
||||
String toStringInternal() {
|
||||
return "";
|
||||
return "<unknown-type>";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,9 @@ class TypeConstraint {
|
|||
|
||||
class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
||||
with StandardBounds {
|
||||
TypeSchemaEnvironment(CoreTypes coreTypes, ClassHierarchy hierarchy)
|
||||
final ClassHierarchy hierarchy;
|
||||
|
||||
TypeSchemaEnvironment(CoreTypes coreTypes, this.hierarchy)
|
||||
: super(coreTypes, hierarchy);
|
||||
|
||||
Class get functionClass => coreTypes.functionClass;
|
||||
|
@ -364,7 +366,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
|
|||
unwrappedSupertype =
|
||||
(unwrappedSupertype as InterfaceType).typeArguments.single;
|
||||
}
|
||||
if (subtype == coreTypes.nullType && unwrappedSupertype is UnknownType) {
|
||||
if (unwrappedSupertype is UnknownType) {
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
return super.performNullabilityAwareSubtypeCheck(subtype, supertype);
|
||||
|
|
|
@ -248,7 +248,6 @@ abstract class SubtypeTest<T, E> {
|
|||
isSubtype('Future<int*>*', 'FutureOr<num*>*');
|
||||
isSubtype('Future<int*>*', 'FutureOr<Object*>*');
|
||||
isSubtype('FutureOr<int*>*', 'FutureOr<int*>*');
|
||||
isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
|
||||
isSubtype('FutureOr<int*>*', 'Object*');
|
||||
isSubtype('Null', 'FutureOr<num?>');
|
||||
isSubtype('Null', 'FutureOr<num>?');
|
||||
|
@ -265,6 +264,14 @@ abstract class SubtypeTest<T, E> {
|
|||
isSubtype('FutureOr<X>', 'FutureOr<Future<X>>',
|
||||
typeParameters: 'X extends Future<Future<X>>');
|
||||
|
||||
isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
|
||||
isSubtype('FutureOr<A>', 'FutureOr<B>', typeParameters: 'B,A extends B');
|
||||
|
||||
isSubtype('X', 'FutureOr<int>',
|
||||
typeParameters: 'X extends FutureOr<int*>*');
|
||||
isSubtype('X*', 'FutureOr<int>',
|
||||
typeParameters: 'X extends FutureOr<int*>*');
|
||||
|
||||
isSubtype('num?', 'FutureOr<FutureOr<FutureOr<num>>?>');
|
||||
isSubtype('Future<num>?', 'FutureOr<FutureOr<FutureOr<num>>?>');
|
||||
isSubtype('Future<Future<num>>?', 'FutureOr<FutureOr<FutureOr<num>>?>');
|
||||
|
@ -282,6 +289,16 @@ abstract class SubtypeTest<T, E> {
|
|||
isSubtype('FutureOr<num>?', 'FutureOr<num?>');
|
||||
isObliviousSubtype('FutureOr<num?>', 'FutureOr<num>?');
|
||||
|
||||
isSubtype('List<FutureOr<List<dynamic>>>',
|
||||
'List<FutureOr<List<FutureOr<dynamic>>>>');
|
||||
isSubtype('List<FutureOr<List<FutureOr<dynamic>>>>',
|
||||
'List<FutureOr<List<dynamic>>>');
|
||||
|
||||
isSubtype('X', 'FutureOr<List<X>>',
|
||||
typeParameters: 'X extends FutureOr<List<X>>');
|
||||
isNotSubtype('X', 'FutureOr<List<X>>',
|
||||
typeParameters: 'X extends List<FutureOr<X>>');
|
||||
|
||||
isSubtype('dynamic', 'FutureOr<Object?>');
|
||||
isSubtype('dynamic', 'FutureOr<Object>?');
|
||||
isSubtype('void', 'FutureOr<Object?>');
|
||||
|
|
|
@ -108,8 +108,8 @@ void performFastaChecks(
|
|||
List<SubtypeCheck> checks, ClassHierarchyBuilder hierarchy) {
|
||||
for (int i = 0; i < checks.length; i++) {
|
||||
SubtypeCheck check = checks[i];
|
||||
bool isSubtype = hierarchy.types.isSubtypeOfKernel(
|
||||
check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
|
||||
bool isSubtype = hierarchy.types
|
||||
.isSubtypeOf(check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
|
||||
if (isSubtype != check.isSubtype) {
|
||||
throw "Check failed: $check";
|
||||
}
|
||||
|
|
|
@ -300,7 +300,6 @@ disjoint
|
|||
dispatched
|
||||
divided
|
||||
dmitryas
|
||||
dupdate
|
||||
doc
|
||||
docs
|
||||
dom
|
||||
|
@ -313,6 +312,7 @@ dq
|
|||
dquote
|
||||
dst
|
||||
dummy
|
||||
dupdate
|
||||
e
|
||||
easy
|
||||
ecma
|
||||
|
@ -343,6 +343,7 @@ eq
|
|||
equation
|
||||
erasure
|
||||
es
|
||||
established
|
||||
estimate
|
||||
eval
|
||||
excludes
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -213,11 +213,11 @@ class C extends core::Object implements self::A<core::int*>, self::B<core::int*,
|
|||
field core::int* field1;
|
||||
field invalid-type field2;
|
||||
field core::int* field3 = 0;
|
||||
field invalid-type field4 = 0 as{TypeError} invalid-type;
|
||||
field invalid-type field4 = 0;
|
||||
field core::int* field5;
|
||||
field invalid-type field6;
|
||||
field core::int* field7 = 0;
|
||||
field invalid-type field8 = 0 as{TypeError} invalid-type;
|
||||
field invalid-type field8 = 0;
|
||||
field dynamic field9;
|
||||
generic-covariant-impl field core::int* field10;
|
||||
generic-covariant-impl field invalid-type field11;
|
||||
|
@ -236,11 +236,11 @@ class D<T extends core::Object* = dynamic> extends core::Object implements self:
|
|||
field core::int* field1;
|
||||
field invalid-type field2;
|
||||
field core::int* field3 = 0;
|
||||
field invalid-type field4 = 0 as{TypeError} invalid-type;
|
||||
field invalid-type field4 = 0;
|
||||
field core::int* field5;
|
||||
field invalid-type field6;
|
||||
field core::int* field7 = 0;
|
||||
field invalid-type field8 = 0 as{TypeError} invalid-type;
|
||||
field invalid-type field8 = 0;
|
||||
field dynamic field9;
|
||||
generic-covariant-impl field self::D::T* field10;
|
||||
generic-covariant-impl field self::D::T* field11;
|
||||
|
|
|
@ -33,6 +33,6 @@ class Operators7 extends core::Object {
|
|||
;
|
||||
operator <<() → dynamic {}
|
||||
operator >(dynamic a) → invalid-type
|
||||
return true as{TypeError} invalid-type;
|
||||
return true;
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -33,6 +33,6 @@ class Operators7 extends core::Object {
|
|||
;
|
||||
operator <<() → dynamic {}
|
||||
operator >(dynamic a) → invalid-type
|
||||
return true as{TypeError} invalid-type;
|
||||
return true;
|
||||
}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -11,6 +11,6 @@ import self as self;
|
|||
import "dart:core";
|
||||
|
||||
static method testDynamic() → invalid-type
|
||||
return 0 as{TypeError} invalid-type;
|
||||
return 0;
|
||||
static method testVoid() → void {}
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:14:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:14:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:14:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:14:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,15 +16,6 @@ library;
|
|||
// foo(List<A> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
|
||||
// - 'List' is from 'dart:core'.
|
||||
// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:14:3: Context: This is the overridden method ('foo').
|
||||
// foo(List<Null> a) {}
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/general_nnbd_opt_out/issue39421.dart:18:12: Error: Can't use 'A' because it is declared more than once.
|
||||
// foo(List<A> a) {}
|
||||
// ^
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@ class C<T extends core::Object* = dynamic> extends core::Object {
|
|||
: super core::Object::•()
|
||||
;
|
||||
method method() → invalid-type
|
||||
return "Hello, World!" as{TypeError} invalid-type;
|
||||
return "Hello, World!";
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}() as{TypeError} core::String*;
|
||||
core::String* s = new self::C::•<dynamic>().{self::C::method}();
|
||||
core::print(s);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,6 @@ library test;
|
|||
//
|
||||
import self as self;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::y) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::y;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -9,6 +9,6 @@ library test;
|
|||
//
|
||||
import self as self;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::y) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::y;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -9,6 +9,6 @@ library test;
|
|||
//
|
||||
import self as self;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::y) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::y;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -9,6 +9,6 @@ library test;
|
|||
//
|
||||
import self as self;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::y) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::y;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -39,8 +39,8 @@ class D extends self::C {
|
|||
return x;
|
||||
}
|
||||
static method main() → dynamic {
|
||||
core::int* y = (let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_do_not_infer_invalid_override_of_generic_method.dart:18:74: Error: Expected 0 type arguments.
|
||||
core::int* y = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_do_not_infer_invalid_override_of_generic_method.dart:18:74: Error: Expected 0 type arguments.
|
||||
. /*error:WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD*/ /*@target=D::m*/ m<int>(
|
||||
^" in new self::D::•().{self::D::m}<core::int*>(42)) as{TypeError} core::int*;
|
||||
^" in new self::D::•().{self::D::m}<core::int*>(42);
|
||||
core::print(y);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class A extends core::Object {
|
|||
return 0;
|
||||
}
|
||||
static field self::A* a = new self::A::•();
|
||||
static field invalid-type b = (() → () →* invalid-type => self::a.{self::A::f}<() →* invalid-type>(self::c)) as{TypeError} invalid-type;
|
||||
static field invalid-type b = () → () →* invalid-type => self::a.{self::A::f}<() →* invalid-type>(self::c);
|
||||
static field () →* invalid-type c = () → invalid-type => self::a.{self::A::f}<invalid-type>(self::b);
|
||||
static field () →* () →* core::int* d = () → () →* core::int* => self::a.{self::A::f}<() →* core::int*>(self::e);
|
||||
static field () →* core::int* e = () → core::int* => self::a.{self::A::g}(self::d);
|
||||
|
|
|
@ -20,7 +20,7 @@ class A extends core::Object {
|
|||
return 0;
|
||||
}
|
||||
static field self::A* a = new self::A::•();
|
||||
static field invalid-type b = (() → () →* invalid-type => self::a.{self::A::f}<() →* invalid-type>(self::c)) as{TypeError} invalid-type;
|
||||
static field invalid-type b = () → () →* invalid-type => self::a.{self::A::f}<() →* invalid-type>(self::c);
|
||||
static field () →* invalid-type c = () → invalid-type => self::a.{self::A::f}<invalid-type>(self::b);
|
||||
static field () →* () →* core::int* d = () → () →* core::int* => self::a.{self::A::f}<() →* core::int*>(self::e);
|
||||
static field () →* core::int* e = () → core::int* => self::a.{self::A::g}(self::d);
|
||||
|
|
|
@ -13,7 +13,7 @@ import "dart:core" as core;
|
|||
static field core::int* intValue = 0;
|
||||
static field core::num* numValue = 0;
|
||||
static field core::double* doubleValue = 0.0;
|
||||
static field invalid-type a = (() → core::num* => self::intValue.{core::num::+}(self::b as{TypeError,ForDynamic} core::num*)) as{TypeError} invalid-type;
|
||||
static field invalid-type a = () → core::num* => self::intValue.{core::num::+}(self::b as{TypeError,ForDynamic} core::num*);
|
||||
static field dynamic b = self::a.call();
|
||||
static field () →* core::num* c = () → core::num* => self::numValue.{core::num::+}(self::d);
|
||||
static field core::num* d = self::c.call();
|
||||
|
|
|
@ -13,7 +13,7 @@ import "dart:core" as core;
|
|||
static field core::int* intValue = 0;
|
||||
static field core::num* numValue = 0;
|
||||
static field core::double* doubleValue = 0.0;
|
||||
static field invalid-type a = (() → core::num* => self::intValue.{core::num::+}(self::b as{TypeError,ForDynamic} core::num*)) as{TypeError} invalid-type;
|
||||
static field invalid-type a = () → core::num* => self::intValue.{core::num::+}(self::b as{TypeError,ForDynamic} core::num*);
|
||||
static field dynamic b = self::a.call();
|
||||
static field () →* core::num* c = () → core::num* => self::numValue.{core::num::+}(self::d);
|
||||
static field core::num* d = self::c.call();
|
||||
|
|
|
@ -11,7 +11,7 @@ import self as self;
|
|||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
field invalid-type x = (() → invalid-type => new self::B::•().{self::B::x}) as{TypeError} invalid-type;
|
||||
field invalid-type x = () → invalid-type => new self::B::•().{self::B::x};
|
||||
field () →* invalid-type y = () → invalid-type => new self::B::•().{self::B::x};
|
||||
synthetic constructor •() → self::A*
|
||||
: super core::Object::•()
|
||||
|
|
|
@ -11,7 +11,7 @@ import self as self;
|
|||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
field invalid-type x = (() → invalid-type => new self::B::•().{self::B::x}) as{TypeError} invalid-type;
|
||||
field invalid-type x = () → invalid-type => new self::B::•().{self::B::x};
|
||||
field () →* invalid-type y = () → invalid-type => new self::B::•().{self::B::x};
|
||||
synthetic constructor •() → self::A*
|
||||
: super core::Object::•()
|
||||
|
|
|
@ -11,7 +11,7 @@ import self as self;
|
|||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
field invalid-type b = (() → () →* invalid-type => self::x) as{TypeError} invalid-type;
|
||||
field invalid-type b = () → () →* invalid-type => self::x;
|
||||
field () →* () →* invalid-type c = () → () →* invalid-type => self::x;
|
||||
synthetic constructor •() → self::A*
|
||||
: super core::Object::•()
|
||||
|
|
|
@ -11,7 +11,7 @@ import self as self;
|
|||
import "dart:core" as core;
|
||||
|
||||
class A extends core::Object {
|
||||
field invalid-type b = (() → () →* invalid-type => self::x) as{TypeError} invalid-type;
|
||||
field invalid-type b = () → () →* invalid-type => self::x;
|
||||
field () →* () →* invalid-type c = () → () →* invalid-type => self::x;
|
||||
synthetic constructor •() → self::A*
|
||||
: super core::Object::•()
|
||||
|
|
|
@ -10,7 +10,7 @@ library test;
|
|||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::f() ?{() →* invalid-type} self::y : self::z) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::f() ?{() →* invalid-type} self::y : self::z;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static field () →* invalid-type z = () → invalid-type => self::x;
|
||||
static method f() → core::bool*
|
||||
|
|
|
@ -10,7 +10,7 @@ library test;
|
|||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
static field invalid-type x = (() → () →* invalid-type => self::f() ?{() →* invalid-type} self::y : self::z) as{TypeError} invalid-type;
|
||||
static field invalid-type x = () → () →* invalid-type => self::f() ?{() →* invalid-type} self::y : self::z;
|
||||
static field () →* invalid-type y = () → invalid-type => self::x;
|
||||
static field () →* invalid-type z = () → invalid-type => self::x;
|
||||
static method f() → core::bool*
|
||||
|
|
|
@ -10,9 +10,9 @@ import self as self;
|
|||
|
||||
typedef F = invalid-type;
|
||||
static method foo(() → void x) → void {
|
||||
self::bar(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::bar(x);
|
||||
self::bar(null);
|
||||
self::baz(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::baz(x);
|
||||
self::baz(null);
|
||||
}
|
||||
static method bar(invalid-type x) → void {}
|
||||
|
|
|
@ -10,9 +10,9 @@ import self as self;
|
|||
|
||||
typedef F = invalid-type;
|
||||
static method foo(() → void x) → void {
|
||||
self::bar(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::bar(x);
|
||||
self::bar(null);
|
||||
self::baz(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::baz(x);
|
||||
self::baz(null);
|
||||
}
|
||||
static method bar(invalid-type x) → void {}
|
||||
|
|
|
@ -10,9 +10,9 @@ import self as self;
|
|||
|
||||
typedef F = invalid-type;
|
||||
static method foo(() → void x) → void {
|
||||
self::bar(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::bar(x);
|
||||
self::bar(null);
|
||||
self::baz(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::baz(x);
|
||||
self::baz(null);
|
||||
}
|
||||
static method bar(invalid-type x) → void {}
|
||||
|
|
|
@ -10,9 +10,9 @@ import self as self;
|
|||
|
||||
typedef F = invalid-type;
|
||||
static method foo(() → void x) → void {
|
||||
self::bar(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::bar(x);
|
||||
self::bar(null);
|
||||
self::baz(x as{TypeError,ForNonNullableByDefault} invalid-type);
|
||||
self::baz(x);
|
||||
self::baz(null);
|
||||
}
|
||||
static method bar(invalid-type x) → void {}
|
||||
|
|
|
@ -85,7 +85,7 @@ Try correcting the name to the name of an existing getter, or defining a getter
|
|||
static method b(dynamic c) → invalid-type
|
||||
return invalid-expression "pkg/front_end/testcases/rasta/issue_000044.dart:7:10: Error: Getter not found: 'd'.
|
||||
a b(c) = d;
|
||||
^" as{TypeError,ForDynamic} invalid-type;
|
||||
^";
|
||||
static method main() → dynamic {
|
||||
self::C* c = null;
|
||||
core::print(#C1);
|
||||
|
|
|
@ -85,7 +85,7 @@ Try correcting the name to the name of an existing getter, or defining a getter
|
|||
static method b(dynamic c) → invalid-type
|
||||
return invalid-expression "pkg/front_end/testcases/rasta/issue_000044.dart:7:10: Error: Getter not found: 'd'.
|
||||
a b(c) = d;
|
||||
^" as{TypeError,ForDynamic} invalid-type;
|
||||
^";
|
||||
static method main() → dynamic {
|
||||
self::C* c = null;
|
||||
core::print(#C1);
|
||||
|
|
|
@ -34,6 +34,6 @@ static field invalid-type T = invalid-expression "pkg/front_end/testcases/regres
|
|||
- 'Type' is from 'dart:core'.
|
||||
Try correcting the operator to an existing operator, or defining a '<' operator.
|
||||
type T = Map<A, B>
|
||||
^" as{TypeError,ForDynamic} invalid-type;
|
||||
^";
|
||||
static field invalid-type B;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -34,6 +34,6 @@ static field invalid-type T = invalid-expression "pkg/front_end/testcases/regres
|
|||
- 'Type' is from 'dart:core'.
|
||||
Try correcting the operator to an existing operator, or defining a '<' operator.
|
||||
type T = Map<A, B>
|
||||
^" as{TypeError,ForDynamic} invalid-type;
|
||||
^";
|
||||
static field invalid-type B;
|
||||
static method main() → dynamic {}
|
||||
|
|
|
@ -19,5 +19,5 @@ class Foo extends core::Object {
|
|||
}
|
||||
static method main() → dynamic {
|
||||
self::Foo* instance = new self::Foo::•();
|
||||
instance.{self::Foo::self} = instance as{TypeError} invalid-type;
|
||||
instance.{self::Foo::self} = instance;
|
||||
}
|
||||
|
|
|
@ -19,5 +19,5 @@ class Foo extends core::Object {
|
|||
}
|
||||
static method main() → dynamic {
|
||||
self::Foo* instance = new self::Foo::•();
|
||||
instance.{self::Foo::self} = instance as{TypeError} invalid-type;
|
||||
instance.{self::Foo::self} = instance;
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@ library;
|
|||
// Future<List<>> f3() async {
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/regress/issue_34850.dart:14:16: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Future<List<>> f3() async {
|
||||
// ^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
|
|
|
@ -50,10 +50,6 @@ library;
|
|||
// Future<List<>> f3() async {
|
||||
// ^
|
||||
//
|
||||
// pkg/front_end/testcases/regress/issue_34850.dart:14:16: Error: Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
// Future<List<>> f3() async {
|
||||
// ^^
|
||||
//
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:async" as asy;
|
||||
|
|
|
@ -18,7 +18,7 @@ import 'package:kernel/kernel.dart'
|
|||
|
||||
import 'package:kernel/target/targets.dart' show Target, TargetFlags, getTarget;
|
||||
|
||||
import 'package:kernel/type_environment.dart' show SubtypeTester;
|
||||
import 'package:kernel/src/types.dart' show Types;
|
||||
|
||||
import 'package:vm/bytecode/gen_bytecode.dart'
|
||||
show createFreshComponentWithBytecode, generateBytecode;
|
||||
|
@ -78,7 +78,7 @@ compileEntryPoint(List<String> arguments) async {
|
|||
stopwatch.stop();
|
||||
|
||||
elapsedTimes.add(stopwatch.elapsedMilliseconds.toDouble());
|
||||
List<Object> typeChecks = SubtypeTester.typeChecks;
|
||||
List<Object> typeChecks = Types.typeChecksForTesting;
|
||||
if (typeChecks?.isNotEmpty ?? false) {
|
||||
BenchMaker.writeTypeChecks("type_checks.json", typeChecks);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,36 @@ abstract class MixinInferrer {
|
|||
void infer(ClassHierarchy hierarchy, Class classNode);
|
||||
}
|
||||
|
||||
/// Core interface for answering queries needed to compute the subtyping
|
||||
/// relation.
|
||||
abstract class ClassHierarchyBase {
|
||||
CoreTypes get coreTypes;
|
||||
|
||||
/// Returns the instantiation of [superclass] that is implemented by [type],
|
||||
/// or `null` if [type] does not implement [superclass] at all.
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes);
|
||||
|
||||
/// Returns the type arguments of the instantiation of [superclass] that is
|
||||
/// implemented by [type], or `null` if [type] does not implement [superclass]
|
||||
/// at all.
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass);
|
||||
|
||||
/// Returns the possibly abstract interface member of [class_] with the given
|
||||
/// [name].
|
||||
///
|
||||
/// If [setter] is `false`, only fields, methods, and getters with that name
|
||||
/// will be found. If [setter] is `true`, only non-final fields and setters
|
||||
/// will be found.
|
||||
///
|
||||
/// If multiple members with that name are inherited and not overridden, the
|
||||
/// member from the first declared supertype is returned.
|
||||
Member getInterfaceMember(Class class_, Name name, {bool setter: false});
|
||||
}
|
||||
|
||||
/// Interface for answering various subclassing queries.
|
||||
abstract class ClassHierarchy {
|
||||
abstract class ClassHierarchy implements ClassHierarchyBase {
|
||||
factory ClassHierarchy(Component component, CoreTypes coreTypes,
|
||||
{HandleAmbiguousSupertypes onAmbiguousSupertypes,
|
||||
MixinInferrer mixinInferrer}) {
|
||||
|
@ -76,17 +104,6 @@ abstract class ClassHierarchy {
|
|||
/// or `null` if [class_] does not implement [superclass] at all.
|
||||
Supertype getClassAsInstanceOf(Class class_, Class superclass);
|
||||
|
||||
/// Returns the instantiation of [superclass] that is implemented by [type],
|
||||
/// or `null` if [type] does not implement [superclass] at all.
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes);
|
||||
|
||||
/// Returns the type arguments of the instantiation of [superclass] that is
|
||||
/// implemented by [type], or `null` if [type] does not implement [superclass]
|
||||
/// at all.
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass);
|
||||
|
||||
/// Returns the instantiation of [superclass] that is implemented by [type],
|
||||
/// or `null` if [type] does not implement [superclass]. [superclass] must
|
||||
/// be a generic class.
|
||||
|
@ -119,17 +136,6 @@ abstract class ClassHierarchy {
|
|||
/// The returned list should not be modified.
|
||||
List<Member> getDispatchTargets(Class class_, {bool setters: false});
|
||||
|
||||
/// Returns the possibly abstract interface member of [class_] with the given
|
||||
/// [name].
|
||||
///
|
||||
/// If [setter] is `false`, only fields, methods, and getters with that name
|
||||
/// will be found. If [setter] is `true`, only non-final fields and setters
|
||||
/// will be found.
|
||||
///
|
||||
/// If multiple members with that name are inherited and not overridden, the
|
||||
/// member from the first declared supertype is returned.
|
||||
Member getInterfaceMember(Class class_, Name name, {bool setter: false});
|
||||
|
||||
/// Returns the list of members denoting the interface for [class_], which
|
||||
/// may include abstract members.
|
||||
///
|
||||
|
|
|
@ -6,17 +6,17 @@ library kernel.hierarchy_based_type_environment;
|
|||
|
||||
import '../ast.dart' show Class, DartType, InterfaceType, Library, Member, Name;
|
||||
|
||||
import '../class_hierarchy.dart' show ClassHierarchy;
|
||||
import '../class_hierarchy.dart' show ClassHierarchyBase;
|
||||
|
||||
import '../core_types.dart' show CoreTypes;
|
||||
|
||||
import '../type_environment.dart' show TypeEnvironment;
|
||||
|
||||
class HierarchyBasedTypeEnvironment extends TypeEnvironment {
|
||||
final ClassHierarchy hierarchy;
|
||||
final ClassHierarchyBase hierarchy;
|
||||
|
||||
HierarchyBasedTypeEnvironment(CoreTypes coreTypes, this.hierarchy)
|
||||
: super.fromSubclass(coreTypes);
|
||||
: super.fromSubclass(coreTypes, hierarchy);
|
||||
|
||||
@override
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
// 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.
|
||||
|
||||
library fasta.types;
|
||||
|
||||
import 'package:kernel/ast.dart'
|
||||
import '../ast.dart'
|
||||
show
|
||||
BottomType,
|
||||
Class,
|
||||
|
@ -23,37 +21,63 @@ import 'package:kernel/ast.dart'
|
|||
Variance,
|
||||
VoidType;
|
||||
|
||||
import 'package:kernel/core_types.dart';
|
||||
import '../class_hierarchy.dart' show ClassHierarchyBase;
|
||||
|
||||
import 'package:kernel/type_algebra.dart'
|
||||
import '../core_types.dart' show CoreTypes;
|
||||
|
||||
import '../type_algebra.dart'
|
||||
show Substitution, combineNullabilitiesForSubstitution;
|
||||
|
||||
import 'package:kernel/type_environment.dart';
|
||||
import '../type_environment.dart' show IsSubtypeOf, SubtypeCheckMode;
|
||||
|
||||
import 'package:kernel/src/future_or.dart';
|
||||
import 'future_or.dart';
|
||||
|
||||
import 'kernel_builder.dart' show ClassHierarchyBuilder;
|
||||
|
||||
class Types implements SubtypeTester {
|
||||
final ClassHierarchyBuilder hierarchy;
|
||||
class Types {
|
||||
final ClassHierarchyBase hierarchy;
|
||||
|
||||
Types(this.hierarchy);
|
||||
|
||||
/// Returns true if [s] is a subtype of [t].
|
||||
bool isSubtypeOfKernel(DartType s, DartType t, SubtypeCheckMode mode) {
|
||||
IsSubtypeOf result = performNullabilityAwareSubtypeCheck(s, t);
|
||||
bool _isSubtypeFromMode(IsSubtypeOf isSubtypeOf, SubtypeCheckMode mode) {
|
||||
switch (mode) {
|
||||
case SubtypeCheckMode.withNullabilities:
|
||||
return result.isSubtypeWhenUsingNullabilities();
|
||||
return isSubtypeOf.isSubtypeWhenUsingNullabilities();
|
||||
case SubtypeCheckMode.ignoringNullabilities:
|
||||
return result.isSubtypeWhenIgnoringNullabilities();
|
||||
return isSubtypeOf.isSubtypeWhenIgnoringNullabilities();
|
||||
default:
|
||||
throw new StateError("Unhandled subtype checking mode '$mode'");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
/// Returns true if [s] is a subtype of [t].
|
||||
bool isSubtypeOf(DartType s, DartType t, SubtypeCheckMode mode) {
|
||||
IsSubtypeOf result = performNullabilityAwareSubtypeCheck(s, t);
|
||||
return _isSubtypeFromMode(result, mode);
|
||||
}
|
||||
|
||||
/// Can be use to collect type checks. To use:
|
||||
/// 1. Rename `performNullabilityAwareSubtypeCheck` to
|
||||
/// `_performNullabilityAwareSubtypeCheck`.
|
||||
/// 2. Rename `_collect_performNullabilityAwareSubtypeCheck` to
|
||||
/// `performNullabilityAwareSubtypeCheck`.
|
||||
/// 3. Comment out the call to `_performNullabilityAwareSubtypeCheck` below.
|
||||
// ignore:unused_element
|
||||
bool _collect_performNullabilityAwareSubtypeCheck(
|
||||
DartType subtype, DartType supertype, SubtypeCheckMode mode) {
|
||||
IsSubtypeOf result = const IsSubtypeOf.always();
|
||||
//result = _performNullabilityAwareSubtypeCheck(subtype, supertype, mode);
|
||||
bool booleanResult = _isSubtypeFromMode(result, mode);
|
||||
typeChecksForTesting ??= <Object>[];
|
||||
typeChecksForTesting.add([subtype, supertype, booleanResult]);
|
||||
return booleanResult;
|
||||
}
|
||||
|
||||
IsSubtypeOf performNullabilityAwareSubtypeCheck(DartType s, DartType t) {
|
||||
// TODO(johnniwinther,dmitryas): Ensure complete handling of InvalidType in
|
||||
// the subtype relation.
|
||||
if (s is InvalidType || t is InvalidType) {
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
|
||||
if (s is BottomType) {
|
||||
return const IsSubtypeOf.always(); // Rule 3.
|
||||
}
|
||||
|
@ -68,33 +92,25 @@ class Types implements SubtypeTester {
|
|||
}
|
||||
if (s is NeverType) {
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, hierarchy.futureOrClass);
|
||||
}
|
||||
|
||||
// TODO(dmitryas): Remove InvalidType from subtype relation.
|
||||
if (s is InvalidType) {
|
||||
// InvalidType is a bottom type.
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
if (t is InvalidType) {
|
||||
return const IsSubtypeOf.never();
|
||||
s, t, hierarchy.coreTypes.futureOrClass);
|
||||
}
|
||||
|
||||
if (t is InterfaceType) {
|
||||
Class cls = t.classNode;
|
||||
if (cls == hierarchy.objectClass &&
|
||||
!(s is InterfaceType && s.classNode == hierarchy.futureOrClass)) {
|
||||
if (cls == hierarchy.coreTypes.objectClass &&
|
||||
!(s is InterfaceType &&
|
||||
s.classNode == hierarchy.coreTypes.futureOrClass)) {
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, hierarchy.futureOrClass);
|
||||
s, t, hierarchy.coreTypes.futureOrClass);
|
||||
}
|
||||
if (cls == hierarchy.futureOrClass) {
|
||||
if (cls == hierarchy.coreTypes.futureOrClass) {
|
||||
const IsFutureOrSubtypeOf relation = const IsFutureOrSubtypeOf();
|
||||
if (s is DynamicType) {
|
||||
return relation.isDynamicRelated(s, t, this);
|
||||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -113,7 +129,7 @@ class Types implements SubtypeTester {
|
|||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -133,7 +149,7 @@ class Types implements SubtypeTester {
|
|||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -154,7 +170,7 @@ class Types implements SubtypeTester {
|
|||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -174,7 +190,7 @@ class Types implements SubtypeTester {
|
|||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -194,7 +210,7 @@ class Types implements SubtypeTester {
|
|||
} else if (s is VoidType) {
|
||||
return relation.isVoidRelated(s, t, this);
|
||||
} else if (s is InterfaceType) {
|
||||
return s.classNode == hierarchy.futureOrClass
|
||||
return s.classNode == hierarchy.coreTypes.futureOrClass
|
||||
? relation.isFutureOrRelated(s, t, this)
|
||||
: relation.isInterfaceRelated(s, t, this);
|
||||
} else if (s is FunctionType) {
|
||||
|
@ -245,7 +261,8 @@ class Types implements SubtypeTester {
|
|||
return const IsSubtypeOf.never();
|
||||
}
|
||||
} else if (variance == Variance.invariant) {
|
||||
result = result.and(isSameTypeKernel(s[i], t[i]));
|
||||
result =
|
||||
result.and(performNullabilityAwareMutualSubtypesCheck(s[i], t[i]));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
|
@ -259,73 +276,32 @@ class Types implements SubtypeTester {
|
|||
return result;
|
||||
}
|
||||
|
||||
IsSubtypeOf isSameTypeKernel(DartType s, DartType t) {
|
||||
return performNullabilityAwareSubtypeCheck(s, t)
|
||||
.andSubtypeCheckFor(t, s, this);
|
||||
}
|
||||
static List<Object> typeChecksForTesting;
|
||||
|
||||
@override
|
||||
bool isSubtypeOf(
|
||||
DartType subtype, DartType supertype, SubtypeCheckMode mode) {
|
||||
return isSubtypeOfKernel(subtype, supertype, mode);
|
||||
}
|
||||
|
||||
@override
|
||||
Class get futureOrClass => hierarchy.coreTypes.futureOrClass;
|
||||
|
||||
@override
|
||||
Class get functionClass => hierarchy.coreTypes.functionClass;
|
||||
|
||||
@override
|
||||
InterfaceType get functionLegacyRawType =>
|
||||
hierarchy.coreTypes.functionLegacyRawType;
|
||||
|
||||
@override
|
||||
InterfaceType futureType(DartType type, Nullability nullability) {
|
||||
return new InterfaceType(
|
||||
hierarchy.coreTypes.futureClass, nullability, <DartType>[type]);
|
||||
}
|
||||
|
||||
@override
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes) {
|
||||
return hierarchy.getKernelTypeAsInstanceOf(type, superclass, clientLibrary);
|
||||
return hierarchy.getTypeAsInstanceOf(
|
||||
type, superclass, clientLibrary, coreTypes);
|
||||
}
|
||||
|
||||
@override
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass) {
|
||||
return hierarchy.getKernelTypeArgumentsAsInstanceOf(type, superclass);
|
||||
return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
|
||||
}
|
||||
|
||||
@override
|
||||
bool isTop(DartType type) {
|
||||
return type is DynamicType ||
|
||||
type is VoidType ||
|
||||
type == objectLegacyRawType ||
|
||||
type == objectNullableRawType;
|
||||
type == hierarchy.coreTypes.objectLegacyRawType ||
|
||||
type == hierarchy.coreTypes.objectNullableRawType;
|
||||
}
|
||||
|
||||
@override
|
||||
InterfaceType get nullType => hierarchy.coreTypes.nullType;
|
||||
|
||||
@override
|
||||
Class get objectClass => hierarchy.coreTypes.objectClass;
|
||||
|
||||
@override
|
||||
InterfaceType get objectLegacyRawType {
|
||||
return hierarchy.coreTypes.objectLegacyRawType;
|
||||
}
|
||||
|
||||
@override
|
||||
InterfaceType get objectNullableRawType {
|
||||
return hierarchy.coreTypes.objectNullableRawType;
|
||||
}
|
||||
|
||||
@override
|
||||
IsSubtypeOf performNullabilityAwareMutualSubtypesCheck(
|
||||
DartType type1, DartType type2) {
|
||||
return isSameTypeKernel(type1, type2);
|
||||
return performNullabilityAwareSubtypeCheck(type1, type2)
|
||||
.andSubtypeCheckFor(type2, type1, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,14 +332,14 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
@override
|
||||
IsSubtypeOf isInterfaceRelated(
|
||||
InterfaceType s, InterfaceType t, Types types) {
|
||||
if (s.classNode == types.hierarchy.nullClass) {
|
||||
if (s.classNode == types.hierarchy.coreTypes.nullClass) {
|
||||
// This is an optimization, to avoid instantiating unnecessary type
|
||||
// arguments in getKernelTypeAsInstanceOf.
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.futureOrClass);
|
||||
s, t, types.hierarchy.coreTypes.futureOrClass);
|
||||
}
|
||||
List<DartType> asSupertypeArguments =
|
||||
types.hierarchy.getKernelTypeArgumentsAsInstanceOf(s, t.classNode);
|
||||
types.hierarchy.getTypeArgumentsAsInstanceOf(s, t.classNode);
|
||||
if (asSupertypeArguments == null) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
|
@ -371,14 +347,15 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
.areTypeArgumentsOfSubtypeKernel(
|
||||
asSupertypeArguments, t.typeArguments, t.classNode.typeParameters)
|
||||
.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.futureOrClass));
|
||||
s, t, types.hierarchy.coreTypes.futureOrClass));
|
||||
}
|
||||
|
||||
@override
|
||||
IsSubtypeOf isTypeParameterRelated(
|
||||
TypeParameterType s, InterfaceType t, Types types) {
|
||||
return types.performNullabilityAwareSubtypeCheck(s.parameter.bound, t).and(
|
||||
new IsSubtypeOf.basedSolelyOnNullabilities(s, t, types.futureOrClass));
|
||||
new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.hierarchy.coreTypes.futureOrClass));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -389,12 +366,12 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
return types
|
||||
.performNullabilityAwareSubtypeCheck(arguments.single, t)
|
||||
.andSubtypeCheckFor(
|
||||
new InterfaceType(types.hierarchy.futureClass,
|
||||
new InterfaceType(types.hierarchy.coreTypes.futureClass,
|
||||
Nullability.nonNullable, arguments),
|
||||
t,
|
||||
types)
|
||||
.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
futureOr, t, types.futureOrClass));
|
||||
futureOr, t, types.hierarchy.coreTypes.futureOrClass));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -411,8 +388,9 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
|
||||
@override
|
||||
IsSubtypeOf isFunctionRelated(FunctionType s, InterfaceType t, Types types) {
|
||||
return t.classNode == types.hierarchy.functionClass
|
||||
? new IsSubtypeOf.basedSolelyOnNullabilities(s, t, types.futureOrClass)
|
||||
return t.classNode == types.hierarchy.coreTypes.functionClass
|
||||
? new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.hierarchy.coreTypes.futureOrClass)
|
||||
: const IsSubtypeOf.never(); // Rule 14.
|
||||
}
|
||||
|
||||
|
@ -420,7 +398,8 @@ class IsInterfaceSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
IsSubtypeOf isTypedefRelated(TypedefType s, InterfaceType t, Types types) {
|
||||
// Rule 5.
|
||||
return types.performNullabilityAwareSubtypeCheck(s.unalias, t).and(
|
||||
new IsSubtypeOf.basedSolelyOnNullabilities(s, t, types.futureOrClass));
|
||||
new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.hierarchy.coreTypes.futureOrClass));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -451,8 +430,8 @@ class IsFunctionSubtypeOf extends TypeRelation<FunctionType> {
|
|||
for (int i = 0; i < sTypeVariables.length; i++) {
|
||||
TypeParameter sTypeVariable = sTypeVariables[i];
|
||||
TypeParameter tTypeVariable = tTypeVariables[i];
|
||||
result = result.and(
|
||||
types.isSameTypeKernel(sTypeVariable.bound, tTypeVariable.bound));
|
||||
result = result.and(types.performNullabilityAwareMutualSubtypesCheck(
|
||||
sTypeVariable.bound, tTypeVariable.bound));
|
||||
typeVariableSubstitution.add(new TypeParameterType.forAlphaRenaming(
|
||||
sTypeVariable, tTypeVariable));
|
||||
}
|
||||
|
@ -465,7 +444,7 @@ class IsFunctionSubtypeOf extends TypeRelation<FunctionType> {
|
|||
for (int i = 0; i < sTypeVariables.length; i++) {
|
||||
TypeParameter sTypeVariable = sTypeVariables[i];
|
||||
TypeParameter tTypeVariable = tTypeVariables[i];
|
||||
result = result.and(types.isSameTypeKernel(
|
||||
result = result.and(types.performNullabilityAwareMutualSubtypesCheck(
|
||||
substitution.substituteType(sTypeVariable.bound),
|
||||
tTypeVariable.bound));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
|
@ -532,7 +511,7 @@ class IsFunctionSubtypeOf extends TypeRelation<FunctionType> {
|
|||
|
||||
@override
|
||||
IsSubtypeOf isInterfaceRelated(InterfaceType s, FunctionType t, Types types) {
|
||||
if (s.classNode == types.hierarchy.nullClass) {
|
||||
if (s.classNode == types.hierarchy.coreTypes.nullClass) {
|
||||
// Rule 4.
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.futureOrClass);
|
||||
|
@ -627,7 +606,7 @@ class IsTypeParameterSubtypeOf extends TypeRelation<TypeParameterType> {
|
|||
@override
|
||||
IsSubtypeOf isInterfaceRelated(
|
||||
InterfaceType s, TypeParameterType t, Types types) {
|
||||
if (s.classNode == types.hierarchy.nullClass) {
|
||||
if (s.classNode == types.hierarchy.coreTypes.nullClass) {
|
||||
// Rule 4.
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, t, types.futureOrClass);
|
||||
|
@ -720,8 +699,8 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
InterfaceType s, InterfaceType futureOr, Types types) {
|
||||
List<DartType> arguments = futureOr.typeArguments;
|
||||
|
||||
Nullability unitedNullability =
|
||||
computeNullabilityOfFutureOr(futureOr, types.hierarchy.futureOrClass);
|
||||
Nullability unitedNullability = computeNullabilityOfFutureOr(
|
||||
futureOr, types.hierarchy.coreTypes.futureOrClass);
|
||||
|
||||
return types
|
||||
// Rule 11.
|
||||
|
@ -730,8 +709,8 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
// Rule 10.
|
||||
.orSubtypeCheckFor(
|
||||
s,
|
||||
new InterfaceType(
|
||||
types.hierarchy.futureClass, unitedNullability, arguments),
|
||||
new InterfaceType(types.hierarchy.coreTypes.futureClass,
|
||||
unitedNullability, arguments),
|
||||
types);
|
||||
}
|
||||
|
||||
|
@ -741,30 +720,50 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
// This follows from combining rules 7, 10, and 11.
|
||||
DartType sArgument = sFutureOr.typeArguments.single;
|
||||
DartType tArgument = tFutureOr.typeArguments.single;
|
||||
DartType sFutureOfArgument = new InterfaceType(types.hierarchy.futureClass,
|
||||
Nullability.nonNullable, sFutureOr.typeArguments);
|
||||
DartType tFutureOfArgument = new InterfaceType(types.hierarchy.futureClass,
|
||||
Nullability.nonNullable, tFutureOr.typeArguments);
|
||||
Nullability sNullability =
|
||||
computeNullabilityOfFutureOr(sFutureOr, types.hierarchy.futureOrClass);
|
||||
Nullability tNullability =
|
||||
computeNullabilityOfFutureOr(tFutureOr, types.hierarchy.futureOrClass);
|
||||
DartType sFutureOfArgument = new InterfaceType(
|
||||
types.hierarchy.coreTypes.futureClass,
|
||||
Nullability.nonNullable,
|
||||
sFutureOr.typeArguments);
|
||||
DartType tFutureOfArgument = new InterfaceType(
|
||||
types.hierarchy.coreTypes.futureClass,
|
||||
Nullability.nonNullable,
|
||||
tFutureOr.typeArguments);
|
||||
Nullability sNullability = computeNullabilityOfFutureOr(
|
||||
sFutureOr, types.hierarchy.coreTypes.futureOrClass);
|
||||
Nullability tNullability = computeNullabilityOfFutureOr(
|
||||
tFutureOr, types.hierarchy.coreTypes.futureOrClass);
|
||||
// The following is an optimized is-subtype-of test for the case where
|
||||
// both LHS and RHS are FutureOrs. It's based on the following:
|
||||
// FutureOr<X> <: FutureOr<Y> iff X <: Y OR (X <: Future<Y> AND
|
||||
// Future<X> <: Y).
|
||||
//
|
||||
// The correctness of that can be shown as follows:
|
||||
// 1. FutureOr<X> <: Y iff X <: Y AND Future<X> <: Y
|
||||
// 2. X <: FutureOr<Y> iff X <: Y OR X <: Future<Y>
|
||||
// 3. 1,2 => FutureOr<X> <: FutureOr<Y> iff
|
||||
// 1. FutureOr<X> <: FutureOr<Y> iff
|
||||
//
|
||||
// X <: FutureOr<Y> AND Future<X> <: FutureOr<Y>
|
||||
//
|
||||
// 2a. X <: FutureOr<Y> iff
|
||||
//
|
||||
// X <: Y OR X <: Future<Y>
|
||||
//
|
||||
// 2b. Future<X> <: FutureOr<Y> iff
|
||||
//
|
||||
// Future<X> <: Y OR Future<X> <: Future<Y>
|
||||
//
|
||||
// 3. 1,2a,2b => FutureOr<X> <: FutureOr<Y> iff
|
||||
//
|
||||
// (X <: Y OR X <: Future<Y>) AND
|
||||
// (Future<X> <: Y OR Future<X> <: Future<Y>)
|
||||
//
|
||||
// 4. X <: Y iff Future<X> <: Future<Y>
|
||||
//
|
||||
// 5. 3,4 => FutureOr<X> <: FutureOr<Y> iff
|
||||
//
|
||||
// (X <: Y OR X <: Future<Y>) AND
|
||||
// (X <: Y OR Future<X> <: Y) iff
|
||||
//
|
||||
// X <: Y OR (X <: Future<Y> AND Future<X> <: Y)
|
||||
//
|
||||
return types
|
||||
.performNullabilityAwareSubtypeCheck(sArgument, tArgument)
|
||||
.or(types
|
||||
|
@ -784,7 +783,7 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
return types.performNullabilityAwareSubtypeCheck(
|
||||
s,
|
||||
argument.withNullability(computeNullabilityOfFutureOr(
|
||||
futureOr, types.hierarchy.futureOrClass)));
|
||||
futureOr, types.hierarchy.coreTypes.futureOrClass)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -794,15 +793,15 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
return types.performNullabilityAwareSubtypeCheck(
|
||||
s,
|
||||
argument.withNullability(computeNullabilityOfFutureOr(
|
||||
futureOr, types.hierarchy.futureOrClass)));
|
||||
futureOr, types.hierarchy.coreTypes.futureOrClass)));
|
||||
}
|
||||
|
||||
@override
|
||||
IsSubtypeOf isTypeParameterRelated(
|
||||
TypeParameterType s, InterfaceType futureOr, Types types) {
|
||||
List<DartType> arguments = futureOr.typeArguments;
|
||||
Nullability unitedNullability =
|
||||
computeNullabilityOfFutureOr(futureOr, types.hierarchy.futureOrClass);
|
||||
Nullability unitedNullability = computeNullabilityOfFutureOr(
|
||||
futureOr, types.hierarchy.coreTypes.futureOrClass);
|
||||
// TODO(dmitryas): Revise the original optimization.
|
||||
return types
|
||||
// Rule 11.
|
||||
|
@ -818,8 +817,8 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
// Rule 10.
|
||||
.orSubtypeCheckFor(
|
||||
s,
|
||||
new InterfaceType(
|
||||
types.hierarchy.futureClass, unitedNullability, arguments),
|
||||
new InterfaceType(types.hierarchy.coreTypes.futureClass,
|
||||
unitedNullability, arguments),
|
||||
types);
|
||||
}
|
||||
|
||||
|
@ -831,7 +830,7 @@ class IsFutureOrSubtypeOf extends TypeRelation<InterfaceType> {
|
|||
return types.performNullabilityAwareSubtypeCheck(
|
||||
s,
|
||||
argument.withNullability(computeNullabilityOfFutureOr(
|
||||
futureOr, types.hierarchy.futureOrClass)));
|
||||
futureOr, types.hierarchy.coreTypes.futureOrClass)));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -873,7 +872,7 @@ class IsIntersectionSubtypeOf extends TypeRelation<TypeParameterType> {
|
|||
@override
|
||||
IsSubtypeOf isInterfaceRelated(
|
||||
InterfaceType s, TypeParameterType intersection, Types types) {
|
||||
if (s.classNode == types.hierarchy.nullClass) {
|
||||
if (s.classNode == types.hierarchy.coreTypes.nullClass) {
|
||||
// Rule 4.
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
s, intersection, types.futureOrClass);
|
||||
|
@ -925,7 +924,7 @@ class IsNeverTypeSubtypeOf implements TypeRelation<NeverType> {
|
|||
}
|
||||
|
||||
IsSubtypeOf isInterfaceRelated(InterfaceType s, NeverType t, Types types) {
|
||||
if (s.classNode == types.hierarchy.nullClass) {
|
||||
if (s.classNode == types.hierarchy.coreTypes.nullClass) {
|
||||
if (t.nullability == Nullability.nullable ||
|
||||
t.nullability == Nullability.legacy) {
|
||||
return const IsSubtypeOf.always();
|
|
@ -6,22 +6,23 @@ library kernel.type_environment;
|
|||
import 'ast.dart';
|
||||
import 'class_hierarchy.dart';
|
||||
import 'core_types.dart';
|
||||
import 'type_algebra.dart';
|
||||
|
||||
import 'src/future_or.dart';
|
||||
import 'src/hierarchy_based_type_environment.dart'
|
||||
show HierarchyBasedTypeEnvironment;
|
||||
import 'src/types.dart';
|
||||
|
||||
typedef void ErrorHandler(TreeNode node, String message);
|
||||
|
||||
abstract class TypeEnvironment extends SubtypeTester {
|
||||
abstract class TypeEnvironment extends Types {
|
||||
final CoreTypes coreTypes;
|
||||
|
||||
/// An error handler for use in debugging, or `null` if type errors should not
|
||||
/// be tolerated. See [typeError].
|
||||
ErrorHandler errorHandler;
|
||||
|
||||
TypeEnvironment.fromSubclass(this.coreTypes);
|
||||
TypeEnvironment.fromSubclass(this.coreTypes, ClassHierarchyBase base)
|
||||
: super(base);
|
||||
|
||||
factory TypeEnvironment(CoreTypes coreTypes, ClassHierarchy hierarchy) {
|
||||
return new HierarchyBasedTypeEnvironment(coreTypes, hierarchy);
|
||||
|
@ -309,11 +310,12 @@ class IsSubtypeOf {
|
|||
unwrappedSupertype =
|
||||
(unwrappedSupertype as InterfaceType).typeArguments.single;
|
||||
}
|
||||
if (unwrappedSubtype is TypeParameterType &&
|
||||
unwrappedSubtype.promotedBound == null &&
|
||||
unwrappedSupertype is TypeParameterType &&
|
||||
unwrappedSupertype.promotedBound == null &&
|
||||
unwrappedSubtype.parameter == unwrappedSupertype.parameter) {
|
||||
Nullability unwrappedSubtypeNullability =
|
||||
computeNullability(unwrappedSubtype, futureOrClass);
|
||||
Nullability unwrappedSupertypeNullability =
|
||||
computeNullability(unwrappedSupertype, futureOrClass);
|
||||
if (unwrappedSubtypeNullability == unwrappedSupertypeNullability) {
|
||||
// The relationship between the types must be established elsewhere.
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +345,7 @@ class IsSubtypeOf {
|
|||
/// [IsSubtypeOf.never] because the right-hand side will not change the
|
||||
/// overall result anyway.
|
||||
IsSubtypeOf andSubtypeCheckFor(
|
||||
DartType subtype, DartType supertype, SubtypeTester tester) {
|
||||
DartType subtype, DartType supertype, Types tester) {
|
||||
if (_value == _valueNever) return this;
|
||||
return this
|
||||
.and(tester.performNullabilityAwareSubtypeCheck(subtype, supertype));
|
||||
|
@ -370,7 +372,7 @@ class IsSubtypeOf {
|
|||
/// as [IsSubtypeOf.always] because the right-hand side will not change the
|
||||
/// overall result anyway.
|
||||
IsSubtypeOf orSubtypeCheckFor(
|
||||
DartType subtype, DartType supertype, SubtypeTester tester) {
|
||||
DartType subtype, DartType supertype, Types tester) {
|
||||
if (_value == _valueAlways) return this;
|
||||
return this
|
||||
.or(tester.performNullabilityAwareSubtypeCheck(subtype, supertype));
|
||||
|
@ -402,340 +404,6 @@ enum SubtypeCheckMode {
|
|||
ignoringNullabilities,
|
||||
}
|
||||
|
||||
/// The part of [TypeEnvironment] that deals with subtype tests.
|
||||
///
|
||||
/// This lives in a separate class so it can be tested independently of the SDK.
|
||||
abstract class SubtypeTester {
|
||||
InterfaceType get objectLegacyRawType;
|
||||
InterfaceType get objectNullableRawType;
|
||||
InterfaceType get nullType;
|
||||
InterfaceType get functionLegacyRawType;
|
||||
Class get objectClass;
|
||||
Class get functionClass;
|
||||
Class get futureOrClass;
|
||||
InterfaceType futureType(DartType type, Nullability nullability);
|
||||
|
||||
static List<Object> typeChecks;
|
||||
|
||||
InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
|
||||
Library clientLibrary, CoreTypes coreTypes);
|
||||
|
||||
List<DartType> getTypeArgumentsAsInstanceOf(
|
||||
InterfaceType type, Class superclass);
|
||||
|
||||
/// Determines if the given type is at the top of the type hierarchy. May be
|
||||
/// overridden in subclasses.
|
||||
bool isTop(DartType type) {
|
||||
return type is DynamicType ||
|
||||
type is VoidType ||
|
||||
type == objectLegacyRawType ||
|
||||
type == objectNullableRawType;
|
||||
}
|
||||
|
||||
/// Can be use to collect type checks. To use:
|
||||
/// 1. Rename `isSubtypeOf` to `_isSubtypeOf`.
|
||||
/// 2. Rename `_collect_isSubtypeOf` to `isSubtypeOf`.
|
||||
/// 3. Comment out the call to `_isSubtypeOf` below.
|
||||
// ignore:unused_element
|
||||
bool _collect_isSubtypeOf(
|
||||
DartType subtype, DartType supertype, SubtypeCheckMode mode) {
|
||||
bool result = true;
|
||||
//result = _isSubtypeOf(subtype, supertype, mode);
|
||||
typeChecks ??= <Object>[];
|
||||
typeChecks.add([subtype, supertype, result]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns true if [subtype] is a subtype of [supertype].
|
||||
bool isSubtypeOf(
|
||||
DartType subtype, DartType supertype, SubtypeCheckMode mode) {
|
||||
IsSubtypeOf result =
|
||||
performNullabilityAwareSubtypeCheck(subtype, supertype);
|
||||
switch (mode) {
|
||||
case SubtypeCheckMode.ignoringNullabilities:
|
||||
return result.isSubtypeWhenIgnoringNullabilities();
|
||||
case SubtypeCheckMode.withNullabilities:
|
||||
return result.isSubtypeWhenUsingNullabilities();
|
||||
default:
|
||||
throw new StateError("Unhandled subtype checking mode '$mode'");
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs a nullability-aware subtype check.
|
||||
///
|
||||
/// The outcome is described in the comments to [IsSubtypeOf].
|
||||
IsSubtypeOf performNullabilityAwareSubtypeCheck(
|
||||
DartType subtype, DartType supertype) {
|
||||
subtype = subtype.unalias;
|
||||
supertype = supertype.unalias;
|
||||
if (identical(subtype, supertype)) return const IsSubtypeOf.always();
|
||||
if (subtype is BottomType) return const IsSubtypeOf.always();
|
||||
if (subtype is NeverType) {
|
||||
return supertype is BottomType
|
||||
? const IsSubtypeOf.never()
|
||||
: new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass);
|
||||
}
|
||||
if (subtype == nullType) {
|
||||
// TODO(dmitryas): Remove InvalidType from subtype relation.
|
||||
if (supertype is InvalidType) {
|
||||
// The return value is supposed to keep the backward compatibility.
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
|
||||
Nullability supertypeNullability =
|
||||
computeNullability(supertype, futureOrClass);
|
||||
if (supertypeNullability == Nullability.nullable ||
|
||||
supertypeNullability == Nullability.legacy) {
|
||||
return const IsSubtypeOf.always();
|
||||
}
|
||||
// See rule 4 of the subtype rules from the Dart Language Specification.
|
||||
return supertype is BottomType || supertype is NeverType
|
||||
? const IsSubtypeOf.never()
|
||||
: const IsSubtypeOf.onlyIfIgnoringNullabilities();
|
||||
}
|
||||
if (isTop(supertype)) return const IsSubtypeOf.always();
|
||||
|
||||
// Handle FutureOr<T> union type.
|
||||
if (subtype is InterfaceType &&
|
||||
identical(subtype.classNode, futureOrClass)) {
|
||||
var subtypeArg = subtype.typeArguments[0];
|
||||
if (supertype is InterfaceType &&
|
||||
identical(supertype.classNode, futureOrClass)) {
|
||||
DartType supertypeArg = supertype.typeArguments[0];
|
||||
Nullability subtypeNullability =
|
||||
computeNullabilityOfFutureOr(subtype, futureOrClass);
|
||||
Nullability supertypeNullability =
|
||||
computeNullabilityOfFutureOr(supertype, futureOrClass);
|
||||
// The following is an optimized is-subtype-of test for the case where
|
||||
// both LHS and RHS are FutureOrs. It's based on the following:
|
||||
// FutureOr<X> <: FutureOr<Y> iff X <: Y OR (X <: Future<Y> AND
|
||||
// Future<X> <: Y).
|
||||
//
|
||||
// The correctness of that can be shown as follows:
|
||||
// 1. FutureOr<X> <: Y iff X <: Y AND Future<X> <: Y
|
||||
// 2. X <: FutureOr<Y> iff X <: Y OR X <: Future<Y>
|
||||
// 3. 1,2 => FutureOr<X> <: FutureOr<Y> iff
|
||||
// (X <: Y OR X <: Future<Y>) AND
|
||||
// (Future<X> <: Y OR Future<X> <: Future<Y>)
|
||||
// 4. X <: Y iff Future<X> <: Future<Y>
|
||||
// 5. 3,4 => FutureOr<X> <: FutureOr<Y> iff
|
||||
// (X <: Y OR X <: Future<Y>) AND
|
||||
// (X <: Y OR Future<X> <: Y) iff
|
||||
// X <: Y OR (X <: Future<Y> AND Future<X> <: Y)
|
||||
return performNullabilityAwareSubtypeCheck(subtypeArg, supertypeArg)
|
||||
.or(performNullabilityAwareSubtypeCheck(subtypeArg,
|
||||
futureType(supertypeArg, Nullability.nonNullable))
|
||||
.andSubtypeCheckFor(
|
||||
futureType(subtypeArg, Nullability.nonNullable),
|
||||
supertypeArg,
|
||||
this))
|
||||
.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype.withNullability(subtypeNullability),
|
||||
supertype.withNullability(supertypeNullability),
|
||||
futureOrClass));
|
||||
}
|
||||
|
||||
// given t1 is Future<A> | A, then:
|
||||
// (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
|
||||
return performNullabilityAwareSubtypeCheck(subtypeArg, supertype)
|
||||
.andSubtypeCheckFor(
|
||||
futureType(subtypeArg, Nullability.nonNullable), supertype, this)
|
||||
.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass));
|
||||
}
|
||||
|
||||
if (supertype is InterfaceType && supertype.classNode == objectClass) {
|
||||
assert(supertype.nullability == Nullability.nonNullable);
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass);
|
||||
}
|
||||
|
||||
if (supertype is InterfaceType &&
|
||||
identical(supertype.classNode, futureOrClass)) {
|
||||
// given t2 is Future<A> | A, then:
|
||||
// t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
|
||||
Nullability unitedNullability =
|
||||
computeNullabilityOfFutureOr(supertype, futureOrClass);
|
||||
DartType supertypeArg = supertype.typeArguments[0];
|
||||
DartType supertypeFuture = futureType(supertypeArg, unitedNullability);
|
||||
return performNullabilityAwareSubtypeCheck(subtype, supertypeFuture)
|
||||
.orSubtypeCheckFor(
|
||||
subtype, supertypeArg.withNullability(unitedNullability), this);
|
||||
}
|
||||
|
||||
if (subtype is InterfaceType && supertype is InterfaceType) {
|
||||
Class supertypeClass = supertype.classNode;
|
||||
List<DartType> upcastTypeArguments =
|
||||
getTypeArgumentsAsInstanceOf(subtype, supertypeClass);
|
||||
if (upcastTypeArguments == null) return const IsSubtypeOf.never();
|
||||
IsSubtypeOf result = const IsSubtypeOf.always();
|
||||
for (int i = 0; i < upcastTypeArguments.length; ++i) {
|
||||
// Termination: the 'supertype' parameter decreases in size.
|
||||
int variance = supertypeClass.typeParameters[i].variance;
|
||||
DartType leftType = upcastTypeArguments[i];
|
||||
DartType rightType = supertype.typeArguments[i];
|
||||
if (variance == Variance.contravariant) {
|
||||
result = result
|
||||
.and(performNullabilityAwareSubtypeCheck(rightType, leftType));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
} else if (variance == Variance.invariant) {
|
||||
result = result.and(
|
||||
performNullabilityAwareMutualSubtypesCheck(leftType, rightType));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
} else {
|
||||
result = result
|
||||
.and(performNullabilityAwareSubtypeCheck(leftType, rightType));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass));
|
||||
}
|
||||
if (subtype is TypeParameterType) {
|
||||
if (supertype is TypeParameterType) {
|
||||
IsSubtypeOf result = const IsSubtypeOf.always();
|
||||
if (subtype.parameter == supertype.parameter) {
|
||||
if (supertype.promotedBound != null) {
|
||||
return performNullabilityAwareSubtypeCheck(
|
||||
subtype,
|
||||
new TypeParameterType(supertype.parameter,
|
||||
supertype.typeParameterTypeNullability))
|
||||
.andSubtypeCheckFor(subtype, supertype.bound, this);
|
||||
} else {
|
||||
// Promoted bound should always be a subtype of the declared bound.
|
||||
// TODO(dmitryas): Use the following assertion when type promotion
|
||||
// is updated.
|
||||
// assert(subtype.promotedBound == null ||
|
||||
// performNullabilityAwareSubtypeCheck(
|
||||
// subtype.bound, supertype.bound)
|
||||
// .isSubtypeWhenUsingNullabilities());
|
||||
assert(subtype.promotedBound == null ||
|
||||
performNullabilityAwareSubtypeCheck(
|
||||
subtype.bound, supertype.bound)
|
||||
.isSubtypeWhenIgnoringNullabilities());
|
||||
result = const IsSubtypeOf.always();
|
||||
}
|
||||
} else {
|
||||
result =
|
||||
performNullabilityAwareSubtypeCheck(subtype.bound, supertype);
|
||||
}
|
||||
if (subtype.nullability == Nullability.undetermined &&
|
||||
supertype.nullability == Nullability.undetermined) {
|
||||
// The two nullabilities are undetermined, but are connected via
|
||||
// additional constraint, namely that they will be equal at run time.
|
||||
return result;
|
||||
}
|
||||
return result.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass));
|
||||
}
|
||||
// Termination: if there are no cyclically bound type parameters, this
|
||||
// recursive call can only occur a finite number of times, before reaching
|
||||
// a shrinking recursive call (or terminating).
|
||||
return performNullabilityAwareSubtypeCheck(subtype.bound, supertype).and(
|
||||
new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass));
|
||||
}
|
||||
if (subtype is FunctionType) {
|
||||
if (supertype is InterfaceType && supertype.classNode == functionClass) {
|
||||
return new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass);
|
||||
}
|
||||
if (supertype is FunctionType) {
|
||||
return _performNullabilityAwareFunctionSubtypeCheck(subtype, supertype);
|
||||
}
|
||||
}
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
|
||||
IsSubtypeOf performNullabilityAwareMutualSubtypesCheck(
|
||||
DartType type1, DartType type2) {
|
||||
// TODO(dmitryas): Replace it with one recursive descent instead of two.
|
||||
return performNullabilityAwareSubtypeCheck(type1, type2)
|
||||
.andSubtypeCheckFor(type2, type1, this);
|
||||
}
|
||||
|
||||
IsSubtypeOf _performNullabilityAwareFunctionSubtypeCheck(
|
||||
FunctionType subtype, FunctionType supertype) {
|
||||
if (subtype.requiredParameterCount > supertype.requiredParameterCount) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
if (subtype.positionalParameters.length <
|
||||
supertype.positionalParameters.length) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
if (subtype.typeParameters.length != supertype.typeParameters.length) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
|
||||
IsSubtypeOf result = const IsSubtypeOf.always();
|
||||
if (subtype.typeParameters.isNotEmpty) {
|
||||
var substitution = <TypeParameter, DartType>{};
|
||||
for (int i = 0; i < subtype.typeParameters.length; ++i) {
|
||||
var subParameter = subtype.typeParameters[i];
|
||||
var superParameter = supertype.typeParameters[i];
|
||||
substitution[subParameter] = new TypeParameterType.forAlphaRenaming(
|
||||
subParameter, superParameter);
|
||||
}
|
||||
for (int i = 0; i < subtype.typeParameters.length; ++i) {
|
||||
var subParameter = subtype.typeParameters[i];
|
||||
var superParameter = supertype.typeParameters[i];
|
||||
var subBound = substitute(subParameter.bound, substitution);
|
||||
// Termination: if there are no cyclically bound type parameters, this
|
||||
// recursive call can only occur a finite number of times before
|
||||
// reaching a shrinking recursive call (or terminating).
|
||||
result = result.and(performNullabilityAwareMutualSubtypesCheck(
|
||||
superParameter.bound, subBound));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
}
|
||||
subtype = substitute(subtype.withoutTypeParameters, substitution);
|
||||
}
|
||||
result = result.and(performNullabilityAwareSubtypeCheck(
|
||||
subtype.returnType, supertype.returnType));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
for (int i = 0; i < supertype.positionalParameters.length; ++i) {
|
||||
var supertypeParameter = supertype.positionalParameters[i];
|
||||
var subtypeParameter = subtype.positionalParameters[i];
|
||||
// Termination: Both types shrink in size.
|
||||
result = result.and(performNullabilityAwareSubtypeCheck(
|
||||
supertypeParameter, subtypeParameter));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
}
|
||||
int subtypeNameIndex = 0;
|
||||
for (NamedType supertypeParameter in supertype.namedParameters) {
|
||||
while (subtypeNameIndex < subtype.namedParameters.length &&
|
||||
subtype.namedParameters[subtypeNameIndex].name !=
|
||||
supertypeParameter.name) {
|
||||
++subtypeNameIndex;
|
||||
}
|
||||
if (subtypeNameIndex == subtype.namedParameters.length) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
NamedType subtypeParameter = subtype.namedParameters[subtypeNameIndex];
|
||||
// Termination: Both types shrink in size.
|
||||
result = result.and(performNullabilityAwareSubtypeCheck(
|
||||
supertypeParameter.type, subtypeParameter.type));
|
||||
if (!result.isSubtypeWhenIgnoringNullabilities()) {
|
||||
return const IsSubtypeOf.never();
|
||||
}
|
||||
}
|
||||
return result.and(new IsSubtypeOf.basedSolelyOnNullabilities(
|
||||
subtype, supertype, futureOrClass));
|
||||
}
|
||||
}
|
||||
|
||||
/// Context object needed for computing `Expression.getStaticType`.
|
||||
///
|
||||
/// The [StaticTypeContext] provides access to the [TypeEnvironment] and the
|
||||
|
|
|
@ -27,18 +27,14 @@ Future<int, String>
|
|||
// [analyzer] STATIC_TYPE_WARNING.WRONG_NUMBER_OF_TYPE_ARGUMENTS
|
||||
// [cfe] Expected 1 type arguments.
|
||||
foo4() async {
|
||||
// [error line 29, column 1]
|
||||
// [cfe] Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
return "String";
|
||||
// ^
|
||||
// [cfe] A value of type 'String' can't be assigned to a variable of type 'FutureOr<invalid-type>'.
|
||||
}
|
||||
|
||||
int
|
||||
// [error line 37, column 1, length 3]
|
||||
// [error line 33, column 1, length 3]
|
||||
// [analyzer] STATIC_TYPE_WARNING.ILLEGAL_ASYNC_RETURN_TYPE
|
||||
foo5() async {
|
||||
// [error line 40, column 1]
|
||||
// [error line 36, column 1]
|
||||
// [cfe] Functions marked 'async' must have a return type assignable to 'Future'.
|
||||
return 3;
|
||||
// ^
|
||||
|
|
|
@ -14,7 +14,5 @@ typedef void G(List<F> l);
|
|||
|
||||
main() {
|
||||
F foo(G g) => g;
|
||||
// ^
|
||||
// [cfe] A value of type 'void Function(List<invalid-type>)' can't be assigned to a variable of type 'void Function(List<void Function(List<invalid-type>)>)'.
|
||||
foo(null);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@ class Foo<T> implements I<T> {
|
|||
// [cfe] Type variables can't be used in static members.
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
|
||||
// ^
|
||||
// [cfe] A value of type 'Foo<String>' can't be assigned to a variable of type 'Foo<invalid-type>'.
|
||||
return new Foo<String>();
|
||||
// ^^^^^^^^^^^^^^^^^
|
||||
// [analyzer] STATIC_TYPE_WARNING.RETURN_OF_INVALID_TYPE
|
||||
|
|
Loading…
Reference in a new issue