CQ. Refactor test type construction to use parseType().
Replace manual type construction utilities in type system tests with a unified string-based type parser. This simplifies test code, improves readability, and enables more expressive type scenarios. Key changes: - Introduce TypeSpecParser and TypeParsingScope to parse types, function types, records, and type parameters from strings. - Add parseType() and related helpers to AbstractTypeSystemTest, replacing ElementsTypesMixin usage. - Remove ElementsTypesMixin and migrate all tests to use parsed types instead of manually constructed TypeImpl instances. - Extend _SpecParser to support: - Promoted type parameter bounds (`T & int`) - Parenthesized vs record types disambiguation - Additional built-in types (InvalidType, UnknownInferredType) - Variance in generic function types - Covariant parameters - Refactor scope construction to use _Scope.forLibraries, reducing duplicated interface/type alias collection logic. - Add standalone materialization flow for type parameters to support parsing in isolation. Impact: - Tests become more declarative and closer to Dart syntax. - Eliminates boilerplate and reduces risk of inconsistencies in manual type construction. - Enables testing of newer type system features (promotion, variance, complex function types) via concise string specs. Change-Id: I85dd0aa88a37142356f14419d0d35350e38b9c8b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/497680 Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import 'package:analyzer/source/line_info.dart';
|
||||
import 'package:analyzer/src/dart/analysis/session.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_schema.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart' as engine;
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
import 'package:analyzer/src/summary2/reference.dart';
|
||||
@@ -116,6 +117,29 @@ class TypeAliasSpec {
|
||||
const TypeAliasSpec(this.header);
|
||||
}
|
||||
|
||||
final class TypeSpecParser {
|
||||
final _Scope _scope;
|
||||
|
||||
TypeSpecParser({
|
||||
required List<LibraryElementImpl> libraries,
|
||||
required List<TypeParameterElementImpl> typeParameters,
|
||||
}) : _scope = _Scope.forLibraries(
|
||||
libraries: libraries,
|
||||
typeParameters: typeParameters,
|
||||
);
|
||||
|
||||
TypeImpl parse(String input) {
|
||||
return _SpecParser.parseType(input).materialize(_scope);
|
||||
}
|
||||
|
||||
List<TypeParameterElementImpl> parseTypeParameters(String input) {
|
||||
var declarations = _TypeParameterDeclarations(
|
||||
_SpecParser.parseTypeParameters(input),
|
||||
);
|
||||
return declarations.materializeStandalone(_Scope.child(_scope));
|
||||
}
|
||||
}
|
||||
|
||||
class _ClassDeclaration {
|
||||
final ClassSpec spec;
|
||||
|
||||
@@ -348,7 +372,7 @@ class _FormalParameterDeclaration {
|
||||
name: parsed.name,
|
||||
nameOffset: 0,
|
||||
parameterKind: parsed.kind,
|
||||
);
|
||||
)..isExplicitlyCovariant = parsed.isCovariant;
|
||||
}
|
||||
|
||||
void resolve(_Scope scope) {
|
||||
@@ -436,46 +460,19 @@ class _LibraryBuilder {
|
||||
}
|
||||
|
||||
_Scope _scopeFor(LibrarySpec spec) {
|
||||
var interfaces = <String, InterfaceElementImpl>{};
|
||||
var typeAliases = <String, TypeAliasElementImpl>{};
|
||||
|
||||
void addInterfaces(LibraryElementImpl library) {
|
||||
for (var element in library.classes) {
|
||||
interfaces[element.name!] = element;
|
||||
}
|
||||
for (var element in library.enums) {
|
||||
interfaces[element.name!] = element;
|
||||
}
|
||||
for (var element in library.extensionTypes) {
|
||||
interfaces[element.name!] = element;
|
||||
}
|
||||
for (var element in library.mixins) {
|
||||
interfaces[element.name!] = element;
|
||||
}
|
||||
}
|
||||
|
||||
void addTypeAliases(LibraryElementImpl library) {
|
||||
for (var element in library.typeAliases) {
|
||||
typeAliases[element.name!] = element;
|
||||
}
|
||||
}
|
||||
var libraries = <LibraryElementImpl>[];
|
||||
|
||||
for (var importUri in spec.imports) {
|
||||
if (externalLibraries[importUri] case var externalLibrary?) {
|
||||
addInterfaces(externalLibrary);
|
||||
addTypeAliases(externalLibrary);
|
||||
libraries.add(externalLibrary);
|
||||
}
|
||||
if (_libraryElements[importUri] case var builtLibrary?) {
|
||||
addInterfaces(builtLibrary);
|
||||
addTypeAliases(builtLibrary);
|
||||
libraries.add(builtLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
var self = _libraryElements[spec.uri]!;
|
||||
addInterfaces(self);
|
||||
addTypeAliases(self);
|
||||
|
||||
return _Scope.root(interfaces: interfaces, typeAliases: typeAliases);
|
||||
libraries.add(_libraryElements[spec.uri]!);
|
||||
return _Scope.forLibraries(libraries: libraries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,14 +765,16 @@ class _ParsedExtensionTypeHeader {
|
||||
}
|
||||
|
||||
class _ParsedFormalParameter {
|
||||
final bool isCovariant;
|
||||
final ParameterKind kind;
|
||||
final String? name;
|
||||
final _ParsedType type;
|
||||
|
||||
_ParsedFormalParameter({
|
||||
required this.type,
|
||||
required this.name,
|
||||
required this.isCovariant,
|
||||
required this.kind,
|
||||
required this.name,
|
||||
required this.type,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -795,8 +794,7 @@ class _ParsedFunctionType implements _ParsedType {
|
||||
var functionScope = _Scope.child(scope);
|
||||
|
||||
var typeParameters = _TypeParameterDeclarations(this.typeParameters);
|
||||
typeParameters.createFragments();
|
||||
typeParameters.resolve(functionScope);
|
||||
typeParameters.materializeStandalone(functionScope);
|
||||
|
||||
var formalParameters = _FormalParameterDeclarations(this.formalParameters);
|
||||
formalParameters.createFragments();
|
||||
@@ -870,6 +868,26 @@ class _ParsedNullableType implements _ParsedType {
|
||||
}
|
||||
}
|
||||
|
||||
class _ParsedPromotedType implements _ParsedType {
|
||||
final _ParsedType base;
|
||||
final _ParsedType promotedBound;
|
||||
|
||||
_ParsedPromotedType({required this.base, required this.promotedBound});
|
||||
|
||||
@override
|
||||
TypeImpl materialize(_Scope scope) {
|
||||
var baseType = base.materialize(scope);
|
||||
if (baseType is! TypeParameterTypeImpl) {
|
||||
throw StateError('Cannot promote a non-type-parameter type: $baseType');
|
||||
}
|
||||
return TypeParameterTypeImpl(
|
||||
element: baseType.element,
|
||||
nullabilitySuffix: baseType.nullabilitySuffix,
|
||||
promotedBound: promotedBound.materialize(scope),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ParsedRecordType implements _ParsedType {
|
||||
final List<({String name, _ParsedType type})> namedFields;
|
||||
final List<_ParsedType> positionalFields;
|
||||
@@ -949,6 +967,48 @@ class _Scope {
|
||||
: _interfaces = parent._interfaces,
|
||||
_typeAliases = parent._typeAliases;
|
||||
|
||||
factory _Scope.forLibraries({
|
||||
required List<LibraryElementImpl> libraries,
|
||||
List<TypeParameterElementImpl> typeParameters = const [],
|
||||
}) {
|
||||
var interfaces = <String, InterfaceElementImpl>{};
|
||||
var typeAliases = <String, TypeAliasElementImpl>{};
|
||||
|
||||
for (var library in libraries) {
|
||||
for (var element in library.classes) {
|
||||
if (element.name case var name?) {
|
||||
interfaces[name] = element;
|
||||
}
|
||||
}
|
||||
for (var element in library.enums) {
|
||||
if (element.name case var name?) {
|
||||
interfaces[name] = element;
|
||||
}
|
||||
}
|
||||
for (var element in library.extensionTypes) {
|
||||
if (element.name case var name?) {
|
||||
interfaces[name] = element;
|
||||
}
|
||||
}
|
||||
for (var element in library.mixins) {
|
||||
if (element.name case var name?) {
|
||||
interfaces[name] = element;
|
||||
}
|
||||
}
|
||||
for (var element in library.typeAliases) {
|
||||
if (element.name case var name?) {
|
||||
typeAliases[name] = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var scope = _Scope.root(interfaces: interfaces, typeAliases: typeAliases);
|
||||
for (var typeParameter in typeParameters) {
|
||||
scope.addTypeParameter(typeParameter);
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
/// Creates a root scope containing all known interfaces.
|
||||
_Scope.root({
|
||||
required Map<String, InterfaceElementImpl> interfaces,
|
||||
@@ -1143,6 +1203,7 @@ class _SpecParser {
|
||||
kind = ParameterKind.NAMED_REQUIRED;
|
||||
}
|
||||
|
||||
var isCovariant = _stream.match('covariant');
|
||||
var type = _parseType();
|
||||
|
||||
String? name;
|
||||
@@ -1150,7 +1211,12 @@ class _SpecParser {
|
||||
name = _stream.consume();
|
||||
}
|
||||
|
||||
return _ParsedFormalParameter(type: type, name: name, kind: kind);
|
||||
return _ParsedFormalParameter(
|
||||
isCovariant: isCovariant,
|
||||
type: type,
|
||||
name: name,
|
||||
kind: kind,
|
||||
);
|
||||
}
|
||||
|
||||
List<_ParsedFormalParameter> _parseFormalParameters() {
|
||||
@@ -1276,44 +1342,17 @@ class _SpecParser {
|
||||
return _parseTypeParametersRest(context: context);
|
||||
}
|
||||
|
||||
_ParsedType _parsePrimaryType() {
|
||||
if (_stream.peekIs('(')) {
|
||||
return _parseRecordType();
|
||||
}
|
||||
|
||||
var name = _stream.consume();
|
||||
switch (name) {
|
||||
case 'dynamic':
|
||||
return _ParsedExplicitType(type: DynamicTypeImpl.instance);
|
||||
case 'Never':
|
||||
return _ParsedExplicitType(type: NeverTypeImpl.instance);
|
||||
case 'void':
|
||||
return _ParsedExplicitType(type: VoidTypeImpl.instance);
|
||||
}
|
||||
|
||||
var args = <_ParsedType>[];
|
||||
if (_stream.match('<')) {
|
||||
while (!_stream.isAtEnd && !_stream.peekIs('>')) {
|
||||
args.add(_parseType());
|
||||
_stream.match(',');
|
||||
}
|
||||
_stream.expect('>');
|
||||
}
|
||||
return _ParsedNamedType(name: name, args: args);
|
||||
}
|
||||
|
||||
_ParsedRecordType _parseRecordType() {
|
||||
_ParsedType _parseParenthesizedOrRecordType() {
|
||||
_stream.expect('(');
|
||||
|
||||
var positionalFields = <_ParsedType>[];
|
||||
var namedFields = <({String name, _ParsedType type})>[];
|
||||
var hasComma = false;
|
||||
|
||||
while (!_stream.isAtEnd && !_stream.peekIsAnyOf(const {')', '{'})) {
|
||||
positionalFields.add(_parseType());
|
||||
if (!_stream.match(',')) {
|
||||
break;
|
||||
}
|
||||
if (_stream.peekIsAnyOf(const {')', '{'})) {
|
||||
hasComma = _stream.match(',');
|
||||
if (!hasComma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1329,34 +1368,82 @@ class _SpecParser {
|
||||
}
|
||||
|
||||
_stream.expect(')');
|
||||
|
||||
// If there is exactly one positional field, no trailing comma, and no
|
||||
// named fields, it is a parenthesized type, not a record type.
|
||||
// Example: `(int)` is parenthesized, but `(int,)` is a record.
|
||||
if (positionalFields.length == 1 && !hasComma && namedFields.isEmpty) {
|
||||
return positionalFields[0];
|
||||
}
|
||||
|
||||
return _ParsedRecordType(
|
||||
positionalFields: positionalFields,
|
||||
namedFields: namedFields,
|
||||
);
|
||||
}
|
||||
|
||||
_ParsedType _parsePrimaryType() {
|
||||
if (_stream.peekIs('(')) {
|
||||
return _parseParenthesizedOrRecordType();
|
||||
}
|
||||
|
||||
var name = _stream.consume();
|
||||
switch (name) {
|
||||
case 'dynamic':
|
||||
return _ParsedExplicitType(type: DynamicTypeImpl.instance);
|
||||
case 'InvalidType':
|
||||
return _ParsedExplicitType(type: InvalidTypeImpl.instance);
|
||||
case 'Never':
|
||||
return _ParsedExplicitType(type: NeverTypeImpl.instance);
|
||||
case 'UnknownInferredType':
|
||||
return _ParsedExplicitType(type: UnknownInferredType.instance);
|
||||
case 'void':
|
||||
return _ParsedExplicitType(type: VoidTypeImpl.instance);
|
||||
}
|
||||
|
||||
var args = <_ParsedType>[];
|
||||
if (_stream.match('<')) {
|
||||
while (!_stream.isAtEnd && !_stream.peekIs('>')) {
|
||||
args.add(_parseType());
|
||||
_stream.match(',');
|
||||
}
|
||||
_stream.expect('>');
|
||||
}
|
||||
return _ParsedNamedType(name: name, args: args);
|
||||
}
|
||||
|
||||
_ParsedType _parseType() {
|
||||
var type = _parsePrimaryType();
|
||||
|
||||
if (_stream.match('Function')) {
|
||||
var typeParameters = _parseOptionalTypeParameters(
|
||||
context: _TypeParameterContext.genericFunctionType,
|
||||
);
|
||||
while (true) {
|
||||
if (_stream.match('?')) {
|
||||
type = _ParsedNullableType(inner: type);
|
||||
continue;
|
||||
}
|
||||
|
||||
_stream.expect('(');
|
||||
var formalParameters = _parseFormalParameters();
|
||||
_stream.expect(')');
|
||||
type = _ParsedFunctionType(
|
||||
returnType: type,
|
||||
formalParameters: formalParameters,
|
||||
typeParameters: typeParameters,
|
||||
);
|
||||
}
|
||||
if (_stream.match('Function')) {
|
||||
var typeParameters = _parseOptionalTypeParameters(
|
||||
context: _TypeParameterContext.genericFunctionType,
|
||||
);
|
||||
|
||||
if (_stream.match('?')) {
|
||||
return _ParsedNullableType(inner: type);
|
||||
_stream.expect('(');
|
||||
var formalParameters = _parseFormalParameters();
|
||||
_stream.expect(')');
|
||||
type = _ParsedFunctionType(
|
||||
returnType: type,
|
||||
formalParameters: formalParameters,
|
||||
typeParameters: typeParameters,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_stream.match('&')) {
|
||||
type = _ParsedPromotedType(base: type, promotedBound: _parseType());
|
||||
continue;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
_ParsedTypeAliasHeader _parseTypeAliasHeader() {
|
||||
@@ -1466,10 +1553,32 @@ class _SpecParser {
|
||||
)._parseExecutableHeader(_ExecutableHeaderContext.topLevelFunction);
|
||||
}
|
||||
|
||||
static _ParsedType parseType(String input) {
|
||||
var parser = _SpecParser._(input);
|
||||
var type = parser._parseType();
|
||||
parser._expectEnd('Unexpected trailing tokens in type.');
|
||||
return type;
|
||||
}
|
||||
|
||||
static _ParsedTypeAliasHeader parseTypeAliasHeader(String input) {
|
||||
return _SpecParser._(input)._parseTypeAliasHeader();
|
||||
}
|
||||
|
||||
static List<_ParsedTypeParameter> parseTypeParameters(String input) {
|
||||
input = input.trim();
|
||||
if (!input.startsWith('<')) {
|
||||
input = '<$input>';
|
||||
}
|
||||
|
||||
var parser = _SpecParser._(input);
|
||||
parser._stream.expect('<');
|
||||
var typeParameters = parser._parseTypeParametersRest(
|
||||
context: _TypeParameterContext.classDeclaration,
|
||||
);
|
||||
parser._expectEnd('Unexpected trailing tokens in type parameters.');
|
||||
return typeParameters;
|
||||
}
|
||||
|
||||
static Variance? _varianceForKeyword(String keyword) {
|
||||
switch (keyword) {
|
||||
case 'out':
|
||||
@@ -1485,7 +1594,7 @@ class _SpecParser {
|
||||
|
||||
class _TokenStream {
|
||||
static final RegExp _tokenizer = RegExp(
|
||||
r'[a-zA-Z_]\w*|<|>|\+|-|\*|/|%|~|&|\||\^|,|\?|\(|\)|\{|\}|\[|\]|=|;',
|
||||
r'[$a-zA-Z_][$\w]*|<|>|\+|-|\*|/|%|~|&|\||\^|,|\?|\(|\)|\{|\}|\[|\]|=|;',
|
||||
);
|
||||
|
||||
final List<String> _tokens;
|
||||
@@ -1612,7 +1721,7 @@ class _TypeAliasDeclaration {
|
||||
enum _TypeParameterContext {
|
||||
classDeclaration(allowsVariance: true),
|
||||
extensionTypeDeclaration(allowsVariance: true),
|
||||
genericFunctionType(allowsVariance: false),
|
||||
genericFunctionType(allowsVariance: true),
|
||||
methodDeclaration(allowsVariance: false),
|
||||
mixinDeclaration(allowsVariance: true),
|
||||
topLevelFunctionDeclaration(allowsVariance: false),
|
||||
@@ -1625,13 +1734,16 @@ enum _TypeParameterContext {
|
||||
|
||||
class _TypeParameterDeclaration {
|
||||
final _ParsedTypeParameter parsed;
|
||||
|
||||
late final TypeParameterFragmentImpl fragment;
|
||||
|
||||
_TypeParameterDeclaration(this.parsed);
|
||||
|
||||
TypeParameterElementImpl get element => fragment.element;
|
||||
|
||||
void createElement() {
|
||||
TypeParameterElementImpl(firstFragment: fragment);
|
||||
}
|
||||
|
||||
TypeParameterFragmentImpl createFragment() {
|
||||
return fragment = TypeParameterFragmentImpl(name: parsed.name);
|
||||
}
|
||||
@@ -1658,12 +1770,25 @@ class _TypeParameterDeclarations {
|
||||
for (var declaration in _declarations) declaration.element,
|
||||
];
|
||||
|
||||
void createElements() {
|
||||
for (var declaration in _declarations) {
|
||||
declaration.createElement();
|
||||
}
|
||||
}
|
||||
|
||||
List<TypeParameterFragmentImpl> createFragments() {
|
||||
return [
|
||||
for (var declaration in _declarations) declaration.createFragment(),
|
||||
];
|
||||
}
|
||||
|
||||
List<TypeParameterElementImpl> materializeStandalone(_Scope scope) {
|
||||
createFragments();
|
||||
createElements();
|
||||
resolve(scope);
|
||||
return elements;
|
||||
}
|
||||
|
||||
void resolve(_Scope scope) {
|
||||
for (var declaration in _declarations) {
|
||||
scope.addTypeParameter(declaration.element);
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
|
||||
// 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.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type_schema.dart';
|
||||
import 'package:analyzer/src/generated/utilities_dart.dart';
|
||||
|
||||
mixin ElementsTypesMixin {
|
||||
InterfaceTypeImpl get boolNone {
|
||||
var element = typeProvider.boolElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get boolQuestion {
|
||||
var element = typeProvider.boolElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get doubleNone {
|
||||
var element = typeProvider.doubleElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get doubleQuestion {
|
||||
var element = typeProvider.doubleElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
TypeImpl get dynamicType => DynamicTypeImpl.instance;
|
||||
|
||||
InterfaceTypeImpl get functionNone {
|
||||
var element = typeProvider.functionElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get functionQuestion {
|
||||
var element = typeProvider.functionElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get intNone {
|
||||
var element = typeProvider.intElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get intQuestion {
|
||||
var element = typeProvider.intElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
TypeImpl get invalidType => InvalidTypeImpl.instance;
|
||||
|
||||
NeverTypeImpl get neverNone => NeverTypeImpl.instance;
|
||||
|
||||
NeverTypeImpl get neverQuestion => NeverTypeImpl.instanceNullable;
|
||||
|
||||
InterfaceTypeImpl get nullNone {
|
||||
var element = typeProvider.nullElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get numNone {
|
||||
var element = typeProvider.numElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get numQuestion {
|
||||
var element = typeProvider.numElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get objectNone {
|
||||
var element = typeProvider.objectElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get objectQuestion {
|
||||
var element = typeProvider.objectElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get recordNone {
|
||||
var element = typeProvider.recordElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get stringNone {
|
||||
var element = typeProvider.stringElement;
|
||||
return interfaceTypeNone(element);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl get stringQuestion {
|
||||
var element = typeProvider.stringElement;
|
||||
return interfaceTypeQuestion(element);
|
||||
}
|
||||
|
||||
LibraryElementImpl get testLibrary => throw UnimplementedError();
|
||||
|
||||
TypeProviderImpl get typeProvider;
|
||||
|
||||
TypeImpl get unknownInferredType => UnknownInferredType.instance;
|
||||
|
||||
VoidTypeImpl get voidNone => VoidTypeImpl.instance;
|
||||
|
||||
InterfaceTypeImpl comparableNone(TypeImpl type) {
|
||||
var coreLibrary = typeProvider.intElement.library;
|
||||
var element = coreLibrary.getClass('Comparable')!;
|
||||
return element.instantiateImpl(
|
||||
typeArguments: [type],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl comparableQuestion(TypeImpl type) {
|
||||
var coreLibrary = typeProvider.intElement.library;
|
||||
var element = coreLibrary.getClass('Comparable')!;
|
||||
return element.instantiateImpl(
|
||||
typeArguments: [type],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypeImpl functionType({
|
||||
required List<TypeParameterElementImpl> typeParameters,
|
||||
required List<FormalParameterElementImpl> formalParameters,
|
||||
required TypeImpl returnType,
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
}) {
|
||||
return FunctionTypeImpl.v2(
|
||||
typeParameters: typeParameters,
|
||||
formalParameters: formalParameters,
|
||||
returnType: returnType,
|
||||
nullabilitySuffix: nullabilitySuffix,
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypeImpl functionTypeNone({
|
||||
List<TypeParameterElementImpl> typeParameters = const [],
|
||||
List<FormalParameterElementImpl> formalParameters = const [],
|
||||
required TypeImpl returnType,
|
||||
}) {
|
||||
return functionType(
|
||||
typeParameters: typeParameters,
|
||||
formalParameters: formalParameters,
|
||||
returnType: returnType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypeImpl functionTypeQuestion({
|
||||
List<TypeParameterElementImpl> typeParameters = const [],
|
||||
List<FormalParameterElementImpl> formalParameters = const [],
|
||||
required TypeImpl returnType,
|
||||
}) {
|
||||
return functionType(
|
||||
typeParameters: typeParameters,
|
||||
formalParameters: formalParameters,
|
||||
returnType: returnType,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl futureNone(TypeImpl type) {
|
||||
return typeProvider.futureElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl futureOrNone(TypeImpl type) {
|
||||
return typeProvider.futureOrElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl futureOrQuestion(TypeImpl type) {
|
||||
return typeProvider.futureOrElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl futureQuestion(TypeImpl type) {
|
||||
return typeProvider.futureElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl interfaceTypeNone(
|
||||
InterfaceElementImpl element, {
|
||||
List<TypeImpl> typeArguments = const [],
|
||||
}) {
|
||||
return element.instantiateImpl(
|
||||
typeArguments: typeArguments,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl interfaceTypeQuestion(
|
||||
InterfaceElementImpl element, {
|
||||
List<TypeImpl> typeArguments = const [],
|
||||
}) {
|
||||
return element.instantiateImpl(
|
||||
typeArguments: typeArguments,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl iterableNone(TypeImpl type) {
|
||||
return typeProvider.iterableElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl iterableQuestion(TypeImpl type) {
|
||||
return typeProvider.iterableElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl listNone(TypeImpl type) {
|
||||
return typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl listQuestion(TypeImpl type) {
|
||||
return typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: <TypeImpl>[type],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl mapNone(TypeImpl key, TypeImpl value) {
|
||||
return typeProvider.mapElement.instantiateImpl(
|
||||
typeArguments: [key, value],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl mapQuestion(TypeImpl key, TypeImpl value) {
|
||||
return typeProvider.mapElement.instantiateImpl(
|
||||
typeArguments: [key, value],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
FormalParameterElementImpl namedParameter({
|
||||
required String name,
|
||||
required TypeImpl type,
|
||||
bool isCovariant = false,
|
||||
}) {
|
||||
var fragment = FormalParameterFragmentImpl(
|
||||
name: name,
|
||||
nameOffset: 0,
|
||||
parameterKind: ParameterKind.NAMED,
|
||||
);
|
||||
fragment.isExplicitlyCovariant = isCovariant;
|
||||
return FormalParameterElementImpl(fragment)..type = type;
|
||||
}
|
||||
|
||||
FormalParameterElementImpl namedRequiredParameter({
|
||||
required String name,
|
||||
required TypeImpl type,
|
||||
bool isCovariant = false,
|
||||
}) {
|
||||
var fragment = FormalParameterFragmentImpl(
|
||||
name: name,
|
||||
nameOffset: 0,
|
||||
parameterKind: ParameterKind.NAMED_REQUIRED,
|
||||
);
|
||||
fragment.isExplicitlyCovariant = isCovariant;
|
||||
return FormalParameterElementImpl(fragment)..type = type;
|
||||
}
|
||||
|
||||
FormalParameterElementImpl positionalParameter({
|
||||
String? name,
|
||||
required TypeImpl type,
|
||||
bool isCovariant = false,
|
||||
}) {
|
||||
var fragment = FormalParameterFragmentImpl(
|
||||
name: name,
|
||||
nameOffset: 0,
|
||||
parameterKind: ParameterKind.POSITIONAL,
|
||||
);
|
||||
fragment.isExplicitlyCovariant = isCovariant;
|
||||
return FormalParameterElementImpl(fragment)..type = type;
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl promotedTypeParameterType({
|
||||
required TypeParameterElementImpl element,
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
required TypeImpl promotedBound,
|
||||
}) {
|
||||
return TypeParameterTypeImpl(
|
||||
element: element,
|
||||
nullabilitySuffix: nullabilitySuffix,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl promotedTypeParameterTypeNone(
|
||||
TypeParameterElementImpl element,
|
||||
TypeImpl promotedBound,
|
||||
) {
|
||||
return promotedTypeParameterType(
|
||||
element: element,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl promotedTypeParameterTypeQuestion(
|
||||
TypeParameterElementImpl element,
|
||||
TypeImpl promotedBound,
|
||||
) {
|
||||
return promotedTypeParameterType(
|
||||
element: element,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
|
||||
RecordTypeImpl recordType({
|
||||
List<TypeImpl> positionalTypes = const [],
|
||||
Map<String, TypeImpl> namedTypes = const {},
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
}) {
|
||||
return RecordTypeImpl(
|
||||
positionalFields: positionalTypes.map((type) {
|
||||
return RecordTypePositionalFieldImpl(type: type);
|
||||
}).toList(),
|
||||
namedFields: namedTypes.entries.map((entry) {
|
||||
return RecordTypeNamedFieldImpl(name: entry.key, type: entry.value);
|
||||
}).toList(),
|
||||
nullabilitySuffix: nullabilitySuffix,
|
||||
);
|
||||
}
|
||||
|
||||
RecordTypeImpl recordTypeNone({
|
||||
List<TypeImpl> positionalTypes = const [],
|
||||
Map<String, TypeImpl> namedTypes = const {},
|
||||
}) {
|
||||
return recordType(
|
||||
positionalTypes: positionalTypes,
|
||||
namedTypes: namedTypes,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
RecordTypeImpl recordTypeQuestion({
|
||||
List<TypeImpl> positionalTypes = const [],
|
||||
Map<String, TypeImpl> namedTypes = const {},
|
||||
}) {
|
||||
return recordType(
|
||||
positionalTypes: positionalTypes,
|
||||
namedTypes: namedTypes,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
}
|
||||
|
||||
FormalParameterElementImpl requiredParameter({
|
||||
String? name,
|
||||
required TypeImpl type,
|
||||
bool isCovariant = false,
|
||||
}) {
|
||||
var fragment = FormalParameterFragmentImpl(
|
||||
name: name,
|
||||
nameOffset: 0,
|
||||
parameterKind: ParameterKind.REQUIRED,
|
||||
);
|
||||
fragment.isExplicitlyCovariant = isCovariant;
|
||||
return FormalParameterElementImpl(fragment)..type = type;
|
||||
}
|
||||
|
||||
TypeImpl typeAliasTypeNone(
|
||||
TypeAliasElementImpl element, {
|
||||
List<TypeImpl> typeArguments = const [],
|
||||
}) {
|
||||
return element.instantiateImpl(
|
||||
typeArguments: typeArguments,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
TypeParameterElementImpl typeParameter(
|
||||
String name, {
|
||||
TypeImpl? bound,
|
||||
Variance? variance,
|
||||
}) {
|
||||
var fragment = TypeParameterFragmentImpl(name: name);
|
||||
|
||||
var element = TypeParameterElementImpl(firstFragment: fragment);
|
||||
element.bound = bound;
|
||||
element.variance = variance;
|
||||
return element;
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl typeParameterType(
|
||||
TypeParameterElementImpl element, {
|
||||
required NullabilitySuffix nullabilitySuffix,
|
||||
TypeImpl? promotedBound,
|
||||
}) {
|
||||
return TypeParameterTypeImpl(
|
||||
element: element,
|
||||
nullabilitySuffix: nullabilitySuffix,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl typeParameterTypeNone(
|
||||
TypeParameterElementImpl element, {
|
||||
TypeImpl? promotedBound,
|
||||
}) {
|
||||
return typeParameterType(
|
||||
element,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl typeParameterTypeQuestion(
|
||||
TypeParameterElementImpl element, {
|
||||
TypeImpl? promotedBound,
|
||||
}) {
|
||||
return typeParameterType(
|
||||
element,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
promotedBound: promotedBound,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,23 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
|
||||
import 'package:analyzer/src/test_utilities/test_library_builder.dart';
|
||||
|
||||
import 'elements_types_mixin.dart';
|
||||
import 'test_analysis_context.dart';
|
||||
|
||||
abstract class AbstractTypeSystemTest with ElementsTypesMixin {
|
||||
abstract class AbstractTypeSystemTest {
|
||||
static const _testLibraryUri = 'package:test/test.dart';
|
||||
|
||||
bool _hasTestLibrary = false;
|
||||
|
||||
late TestAnalysisContext analysisContext;
|
||||
|
||||
@override
|
||||
late LibraryElementImpl testLibrary;
|
||||
|
||||
@override
|
||||
late TypeProviderImpl typeProvider;
|
||||
|
||||
late TypeSystemImpl typeSystem;
|
||||
@@ -73,6 +73,7 @@ abstract class AbstractTypeSystemTest with ElementsTypesMixin {
|
||||
typeAliases: typeAliases,
|
||||
),
|
||||
}, externalLibraries: externalLibraries)[_testLibraryUri]!;
|
||||
_hasTestLibrary = true;
|
||||
return testLibrary;
|
||||
}
|
||||
|
||||
@@ -92,8 +93,43 @@ abstract class AbstractTypeSystemTest with ElementsTypesMixin {
|
||||
return testLibrary.getMixin(name)!;
|
||||
}
|
||||
|
||||
FunctionTypeImpl parseFunctionType(
|
||||
String input, {
|
||||
List<LibraryElementImpl>? libraries,
|
||||
}) {
|
||||
return _typeParsingScope(libraries: libraries).parseFunctionType(input);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl parseInterfaceType(
|
||||
String input, {
|
||||
List<LibraryElementImpl>? libraries,
|
||||
}) {
|
||||
return _typeParsingScope(libraries: libraries).parseInterfaceType(input);
|
||||
}
|
||||
|
||||
RecordTypeImpl parseRecordType(
|
||||
String input, {
|
||||
List<LibraryElementImpl>? libraries,
|
||||
}) {
|
||||
return _typeParsingScope(libraries: libraries).parseRecordType(input);
|
||||
}
|
||||
|
||||
TypeImpl parseType(String input, {List<LibraryElementImpl>? libraries}) {
|
||||
return _typeParsingScope(libraries: libraries).parseType(input);
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl parseTypeParameterType(
|
||||
String input, {
|
||||
List<LibraryElementImpl>? libraries,
|
||||
}) {
|
||||
return _typeParsingScope(
|
||||
libraries: libraries,
|
||||
).parseTypeParameterType(input);
|
||||
}
|
||||
|
||||
void setUp() {
|
||||
analysisContext = TestAnalysisContext();
|
||||
_hasTestLibrary = false;
|
||||
typeProvider = analysisContext.typeProvider;
|
||||
typeSystem = analysisContext.typeSystem;
|
||||
typeSystemOperations = TypeSystemOperations(
|
||||
@@ -105,4 +141,99 @@ abstract class AbstractTypeSystemTest with ElementsTypesMixin {
|
||||
TypeAliasElementImpl typeAliasElement(String name) {
|
||||
return testLibrary.getTypeAlias(name)! as TypeAliasElementImpl;
|
||||
}
|
||||
|
||||
R withTypeParameterScope<R>(
|
||||
String spec,
|
||||
R Function(TypeParsingScope scope) operation, {
|
||||
List<LibraryElementImpl>? libraries,
|
||||
List<TypeParameterElementImpl> typeParameters = const [],
|
||||
}) {
|
||||
return _typeParsingScope(
|
||||
libraries: libraries,
|
||||
typeParameters: typeParameters,
|
||||
).withTypeParameterScope(spec, operation);
|
||||
}
|
||||
|
||||
TypeParsingScope _typeParsingScope({
|
||||
List<LibraryElementImpl>? libraries,
|
||||
List<TypeParameterElementImpl> typeParameters = const [],
|
||||
}) {
|
||||
return TypeParsingScope(
|
||||
libraries:
|
||||
libraries ??
|
||||
[
|
||||
analysisContext.coreLibrary,
|
||||
analysisContext.asyncLibrary,
|
||||
if (_hasTestLibrary) testLibrary,
|
||||
],
|
||||
typeParameters: typeParameters,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses test type specs against a fixed library and type-parameter scope.
|
||||
class TypeParsingScope {
|
||||
final List<LibraryElementImpl> _libraries;
|
||||
final List<TypeParameterElementImpl> _typeParameters;
|
||||
|
||||
TypeParsingScope({
|
||||
required List<LibraryElementImpl> libraries,
|
||||
required List<TypeParameterElementImpl> typeParameters,
|
||||
}) : _libraries = List.unmodifiable(libraries),
|
||||
_typeParameters = List.unmodifiable(typeParameters);
|
||||
|
||||
FunctionTypeImpl parseFunctionType(String input) {
|
||||
return parseType(input);
|
||||
}
|
||||
|
||||
InterfaceTypeImpl parseInterfaceType(String input) {
|
||||
return parseType(input);
|
||||
}
|
||||
|
||||
RecordTypeImpl parseRecordType(String input) {
|
||||
return parseType(input);
|
||||
}
|
||||
|
||||
T parseType<T extends TypeImpl>(String input) {
|
||||
var type = TypeSpecParser(
|
||||
libraries: _libraries,
|
||||
typeParameters: _typeParameters,
|
||||
).parse(input);
|
||||
|
||||
if (type is T) {
|
||||
return type;
|
||||
}
|
||||
throw StateError('Expected $T for "$input", got: $type');
|
||||
}
|
||||
|
||||
TypeParameterTypeImpl parseTypeParameterType(String input) {
|
||||
return parseType(input);
|
||||
}
|
||||
|
||||
TypeParameterElementImpl typeParameter(String name) {
|
||||
for (var i = _typeParameters.length - 1; i >= 0; i--) {
|
||||
var element = _typeParameters[i];
|
||||
if (element.name == name) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
throw StateError('Unknown type parameter: $name');
|
||||
}
|
||||
|
||||
R withTypeParameterScope<R>(
|
||||
String spec,
|
||||
R Function(TypeParsingScope scope) operation,
|
||||
) {
|
||||
var newTypeParameters = TypeSpecParser(
|
||||
libraries: _libraries,
|
||||
typeParameters: _typeParameters,
|
||||
).parseTypeParameters(spec);
|
||||
|
||||
return operation(
|
||||
TypeParsingScope(
|
||||
libraries: _libraries,
|
||||
typeParameters: [..._typeParameters, ...newTypeParameters],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,14 +30,14 @@ class TryPromoteToTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
promotes(intNone, intNone);
|
||||
promotes(intQuestion, intNone);
|
||||
promotes(parseType('int'), parseType('int'));
|
||||
promotes(parseType('int?'), parseType('int'));
|
||||
|
||||
promotes(numNone, intNone);
|
||||
promotes(numQuestion, intNone);
|
||||
promotes(parseType('num'), parseType('int'));
|
||||
promotes(parseType('num?'), parseType('int'));
|
||||
|
||||
notPromotes(intNone, doubleNone);
|
||||
notPromotes(intNone, intQuestion);
|
||||
notPromotes(parseType('int'), parseType('double'));
|
||||
notPromotes(parseType('int'), parseType('int?'));
|
||||
}
|
||||
|
||||
test_typeParameter() {
|
||||
@@ -49,15 +49,16 @@ class TryPromoteToTest extends AbstractTypeSystemTest {
|
||||
expect(type.getDisplayString(), expected);
|
||||
}
|
||||
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
var T_question = typeParameterTypeQuestion(T);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T_none = scope.parseTypeParameterType('T');
|
||||
var T_question = scope.parseTypeParameterType('T?');
|
||||
|
||||
check(tryPromote(numNone, T_none), 'T & num');
|
||||
check(tryPromote(numQuestion, T_none), 'T & num?');
|
||||
check(tryPromote(parseType('num'), T_none), 'T & num');
|
||||
check(tryPromote(parseType('num?'), T_none), 'T & num?');
|
||||
|
||||
check(tryPromote(numNone, T_question), 'T & num');
|
||||
check(tryPromote(numQuestion, T_question), '(T & num?)?');
|
||||
check(tryPromote(parseType('num'), T_question), 'T & num');
|
||||
check(tryPromote(parseType('num?'), T_question), '(T & num?)?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_twice() {
|
||||
@@ -76,13 +77,15 @@ class TryPromoteToTest extends AbstractTypeSystemTest {
|
||||
expect(type.promotedBound, promotedBound);
|
||||
}
|
||||
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var T_none = scope.parseTypeParameterType('T');
|
||||
|
||||
var T1 = tryPromote(numNone, T_none);
|
||||
check(T1, T, NullabilitySuffix.none, numNone);
|
||||
var T1 = tryPromote(parseType('num'), T_none);
|
||||
check(T1, T, NullabilitySuffix.none, parseType('num'));
|
||||
|
||||
var T2 = tryPromote(intNone, T1);
|
||||
check(T2, T, NullabilitySuffix.none, intNone);
|
||||
var T2 = tryPromote(parseType('int'), T1);
|
||||
check(T2, T, NullabilitySuffix.none, parseType('int'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,51 +18,39 @@ main() {
|
||||
@reflectiveTest
|
||||
class HasTypeParameterReferenceTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_checkFalse(dynamicType);
|
||||
_checkFalse(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_checkFalse(functionTypeNone(returnType: voidNone));
|
||||
_checkFalse(parseType('void Function()'));
|
||||
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
|
||||
_checkTrue(functionTypeNone(returnType: T_none));
|
||||
|
||||
_checkTrue(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: T_none)],
|
||||
),
|
||||
);
|
||||
|
||||
_checkTrue(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [typeParameter('S', bound: T_none)],
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_checkTrue(scope.parseType('T Function()'));
|
||||
_checkTrue(scope.parseType('void Function(T)'));
|
||||
_checkTrue(scope.parseType('void Function<S extends T>()'));
|
||||
});
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_checkFalse(intNone);
|
||||
_checkFalse(intQuestion);
|
||||
_checkFalse(parseType('int'));
|
||||
_checkFalse(parseType('int?'));
|
||||
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
_checkTrue(listNone(T_none));
|
||||
_checkTrue(mapNone(T_none, intNone));
|
||||
_checkTrue(mapNone(intNone, T_none));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_checkTrue(scope.parseType('List<T>'));
|
||||
_checkTrue(scope.parseType('Map<T, int>'));
|
||||
_checkTrue(scope.parseType('Map<int, T>'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter() {
|
||||
var T = typeParameter('T');
|
||||
_checkTrue(typeParameterTypeNone(T));
|
||||
_checkTrue(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_checkTrue(scope.parseType('T'));
|
||||
_checkTrue(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_checkFalse(voidNone);
|
||||
_checkFalse(parseType('void'));
|
||||
}
|
||||
|
||||
void _checkFalse(DartType type) {
|
||||
|
||||
@@ -26,92 +26,85 @@ class IsAlwaysExhaustiveTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_class_bool() {
|
||||
isAlwaysExhaustive(boolNone);
|
||||
isAlwaysExhaustive(boolQuestion);
|
||||
isAlwaysExhaustive(parseType('bool'));
|
||||
isAlwaysExhaustive(parseType('bool?'));
|
||||
}
|
||||
|
||||
test_class_int() {
|
||||
isNotAlwaysExhaustive(intNone);
|
||||
isNotAlwaysExhaustive(intQuestion);
|
||||
isNotAlwaysExhaustive(parseType('int'));
|
||||
isNotAlwaysExhaustive(parseType('int?'));
|
||||
}
|
||||
|
||||
test_class_Null() {
|
||||
isAlwaysExhaustive(nullNone);
|
||||
isAlwaysExhaustive(parseType('Null'));
|
||||
}
|
||||
|
||||
test_class_sealed() {
|
||||
buildTestLibrary(classes: [ClassSpec('sealed class A')]);
|
||||
var A = classElement('A');
|
||||
isAlwaysExhaustive(interfaceTypeNone(A));
|
||||
isAlwaysExhaustive(interfaceTypeQuestion(A));
|
||||
isAlwaysExhaustive(parseType('A'));
|
||||
isAlwaysExhaustive(parseType('A?'));
|
||||
}
|
||||
|
||||
test_enum() {
|
||||
buildTestLibrary(enums: [EnumSpec('enum E')]);
|
||||
var E = enumElement('E');
|
||||
isAlwaysExhaustive(interfaceTypeNone(E));
|
||||
isAlwaysExhaustive(interfaceTypeQuestion(E));
|
||||
isAlwaysExhaustive(parseType('E'));
|
||||
isAlwaysExhaustive(parseType('E?'));
|
||||
}
|
||||
|
||||
test_extensionType() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(bool it)')],
|
||||
);
|
||||
isAlwaysExhaustive(interfaceTypeNone(extensionTypeElement('A')));
|
||||
isAlwaysExhaustive(parseType('A'));
|
||||
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(bool? it)')],
|
||||
);
|
||||
isAlwaysExhaustive(interfaceTypeNone(extensionTypeElement('A')));
|
||||
isAlwaysExhaustive(parseType('A'));
|
||||
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
isNotAlwaysExhaustive(interfaceTypeNone(extensionTypeElement('A')));
|
||||
isNotAlwaysExhaustive(parseType('A'));
|
||||
}
|
||||
|
||||
test_futureOr() {
|
||||
isAlwaysExhaustive(futureOrNone(boolNone));
|
||||
isAlwaysExhaustive(futureOrQuestion(boolNone));
|
||||
isAlwaysExhaustive(parseType('FutureOr<bool>'));
|
||||
isAlwaysExhaustive(parseType('FutureOr<bool>?'));
|
||||
|
||||
isAlwaysExhaustive(futureOrNone(boolQuestion));
|
||||
isAlwaysExhaustive(futureOrQuestion(boolQuestion));
|
||||
isAlwaysExhaustive(parseType('FutureOr<bool?>'));
|
||||
isAlwaysExhaustive(parseType('FutureOr<bool?>?'));
|
||||
|
||||
isNotAlwaysExhaustive(futureOrNone(intNone));
|
||||
isNotAlwaysExhaustive(futureOrQuestion(intNone));
|
||||
isNotAlwaysExhaustive(parseType('FutureOr<int>'));
|
||||
isNotAlwaysExhaustive(parseType('FutureOr<int>?'));
|
||||
}
|
||||
|
||||
test_recordType() {
|
||||
isAlwaysExhaustive(recordTypeNone(positionalTypes: [boolNone]));
|
||||
isAlwaysExhaustive(parseType('(bool,)'));
|
||||
|
||||
isAlwaysExhaustive(recordTypeNone(namedTypes: {'f0': boolNone}));
|
||||
isAlwaysExhaustive(parseType('({bool f0})'));
|
||||
|
||||
isNotAlwaysExhaustive(recordTypeNone(positionalTypes: [intNone]));
|
||||
isNotAlwaysExhaustive(parseType('(int,)'));
|
||||
|
||||
isNotAlwaysExhaustive(recordTypeNone(positionalTypes: [boolNone, intNone]));
|
||||
isNotAlwaysExhaustive(parseType('(bool, int)'));
|
||||
|
||||
isNotAlwaysExhaustive(recordTypeNone(namedTypes: {'f0': intNone}));
|
||||
isNotAlwaysExhaustive(parseType('({int f0})'));
|
||||
|
||||
isNotAlwaysExhaustive(
|
||||
recordTypeNone(namedTypes: {'f0': boolNone, 'f1': intNone}),
|
||||
);
|
||||
isNotAlwaysExhaustive(parseType('({bool f0, int f1})'));
|
||||
}
|
||||
|
||||
test_typeParameter() {
|
||||
isAlwaysExhaustive(
|
||||
typeParameterTypeNone(typeParameter('T', bound: boolNone)),
|
||||
);
|
||||
withTypeParameterScope('T extends bool', (scope) {
|
||||
isAlwaysExhaustive(scope.parseType('T'));
|
||||
});
|
||||
|
||||
isNotAlwaysExhaustive(
|
||||
typeParameterTypeNone(typeParameter('T', bound: numNone)),
|
||||
);
|
||||
withTypeParameterScope('T extends num', (scope) {
|
||||
isNotAlwaysExhaustive(scope.parseType('T'));
|
||||
});
|
||||
|
||||
isAlwaysExhaustive(
|
||||
typeParameterTypeNone(typeParameter('T'), promotedBound: boolNone),
|
||||
);
|
||||
|
||||
isNotAlwaysExhaustive(
|
||||
typeParameterTypeNone(typeParameter('T'), promotedBound: intNone),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isAlwaysExhaustive(scope.parseType('T & bool'));
|
||||
isNotAlwaysExhaustive(scope.parseType('T & int'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,21 +33,21 @@ class IsAssignableToTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamicType() {
|
||||
isAssignable(dynamicType, dynamicType);
|
||||
isAssignable(dynamicType, invalidType);
|
||||
isAssignable(dynamicType, intNone);
|
||||
isAssignable(parseType('dynamic'), parseType('dynamic'));
|
||||
isAssignable(parseType('dynamic'), parseType('InvalidType'));
|
||||
isAssignable(parseType('dynamic'), parseType('int'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
isAssignable(intNone, numNone);
|
||||
isAssignable(doubleNone, numNone);
|
||||
isAssignable(parseType('int'), parseType('num'));
|
||||
isAssignable(parseType('double'), parseType('num'));
|
||||
|
||||
isNotAssignable(numNone, intNone);
|
||||
isNotAssignable(parseType('num'), parseType('int'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isAssignable(invalidType, invalidType);
|
||||
isAssignable(invalidType, dynamicType);
|
||||
isAssignable(invalidType, intNone);
|
||||
isAssignable(parseType('InvalidType'), parseType('InvalidType'));
|
||||
isAssignable(parseType('InvalidType'), parseType('dynamic'));
|
||||
isAssignable(parseType('InvalidType'), parseType('int'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +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.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
|
||||
import 'package:analyzer/dart/constant/value.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
@@ -74,121 +75,72 @@ class FunctionTypeImplTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
void test_getNamedParameterTypes_namedParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: intNone),
|
||||
namedParameter(name: 'b', type: doubleNone),
|
||||
namedParameter(name: 'c', type: stringNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function(int a, {double b, String c})');
|
||||
Map<String, DartType> types = type.namedParameterTypes;
|
||||
expect(types, hasLength(2));
|
||||
expect(types['b'], doubleNone);
|
||||
expect(types['c'], stringNone);
|
||||
expect(types['b'], parseType('double'));
|
||||
expect(types['c'], parseType('String'));
|
||||
}
|
||||
|
||||
void test_getNamedParameterTypes_noNamedParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
requiredParameter(type: intNone),
|
||||
requiredParameter(type: doubleNone),
|
||||
positionalParameter(type: stringNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function(int, double, [String])');
|
||||
Map<String, DartType> types = type.namedParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getNamedParameterTypes_noParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function()');
|
||||
Map<String, DartType> types = type.namedParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getNormalParameterTypes_noNormalParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
positionalParameter(type: intNone),
|
||||
positionalParameter(type: doubleNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function([int, double])');
|
||||
List<DartType> types = type.normalParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getNormalParameterTypes_noParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function()');
|
||||
List<DartType> types = type.normalParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getNormalParameterTypes_normalParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
requiredParameter(type: intNone),
|
||||
requiredParameter(type: doubleNone),
|
||||
positionalParameter(type: stringNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function(int, double, [String])');
|
||||
List<DartType> types = type.normalParameterTypes;
|
||||
expect(types, hasLength(2));
|
||||
expect(types[0], intNone);
|
||||
expect(types[1], doubleNone);
|
||||
expect(types[0], parseType('int'));
|
||||
expect(types[1], parseType('double'));
|
||||
}
|
||||
|
||||
void test_getOptionalParameterTypes_noOptionalParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: intNone),
|
||||
namedParameter(name: 'b', type: doubleNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function(int a, {double b})');
|
||||
List<DartType> types = type.optionalParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getOptionalParameterTypes_noParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function()');
|
||||
List<DartType> types = type.optionalParameterTypes;
|
||||
expect(types, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getOptionalParameterTypes_optionalParameters() {
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [],
|
||||
formalParameters: [
|
||||
requiredParameter(type: intNone),
|
||||
positionalParameter(type: doubleNone),
|
||||
positionalParameter(type: stringNone),
|
||||
],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var type = parseFunctionType('void Function(int, [double, String])');
|
||||
List<DartType> types = type.optionalParameterTypes;
|
||||
expect(types, hasLength(2));
|
||||
expect(types[0], doubleNone);
|
||||
expect(types[1], stringNone);
|
||||
expect(types[0], parseType('double'));
|
||||
expect(types[1], parseType('String'));
|
||||
}
|
||||
|
||||
void test_typeParameters_variance() {
|
||||
var type = parseFunctionType('void Function<in T, inout U, out V>()');
|
||||
var typeParameters = type.typeParameters;
|
||||
expect(typeParameters, hasLength(3));
|
||||
expect(typeParameters[0].variance, Variance.contravariant);
|
||||
expect(typeParameters[1].variance, Variance.invariant);
|
||||
expect(typeParameters[2].variance, Variance.covariant);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,59 +433,89 @@ class B extends A {}
|
||||
@reflectiveTest
|
||||
class TypeParameterTypeImplTest extends AbstractTypeSystemTest {
|
||||
void test_asInstanceOf_hasBound_element() {
|
||||
var T = typeParameter('T', bound: listNone(intNone));
|
||||
_assert_asInstanceOf(
|
||||
typeParameterTypeNone(T),
|
||||
typeProvider.iterableElement,
|
||||
'Iterable<int>',
|
||||
);
|
||||
withTypeParameterScope('T extends List<int>', (scope) {
|
||||
_assert_asInstanceOf(
|
||||
scope.parseType('T'),
|
||||
typeProvider.iterableElement,
|
||||
'Iterable<int>',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void test_asInstanceOf_hasBound_element_noMatch() {
|
||||
var T = typeParameter('T', bound: numNone);
|
||||
_assert_asInstanceOf(
|
||||
typeParameterTypeNone(T),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
withTypeParameterScope('T extends num', (scope) {
|
||||
_assert_asInstanceOf(
|
||||
scope.parseType('T'),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void test_asInstanceOf_hasBound_promoted() {
|
||||
var T = typeParameter('T');
|
||||
_assert_asInstanceOf(
|
||||
typeParameterTypeNone(T, promotedBound: listNone(intNone)),
|
||||
typeProvider.iterableElement,
|
||||
'Iterable<int>',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assert_asInstanceOf(
|
||||
scope.parseType('T & List<int>'),
|
||||
typeProvider.iterableElement,
|
||||
'Iterable<int>',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void test_asInstanceOf_hasBound_promoted_noMatch() {
|
||||
var T = typeParameter('T');
|
||||
_assert_asInstanceOf(
|
||||
typeParameterTypeNone(T, promotedBound: numNone),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assert_asInstanceOf(
|
||||
scope.parseType('T & num'),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void test_asInstanceOf_noBound() {
|
||||
var T = typeParameter('T');
|
||||
_assert_asInstanceOf(
|
||||
typeParameterTypeNone(T),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assert_asInstanceOf(
|
||||
scope.parseType('T'),
|
||||
typeProvider.iterableElement,
|
||||
null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void test_creation() {
|
||||
var element = typeParameter('E');
|
||||
expect(typeParameterTypeNone(element), isNotNull);
|
||||
withTypeParameterScope('E', (scope) {
|
||||
var E = scope.typeParameter('E');
|
||||
expect(E, isNotNull);
|
||||
expect(scope.parseTypeParameterType('E'), isNotNull);
|
||||
});
|
||||
}
|
||||
|
||||
void test_getElement() {
|
||||
var element = typeParameter('E');
|
||||
TypeParameterTypeImpl type = typeParameterTypeNone(element);
|
||||
expect(type.element, element);
|
||||
withTypeParameterScope('E', (scope) {
|
||||
var E = scope.typeParameter('E');
|
||||
TypeParameterTypeImpl type = scope.parseTypeParameterType('E');
|
||||
expect(type.element, E);
|
||||
});
|
||||
}
|
||||
|
||||
void test_parse_promotedBound() {
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var type = scope.parseTypeParameterType('T & int');
|
||||
expect(type.element, same(T));
|
||||
expect(type.promotedBound, parseType('int'));
|
||||
expect(type.getDisplayString(), 'T & int');
|
||||
});
|
||||
}
|
||||
|
||||
void test_parse_promotedBound_question() {
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var type = scope.parseTypeParameterType('(T & int)?');
|
||||
expect(type.element, same(T));
|
||||
expect(type.promotedBound, parseType('int'));
|
||||
expect(type.getDisplayString(), '(T & int)?');
|
||||
});
|
||||
}
|
||||
|
||||
void _assert_asInstanceOf(
|
||||
|
||||
@@ -2,15 +2,11 @@
|
||||
// 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.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/flow_analysis/factory_type_test_helper.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_provider.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:test/test.dart' as test;
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../../generated/elements_types_mixin.dart';
|
||||
import '../../../generated/test_analysis_context.dart';
|
||||
import '../../../generated/type_system_base.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
@@ -19,38 +15,72 @@ main() {
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class FactorTypeTest with FactorTypeTestMixin<TypeImpl>, ElementsTypesMixin {
|
||||
@override
|
||||
late final TypeProviderImpl typeProvider;
|
||||
|
||||
late final TypeSystemImpl typeSystem;
|
||||
|
||||
@override
|
||||
TypeImpl get voidType => typeProvider.voidType;
|
||||
|
||||
@override
|
||||
void expect(
|
||||
TypeImpl T,
|
||||
TypeImpl S,
|
||||
String actualResult,
|
||||
String expectedResult,
|
||||
) {
|
||||
test.expect(actualResult, expectedResult);
|
||||
class FactorTypeTest extends AbstractTypeSystemTest {
|
||||
void check(TypeImpl T, TypeImpl S, String expectedStr) {
|
||||
TypeImpl result = typeSystem.factor(T, S);
|
||||
String resultStr = result.getDisplayString();
|
||||
test.expect(resultStr, expectedStr);
|
||||
}
|
||||
|
||||
@override
|
||||
TypeImpl factor(TypeImpl T, TypeImpl S) {
|
||||
return typeSystem.factor(T, S);
|
||||
void test_dynamic() {
|
||||
check(parseType('dynamic'), parseType('int'), 'dynamic');
|
||||
}
|
||||
|
||||
void setUp() {
|
||||
var analysisContext = TestAnalysisContext();
|
||||
typeProvider = analysisContext.typeProvider;
|
||||
typeSystem = analysisContext.typeSystem;
|
||||
void test_futureOr() {
|
||||
check(parseType('FutureOr<int>'), parseType('int'), 'Future<int>');
|
||||
check(parseType('FutureOr<int>'), parseType('Future<int>'), 'int');
|
||||
|
||||
check(parseType('FutureOr<int?>'), parseType('int'), 'FutureOr<int?>');
|
||||
check(
|
||||
parseType('FutureOr<int?>'),
|
||||
parseType('Future<int>'),
|
||||
'FutureOr<int?>',
|
||||
);
|
||||
check(parseType('FutureOr<int?>'), parseType('int?'), 'Future<int?>');
|
||||
check(parseType('FutureOr<int?>'), parseType('Future<int?>'), 'int?');
|
||||
|
||||
check(parseType('FutureOr<int>'), parseType('num'), 'Future<int>');
|
||||
check(parseType('FutureOr<int>'), parseType('Future<num>'), 'int');
|
||||
}
|
||||
|
||||
@override
|
||||
String typeString(covariant TypeImpl type) {
|
||||
return type.getDisplayString();
|
||||
void test_object() {
|
||||
check(parseType('Object'), parseType('Object'), 'Never');
|
||||
check(parseType('Object'), parseType('Object?'), 'Never');
|
||||
|
||||
check(parseType('Object'), parseType('int'), 'Object');
|
||||
check(parseType('Object'), parseType('int?'), 'Object');
|
||||
|
||||
check(parseType('Object?'), parseType('Object'), 'Never?');
|
||||
check(parseType('Object?'), parseType('Object?'), 'Never');
|
||||
|
||||
check(parseType('Object?'), parseType('int'), 'Object?');
|
||||
check(parseType('Object?'), parseType('int?'), 'Object');
|
||||
}
|
||||
|
||||
void test_subtype() {
|
||||
check(parseType('int'), parseType('int'), 'Never');
|
||||
check(parseType('int'), parseType('int?'), 'Never');
|
||||
|
||||
check(parseType('int?'), parseType('int'), 'Never?');
|
||||
check(parseType('int?'), parseType('int?'), 'Never');
|
||||
|
||||
check(parseType('int'), parseType('num'), 'Never');
|
||||
check(parseType('int'), parseType('num?'), 'Never');
|
||||
|
||||
check(parseType('int?'), parseType('num'), 'Never?');
|
||||
check(parseType('int?'), parseType('num?'), 'Never');
|
||||
|
||||
check(parseType('int'), parseType('Null'), 'int');
|
||||
check(parseType('int?'), parseType('Null'), 'int');
|
||||
|
||||
check(parseType('int'), parseType('String'), 'int');
|
||||
check(parseType('int?'), parseType('String'), 'int?');
|
||||
|
||||
check(parseType('int'), parseType('String?'), 'int');
|
||||
check(parseType('int?'), parseType('String?'), 'int');
|
||||
}
|
||||
|
||||
void test_void() {
|
||||
check(parseType('void'), parseType('int'), 'void');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,94 +20,81 @@ main() {
|
||||
@reflectiveTest
|
||||
class FlattenTypeTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_check(dynamicType, 'dynamic');
|
||||
_check(parseType('dynamic'), 'dynamic');
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_check(intNone, 'int');
|
||||
_check(intQuestion, 'int?');
|
||||
_check(parseType('int'), 'int');
|
||||
_check(parseType('int?'), 'int?');
|
||||
}
|
||||
|
||||
test_interfaceType_none_hasFutureType() {
|
||||
_check(futureNone(intNone), 'int');
|
||||
_check(futureNone(intQuestion), 'int?');
|
||||
_check(parseType('Future<int>'), 'int');
|
||||
_check(parseType('Future<int?>'), 'int?');
|
||||
|
||||
_check(futureQuestion(intNone), 'int?');
|
||||
_check(futureQuestion(intQuestion), 'int?');
|
||||
_check(parseType('Future<int>?'), 'int?');
|
||||
_check(parseType('Future<int?>?'), 'int?');
|
||||
|
||||
_check(futureOrNone(intNone), 'int');
|
||||
_check(futureOrNone(intQuestion), 'int?');
|
||||
_check(parseType('FutureOr<int>'), 'int');
|
||||
_check(parseType('FutureOr<int?>'), 'int?');
|
||||
|
||||
_check(futureOrQuestion(intNone), 'int?');
|
||||
_check(futureOrQuestion(intQuestion), 'int?');
|
||||
_check(parseType('FutureOr<int>?'), 'int?');
|
||||
_check(parseType('FutureOr<int?>?'), 'int?');
|
||||
|
||||
_check(futureOrNone(futureNone(intNone)), 'Future<int>');
|
||||
_check(futureOrNone(futureNone(intQuestion)), 'Future<int?>');
|
||||
_check(parseType('FutureOr<Future<int>>'), 'Future<int>');
|
||||
_check(parseType('FutureOr<Future<int?>>'), 'Future<int?>');
|
||||
|
||||
_check(futureOrQuestion(futureNone(intNone)), 'Future<int>?');
|
||||
_check(futureOrQuestion(futureNone(intQuestion)), 'Future<int?>?');
|
||||
_check(parseType('FutureOr<Future<int>>?'), 'Future<int>?');
|
||||
_check(parseType('FutureOr<Future<int?>>?'), 'Future<int?>?');
|
||||
}
|
||||
|
||||
test_interfaceType_question() {
|
||||
_check(futureQuestion(intNone), 'int?');
|
||||
_check(futureQuestion(intQuestion), 'int?');
|
||||
_check(parseType('Future<int>?'), 'int?');
|
||||
_check(parseType('Future<int?>?'), 'int?');
|
||||
}
|
||||
|
||||
test_typeParameterType_none() {
|
||||
// T extends Future<int>
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: futureNone(intNone))),
|
||||
'int',
|
||||
);
|
||||
withTypeParameterScope('T extends Future<int>', (scope) {
|
||||
_check(scope.parseType('T'), 'int');
|
||||
});
|
||||
|
||||
// T extends FutureOr<int>
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: futureOrNone(intNone))),
|
||||
'int',
|
||||
);
|
||||
withTypeParameterScope('T extends FutureOr<int>', (scope) {
|
||||
_check(scope.parseType('T'), 'int');
|
||||
});
|
||||
|
||||
// T & Future<int>
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T'),
|
||||
promotedBound: futureNone(intNone),
|
||||
),
|
||||
'int',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & Future<int>'), 'int');
|
||||
});
|
||||
|
||||
// T & FutureOr<int>
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T'),
|
||||
promotedBound: futureOrNone(intNone),
|
||||
),
|
||||
'int',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & FutureOr<int>'), 'int');
|
||||
});
|
||||
|
||||
// T extends int
|
||||
_check(typeParameterTypeNone(typeParameter('T', bound: intNone)), 'T');
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_check(scope.parseType('T'), 'T');
|
||||
});
|
||||
|
||||
// T & int
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T'), promotedBound: intNone),
|
||||
'T',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & int'), 'T');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameterType_question() {
|
||||
// T extends Future<int>
|
||||
_check(
|
||||
typeParameterTypeQuestion(typeParameter('T', bound: futureNone(intNone))),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends Future<int>', (scope) {
|
||||
_check(scope.parseType('T?'), 'int?');
|
||||
});
|
||||
|
||||
// T extends FutureOr<int>
|
||||
_check(
|
||||
typeParameterTypeQuestion(
|
||||
typeParameter('T', bound: futureOrNone(intNone)),
|
||||
),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends FutureOr<int>', (scope) {
|
||||
_check(scope.parseType('T?'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_unknownInferredType() {
|
||||
@@ -124,11 +111,11 @@ class FlattenTypeTest extends AbstractTypeSystemTest {
|
||||
@reflectiveTest
|
||||
class FutureTypeTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_check(dynamicType, null);
|
||||
_check(parseType('dynamic'), null);
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_check(functionTypeNone(returnType: voidNone), null);
|
||||
_check(parseType('void Function()'), null);
|
||||
}
|
||||
|
||||
test_implements_Future() {
|
||||
@@ -136,82 +123,71 @@ class FutureTypeTest extends AbstractTypeSystemTest {
|
||||
imports: ['dart:core', 'dart:async'],
|
||||
classes: [ClassSpec('class A implements Future<int>')],
|
||||
);
|
||||
var A = classElement('A');
|
||||
|
||||
_check(interfaceTypeNone(A), 'Future<int>');
|
||||
_check(interfaceTypeQuestion(A), null);
|
||||
_check(parseType('A'), 'Future<int>');
|
||||
_check(parseType('A?'), null);
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_check(objectNone, null);
|
||||
_check(objectQuestion, null);
|
||||
_check(parseType('Object'), null);
|
||||
_check(parseType('Object?'), null);
|
||||
|
||||
_check(intNone, null);
|
||||
_check(intQuestion, null);
|
||||
_check(parseType('int'), null);
|
||||
_check(parseType('int?'), null);
|
||||
|
||||
_check(listNone(intNone), null);
|
||||
_check(listNone(intQuestion), null);
|
||||
_check(parseType('List<int>'), null);
|
||||
_check(parseType('List<int?>'), null);
|
||||
|
||||
_check(listQuestion(intNone), null);
|
||||
_check(listQuestion(intQuestion), null);
|
||||
_check(parseType('List<int>?'), null);
|
||||
_check(parseType('List<int?>?'), null);
|
||||
|
||||
_check(futureNone(intNone), 'Future<int>');
|
||||
_check(futureNone(intQuestion), 'Future<int?>');
|
||||
_check(parseType('Future<int>'), 'Future<int>');
|
||||
_check(parseType('Future<int?>'), 'Future<int?>');
|
||||
|
||||
_check(futureQuestion(intNone), 'Future<int>?');
|
||||
_check(futureQuestion(intQuestion), 'Future<int?>?');
|
||||
_check(parseType('Future<int>?'), 'Future<int>?');
|
||||
_check(parseType('Future<int?>?'), 'Future<int?>?');
|
||||
|
||||
_check(futureOrNone(intNone), 'FutureOr<int>');
|
||||
_check(futureOrNone(intQuestion), 'FutureOr<int?>');
|
||||
_check(parseType('FutureOr<int>'), 'FutureOr<int>');
|
||||
_check(parseType('FutureOr<int?>'), 'FutureOr<int?>');
|
||||
|
||||
_check(futureOrQuestion(intNone), 'FutureOr<int>?');
|
||||
_check(futureOrQuestion(intQuestion), 'FutureOr<int?>?');
|
||||
_check(parseType('FutureOr<int>?'), 'FutureOr<int>?');
|
||||
_check(parseType('FutureOr<int?>?'), 'FutureOr<int?>?');
|
||||
|
||||
_check(futureNone(futureNone(intNone)), 'Future<Future<int>>');
|
||||
_check(futureNone(futureOrNone(intNone)), 'Future<FutureOr<int>>');
|
||||
_check(futureOrNone(futureNone(intNone)), 'FutureOr<Future<int>>');
|
||||
_check(futureOrNone(futureOrNone(intNone)), 'FutureOr<FutureOr<int>>');
|
||||
_check(parseType('Future<Future<int>>'), 'Future<Future<int>>');
|
||||
_check(parseType('Future<FutureOr<int>>'), 'Future<FutureOr<int>>');
|
||||
_check(parseType('FutureOr<Future<int>>'), 'FutureOr<Future<int>>');
|
||||
_check(parseType('FutureOr<FutureOr<int>>'), 'FutureOr<FutureOr<int>>');
|
||||
}
|
||||
|
||||
test_typeParameterType_none() {
|
||||
// T extends Future<int>
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: futureNone(intNone))),
|
||||
'Future<int>',
|
||||
);
|
||||
withTypeParameterScope('T extends Future<int>', (scope) {
|
||||
_check(scope.parseType('T'), 'Future<int>');
|
||||
});
|
||||
|
||||
// T extends FutureOr<int>
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: futureOrNone(intNone))),
|
||||
'FutureOr<int>',
|
||||
);
|
||||
withTypeParameterScope('T extends FutureOr<int>', (scope) {
|
||||
_check(scope.parseType('T'), 'FutureOr<int>');
|
||||
});
|
||||
|
||||
// T & Future<int>
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T'),
|
||||
promotedBound: futureNone(intNone),
|
||||
),
|
||||
'Future<int>',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & Future<int>'), 'Future<int>');
|
||||
});
|
||||
|
||||
// T & FutureOr<int>
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T'),
|
||||
promotedBound: futureOrNone(intNone),
|
||||
),
|
||||
'FutureOr<int>',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & FutureOr<int>'), 'FutureOr<int>');
|
||||
});
|
||||
|
||||
// T extends int
|
||||
_check(typeParameterTypeNone(typeParameter('T', bound: intNone)), null);
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_check(scope.parseType('T'), null);
|
||||
});
|
||||
|
||||
// T & int
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T'), promotedBound: intNone),
|
||||
null,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T & int'), null);
|
||||
});
|
||||
}
|
||||
|
||||
test_unknownInferredType() {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/test_utilities/test_library_builder.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -25,8 +24,6 @@ DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
|
||||
class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
final Map<String, InterfaceTypeImpl> _classTypes = {};
|
||||
|
||||
InterfaceType get intType => typeProvider.intType;
|
||||
|
||||
ClassElement get listElement => typeProvider.listElement;
|
||||
|
||||
ClassElement get mapElement => typeProvider.mapElement;
|
||||
@@ -36,7 +33,7 @@ class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
void basicChecks(
|
||||
FunctionType f, {
|
||||
displayName = 'dynamic Function()',
|
||||
returnType,
|
||||
returnType = 'dynamic',
|
||||
namedParameterTypes = isEmpty,
|
||||
normalParameterNames = isEmpty,
|
||||
normalParameterTypes = isEmpty,
|
||||
@@ -44,28 +41,45 @@ class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
optionalParameterTypes = isEmpty,
|
||||
parameters = isEmpty,
|
||||
typeFormals = isEmpty,
|
||||
typeParameters = isEmpty,
|
||||
}) {
|
||||
// DartType properties
|
||||
expect(f.getDisplayString(), displayName, reason: 'displayName');
|
||||
// FunctionType properties
|
||||
expect(
|
||||
f.namedParameterTypes,
|
||||
f.namedParameterTypes.map((name, type) {
|
||||
return MapEntry(name, _typeStr(type));
|
||||
}),
|
||||
namedParameterTypes,
|
||||
reason: 'namedParameterTypes',
|
||||
);
|
||||
expect(
|
||||
f.normalParameterTypes,
|
||||
f.formalParameters
|
||||
.where((parameter) => parameter.isRequiredPositional)
|
||||
.map((parameter) => parameter.name)
|
||||
.toList(),
|
||||
normalParameterNames,
|
||||
reason: 'normalParameterNames',
|
||||
);
|
||||
expect(
|
||||
f.normalParameterTypes.map(_typeStr).toList(),
|
||||
normalParameterTypes,
|
||||
reason: 'normalParameterTypes',
|
||||
);
|
||||
expect(
|
||||
f.optionalParameterTypes,
|
||||
f.formalParameters
|
||||
.where((parameter) => parameter.isOptionalPositional)
|
||||
.map((parameter) => parameter.name)
|
||||
.toList(),
|
||||
optionalParameterNames,
|
||||
reason: 'optionalParameterNames',
|
||||
);
|
||||
expect(
|
||||
f.optionalParameterTypes.map(_typeStr).toList(),
|
||||
optionalParameterTypes,
|
||||
reason: 'optionalParameterTypes',
|
||||
);
|
||||
expect(f.formalParameters, parameters, reason: 'parameters');
|
||||
expect(f.returnType, returnType ?? same(dynamicType), reason: 'returnType');
|
||||
expect(_typeStr(f.returnType), returnType, reason: 'returnType');
|
||||
expect(f.typeParameters, typeFormals, reason: 'typeFormals');
|
||||
}
|
||||
|
||||
@@ -81,367 +95,160 @@ class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
);
|
||||
|
||||
test_equality_leftRequired_rightPositional() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
positionalParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function(int a)');
|
||||
var f2 = parseFunctionType('void Function([int a])');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_differentName() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'b', type: typeProvider.intType)],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a})');
|
||||
var f2 = parseFunctionType('void Function({int b})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_differentType() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a})');
|
||||
var f2 = parseFunctionType('void Function({double a})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_equal() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: typeProvider.intType),
|
||||
namedParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: typeProvider.intType),
|
||||
namedParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a, double b})');
|
||||
var f2 = parseFunctionType('void Function({int a, double b})');
|
||||
expect(f1, f2);
|
||||
}
|
||||
|
||||
test_equality_namedParameters_extraLeft() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: typeProvider.intType),
|
||||
namedParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a, double b})');
|
||||
var f2 = parseFunctionType('void Function({int a})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_extraRight() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: typeProvider.intType),
|
||||
namedParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a})');
|
||||
var f2 = parseFunctionType('void Function({int a, double b})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_required_left() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedRequiredParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({required int a})');
|
||||
var f2 = parseFunctionType('void Function({int a})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_namedParameters_required_right() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [namedParameter(name: 'a', type: typeProvider.intType)],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
namedRequiredParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function({int a})');
|
||||
var f2 = parseFunctionType('void Function({required int a})');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_requiredParameters_extraLeft() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
requiredParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function(int a, double b)');
|
||||
var f2 = parseFunctionType('void Function(int a)');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_equality_requiredParameters_extraRight() {
|
||||
var f1 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
],
|
||||
);
|
||||
var f2 = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
requiredParameter(name: 'b', type: typeProvider.doubleType),
|
||||
],
|
||||
);
|
||||
var f1 = parseFunctionType('void Function(int a)');
|
||||
var f2 = parseFunctionType('void Function(int a, double b)');
|
||||
expect(f1, isNot(equals(f2)));
|
||||
}
|
||||
|
||||
test_hash_namedParameterOptionality() {
|
||||
_testHashesSometimesDifferPairwise(
|
||||
(i) => (
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [namedParameter(name: 'p$i', type: typeProvider.intType)],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
namedRequiredParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
parseFunctionType('void Function({int p$i})'),
|
||||
parseFunctionType('void Function({required int p$i})'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_nullabilitySuffix() {
|
||||
_testHashesSometimesDifferPairwise((i) {
|
||||
var cType = _classType('C$i');
|
||||
_classType('C$i');
|
||||
return (
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [requiredParameter(name: 'x', type: cType)],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [requiredParameter(name: 'x', type: cType)],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
),
|
||||
parseFunctionType('void Function(C$i x)'),
|
||||
parseFunctionType('void Function(C$i x)?'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_hash_optionalNamedParameterName() {
|
||||
_testHashesSometimesDiffer(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [namedParameter(name: 'p$i', type: typeProvider.intType)],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
(i) => parseFunctionType('void Function({int p$i})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_optionalNamedParameterType() {
|
||||
_testHashesSometimesDiffer(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [namedParameter(name: 'x', type: _classType('C$i'))],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
_testHashesSometimesDiffer((i) {
|
||||
_classType('C$i');
|
||||
return parseFunctionType('void Function({C$i x})');
|
||||
});
|
||||
}
|
||||
|
||||
test_hash_optionalPositionalParameterName() {
|
||||
// Optional parameter names are irrelevant
|
||||
_testHashesAlwaysEqual(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
positionalParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
(i) => parseFunctionType('void Function([int p$i])'),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_optionalPositionalParameterType() {
|
||||
_testHashesAlwaysEqual(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [positionalParameter(name: 'x', type: _classType('C$i'))],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
_testHashesAlwaysEqual((i) {
|
||||
_classType('C$i');
|
||||
return parseFunctionType('void Function([C$i x])');
|
||||
});
|
||||
}
|
||||
|
||||
test_hash_positionalParameterOptionality() {
|
||||
_testHashesSometimesDifferPairwise(
|
||||
(i) => (
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
requiredParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
positionalParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
parseFunctionType('void Function(int p$i)'),
|
||||
parseFunctionType('void Function([int p$i])'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_requiredNamedParameterName() {
|
||||
_testHashesSometimesDiffer(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
namedRequiredParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
(i) => parseFunctionType('void Function({required int p$i})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_requiredNamedParameterType() {
|
||||
_testHashesSometimesDiffer(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
namedRequiredParameter(name: 'x', type: _classType('C$i')),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
_testHashesSometimesDiffer((i) {
|
||||
_classType('C$i');
|
||||
return parseFunctionType('void Function({required C$i x})');
|
||||
});
|
||||
}
|
||||
|
||||
test_hash_requiredPositionalParameterName() {
|
||||
// Required parameter names are irrelevant
|
||||
_testHashesAlwaysEqual(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [
|
||||
requiredParameter(name: 'p$i', type: typeProvider.intType),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
_testHashesAlwaysEqual((i) => parseFunctionType('void Function(int p$i)'));
|
||||
}
|
||||
|
||||
test_hash_requiredPositionalParameterType() {
|
||||
_testHashesAlwaysEqual(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [requiredParameter(name: 'x', type: _classType('C$i'))],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_returnType() {
|
||||
_testHashesSometimesDiffer(
|
||||
(i) => FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: const [],
|
||||
returnType: _classType('C$i'),
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test_hash_typeFormalNames() {
|
||||
_testHashesAlwaysEqual((i) {
|
||||
var t = TypeParameterElementImpl.synthetic(name: 'T$i');
|
||||
var u = TypeParameterElementImpl.synthetic(name: 'U$i');
|
||||
return FunctionTypeImpl(
|
||||
typeParameters: [t, u],
|
||||
parameters: [
|
||||
requiredParameter(
|
||||
name: 'x',
|
||||
type: TypeParameterTypeImpl(
|
||||
element: t,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
),
|
||||
requiredParameter(
|
||||
name: 'y',
|
||||
type: TypeParameterTypeImpl(
|
||||
element: t,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: typeProvider.voidType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
_classType('C$i');
|
||||
return parseFunctionType('void Function(C$i x)');
|
||||
});
|
||||
}
|
||||
|
||||
test_new_sortsNamedParameters() {
|
||||
var f = functionTypeNone(
|
||||
returnType: typeProvider.voidType,
|
||||
formalParameters: [
|
||||
requiredParameter(name: 'a', type: typeProvider.intType),
|
||||
namedParameter(name: 'c', type: typeProvider.intType),
|
||||
namedParameter(name: 'b', type: typeProvider.intType),
|
||||
],
|
||||
test_hash_returnType() {
|
||||
_testHashesSometimesDiffer((i) {
|
||||
_classType('C$i');
|
||||
return parseFunctionType('C$i Function()');
|
||||
});
|
||||
}
|
||||
|
||||
test_hash_typeFormalNames() {
|
||||
_testHashesAlwaysEqual(
|
||||
(i) => parseFunctionType('void Function<T$i, U$i>(T$i x, T$i y)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_new_sortsNamedParameters() {
|
||||
var f = parseFunctionType('void Function(int a, {int c, int b})');
|
||||
var parameters = f.formalParameters;
|
||||
expect(parameters, hasLength(3));
|
||||
expect(parameters[0].name, 'a');
|
||||
@@ -450,145 +257,91 @@ class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_synthetic() {
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: const [],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function()');
|
||||
basicChecks(f);
|
||||
}
|
||||
|
||||
test_synthetic_instantiate() {
|
||||
// T Function<T>(T x)
|
||||
var t = typeParameter('T');
|
||||
var x = requiredParameter(name: 'x', type: typeParameterTypeNone(t));
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: [t],
|
||||
parameters: [x],
|
||||
returnType: typeParameterTypeNone(t),
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('T Function<T>(T x)');
|
||||
FunctionType instantiated = f.instantiate([objectType]);
|
||||
basicChecks(
|
||||
instantiated,
|
||||
displayName: 'Object Function(Object)',
|
||||
returnType: same(objectType),
|
||||
returnType: 'Object',
|
||||
normalParameterNames: ['x'],
|
||||
normalParameterTypes: [same(objectType)],
|
||||
normalParameterTypes: ['Object'],
|
||||
parameters: hasLength(1),
|
||||
);
|
||||
}
|
||||
|
||||
test_synthetic_instantiate_argument_length_mismatch() {
|
||||
// dynamic Function<T>()
|
||||
var t = typeParameter('T');
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: [t],
|
||||
parameters: const [],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function<T>()');
|
||||
expect(() => f.instantiate([]), throwsA(TypeMatcher<ArgumentError>()));
|
||||
}
|
||||
|
||||
test_synthetic_instantiate_no_type_formals() {
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: const [],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function()');
|
||||
expect(f.instantiate([]), same(f));
|
||||
}
|
||||
|
||||
test_synthetic_namedParameter() {
|
||||
var p = namedParameter(name: 'x', type: objectType);
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [p],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function({Object x})');
|
||||
basicChecks(
|
||||
f,
|
||||
displayName: 'dynamic Function({Object x})',
|
||||
namedParameterTypes: {'x': same(objectType)},
|
||||
namedParameterTypes: {'x': 'Object'},
|
||||
parameters: hasLength(1),
|
||||
);
|
||||
expect(f.formalParameters[0].isNamed, isTrue);
|
||||
expect(f.formalParameters[0].name, 'x');
|
||||
expect(f.formalParameters[0].type, same(objectType));
|
||||
expect(_typeStr(f.formalParameters[0].type), 'Object');
|
||||
}
|
||||
|
||||
test_synthetic_normalParameter() {
|
||||
var p = requiredParameter(name: 'x', type: objectType);
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [p],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function(Object x)');
|
||||
basicChecks(
|
||||
f,
|
||||
displayName: 'dynamic Function(Object)',
|
||||
normalParameterNames: ['x'],
|
||||
normalParameterTypes: [same(objectType)],
|
||||
normalParameterTypes: ['Object'],
|
||||
parameters: hasLength(1),
|
||||
);
|
||||
expect(f.formalParameters[0].isRequiredPositional, isTrue);
|
||||
expect(f.formalParameters[0].name, 'x');
|
||||
expect(f.formalParameters[0].type, same(objectType));
|
||||
expect(_typeStr(f.formalParameters[0].type), 'Object');
|
||||
}
|
||||
|
||||
test_synthetic_optionalParameter() {
|
||||
var p = positionalParameter(name: 'x', type: objectType);
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: [p],
|
||||
returnType: dynamicType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('dynamic Function([Object x])');
|
||||
basicChecks(
|
||||
f,
|
||||
displayName: 'dynamic Function([Object])',
|
||||
optionalParameterNames: ['x'],
|
||||
optionalParameterTypes: [same(objectType)],
|
||||
optionalParameterTypes: ['Object'],
|
||||
parameters: hasLength(1),
|
||||
);
|
||||
expect(f.formalParameters[0].isOptionalPositional, isTrue);
|
||||
expect(f.formalParameters[0].name, 'x');
|
||||
expect(f.formalParameters[0].type, same(objectType));
|
||||
expect(_typeStr(f.formalParameters[0].type), 'Object');
|
||||
}
|
||||
|
||||
test_synthetic_returnType() {
|
||||
FunctionType f = FunctionTypeImpl(
|
||||
typeParameters: const [],
|
||||
parameters: const [],
|
||||
returnType: objectType,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
basicChecks(
|
||||
f,
|
||||
displayName: 'Object Function()',
|
||||
returnType: same(objectType),
|
||||
);
|
||||
FunctionType f = parseFunctionType('Object Function()');
|
||||
basicChecks(f, displayName: 'Object Function()', returnType: 'Object');
|
||||
}
|
||||
|
||||
test_synthetic_typeFormals() {
|
||||
var t = typeParameter('T');
|
||||
FunctionType f = FunctionTypeImpl.v2(
|
||||
typeParameters: [t],
|
||||
formalParameters: const [],
|
||||
returnType: typeParameterTypeNone(t),
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
FunctionType f = parseFunctionType('T Function<T>()');
|
||||
var t = f.typeParameters.single;
|
||||
basicChecks(
|
||||
f,
|
||||
displayName: 'T Function<T>()',
|
||||
returnType: typeParameterTypeNone(t),
|
||||
returnType: 'T',
|
||||
typeFormals: [same(t)],
|
||||
);
|
||||
expect((f.returnType as TypeParameterType).element, same(t));
|
||||
}
|
||||
|
||||
InterfaceTypeImpl _classType(String name) {
|
||||
@@ -650,8 +403,9 @@ class FunctionTypeTest extends AbstractTypeSystemTest {
|
||||
for (var i = 1; i < 10; i++) {
|
||||
var (x, y) = generate(i);
|
||||
if (x.hashCode != y.hashCode) return;
|
||||
x = y;
|
||||
}
|
||||
fail('Hashes never differed');
|
||||
}
|
||||
|
||||
String _typeStr(DartType type) => type.getDisplayString();
|
||||
}
|
||||
|
||||
@@ -17,38 +17,34 @@ main() {
|
||||
@reflectiveTest
|
||||
class FutureOrBaseTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_check(dynamicType, 'dynamic');
|
||||
_check(parseType('dynamic'), 'dynamic');
|
||||
}
|
||||
|
||||
test_futureOr() {
|
||||
void check(TypeImpl S, String expected) {
|
||||
_check(futureOrNone(S), expected);
|
||||
}
|
||||
_check(parseType('FutureOr<int>'), 'int');
|
||||
_check(parseType('FutureOr<int?>'), 'int?');
|
||||
|
||||
check(intNone, 'int');
|
||||
check(intQuestion, 'int?');
|
||||
_check(parseType('FutureOr<dynamic>'), 'dynamic');
|
||||
_check(parseType('FutureOr<void>'), 'void');
|
||||
|
||||
check(dynamicType, 'dynamic');
|
||||
check(voidNone, 'void');
|
||||
_check(parseType('FutureOr<Never>'), 'Never');
|
||||
_check(parseType('FutureOr<Never?>'), 'Never?');
|
||||
|
||||
check(neverNone, 'Never');
|
||||
check(neverQuestion, 'Never?');
|
||||
|
||||
check(objectNone, 'Object');
|
||||
check(objectQuestion, 'Object?');
|
||||
_check(parseType('FutureOr<Object>'), 'Object');
|
||||
_check(parseType('FutureOr<Object?>'), 'Object?');
|
||||
}
|
||||
|
||||
test_other() {
|
||||
_check(intNone, 'int');
|
||||
_check(intQuestion, 'int?');
|
||||
_check(parseType('int'), 'int');
|
||||
_check(parseType('int?'), 'int?');
|
||||
|
||||
_check(objectNone, 'Object');
|
||||
_check(objectQuestion, 'Object?');
|
||||
_check(parseType('Object'), 'Object');
|
||||
_check(parseType('Object?'), 'Object?');
|
||||
}
|
||||
|
||||
/// futureValueType(`void`) = `void`.
|
||||
test_void() {
|
||||
_check(voidNone, 'void');
|
||||
_check(parseType('void'), 'void');
|
||||
}
|
||||
|
||||
void _check(TypeImpl T, String expected) {
|
||||
|
||||
@@ -18,73 +18,65 @@ main() {
|
||||
class FutureValueTypeTest extends AbstractTypeSystemTest {
|
||||
/// futureValueType(`dynamic`) = `dynamic`.
|
||||
test_dynamic() {
|
||||
_check(dynamicType, 'dynamic');
|
||||
_check(parseType('dynamic'), 'dynamic');
|
||||
}
|
||||
|
||||
/// futureValueType(Future<`S`>) = `S`, for all `S`.
|
||||
test_future() {
|
||||
void check(TypeImpl S, String expected) {
|
||||
_check(futureNone(S), expected);
|
||||
}
|
||||
_check(parseType('Future<int>'), 'int');
|
||||
_check(parseType('Future<int?>'), 'int?');
|
||||
|
||||
check(intNone, 'int');
|
||||
check(intQuestion, 'int?');
|
||||
_check(parseType('Future<dynamic>'), 'dynamic');
|
||||
_check(parseType('Future<void>'), 'void');
|
||||
|
||||
check(dynamicType, 'dynamic');
|
||||
check(voidNone, 'void');
|
||||
_check(parseType('Future<Never>'), 'Never');
|
||||
_check(parseType('Future<Never?>'), 'Never?');
|
||||
|
||||
check(neverNone, 'Never');
|
||||
check(neverQuestion, 'Never?');
|
||||
|
||||
check(objectNone, 'Object');
|
||||
check(objectQuestion, 'Object?');
|
||||
_check(parseType('Future<Object>'), 'Object');
|
||||
_check(parseType('Future<Object?>'), 'Object?');
|
||||
}
|
||||
|
||||
/// futureValueType(FutureOr<`S`>) = `S`, for all `S`.
|
||||
test_futureOr() {
|
||||
void check(TypeImpl S, String expected) {
|
||||
_check(futureOrNone(S), expected);
|
||||
}
|
||||
_check(parseType('FutureOr<int>'), 'int');
|
||||
_check(parseType('FutureOr<int?>'), 'int?');
|
||||
|
||||
check(intNone, 'int');
|
||||
check(intQuestion, 'int?');
|
||||
_check(parseType('FutureOr<dynamic>'), 'dynamic');
|
||||
_check(parseType('FutureOr<void>'), 'void');
|
||||
|
||||
check(dynamicType, 'dynamic');
|
||||
check(voidNone, 'void');
|
||||
_check(parseType('FutureOr<Never>'), 'Never');
|
||||
_check(parseType('FutureOr<Never?>'), 'Never?');
|
||||
|
||||
check(neverNone, 'Never');
|
||||
check(neverQuestion, 'Never?');
|
||||
|
||||
check(objectNone, 'Object');
|
||||
check(objectQuestion, 'Object?');
|
||||
_check(parseType('FutureOr<Object>'), 'Object');
|
||||
_check(parseType('FutureOr<Object?>'), 'Object?');
|
||||
}
|
||||
|
||||
/// Otherwise, for all `S`, futureValueType(`S`) = `Object?`.
|
||||
test_other() {
|
||||
_check(objectNone, 'Object?');
|
||||
_check(intNone, 'Object?');
|
||||
_check(parseType('Object'), 'Object?');
|
||||
_check(parseType('int'), 'Object?');
|
||||
}
|
||||
|
||||
/// futureValueType(`S?`) = futureValueType(`S`), for all `S`.
|
||||
test_suffix_question() {
|
||||
_check(intQuestion, 'Object?');
|
||||
_check(parseType('int?'), 'Object?');
|
||||
|
||||
_check(futureQuestion(intNone), 'int');
|
||||
_check(futureQuestion(intQuestion), 'int?');
|
||||
_check(parseType('Future<int>?'), 'int');
|
||||
_check(parseType('Future<int?>?'), 'int?');
|
||||
|
||||
_check(futureOrQuestion(intNone), 'int');
|
||||
_check(futureOrQuestion(intQuestion), 'int?');
|
||||
_check(parseType('FutureOr<int>?'), 'int');
|
||||
_check(parseType('FutureOr<int?>?'), 'int?');
|
||||
|
||||
_check(futureQuestion(objectNone), 'Object');
|
||||
_check(futureQuestion(objectQuestion), 'Object?');
|
||||
_check(parseType('Future<Object>?'), 'Object');
|
||||
_check(parseType('Future<Object?>?'), 'Object?');
|
||||
|
||||
_check(futureQuestion(dynamicType), 'dynamic');
|
||||
_check(futureQuestion(voidNone), 'void');
|
||||
_check(parseType('Future<dynamic>?'), 'dynamic');
|
||||
_check(parseType('Future<void>?'), 'void');
|
||||
}
|
||||
|
||||
/// futureValueType(`void`) = `void`.
|
||||
test_void() {
|
||||
_check(voidNone, 'void');
|
||||
_check(parseType('void'), 'void');
|
||||
}
|
||||
|
||||
void _check(TypeImpl T, String expected) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
@@ -29,19 +28,12 @@ main() {
|
||||
class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
|
||||
void test_boundedByAnotherTypeParameter() {
|
||||
// <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
|
||||
var tFrom = typeParameter('TFrom');
|
||||
var tTo = typeParameter(
|
||||
'TTo',
|
||||
bound: iterableNone(typeParameterTypeNone(tFrom)),
|
||||
var cast = parseFunctionType(
|
||||
'TTo Function<TFrom, TTo extends Iterable<TFrom>>(TFrom)',
|
||||
);
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [tFrom, tTo],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(tFrom))],
|
||||
returnType: typeParameterTypeNone(tTo),
|
||||
);
|
||||
_assertTypes(_inferCall(cast, [stringNone]), [
|
||||
stringNone,
|
||||
iterableNone(stringNone),
|
||||
_assertTypes(_inferCall(cast, [parseType('String')]), [
|
||||
parseType('String'),
|
||||
parseType('Iterable<String>'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -59,23 +51,16 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
);
|
||||
|
||||
// class A {}
|
||||
var A = classElement('A');
|
||||
var typeA = interfaceTypeNone(A);
|
||||
|
||||
// class B extends A {}
|
||||
var B = classElement('B');
|
||||
var typeB = interfaceTypeNone(B);
|
||||
var typeB = parseInterfaceType('B');
|
||||
|
||||
// class C<T extends A> { S m<S extends T>(S); }
|
||||
var C = classElement('C');
|
||||
|
||||
// C<Object> cOfObject;
|
||||
var cOfObject = interfaceTypeNone(C, typeArguments: [objectNone]);
|
||||
var cOfObject = parseInterfaceType('C<Object>');
|
||||
// C<A> cOfA;
|
||||
var cOfA = interfaceTypeNone(C, typeArguments: [typeA]);
|
||||
var cOfA = parseInterfaceType('C<A>');
|
||||
// C<B> cOfB;
|
||||
var cOfB = interfaceTypeNone(C, typeArguments: [typeB]);
|
||||
var cOfB = parseInterfaceType('C<B>');
|
||||
// B b;
|
||||
// cOfB.m(b); // infer <B>
|
||||
_assertType(
|
||||
@@ -108,25 +93,15 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
);
|
||||
|
||||
// class A {}
|
||||
var A = classElement('A');
|
||||
var typeA = interfaceTypeNone(A);
|
||||
|
||||
// class B extends A {}
|
||||
var B = classElement('B');
|
||||
var typeB = interfaceTypeNone(B);
|
||||
|
||||
// class C<T extends A> { S m<S extends Iterable<T>>(S); }
|
||||
var C = classElement('C');
|
||||
|
||||
// C<Object> cOfObject;
|
||||
var cOfObject = interfaceTypeNone(C, typeArguments: [objectNone]);
|
||||
var cOfObject = parseInterfaceType('C<Object>');
|
||||
// C<A> cOfA;
|
||||
var cOfA = interfaceTypeNone(C, typeArguments: [typeA]);
|
||||
var cOfA = parseInterfaceType('C<A>');
|
||||
// C<B> cOfB;
|
||||
var cOfB = interfaceTypeNone(C, typeArguments: [typeB]);
|
||||
var cOfB = parseInterfaceType('C<B>');
|
||||
// List<B> b;
|
||||
var listOfB = listNone(typeB);
|
||||
var listOfB = parseType('List<B>');
|
||||
// cOfB.m(b); // infer <B>
|
||||
_assertType(
|
||||
_inferCall2(cOfB.getMethod('m')!.type, [listOfB]),
|
||||
@@ -152,33 +127,23 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
);
|
||||
|
||||
// class A<T extends A<T>>
|
||||
var A = classElement('Cloneable');
|
||||
// class Cloneable<T extends Cloneable<T>>
|
||||
|
||||
// class B extends A<B> {}
|
||||
var B = classElement('B');
|
||||
var typeB = interfaceTypeNone(B);
|
||||
|
||||
// <S extends A<S>>
|
||||
var S = typeParameter('S');
|
||||
var typeS = typeParameterTypeNone(S);
|
||||
S.bound = interfaceTypeNone(A, typeArguments: [typeS]);
|
||||
var typeB = parseInterfaceType('B');
|
||||
|
||||
// (S, S) -> S
|
||||
var clone = functionTypeNone(
|
||||
typeParameters: [S],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeS),
|
||||
requiredParameter(type: typeS),
|
||||
],
|
||||
returnType: typeS,
|
||||
);
|
||||
var clone = parseFunctionType('S Function<S extends Cloneable<S>>(S, S)');
|
||||
_assertTypes(_inferCall(clone, [typeB, typeB]), [typeB]);
|
||||
|
||||
// Something invalid...
|
||||
_assertTypes(_inferCall(clone, [stringNone, numNone], expectError: true), [
|
||||
interfaceTypeNone(A, typeArguments: [objectQuestion]),
|
||||
]);
|
||||
_assertTypes(
|
||||
_inferCall(clone, [
|
||||
parseType('String'),
|
||||
parseType('num'),
|
||||
], expectError: true),
|
||||
[parseInterfaceType('Cloneable<Object?>')],
|
||||
);
|
||||
}
|
||||
|
||||
void test_buildTestLibrary_topLevelFunctionHeader() {
|
||||
@@ -203,360 +168,167 @@ class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
|
||||
/// https://github.com/dart-lang/language/issues/1182#issuecomment-702272641
|
||||
void test_demoteType() {
|
||||
// <T>(T x) -> void
|
||||
var T = typeParameter('T');
|
||||
var rawType = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var rawType = parseFunctionType('void Function<T>(T)');
|
||||
|
||||
var S = typeParameter('S');
|
||||
var S_and_int = typeParameterTypeNone(S, promotedBound: intNone);
|
||||
withTypeParameterScope('S', (scope) {
|
||||
var S = scope.typeParameter('S');
|
||||
var S_and_int = scope.parseTypeParameterType('S & int');
|
||||
|
||||
var inferredTypes = _inferCall(rawType, [S_and_int]);
|
||||
var inferredType = inferredTypes[0] as TypeParameterTypeImpl;
|
||||
expect(inferredType.element, S);
|
||||
expect(inferredType.promotedBound, isNull);
|
||||
var inferredTypes = _inferCall(rawType, [S_and_int]);
|
||||
var inferredType = inferredTypes[0] as TypeParameterTypeImpl;
|
||||
expect(inferredType.element, S);
|
||||
expect(inferredType.promotedBound, isNull);
|
||||
});
|
||||
}
|
||||
|
||||
void test_genericCastFunction() {
|
||||
// <TFrom, TTo>(TFrom) -> TTo
|
||||
var tFrom = typeParameter('TFrom');
|
||||
var tTo = typeParameter('TTo');
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [tFrom, tTo],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(tFrom))],
|
||||
returnType: typeParameterTypeNone(tTo),
|
||||
);
|
||||
_assertTypes(_inferCall(cast, [intNone]), [intNone, dynamicType]);
|
||||
var cast = parseFunctionType('TTo Function<TFrom, TTo>(TFrom)');
|
||||
_assertTypes(_inferCall(cast, [parseType('int')]), [
|
||||
parseType('int'),
|
||||
parseType('dynamic'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_genericCastFunctionWithUpperBound() {
|
||||
// <TFrom, TTo extends TFrom>(TFrom) -> TTo
|
||||
var tFrom = typeParameter('TFrom');
|
||||
var tTo = typeParameter('TTo', bound: typeParameterTypeNone(tFrom));
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [tFrom, tTo],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(tFrom))],
|
||||
returnType: typeParameterTypeNone(tTo),
|
||||
var cast = parseFunctionType(
|
||||
'TTo Function<TFrom, TTo extends TFrom>(TFrom)',
|
||||
);
|
||||
_assertTypes(_inferCall(cast, [intNone]), [intNone, intNone]);
|
||||
_assertTypes(_inferCall(cast, [parseType('int')]), [
|
||||
parseType('int'),
|
||||
parseType('int'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_parameter_contravariantUseUpperBound() {
|
||||
// <T>(T x, void Function(T) y) -> T
|
||||
// Generates constraints int <: T <: num.
|
||||
// Since T is contravariant, choose num.
|
||||
var T = typeParameter('T', variance: Variance.contravariant);
|
||||
var tFunction = functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var numFunction = functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var function = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
requiredParameter(type: tFunction),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
var numFunction = parseFunctionType('void Function(num)');
|
||||
var function = parseFunctionType('T Function<in T>(T, void Function(T))');
|
||||
|
||||
_assertTypes(_inferCall(function, [intNone, numFunction]), [numNone]);
|
||||
_assertTypes(_inferCall(function, [parseType('int'), numFunction]), [
|
||||
parseType('num'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_parameter_covariantUseLowerBound() {
|
||||
// <T>(T x, void Function(T) y) -> T
|
||||
// Generates constraints int <: T <: num.
|
||||
// Since T is covariant, choose int.
|
||||
var T = typeParameter('T', variance: Variance.covariant);
|
||||
var tFunction = functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var numFunction = functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: voidNone,
|
||||
);
|
||||
var function = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
requiredParameter(type: tFunction),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
var numFunction = parseFunctionType('void Function(num)');
|
||||
var function = parseFunctionType('T Function<out T>(T, void Function(T))');
|
||||
|
||||
_assertTypes(_inferCall(function, [intNone, numFunction]), [intNone]);
|
||||
_assertTypes(_inferCall(function, [parseType('int'), numFunction]), [
|
||||
parseType('int'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_parametersToFunctionParam() {
|
||||
// <T>(f(T t)) -> T
|
||||
var T = typeParameter('T');
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
var cast = parseFunctionType('T Function<T>(dynamic Function(T))');
|
||||
_assertTypes(
|
||||
_inferCall(cast, [
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
]),
|
||||
[numNone],
|
||||
_inferCall(cast, [parseFunctionType('dynamic Function(num)')]),
|
||||
[parseType('num')],
|
||||
);
|
||||
}
|
||||
|
||||
void test_parametersUseLeastUpperBound() {
|
||||
// <T>(T x, T y) -> T
|
||||
var T = typeParameter('T');
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(cast, [intNone, doubleNone]), [numNone]);
|
||||
var cast = parseFunctionType('T Function<T>(T, T)');
|
||||
_assertTypes(_inferCall(cast, [parseType('int'), parseType('double')]), [
|
||||
parseType('num'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_parameterTypeUsesUpperBound() {
|
||||
// <T extends num>(T) -> dynamic
|
||||
var T = typeParameter('T', bound: numNone);
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: dynamicType,
|
||||
);
|
||||
_assertTypes(_inferCall(f, [intNone]), [intNone]);
|
||||
var f = parseFunctionType('dynamic Function<T extends num>(T)');
|
||||
_assertTypes(_inferCall(f, [parseType('int')]), [parseType('int')]);
|
||||
}
|
||||
|
||||
void test_returnFunctionWithGenericParameter() {
|
||||
// <T>(T -> T) -> (T -> void)
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: voidNone,
|
||||
),
|
||||
);
|
||||
_assertTypes(
|
||||
_inferCall(f, [
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: intNone,
|
||||
),
|
||||
]),
|
||||
[intNone],
|
||||
);
|
||||
var f = parseFunctionType('void Function(T) Function<T>(T Function(T))');
|
||||
_assertTypes(_inferCall(f, [parseFunctionType('int Function(num)')]), [
|
||||
parseType('int'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_returnFunctionWithGenericParameterAndContext() {
|
||||
// <T>(T -> T) -> (T -> Null)
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: nullNone,
|
||||
),
|
||||
);
|
||||
var f = parseFunctionType('Null Function(T) Function<T>(T Function(T))');
|
||||
_assertTypes(
|
||||
_inferCall(
|
||||
f,
|
||||
[],
|
||||
returnType: functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: intQuestion,
|
||||
),
|
||||
),
|
||||
[numNone],
|
||||
_inferCall(f, [], returnType: parseFunctionType('int? Function(num)')),
|
||||
[parseType('num')],
|
||||
);
|
||||
}
|
||||
|
||||
void test_returnFunctionWithGenericParameterAndReturn() {
|
||||
// <T>(T -> T) -> (T -> T)
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
),
|
||||
);
|
||||
_assertTypes(
|
||||
_inferCall(f, [
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: intNone,
|
||||
),
|
||||
]),
|
||||
[intNone],
|
||||
);
|
||||
var f = parseFunctionType('T Function(T) Function<T>(T Function(T))');
|
||||
_assertTypes(_inferCall(f, [parseFunctionType('int Function(num)')]), [
|
||||
parseType('int'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_returnFunctionWithGenericReturn() {
|
||||
// <T>(T -> T) -> (() -> T)
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: functionTypeNone(returnType: typeParameterTypeNone(T)),
|
||||
);
|
||||
_assertTypes(
|
||||
_inferCall(f, [
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: intNone,
|
||||
),
|
||||
]),
|
||||
[intNone],
|
||||
);
|
||||
var f = parseFunctionType('T Function() Function<T>(T Function(T))');
|
||||
_assertTypes(_inferCall(f, [parseFunctionType('int Function(num)')]), [
|
||||
parseType('int'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_returnTypeFromContext() {
|
||||
// <T>() -> T
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(f, [], returnType: stringNone), [stringNone]);
|
||||
var f = parseFunctionType('T Function<T>()');
|
||||
_assertTypes(_inferCall(f, [], returnType: parseType('String')), [
|
||||
parseType('String'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_returnTypeWithBoundFromContext() {
|
||||
// <T extends num>() -> T
|
||||
var T = typeParameter('T', bound: numNone);
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(f, [], returnType: doubleNone), [doubleNone]);
|
||||
var f = parseFunctionType('T Function<T extends num>()');
|
||||
_assertTypes(_inferCall(f, [], returnType: parseType('double')), [
|
||||
parseType('double'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_returnTypeWithBoundFromInvalidContext() {
|
||||
// <T extends num>() -> T
|
||||
var T = typeParameter('T', bound: numNone);
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(f, [], returnType: stringNone), [neverNone]);
|
||||
var f = parseFunctionType('T Function<T extends num>()');
|
||||
_assertTypes(_inferCall(f, [], returnType: parseType('String')), [
|
||||
parseType('Never'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_unifyParametersToFunctionParam() {
|
||||
// <T>(f(T t), g(T t)) -> T
|
||||
var T = typeParameter('T');
|
||||
var cast = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
),
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
var cast = parseFunctionType(
|
||||
'T Function<T>(dynamic Function(T), dynamic Function(T))',
|
||||
);
|
||||
_assertTypes(
|
||||
_inferCall(cast, [
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: doubleNone)],
|
||||
returnType: dynamicType,
|
||||
),
|
||||
parseFunctionType('dynamic Function(int)'),
|
||||
parseFunctionType('dynamic Function(double)'),
|
||||
]),
|
||||
[neverNone],
|
||||
[parseType('Never')],
|
||||
);
|
||||
}
|
||||
|
||||
void test_unusedReturnTypeIsDynamic() {
|
||||
// <T>() -> T
|
||||
var T = typeParameter('T');
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(f, []), [dynamicType]);
|
||||
var f = parseFunctionType('T Function<T>()');
|
||||
_assertTypes(_inferCall(f, []), [parseType('dynamic')]);
|
||||
}
|
||||
|
||||
void test_unusedReturnTypeWithUpperBound() {
|
||||
// <T extends num>() -> T
|
||||
var T = typeParameter('T', bound: numNone);
|
||||
var f = functionTypeNone(
|
||||
typeParameters: [T],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
_assertTypes(_inferCall(f, []), [numNone]);
|
||||
var f = parseFunctionType('T Function<T extends num>()');
|
||||
_assertTypes(_inferCall(f, []), [parseType('num')]);
|
||||
}
|
||||
|
||||
void _assertType(DartType type, String expected) {
|
||||
|
||||
@@ -26,8 +26,8 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_class_int() {
|
||||
isNotIncompatible(intNone);
|
||||
isNotIncompatible(intQuestion);
|
||||
isNotIncompatible(parseType('int'));
|
||||
isNotIncompatible(parseType('int?'));
|
||||
}
|
||||
|
||||
test_extensionType_implementsFuture() {
|
||||
@@ -39,7 +39,7 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
),
|
||||
],
|
||||
);
|
||||
isNotIncompatible(interfaceTypeNone(extensionTypeElement('A')));
|
||||
isNotIncompatible(parseInterfaceType('A'));
|
||||
}
|
||||
|
||||
test_extensionType_notImplementsFuture() {
|
||||
@@ -47,15 +47,15 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
imports: ['dart:core', 'dart:async'],
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(Future<int> it)')],
|
||||
);
|
||||
isIncompatible(interfaceTypeNone(extensionTypeElement('A')));
|
||||
isIncompatible(parseInterfaceType('A'));
|
||||
}
|
||||
|
||||
test_futureInt() {
|
||||
isNotIncompatible(futureNone(intNone));
|
||||
isNotIncompatible(parseType('Future<int>'));
|
||||
}
|
||||
|
||||
test_futureOrInt() {
|
||||
isNotIncompatible(futureOrNone(intNone));
|
||||
isNotIncompatible(parseType('FutureOr<int>'));
|
||||
}
|
||||
|
||||
test_typeParameter_bound_extensionType_implementsFuture() {
|
||||
@@ -67,11 +67,9 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
),
|
||||
],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
|
||||
isNotIncompatible(
|
||||
typeParameterTypeNone(typeParameter('T', bound: interfaceTypeNone(A))),
|
||||
);
|
||||
withTypeParameterScope('T extends A', (scope) {
|
||||
isNotIncompatible(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_extensionType_notImplementsFuture() {
|
||||
@@ -79,17 +77,15 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
imports: ['dart:core', 'dart:async'],
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(Future<int> it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
|
||||
isIncompatible(
|
||||
typeParameterTypeNone(typeParameter('T', bound: interfaceTypeNone(A))),
|
||||
);
|
||||
withTypeParameterScope('T extends A', (scope) {
|
||||
isIncompatible(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_numNone() {
|
||||
isNotIncompatible(
|
||||
typeParameterTypeNone(typeParameter('T', bound: numNone)),
|
||||
);
|
||||
withTypeParameterScope('T extends num', (scope) {
|
||||
isNotIncompatible(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound_extensionType_implementsFuture() {
|
||||
@@ -104,15 +100,9 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
),
|
||||
],
|
||||
);
|
||||
var N = extensionTypeElement('N');
|
||||
var F = extensionTypeElement('F');
|
||||
|
||||
isNotIncompatible(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T', bound: interfaceTypeNone(N)),
|
||||
promotedBound: interfaceTypeNone(F),
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T extends N', (scope) {
|
||||
isNotIncompatible(scope.parseType('T & F'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound_extensionType_notImplementsFuture() {
|
||||
@@ -120,19 +110,14 @@ class IsIncompatibleWithAwaitTest extends AbstractTypeSystemTest {
|
||||
imports: ['dart:core', 'dart:async'],
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(Future<int> it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
|
||||
isIncompatible(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T'),
|
||||
promotedBound: interfaceTypeNone(A),
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isIncompatible(scope.parseType('T & A'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound_intNone() {
|
||||
isNotIncompatible(
|
||||
typeParameterTypeNone(typeParameter('T'), promotedBound: intNone),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isNotIncompatible(scope.parseType('T & int'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,52 +18,47 @@ main() {
|
||||
@reflectiveTest
|
||||
class IsKnownTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_checkKnown(dynamicType);
|
||||
_checkKnown(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_function() {
|
||||
_checkKnown(functionTypeNone(returnType: voidNone));
|
||||
_checkKnown(parseType('void Function()'));
|
||||
|
||||
_checkUnknown(functionTypeNone(returnType: unknownInferredType));
|
||||
_checkUnknown(parseType('UnknownInferredType Function()'));
|
||||
|
||||
_checkUnknown(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: unknownInferredType)],
|
||||
),
|
||||
);
|
||||
_checkUnknown(parseType('void Function(UnknownInferredType)'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
_checkKnown(intNone);
|
||||
_checkKnown(listNone(intNone));
|
||||
_checkUnknown(listNone(unknownInferredType));
|
||||
_checkKnown(parseType('int'));
|
||||
_checkKnown(parseType('List<int>'));
|
||||
_checkUnknown(parseType('List<UnknownInferredType>'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_checkKnown(neverNone);
|
||||
_checkKnown(parseType('Never'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
_checkKnown(nullNone);
|
||||
_checkKnown(parseType('Null'));
|
||||
}
|
||||
|
||||
test_record() {
|
||||
_checkKnown(recordTypeNone(positionalTypes: [intNone]));
|
||||
_checkKnown(parseRecordType('(int,)'));
|
||||
|
||||
_checkUnknown(recordTypeNone(positionalTypes: [unknownInferredType]));
|
||||
_checkUnknown(parseType('(UnknownInferredType,)'));
|
||||
|
||||
_checkKnown(recordTypeNone(namedTypes: {'x': intNone}));
|
||||
_checkKnown(parseRecordType('({int x})'));
|
||||
|
||||
_checkUnknown(recordTypeNone(namedTypes: {'x': unknownInferredType}));
|
||||
_checkUnknown(parseType('({UnknownInferredType x})'));
|
||||
}
|
||||
|
||||
test_unknownInferredType() {
|
||||
_checkUnknown(unknownInferredType);
|
||||
_checkUnknown(parseType('UnknownInferredType'));
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_checkKnown(voidNone);
|
||||
_checkKnown(parseType('void'));
|
||||
}
|
||||
|
||||
void _checkKnown(DartType type) {
|
||||
|
||||
@@ -17,115 +17,108 @@ main() {
|
||||
|
||||
@reflectiveTest
|
||||
class GreatestClosureTest extends AbstractTypeSystemTest {
|
||||
late final TypeParameterElementImpl T;
|
||||
late final TypeParameterTypeImpl T_none;
|
||||
late final TypeParameterTypeImpl T_question;
|
||||
|
||||
@override
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
|
||||
T = typeParameter('T');
|
||||
T_none = typeParameterTypeNone(T);
|
||||
T_question = typeParameterTypeQuestion(T);
|
||||
}
|
||||
|
||||
test_contravariant() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: T_none)],
|
||||
),
|
||||
greatest: 'void Function(Never)',
|
||||
least: 'void Function(Object?)',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: T_none)],
|
||||
),
|
||||
),
|
||||
greatest: 'void Function(Never) Function()',
|
||||
least: 'void Function(Object?) Function()',
|
||||
);
|
||||
_check(
|
||||
scope.parseType('void Function(T)'),
|
||||
typeParameters: [T],
|
||||
greatest: 'void Function(Never)',
|
||||
least: 'void Function(Object?)',
|
||||
);
|
||||
|
||||
_check(
|
||||
scope.parseType('void Function(T) Function()'),
|
||||
typeParameters: [T],
|
||||
greatest: 'void Function(Never) Function()',
|
||||
least: 'void Function(Object?) Function()',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_covariant() {
|
||||
_check(T_none, greatest: 'Object?', least: 'Never');
|
||||
_check(T_question, greatest: 'Object?', least: 'Never?');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
_check(listNone(T_none), greatest: 'List<Object?>', least: 'List<Never>');
|
||||
_check(
|
||||
scope.parseTypeParameterType('T'),
|
||||
typeParameters: [T],
|
||||
greatest: 'Object?',
|
||||
least: 'Never',
|
||||
);
|
||||
_check(
|
||||
scope.parseTypeParameterType('T?'),
|
||||
typeParameters: [T],
|
||||
greatest: 'Object?',
|
||||
least: 'Never?',
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
returnType: intNone,
|
||||
formalParameters: [requiredParameter(type: T_none)],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
greatest: 'void Function(int Function(Object?))',
|
||||
least: 'void Function(int Function(Never))',
|
||||
);
|
||||
_check(
|
||||
scope.parseType('List<T>'),
|
||||
typeParameters: [T],
|
||||
greatest: 'List<Object?>',
|
||||
least: 'List<Never>',
|
||||
);
|
||||
|
||||
_check(
|
||||
scope.parseType('void Function(int Function(T))'),
|
||||
typeParameters: [T],
|
||||
greatest: 'void Function(int Function(Object?))',
|
||||
least: 'void Function(int Function(Never))',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_function() {
|
||||
// void Function<U extends T>()
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeParameters: [typeParameter('U', bound: T_none)],
|
||||
returnType: voidNone,
|
||||
),
|
||||
greatest: 'Function',
|
||||
least: 'Never',
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(
|
||||
scope.parseType('void Function<U extends T>()'),
|
||||
typeParameters: [scope.typeParameter('T')],
|
||||
greatest: 'Function',
|
||||
least: 'Never',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_unrelated() {
|
||||
_check1(intNone, 'int');
|
||||
_check1(intQuestion, 'int?');
|
||||
withTypeParameterScope('T, U', (scope) {
|
||||
void checkUnchanged(TypeImpl type, String expected) {
|
||||
var T = scope.typeParameter('T');
|
||||
_check(type, typeParameters: [T], greatest: expected, least: expected);
|
||||
}
|
||||
|
||||
_check1(listNone(intNone), 'List<int>');
|
||||
_check1(listQuestion(intNone), 'List<int>?');
|
||||
checkUnchanged(parseType('int'), 'int');
|
||||
checkUnchanged(parseType('int?'), 'int?');
|
||||
|
||||
_check1(objectNone, 'Object');
|
||||
_check1(objectQuestion, 'Object?');
|
||||
checkUnchanged(parseType('List<int>'), 'List<int>');
|
||||
checkUnchanged(parseType('List<int>?'), 'List<int>?');
|
||||
|
||||
_check1(neverNone, 'Never');
|
||||
_check1(neverQuestion, 'Never?');
|
||||
checkUnchanged(parseType('Object'), 'Object');
|
||||
checkUnchanged(parseType('Object?'), 'Object?');
|
||||
|
||||
_check1(dynamicType, 'dynamic');
|
||||
checkUnchanged(parseType('Never'), 'Never');
|
||||
checkUnchanged(parseType('Never?'), 'Never?');
|
||||
|
||||
_check1(
|
||||
functionTypeNone(
|
||||
returnType: stringNone,
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
),
|
||||
'String Function(int)',
|
||||
);
|
||||
checkUnchanged(parseType('dynamic'), 'dynamic');
|
||||
|
||||
_check1(typeParameterTypeNone(typeParameter('U')), 'U');
|
||||
checkUnchanged(parseType('String Function(int)'), 'String Function(int)');
|
||||
|
||||
checkUnchanged(scope.parseType('U'), 'U');
|
||||
});
|
||||
}
|
||||
|
||||
void _check(
|
||||
TypeImpl type, {
|
||||
required List<TypeParameterElementImpl> typeParameters,
|
||||
required String greatest,
|
||||
required String least,
|
||||
}) {
|
||||
var greatestResult = typeSystem.greatestClosure(type, [T]);
|
||||
var greatestResult = typeSystem.greatestClosure(type, typeParameters);
|
||||
expect(greatestResult.getDisplayString(), greatest);
|
||||
|
||||
var leastResult = typeSystem.leastClosure(type, [T]);
|
||||
var leastResult = typeSystem.leastClosure(type, typeParameters);
|
||||
expect(leastResult.getDisplayString(), least);
|
||||
}
|
||||
|
||||
void _check1(TypeImpl type, String expected) {
|
||||
_check(type, greatest: expected, least: expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/least_upper_bound.dart';
|
||||
import 'package:analyzer/src/test_utilities/test_library_builder.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -25,18 +24,14 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
classes: [ClassSpec('class A'), ClassSpec('class X extends A with M1')],
|
||||
mixins: [MixinSpec('mixin M1')],
|
||||
);
|
||||
var M1 = mixinElement('M1');
|
||||
expect(_toElement(M1), 2);
|
||||
|
||||
var A = classElement('A');
|
||||
expect(_toElement(A), 2);
|
||||
var X = classElement('X');
|
||||
expect(_toType(parseInterfaceType('M1')), 2);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
|
||||
// class _X&A&M1 extends A implements M1 {}
|
||||
// length: 2
|
||||
// class X extends _X&A&M1 {}
|
||||
// length: 3
|
||||
expect(_toElement(X), 4);
|
||||
expect(_toType(parseInterfaceType('X')), 4);
|
||||
}
|
||||
|
||||
void test_class_mixins2() {
|
||||
@@ -47,14 +42,9 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M1'), MixinSpec('mixin M2')],
|
||||
);
|
||||
var M1 = mixinElement('M1');
|
||||
var M2 = mixinElement('M2');
|
||||
expect(_toElement(M1), 2);
|
||||
expect(_toElement(M2), 2);
|
||||
|
||||
var A = classElement('A');
|
||||
expect(_toElement(A), 2);
|
||||
var X = classElement('X');
|
||||
expect(_toType(parseInterfaceType('M1')), 2);
|
||||
expect(_toType(parseInterfaceType('M2')), 2);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
|
||||
// class _X&A&M1 extends A implements M1 {}
|
||||
// length: 2
|
||||
@@ -62,7 +52,7 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
// length: 3
|
||||
// class X extends _X&A&M1&M2 {}
|
||||
// length: 4
|
||||
expect(_toElement(X), 5);
|
||||
expect(_toType(parseInterfaceType('X')), 5);
|
||||
}
|
||||
|
||||
void test_class_mixins_longerViaSecondMixin() {
|
||||
@@ -76,22 +66,12 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M1'), MixinSpec('mixin M2 implements I3')],
|
||||
);
|
||||
var I1 = classElement('I1');
|
||||
var I2 = classElement('I2');
|
||||
var I3 = classElement('I3');
|
||||
|
||||
expect(_toElement(I1), 2);
|
||||
expect(_toElement(I2), 3);
|
||||
expect(_toElement(I3), 4);
|
||||
|
||||
var M1 = mixinElement('M1');
|
||||
var M2 = mixinElement('M2');
|
||||
expect(_toElement(M1), 2);
|
||||
expect(_toElement(M2), 5);
|
||||
|
||||
var A = classElement('A');
|
||||
expect(_toElement(A), 2);
|
||||
var X = classElement('X');
|
||||
expect(_toType(parseInterfaceType('I1')), 2);
|
||||
expect(_toType(parseInterfaceType('I2')), 3);
|
||||
expect(_toType(parseInterfaceType('I3')), 4);
|
||||
expect(_toType(parseInterfaceType('M1')), 2);
|
||||
expect(_toType(parseInterfaceType('M2')), 5);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
|
||||
// class _X&A&M1 extends A implements M1 {}
|
||||
// length: 2
|
||||
@@ -99,7 +79,7 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
// length: 5 = max(1 + _X&A&M1, 1 + M2)
|
||||
// class X extends _X&A&M1&M2 {}
|
||||
// length: 6
|
||||
expect(_toElement(X), 7);
|
||||
expect(_toType(parseInterfaceType('X')), 7);
|
||||
}
|
||||
|
||||
void test_class_multipleInterfacePaths() {
|
||||
@@ -125,13 +105,11 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class E implements B, D'),
|
||||
],
|
||||
);
|
||||
var classB = classElement('B');
|
||||
var classE = classElement('E');
|
||||
// assertion: even though the longest path to Object for typeB is 2, and
|
||||
// typeE implements typeB, the longest path for typeE is 4 since it also
|
||||
// implements typeD
|
||||
expect(_toElement(classB), 3);
|
||||
expect(_toElement(classE), 5);
|
||||
expect(_toType(parseInterfaceType('B')), 3);
|
||||
expect(_toType(parseInterfaceType('E')), 5);
|
||||
}
|
||||
|
||||
void test_class_multipleSuperclassPaths() {
|
||||
@@ -157,32 +135,27 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class E extends B implements D'),
|
||||
],
|
||||
);
|
||||
var classB = classElement('B');
|
||||
var classE = classElement('E');
|
||||
// assertion: even though the longest path to Object for typeB is 2, and
|
||||
// typeE extends typeB, the longest path for typeE is 4 since it also
|
||||
// implements typeD
|
||||
expect(_toElement(classB), 3);
|
||||
expect(_toElement(classE), 5);
|
||||
expect(_toType(parseInterfaceType('B')), 3);
|
||||
expect(_toType(parseInterfaceType('E')), 5);
|
||||
}
|
||||
|
||||
void test_class_null() {
|
||||
expect(_toType(nullNone), 1);
|
||||
expect(_toType(parseInterfaceType('Null')), 1);
|
||||
}
|
||||
|
||||
void test_class_object() {
|
||||
expect(_toType(objectQuestion), 0);
|
||||
expect(_toType(objectNone), 1);
|
||||
expect(_toType(parseInterfaceType('Object?')), 0);
|
||||
expect(_toType(parseInterfaceType('Object')), 1);
|
||||
}
|
||||
|
||||
void test_class_recursion() {
|
||||
buildTestLibrary(
|
||||
classes: [ClassSpec('class A'), ClassSpec('class B extends A')],
|
||||
classes: [ClassSpec('class A extends B'), ClassSpec('class B extends A')],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var classB = classElement('B');
|
||||
classA.supertype = interfaceTypeNone(classB);
|
||||
expect(_toElement(classA), 2);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
}
|
||||
|
||||
void test_class_singleInterfacePath() {
|
||||
@@ -204,12 +177,9 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class C implements B'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var classB = classElement('B');
|
||||
var classC = classElement('C');
|
||||
expect(_toElement(classA), 2);
|
||||
expect(_toElement(classB), 3);
|
||||
expect(_toElement(classC), 4);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
expect(_toType(parseInterfaceType('B')), 3);
|
||||
expect(_toType(parseInterfaceType('C')), 4);
|
||||
}
|
||||
|
||||
void test_class_singleSuperclassPath() {
|
||||
@@ -231,12 +201,9 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class C extends B'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var classB = classElement('B');
|
||||
var classC = classElement('C');
|
||||
expect(_toElement(classA), 2);
|
||||
expect(_toElement(classB), 3);
|
||||
expect(_toElement(classC), 4);
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
expect(_toType(parseInterfaceType('B')), 3);
|
||||
expect(_toType(parseInterfaceType('C')), 4);
|
||||
}
|
||||
|
||||
void test_mixin_constraints_interfaces_allSame() {
|
||||
@@ -249,18 +216,13 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M on A, B implements I, J')],
|
||||
);
|
||||
var A = classElement('A');
|
||||
var B = classElement('B');
|
||||
var I = classElement('I');
|
||||
var J = classElement('J');
|
||||
expect(_toElement(A), 2);
|
||||
expect(_toElement(B), 2);
|
||||
expect(_toElement(I), 2);
|
||||
expect(_toElement(J), 2);
|
||||
var M = mixinElement('M');
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
expect(_toType(parseInterfaceType('B')), 2);
|
||||
expect(_toType(parseInterfaceType('I')), 2);
|
||||
expect(_toType(parseInterfaceType('J')), 2);
|
||||
// The interface of M is:
|
||||
// class _M&A&A implements A, B, I, J {}
|
||||
expect(_toElement(M), 3);
|
||||
expect(_toType(parseInterfaceType('M')), 3);
|
||||
}
|
||||
|
||||
void test_mixin_longerConstraint_1() {
|
||||
@@ -274,18 +236,13 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M on A, B implements I, J')],
|
||||
);
|
||||
var A = classElement('A');
|
||||
var B = classElement('B');
|
||||
var I = classElement('I');
|
||||
var J = classElement('J');
|
||||
expect(_toElement(A), 3);
|
||||
expect(_toElement(B), 2);
|
||||
expect(_toElement(I), 2);
|
||||
expect(_toElement(J), 2);
|
||||
var M = mixinElement('M');
|
||||
expect(_toType(parseInterfaceType('A')), 3);
|
||||
expect(_toType(parseInterfaceType('B')), 2);
|
||||
expect(_toType(parseInterfaceType('I')), 2);
|
||||
expect(_toType(parseInterfaceType('J')), 2);
|
||||
// The interface of M is:
|
||||
// class _M&A&A implements A, B, I, J {}
|
||||
expect(_toElement(M), 4);
|
||||
expect(_toType(parseInterfaceType('M')), 4);
|
||||
}
|
||||
|
||||
void test_mixin_longerConstraint_2() {
|
||||
@@ -299,18 +256,13 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M on A, B implements I, J')],
|
||||
);
|
||||
var A = classElement('A');
|
||||
var B = classElement('B');
|
||||
var I = classElement('I');
|
||||
var J = classElement('J');
|
||||
expect(_toElement(A), 2);
|
||||
expect(_toElement(B), 3);
|
||||
expect(_toElement(I), 2);
|
||||
expect(_toElement(J), 2);
|
||||
var M = mixinElement('M');
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
expect(_toType(parseInterfaceType('B')), 3);
|
||||
expect(_toType(parseInterfaceType('I')), 2);
|
||||
expect(_toType(parseInterfaceType('J')), 2);
|
||||
// The interface of M is:
|
||||
// class _M&A&A implements A, B, I, J {}
|
||||
expect(_toElement(M), 4);
|
||||
expect(_toType(parseInterfaceType('M')), 4);
|
||||
}
|
||||
|
||||
void test_mixin_longerInterface_1() {
|
||||
@@ -324,23 +276,13 @@ class PathToObjectTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M on A, B implements I, J')],
|
||||
);
|
||||
var A = classElement('A');
|
||||
var B = classElement('B');
|
||||
var I = classElement('I');
|
||||
var J = classElement('J');
|
||||
expect(_toElement(A), 2);
|
||||
expect(_toElement(B), 2);
|
||||
expect(_toElement(I), 3);
|
||||
expect(_toElement(J), 2);
|
||||
var M = mixinElement('M');
|
||||
expect(_toType(parseInterfaceType('A')), 2);
|
||||
expect(_toType(parseInterfaceType('B')), 2);
|
||||
expect(_toType(parseInterfaceType('I')), 3);
|
||||
expect(_toType(parseInterfaceType('J')), 2);
|
||||
// The interface of M is:
|
||||
// class _M&A&A implements A, B, I, J {}
|
||||
expect(_toElement(M), 4);
|
||||
}
|
||||
|
||||
int _toElement(InterfaceElementImpl element) {
|
||||
var type = interfaceTypeNone(element);
|
||||
return _toType(type);
|
||||
expect(_toType(parseInterfaceType('M')), 4);
|
||||
}
|
||||
|
||||
int _toType(InterfaceType type) {
|
||||
@@ -371,36 +313,28 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class D'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var classC = classElement('C');
|
||||
var classD = classElement('D');
|
||||
var instA = parseInterfaceType('A');
|
||||
|
||||
// A
|
||||
expect(
|
||||
_superInterfaces(instA),
|
||||
unorderedEquals([objectQuestion, objectNone]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object')]),
|
||||
);
|
||||
|
||||
// B<D>
|
||||
expect(
|
||||
_superInterfaces(
|
||||
interfaceTypeNone(classB, typeArguments: [interfaceTypeNone(classD)]),
|
||||
),
|
||||
unorderedEquals([objectQuestion, objectNone, instA]),
|
||||
_superInterfaces(parseInterfaceType('B<D>')),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object'), instA]),
|
||||
);
|
||||
|
||||
// C<D>
|
||||
expect(
|
||||
_superInterfaces(
|
||||
interfaceTypeNone(classC, typeArguments: [interfaceTypeNone(classD)]),
|
||||
),
|
||||
_superInterfaces(parseInterfaceType('C<D>')),
|
||||
unorderedEquals([
|
||||
objectQuestion,
|
||||
objectNone,
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
interfaceTypeNone(classB, typeArguments: [interfaceTypeNone(classD)]),
|
||||
parseInterfaceType('B<D>'),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@@ -424,36 +358,28 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class D'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var classC = classElement('C');
|
||||
var classD = classElement('D');
|
||||
var instA = parseInterfaceType('A');
|
||||
|
||||
// A
|
||||
expect(
|
||||
_superInterfaces(instA),
|
||||
unorderedEquals([objectQuestion, objectNone]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object')]),
|
||||
);
|
||||
|
||||
// B<D>
|
||||
expect(
|
||||
_superInterfaces(
|
||||
interfaceTypeNone(classB, typeArguments: [interfaceTypeNone(classD)]),
|
||||
),
|
||||
unorderedEquals([objectQuestion, objectNone, instA]),
|
||||
_superInterfaces(parseInterfaceType('B<D>')),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object'), instA]),
|
||||
);
|
||||
|
||||
// C<D>
|
||||
expect(
|
||||
_superInterfaces(
|
||||
interfaceTypeNone(classC, typeArguments: [interfaceTypeNone(classD)]),
|
||||
),
|
||||
_superInterfaces(parseInterfaceType('C<D>')),
|
||||
unorderedEquals([
|
||||
objectQuestion,
|
||||
objectNone,
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
interfaceTypeNone(classB, typeArguments: [interfaceTypeNone(classD)]),
|
||||
parseInterfaceType('B<D>'),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@@ -467,29 +393,30 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M on B, C')],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var mixinM = mixinElement('M');
|
||||
var instM = interfaceTypeNone(mixinM);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
var instM = parseInterfaceType('M');
|
||||
|
||||
expect(
|
||||
_superInterfaces(instM),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB, instC]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
instC,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_mixin_constraints_object() {
|
||||
buildTestLibrary(mixins: [MixinSpec('mixin M')]);
|
||||
var mixinM = mixinElement('M');
|
||||
var instM = interfaceTypeNone(mixinM);
|
||||
var instM = parseInterfaceType('M');
|
||||
|
||||
expect(
|
||||
_superInterfaces(instM),
|
||||
unorderedEquals([objectQuestion, objectNone]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object')]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -502,18 +429,20 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
],
|
||||
mixins: [MixinSpec('mixin M implements B, C')],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var mixinM = mixinElement('M');
|
||||
var instM = interfaceTypeNone(mixinM);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
var instM = parseInterfaceType('M');
|
||||
|
||||
expect(
|
||||
_superInterfaces(instM),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB, instC]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
instC,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -527,27 +456,34 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class E implements B, D'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var classD = classElement('D');
|
||||
var instD = interfaceTypeNone(classD);
|
||||
var classE = classElement('E');
|
||||
var instE = interfaceTypeNone(classE);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
var instD = parseInterfaceType('D');
|
||||
var instE = parseInterfaceType('E');
|
||||
|
||||
// D
|
||||
expect(
|
||||
_superInterfaces(instD),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instC]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instC,
|
||||
]),
|
||||
);
|
||||
|
||||
// E
|
||||
expect(
|
||||
_superInterfaces(instE),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB, instC, instD]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
instC,
|
||||
instD,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -561,27 +497,34 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class E extends B implements D'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var classD = classElement('D');
|
||||
var instD = interfaceTypeNone(classD);
|
||||
var classE = classElement('E');
|
||||
var instE = interfaceTypeNone(classE);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
var instD = parseInterfaceType('D');
|
||||
var instE = parseInterfaceType('E');
|
||||
|
||||
// D
|
||||
expect(
|
||||
_superInterfaces(instD),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instC]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instC,
|
||||
]),
|
||||
);
|
||||
|
||||
// E
|
||||
expect(
|
||||
_superInterfaces(instE),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB, instC, instD]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
instC,
|
||||
instD,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -590,9 +533,8 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
classes: [ClassSpec('class A'), ClassSpec('class B extends A')],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
|
||||
classA.supertype = instB;
|
||||
|
||||
@@ -609,29 +551,31 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class C implements B'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
|
||||
// A
|
||||
expect(
|
||||
_superInterfaces(instA),
|
||||
unorderedEquals([objectQuestion, objectNone]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object')]),
|
||||
);
|
||||
|
||||
// B
|
||||
expect(
|
||||
_superInterfaces(instB),
|
||||
unorderedEquals([objectQuestion, objectNone, instA]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object'), instA]),
|
||||
);
|
||||
|
||||
// C
|
||||
expect(
|
||||
_superInterfaces(instC),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -650,29 +594,31 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest {
|
||||
ClassSpec('class C extends B'),
|
||||
],
|
||||
);
|
||||
var classA = classElement('A');
|
||||
var instA = interfaceTypeNone(classA);
|
||||
var classB = classElement('B');
|
||||
var instB = interfaceTypeNone(classB);
|
||||
var classC = classElement('C');
|
||||
var instC = interfaceTypeNone(classC);
|
||||
var instA = parseInterfaceType('A');
|
||||
var instB = parseInterfaceType('B');
|
||||
var instC = parseInterfaceType('C');
|
||||
|
||||
// A
|
||||
expect(
|
||||
_superInterfaces(instA),
|
||||
unorderedEquals([objectQuestion, objectNone]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object')]),
|
||||
);
|
||||
|
||||
// B
|
||||
expect(
|
||||
_superInterfaces(instB),
|
||||
unorderedEquals([objectQuestion, objectNone, instA]),
|
||||
unorderedEquals([parseType('Object?'), parseType('Object'), instA]),
|
||||
);
|
||||
|
||||
// C
|
||||
expect(
|
||||
_superInterfaces(instC),
|
||||
unorderedEquals([objectQuestion, objectNone, instA, instB]),
|
||||
unorderedEquals([
|
||||
parseType('Object?'),
|
||||
parseType('Object'),
|
||||
instA,
|
||||
instB,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+67
-72
@@ -4,8 +4,8 @@
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/non_covariant_type_parameter_position.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
@@ -20,116 +20,111 @@ main() {
|
||||
@reflectiveTest
|
||||
class NonCovariantTypeParameterPositionVisitorTest
|
||||
extends AbstractTypeSystemTest {
|
||||
late final T_element = typeParameter('T');
|
||||
late final T = typeParameterTypeNone(T_element);
|
||||
|
||||
FunctionTypeImpl get _contravariantT {
|
||||
return functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: T)],
|
||||
);
|
||||
}
|
||||
|
||||
void expectNonCovariant(DartType type) {
|
||||
var actual = _compute(type);
|
||||
void expectNonCovariant(DartType type, TypeParameterElementImpl T) {
|
||||
var actual = _compute(type, T);
|
||||
expect(actual, isTrue);
|
||||
}
|
||||
|
||||
void expectNotNonCovariant(DartType type) {
|
||||
var actual = _compute(type);
|
||||
void expectNotNonCovariant(DartType type, TypeParameterElementImpl T) {
|
||||
var actual = _compute(type, T);
|
||||
expect(actual, isFalse);
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
expectNotNonCovariant(dynamicType);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
expectNotNonCovariant(parseType('dynamic'), scope.typeParameter('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_function() {
|
||||
expectNotNonCovariant(functionTypeNone(returnType: T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
// void Function(T)
|
||||
expectNonCovariant(_contravariantT);
|
||||
expectNotNonCovariant(scope.parseType('T Function()'), T);
|
||||
|
||||
// void Function(T) Function()
|
||||
expectNonCovariant(functionTypeNone(returnType: _contravariantT));
|
||||
// void Function(T)
|
||||
expectNonCovariant(scope.parseType('void Function([T])'), T);
|
||||
|
||||
// void Function(void Function(T))
|
||||
expectNotNonCovariant(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: _contravariantT)],
|
||||
),
|
||||
);
|
||||
// void Function(T) Function()
|
||||
expectNonCovariant(scope.parseType('void Function([T]) Function()'), T);
|
||||
|
||||
// T Function(T)
|
||||
expectNonCovariant(
|
||||
functionTypeNone(
|
||||
returnType: T,
|
||||
formalParameters: [positionalParameter(type: T)],
|
||||
),
|
||||
);
|
||||
// void Function(void Function(T))
|
||||
expectNotNonCovariant(
|
||||
scope.parseType('void Function([void Function([T])])'),
|
||||
T,
|
||||
);
|
||||
|
||||
// T Function(T)
|
||||
expectNonCovariant(scope.parseType('T Function([T])'), T);
|
||||
|
||||
// void Function<U extends T>()
|
||||
expectNonCovariant(scope.parseType('void Function<U extends T>()'), T);
|
||||
});
|
||||
|
||||
// Not the `T` for which we check.
|
||||
var T2 = typeParameter('T');
|
||||
expectNotNonCovariant(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
positionalParameter(type: typeParameterTypeNone(T2)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// void Function<U extends T>()
|
||||
expectNonCovariant(
|
||||
functionTypeNone(
|
||||
typeParameters: [typeParameter('U', bound: T)],
|
||||
returnType: voidNone,
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T', (scope1) {
|
||||
var T = scope1.typeParameter('T');
|
||||
scope1.withTypeParameterScope('T', (scope2) {
|
||||
expectNotNonCovariant(scope2.parseType('void Function([T])'), T);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
expectNotNonCovariant(intNone);
|
||||
expectNotNonCovariant(listNone(T));
|
||||
expectNonCovariant(listNone(_contravariantT));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
expectNotNonCovariant(parseType('int'), T);
|
||||
expectNotNonCovariant(scope.parseType('List<T>'), T);
|
||||
expectNonCovariant(scope.parseType('List<void Function([T])>'), T);
|
||||
});
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
expectNotNonCovariant(invalidType);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
expectNotNonCovariant(parseType('InvalidType'), scope.typeParameter('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_never() {
|
||||
expectNotNonCovariant(neverNone);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
expectNotNonCovariant(parseType('Never'), scope.typeParameter('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_record() {
|
||||
expectNotNonCovariant(recordTypeNone(positionalTypes: [T]));
|
||||
|
||||
expectNonCovariant(recordTypeNone(positionalTypes: [_contravariantT]));
|
||||
|
||||
expectNonCovariant(recordTypeNone(positionalTypes: [T, _contravariantT]));
|
||||
|
||||
expectNotNonCovariant(recordTypeNone(namedTypes: {'a': T}));
|
||||
|
||||
expectNonCovariant(recordTypeNone(namedTypes: {'a': _contravariantT}));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
expectNotNonCovariant(scope.parseType('(T,)'), T);
|
||||
expectNonCovariant(scope.parseType('(void Function([T]),)'), T);
|
||||
expectNonCovariant(scope.parseType('(T, void Function([T]))'), T);
|
||||
expectNotNonCovariant(scope.parseType('({T a})'), T);
|
||||
expectNonCovariant(scope.parseType('({void Function([T]) a})'), T);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter() {
|
||||
expectNotNonCovariant(T);
|
||||
withTypeParameterScope('T', (scope1) {
|
||||
var T = scope1.typeParameter('T');
|
||||
scope1.withTypeParameterScope('U', (scope2) {
|
||||
expectNotNonCovariant(scope2.parseType('U'), T);
|
||||
});
|
||||
});
|
||||
|
||||
var U = typeParameter('U');
|
||||
expectNotNonCovariant(typeParameterTypeNone(U));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
expectNotNonCovariant(scope.parseType('T'), scope.typeParameter('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
expectNotNonCovariant(voidNone);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
expectNotNonCovariant(parseType('void'), scope.typeParameter('T'));
|
||||
});
|
||||
}
|
||||
|
||||
bool _compute(DartType type) {
|
||||
bool _compute(DartType type, TypeParameterElementImpl T) {
|
||||
return type.accept(
|
||||
NonCovariantTypeParameterPositionVisitor([
|
||||
T_element,
|
||||
T,
|
||||
], initialVariance: Variance.covariant),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
@@ -21,183 +20,76 @@ main() {
|
||||
class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
|
||||
test_functionType_parameter() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: futureOrNone(objectNone))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: objectNone)],
|
||||
),
|
||||
parseType('void Function(FutureOr<Object>)'),
|
||||
parseType('void Function(Object)'),
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
namedParameter(name: 'a', type: futureOrNone(objectNone)),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedParameter(name: 'a', type: objectNone)],
|
||||
),
|
||||
parseType('void Function({FutureOr<Object> a})'),
|
||||
parseType('void Function({Object a})'),
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
namedRequiredParameter(name: 'a', type: futureOrNone(objectNone)),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedRequiredParameter(name: 'a', type: objectNone)],
|
||||
),
|
||||
parseType('void Function({required FutureOr<Object> a})'),
|
||||
parseType('void Function({required Object a})'),
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: futureOrNone(objectNone))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: objectNone)],
|
||||
),
|
||||
parseType('void Function([FutureOr<Object>])'),
|
||||
parseType('void Function([Object])'),
|
||||
);
|
||||
}
|
||||
|
||||
test_functionType_parameter_covariant() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
requiredParameter(type: futureOrNone(objectNone), isCovariant: true),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
requiredParameter(type: objectNone, isCovariant: true),
|
||||
],
|
||||
),
|
||||
parseType('void Function(covariant FutureOr<Object>)'),
|
||||
parseType('void Function(covariant Object)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_functionType_parameter_typeParameter() {
|
||||
TypeParameterElementImpl T;
|
||||
TypeParameterElementImpl T2;
|
||||
|
||||
T = typeParameter('T', bound: neverNone);
|
||||
T2 = typeParameter('T2', bound: neverNone);
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [T],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [T2],
|
||||
formalParameters: [requiredParameter(type: neverNone)],
|
||||
),
|
||||
parseType('void Function<T extends Never>(T)'),
|
||||
parseType('void Function<T2 extends Never>(Never)'),
|
||||
);
|
||||
|
||||
T = typeParameter('T', bound: iterableNone(futureOrNone(dynamicType)));
|
||||
T2 = typeParameter('T2', bound: iterableNone(dynamicType));
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [T],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [T2],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T2))],
|
||||
),
|
||||
parseType('void Function<T extends Iterable<FutureOr<dynamic>>>(T)'),
|
||||
parseType('void Function<T2 extends Iterable<dynamic>>(T2)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_functionType_returnType() {
|
||||
_check(
|
||||
functionTypeNone(returnType: futureOrNone(objectNone)),
|
||||
functionTypeNone(returnType: objectNone),
|
||||
parseType('FutureOr<Object> Function()'),
|
||||
parseType('Object Function()'),
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(returnType: intNone),
|
||||
functionTypeNone(returnType: intNone),
|
||||
);
|
||||
_check(parseType('int Function()'), parseType('int Function()'));
|
||||
}
|
||||
|
||||
test_functionType_typeParameter_bound_normalized() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [typeParameter('T', bound: futureOrNone(objectNone))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
typeParameters: [typeParameter('T', bound: objectNone)],
|
||||
),
|
||||
parseType('void Function<T extends FutureOr<Object>>()'),
|
||||
parseType('void Function<T extends Object>()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_functionType_typeParameter_bound_unchanged() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: intNone,
|
||||
typeParameters: [typeParameter('T', bound: numNone)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: intNone,
|
||||
typeParameters: [typeParameter('T', bound: numNone)],
|
||||
),
|
||||
parseType('int Function<T extends num>()'),
|
||||
parseType('int Function<T extends num>()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_functionType_typeParameter_fresh() {
|
||||
var T = typeParameter('T');
|
||||
var T2 = typeParameter('T');
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: typeParameterTypeNone(T),
|
||||
typeParameters: [T],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T))],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: typeParameterTypeNone(T2),
|
||||
typeParameters: [T2],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(T2))],
|
||||
),
|
||||
);
|
||||
_check(parseType('T Function<T>(T)'), parseType('U Function<U>(U)'));
|
||||
}
|
||||
|
||||
test_functionType_typeParameter_fresh_bound() {
|
||||
var T = typeParameter('T');
|
||||
var S = typeParameter('S', bound: typeParameterTypeNone(T));
|
||||
var T2 = typeParameter('T');
|
||||
var S2 = typeParameter('S', bound: typeParameterTypeNone(T2));
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: typeParameterTypeNone(T),
|
||||
typeParameters: [T, S],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T)),
|
||||
requiredParameter(type: typeParameterTypeNone(S)),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: typeParameterTypeNone(T2),
|
||||
typeParameters: [T2, S2],
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T2)),
|
||||
requiredParameter(type: typeParameterTypeNone(S2)),
|
||||
],
|
||||
),
|
||||
parseType('T Function<T, S extends T>(T, S)'),
|
||||
parseType('U Function<U, V extends U>(U, V)'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -205,40 +97,43 @@ class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
|
||||
/// * let S be NORM(T)
|
||||
test_futureOr() {
|
||||
void check(TypeImpl T, TypeImpl expected) {
|
||||
var input = futureOrNone(T);
|
||||
var input = typeProvider.futureOrElement.instantiateImpl(
|
||||
typeArguments: [T],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
_check(input, expected);
|
||||
}
|
||||
|
||||
// * if S is a top type then S
|
||||
check(dynamicType, dynamicType);
|
||||
check(invalidType, invalidType);
|
||||
check(voidNone, voidNone);
|
||||
check(objectQuestion, objectQuestion);
|
||||
check(parseType('dynamic'), parseType('dynamic'));
|
||||
check(parseType('InvalidType'), parseType('InvalidType'));
|
||||
check(parseType('void'), parseType('void'));
|
||||
check(parseType('Object?'), parseType('Object?'));
|
||||
|
||||
// * if S is Object then S
|
||||
check(objectNone, objectNone);
|
||||
check(parseType('Object'), parseType('Object'));
|
||||
|
||||
// * if S is Never then Future<Never>
|
||||
check(neverNone, futureNone(neverNone));
|
||||
check(parseType('Never'), parseType('Future<Never>'));
|
||||
|
||||
// * if S is Null then Future<Null>?
|
||||
check(nullNone, futureQuestion(nullNone));
|
||||
check(parseType('Null'), parseType('Future<Null>?'));
|
||||
|
||||
// * else FutureOr<S>
|
||||
check(intNone, futureOrNone(intNone));
|
||||
check(parseType('int'), parseType('FutureOr<int>'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_check(listNone(intNone), listNone(intNone));
|
||||
_check(parseType('List<int>'), parseType('List<int>'));
|
||||
|
||||
_check(listNone(futureOrNone(objectNone)), listNone(objectNone));
|
||||
_check(parseType('List<FutureOr<Object>>'), parseType('List<Object>'));
|
||||
}
|
||||
|
||||
test_primitive() {
|
||||
_check(dynamicType, dynamicType);
|
||||
_check(neverNone, neverNone);
|
||||
_check(voidNone, voidNone);
|
||||
_check(intNone, intNone);
|
||||
_check(parseType('dynamic'), parseType('dynamic'));
|
||||
_check(parseType('Never'), parseType('Never'));
|
||||
_check(parseType('void'), parseType('void'));
|
||||
_check(parseType('int'), parseType('int'));
|
||||
}
|
||||
|
||||
/// NORM(T?)
|
||||
@@ -250,12 +145,12 @@ class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
|
||||
}
|
||||
|
||||
// * if S is a top type then S
|
||||
check(futureOrQuestion(dynamicType), dynamicType);
|
||||
check(futureOrQuestion(voidNone), voidNone);
|
||||
check(futureOrQuestion(objectQuestion), objectQuestion);
|
||||
check(parseType('FutureOr<dynamic>?'), parseType('dynamic'));
|
||||
check(parseType('FutureOr<void>?'), parseType('void'));
|
||||
check(parseType('FutureOr<Object?>?'), parseType('Object?'));
|
||||
|
||||
// * if S is Never then Null
|
||||
check(neverQuestion, nullNone);
|
||||
check(parseType('Never?'), parseType('Null'));
|
||||
|
||||
// * if S is Never* then Null
|
||||
// Analyzer: impossible, we have only one suffix
|
||||
@@ -264,7 +159,7 @@ class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
|
||||
// Analyzer: impossible; `Null?` is always represented as `Null`.
|
||||
|
||||
// * if S is FutureOr<R> and R is nullable then S
|
||||
check(futureOrQuestion(intQuestion), futureOrNone(intQuestion));
|
||||
check(parseType('FutureOr<int?>?'), parseType('FutureOr<int?>'));
|
||||
|
||||
// * if S is FutureOr<R>* and R is nullable then FutureOr<R>
|
||||
// Analyzer: impossible, we have only one suffix
|
||||
@@ -272,95 +167,73 @@ class NormalizeTypeTest extends AbstractTypeSystemTest with StringTypes {
|
||||
// * if S is R? then R?
|
||||
// * if S is R* then R?
|
||||
// * else S?
|
||||
check(intQuestion, intQuestion);
|
||||
check(objectQuestion, objectQuestion);
|
||||
check(futureOrQuestion(objectNone), objectQuestion);
|
||||
check(parseType('int?'), parseType('int?'));
|
||||
check(parseType('Object?'), parseType('Object?'));
|
||||
check(parseType('FutureOr<Object>?'), parseType('Object?'));
|
||||
}
|
||||
|
||||
test_recordType() {
|
||||
_check(parseRecordType('(int,)'), parseRecordType('(int,)'));
|
||||
|
||||
_check(
|
||||
recordTypeNone(positionalTypes: [intNone]),
|
||||
recordTypeNone(positionalTypes: [intNone]),
|
||||
parseRecordType('(FutureOr<Object>,)'),
|
||||
parseRecordType('(Object,)'),
|
||||
);
|
||||
|
||||
_check(
|
||||
recordTypeNone(positionalTypes: [futureOrNone(objectNone)]),
|
||||
recordTypeNone(positionalTypes: [objectNone]),
|
||||
);
|
||||
|
||||
_check(
|
||||
recordTypeNone(namedTypes: {'foo': futureOrNone(objectNone)}),
|
||||
recordTypeNone(namedTypes: {'foo': objectNone}),
|
||||
parseRecordType('({FutureOr<Object> foo})'),
|
||||
parseRecordType('({Object foo})'),
|
||||
);
|
||||
}
|
||||
|
||||
/// NORM(X & T)
|
||||
/// * let S be NORM(T)
|
||||
test_typeParameter_bound() {
|
||||
TypeParameterElementImpl T;
|
||||
|
||||
// * if S is Never then Never
|
||||
T = typeParameter('T', bound: neverNone);
|
||||
_check(typeParameterTypeNone(T), neverNone);
|
||||
withTypeParameterScope('T extends Never', (scope) {
|
||||
_check(scope.parseType('T'), parseType('Never'));
|
||||
});
|
||||
|
||||
// * else X
|
||||
T = typeParameter('T');
|
||||
_check(typeParameterTypeNone(T), typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T'), scope.parseType('T'));
|
||||
});
|
||||
|
||||
// * else X
|
||||
T = typeParameter('T', bound: futureOrNone(objectNone));
|
||||
_check(typeParameterTypeNone(T), typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends FutureOr<Object>', (scope) {
|
||||
_check(scope.parseType('T'), scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_recursive() {
|
||||
var T = typeParameter('T');
|
||||
T.bound = iterableNone(typeParameterTypeNone(T));
|
||||
_check(typeParameterTypeNone(T), typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends Iterable<T>', (scope) {
|
||||
_check(scope.parseType('T'), scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promoted() {
|
||||
var T = typeParameter('T');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
// * if S is Never then Never
|
||||
_check(scope.parseType('T & Never'), parseType('Never'));
|
||||
|
||||
// * if S is Never then Never
|
||||
_check(promotedTypeParameterTypeNone(T, neverNone), neverNone);
|
||||
// * if S is a top type then X
|
||||
_check(scope.parseType('T & Object?'), scope.parseType('T'));
|
||||
_check(scope.parseType('T & FutureOr<Object>?'), scope.parseType('T'));
|
||||
|
||||
// * if S is a top type then X
|
||||
_check(
|
||||
promotedTypeParameterTypeNone(T, objectQuestion),
|
||||
typeParameterTypeNone(T),
|
||||
);
|
||||
_check(
|
||||
promotedTypeParameterTypeNone(T, futureOrQuestion(objectNone)),
|
||||
typeParameterTypeNone(T),
|
||||
);
|
||||
// * if S is X then X
|
||||
_check(scope.parseType('T & T'), scope.parseType('T'));
|
||||
|
||||
// * if S is X then X
|
||||
_check(
|
||||
promotedTypeParameterTypeNone(T, typeParameterTypeNone(T)),
|
||||
typeParameterTypeNone(T),
|
||||
);
|
||||
// else X & S
|
||||
_check(
|
||||
scope.parseType('T & FutureOr<Never>'),
|
||||
scope.parseType('T & Future<Never>'),
|
||||
);
|
||||
});
|
||||
|
||||
// * if S is Object and NORM(B) is Object where B is the bound of X then X
|
||||
T = typeParameter('T', bound: objectNone);
|
||||
_check(
|
||||
promotedTypeParameterTypeNone(T, futureOrNone(objectNone)),
|
||||
typeParameterTypeNone(T),
|
||||
);
|
||||
|
||||
// else X & S
|
||||
T = typeParameter('T');
|
||||
_check(
|
||||
promotedTypeParameterType(
|
||||
element: T,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
promotedBound: futureOrNone(neverNone),
|
||||
),
|
||||
promotedTypeParameterType(
|
||||
element: T,
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
promotedBound: futureNone(neverNone),
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T extends Object', (scope) {
|
||||
_check(scope.parseType('T & FutureOr<Object>'), scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
void _assertNullability(TypeImpl type, NullabilitySuffix expected) {
|
||||
|
||||
@@ -34,100 +34,91 @@ class IsNonNullableTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
isNotNonNullable(dynamicType);
|
||||
isNotNonNullable(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_function() {
|
||||
isNonNullable(functionTypeNone(returnType: voidNone));
|
||||
isNonNullable(parseType('void Function()'));
|
||||
|
||||
isNotNonNullable(functionTypeQuestion(returnType: voidNone));
|
||||
isNotNonNullable(parseType('void Function()?'));
|
||||
}
|
||||
|
||||
test_functionClass() {
|
||||
isNonNullable(functionNone);
|
||||
isNotNonNullable(functionQuestion);
|
||||
isNonNullable(parseType('Function'));
|
||||
isNotNonNullable(parseType('Function?'));
|
||||
}
|
||||
|
||||
test_futureOr_noneArgument() {
|
||||
isNonNullable(futureOrNone(intNone));
|
||||
isNonNullable(parseType('FutureOr<int>'));
|
||||
|
||||
isNotNonNullable(futureOrQuestion(intNone));
|
||||
isNotNonNullable(parseType('FutureOr<int>?'));
|
||||
}
|
||||
|
||||
test_futureOr_questionArgument() {
|
||||
isNotNonNullable(futureOrNone(intQuestion));
|
||||
isNotNonNullable(parseType('FutureOr<int?>'));
|
||||
|
||||
isNotNonNullable(futureOrQuestion(intQuestion));
|
||||
isNotNonNullable(parseType('FutureOr<int?>?'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
isNonNullable(intNone);
|
||||
isNotNonNullable(intQuestion);
|
||||
isNonNullable(parseType('int'));
|
||||
isNotNonNullable(parseType('int?'));
|
||||
}
|
||||
|
||||
test_interface_extensionType2() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
buildTestLibrary(
|
||||
extensionTypes: [
|
||||
ExtensionTypeSpec('extension type A(int it) implements int'),
|
||||
ExtensionTypeSpec('extension type A(int it)'),
|
||||
ExtensionTypeSpec('extension type B(int it) implements int'),
|
||||
],
|
||||
);
|
||||
var AWithInt = extensionTypeElement('A');
|
||||
isNotNonNullable(interfaceTypeNone(A));
|
||||
|
||||
isNonNullable(interfaceTypeNone(AWithInt));
|
||||
isNotNonNullable(parseInterfaceType('A'));
|
||||
isNonNullable(parseInterfaceType('B'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isNotNonNullable(invalidType);
|
||||
isNotNonNullable(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
isNonNullable(neverNone);
|
||||
isNotNonNullable(neverQuestion);
|
||||
isNonNullable(parseType('Never'));
|
||||
isNotNonNullable(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
isNotNonNullable(nullNone);
|
||||
isNotNonNullable(parseType('Null'));
|
||||
}
|
||||
|
||||
test_typeParameter_boundNone() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
isNonNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNotNonNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
isNonNullable(scope.parseType('T'));
|
||||
isNotNonNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_boundQuestion() {
|
||||
var T = typeParameter('T', bound: intQuestion);
|
||||
|
||||
isNotNonNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNotNonNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
isNotNonNullable(scope.parseType('T'));
|
||||
isNotNonNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBoundNone() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
isNonNullable(typeParameterTypeNone(T, promotedBound: intNone));
|
||||
|
||||
isNonNullable(typeParameterTypeQuestion(T, promotedBound: intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isNonNullable(scope.parseType('T & int'));
|
||||
isNonNullable(scope.parseType('(T & int)?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBoundQuestion() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
isNotNonNullable(typeParameterTypeNone(T, promotedBound: intQuestion));
|
||||
|
||||
isNotNonNullable(typeParameterTypeQuestion(T, promotedBound: intQuestion));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isNotNonNullable(scope.parseType('T & int?'));
|
||||
isNotNonNullable(scope.parseType('(T & int?)?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
isNotNonNullable(voidNone);
|
||||
isNotNonNullable(parseType('void'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,102 +133,92 @@ class IsNullableTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
isNullable(dynamicType);
|
||||
isNullable(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_function() {
|
||||
isNotNullable(functionTypeNone(returnType: voidNone));
|
||||
isNotNullable(parseType('void Function()'));
|
||||
|
||||
isNullable(functionTypeQuestion(returnType: voidNone));
|
||||
isNullable(parseType('void Function()?'));
|
||||
}
|
||||
|
||||
test_functionClass() {
|
||||
isNotNullable(functionNone);
|
||||
isNullable(functionQuestion);
|
||||
isNotNullable(parseType('Function'));
|
||||
isNullable(parseType('Function?'));
|
||||
}
|
||||
|
||||
test_futureOr_noneArgument() {
|
||||
isNotNullable(futureOrNone(intNone));
|
||||
isNotNullable(parseType('FutureOr<int>'));
|
||||
|
||||
isNullable(futureOrQuestion(intNone));
|
||||
isNullable(parseType('FutureOr<int>?'));
|
||||
}
|
||||
|
||||
test_futureOr_questionArgument() {
|
||||
isNullable(futureOrNone(intQuestion));
|
||||
isNullable(parseType('FutureOr<int?>'));
|
||||
|
||||
isNullable(futureOrQuestion(intQuestion));
|
||||
isNullable(parseType('FutureOr<int?>?'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
isNotNullable(intNone);
|
||||
isNullable(intQuestion);
|
||||
isNotNullable(parseType('int'));
|
||||
isNullable(parseType('int?'));
|
||||
}
|
||||
|
||||
test_interface_extensionType2() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
buildTestLibrary(
|
||||
extensionTypes: [
|
||||
ExtensionTypeSpec('extension type A(int it) implements int'),
|
||||
ExtensionTypeSpec('extension type A(int it)'),
|
||||
ExtensionTypeSpec('extension type B(int it) implements int'),
|
||||
],
|
||||
);
|
||||
var AWithInt = extensionTypeElement('A');
|
||||
isNotNullable(interfaceTypeNone(A));
|
||||
|
||||
isNotNullable(interfaceTypeNone(AWithInt));
|
||||
|
||||
isNullable(interfaceTypeQuestion(AWithInt));
|
||||
isNotNullable(parseInterfaceType('A'));
|
||||
isNotNullable(parseInterfaceType('B'));
|
||||
isNullable(parseInterfaceType('B?'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isNullable(invalidType);
|
||||
isNullable(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
isNotNullable(neverNone);
|
||||
isNullable(neverQuestion);
|
||||
isNotNullable(parseType('Never'));
|
||||
isNullable(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
isNullable(nullNone);
|
||||
isNullable(parseType('Null'));
|
||||
}
|
||||
|
||||
test_typeParameter_boundNone() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
isNotNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
isNotNullable(scope.parseType('T'));
|
||||
isNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_boundQuestion_none() {
|
||||
var T = typeParameter('T', bound: intQuestion);
|
||||
|
||||
isNotNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
isNotNullable(scope.parseType('T'));
|
||||
isNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBoundNone() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
isNotNullable(typeParameterTypeNone(T, promotedBound: intNone));
|
||||
|
||||
isNotNullable(typeParameterTypeQuestion(T, promotedBound: intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isNotNullable(scope.parseType('T & int'));
|
||||
isNotNullable(scope.parseType('(T & int)?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBoundQuestion() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
isNullable(typeParameterTypeNone(T, promotedBound: intQuestion));
|
||||
|
||||
isNullable(typeParameterTypeQuestion(T, promotedBound: intQuestion));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
isNullable(scope.parseType('T & int?'));
|
||||
isNullable(scope.parseType('(T & int?)?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
isNullable(voidNone);
|
||||
isNullable(parseType('void'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,50 +233,45 @@ class IsPotentiallyNonNullableTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
isNotPotentiallyNonNullable(dynamicType);
|
||||
isNotPotentiallyNonNullable(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_futureOr() {
|
||||
isPotentiallyNonNullable(futureOrNone(intNone));
|
||||
isPotentiallyNonNullable(parseType('FutureOr<int>'));
|
||||
|
||||
isNotPotentiallyNonNullable(futureOrNone(intQuestion));
|
||||
isNotPotentiallyNonNullable(parseType('FutureOr<int?>'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
isPotentiallyNonNullable(intNone);
|
||||
isNotPotentiallyNonNullable(intQuestion);
|
||||
isPotentiallyNonNullable(parseType('int'));
|
||||
isNotPotentiallyNonNullable(parseType('int?'));
|
||||
}
|
||||
|
||||
test_interface_extensionType2() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
buildTestLibrary(
|
||||
extensionTypes: [
|
||||
ExtensionTypeSpec('extension type A(int it) implements int'),
|
||||
ExtensionTypeSpec('extension type A(int it)'),
|
||||
ExtensionTypeSpec('extension type B(int it) implements int'),
|
||||
],
|
||||
);
|
||||
var AWithInt = extensionTypeElement('A');
|
||||
isPotentiallyNonNullable(interfaceTypeNone(A));
|
||||
|
||||
isPotentiallyNonNullable(interfaceTypeNone(AWithInt));
|
||||
isPotentiallyNonNullable(parseInterfaceType('A'));
|
||||
isPotentiallyNonNullable(parseInterfaceType('B'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isNotPotentiallyNonNullable(invalidType);
|
||||
isNotPotentiallyNonNullable(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
isPotentiallyNonNullable(neverNone);
|
||||
isPotentiallyNonNullable(parseType('Never'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
isNotPotentiallyNonNullable(nullNone);
|
||||
isNotPotentiallyNonNullable(parseType('Null'));
|
||||
}
|
||||
|
||||
test_void() {
|
||||
isNotPotentiallyNonNullable(voidNone);
|
||||
isNotPotentiallyNonNullable(parseType('void'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,52 +286,46 @@ class IsPotentiallyNullableTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
isPotentiallyNullable(dynamicType);
|
||||
isPotentiallyNullable(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_futureOr() {
|
||||
isNotPotentiallyNullable(futureOrNone(intNone));
|
||||
isNotPotentiallyNullable(parseType('FutureOr<int>'));
|
||||
|
||||
isPotentiallyNullable(futureOrNone(intQuestion));
|
||||
isPotentiallyNullable(parseType('FutureOr<int?>'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
isNotPotentiallyNullable(intNone);
|
||||
isPotentiallyNullable(intQuestion);
|
||||
isNotPotentiallyNullable(parseType('int'));
|
||||
isPotentiallyNullable(parseType('int?'));
|
||||
}
|
||||
|
||||
test_interface_extensionType2() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
buildTestLibrary(
|
||||
extensionTypes: [
|
||||
ExtensionTypeSpec('extension type A(int it) implements int'),
|
||||
ExtensionTypeSpec('extension type A(int it)'),
|
||||
ExtensionTypeSpec('extension type B(int it) implements int'),
|
||||
],
|
||||
);
|
||||
var AWithInt = extensionTypeElement('A');
|
||||
isPotentiallyNullable(interfaceTypeQuestion(A));
|
||||
|
||||
isPotentiallyNullable(interfaceTypeNone(A));
|
||||
|
||||
isNotPotentiallyNullable(interfaceTypeNone(AWithInt));
|
||||
isPotentiallyNullable(parseInterfaceType('A?'));
|
||||
isPotentiallyNullable(parseInterfaceType('A'));
|
||||
isNotPotentiallyNullable(parseInterfaceType('B'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isPotentiallyNullable(invalidType);
|
||||
isPotentiallyNullable(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
isNotPotentiallyNullable(neverNone);
|
||||
isNotPotentiallyNullable(parseType('Never'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
isPotentiallyNullable(nullNone);
|
||||
isPotentiallyNullable(parseType('Null'));
|
||||
}
|
||||
|
||||
test_void() {
|
||||
isPotentiallyNullable(voidNone);
|
||||
isPotentiallyNullable(parseType('void'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,226 +340,220 @@ class IsStrictlyNonNullableTest extends AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
isNotStrictlyNonNullable(dynamicType);
|
||||
isNotStrictlyNonNullable(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_function() {
|
||||
isStrictlyNonNullable(functionTypeNone(returnType: voidNone));
|
||||
isStrictlyNonNullable(parseType('void Function()'));
|
||||
|
||||
isNotStrictlyNonNullable(functionTypeQuestion(returnType: voidNone));
|
||||
isNotStrictlyNonNullable(parseType('void Function()?'));
|
||||
}
|
||||
|
||||
test_functionClass() {
|
||||
isStrictlyNonNullable(functionNone);
|
||||
isNotStrictlyNonNullable(functionQuestion);
|
||||
isStrictlyNonNullable(parseType('Function'));
|
||||
isNotStrictlyNonNullable(parseType('Function?'));
|
||||
}
|
||||
|
||||
test_futureOr_noneArgument() {
|
||||
isStrictlyNonNullable(futureOrNone(intNone));
|
||||
isStrictlyNonNullable(parseType('FutureOr<int>'));
|
||||
|
||||
isNotStrictlyNonNullable(futureOrQuestion(intNone));
|
||||
isNotStrictlyNonNullable(parseType('FutureOr<int>?'));
|
||||
}
|
||||
|
||||
test_futureOr_questionArgument() {
|
||||
isNotStrictlyNonNullable(futureOrNone(intQuestion));
|
||||
isNotStrictlyNonNullable(parseType('FutureOr<int?>'));
|
||||
|
||||
isNotStrictlyNonNullable(futureOrQuestion(intQuestion));
|
||||
isNotStrictlyNonNullable(parseType('FutureOr<int?>?'));
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
isStrictlyNonNullable(intNone);
|
||||
isNotStrictlyNonNullable(intQuestion);
|
||||
isStrictlyNonNullable(parseType('int'));
|
||||
isNotStrictlyNonNullable(parseType('int?'));
|
||||
}
|
||||
|
||||
test_interface_extensionType2() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var A = extensionTypeElement('A');
|
||||
buildTestLibrary(
|
||||
extensionTypes: [
|
||||
ExtensionTypeSpec('extension type A(int it) implements int'),
|
||||
ExtensionTypeSpec('extension type A(int it)'),
|
||||
ExtensionTypeSpec('extension type B(int it) implements int'),
|
||||
],
|
||||
);
|
||||
var AWithInt = extensionTypeElement('A');
|
||||
isNotStrictlyNonNullable(interfaceTypeNone(A));
|
||||
|
||||
isStrictlyNonNullable(interfaceTypeNone(AWithInt));
|
||||
isNotStrictlyNonNullable(parseInterfaceType('A'));
|
||||
isStrictlyNonNullable(parseInterfaceType('B'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
isNotStrictlyNonNullable(invalidType);
|
||||
isNotStrictlyNonNullable(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
isStrictlyNonNullable(neverNone);
|
||||
isNotStrictlyNonNullable(neverQuestion);
|
||||
isStrictlyNonNullable(parseType('Never'));
|
||||
isNotStrictlyNonNullable(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
isNotStrictlyNonNullable(nullNone);
|
||||
isNotStrictlyNonNullable(parseType('Null'));
|
||||
}
|
||||
|
||||
test_typeParameter_boundNone() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
isStrictlyNonNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNotStrictlyNonNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
isStrictlyNonNullable(scope.parseType('T'));
|
||||
isNotStrictlyNonNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_boundQuestion() {
|
||||
var T = typeParameter('T', bound: intQuestion);
|
||||
|
||||
isNotStrictlyNonNullable(typeParameterTypeNone(T));
|
||||
|
||||
isNotStrictlyNonNullable(typeParameterTypeQuestion(T));
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
isNotStrictlyNonNullable(scope.parseType('T'));
|
||||
isNotStrictlyNonNullable(scope.parseType('T?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
isNotStrictlyNonNullable(voidNone);
|
||||
isNotStrictlyNonNullable(parseType('void'));
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class PromoteToNonNullTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_check(dynamicType, dynamicType);
|
||||
_check(parseType('dynamic'), parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
// NonNull(T0 Function(...)) = T0 Function(...)
|
||||
_check(
|
||||
functionTypeQuestion(returnType: voidNone),
|
||||
functionTypeNone(returnType: voidNone),
|
||||
);
|
||||
_check(parseType('void Function()?'), parseType('void Function()'));
|
||||
}
|
||||
|
||||
test_futureOr_question() {
|
||||
// NonNull(FutureOr<T>) = FutureOr<T>
|
||||
_check(futureOrQuestion(stringQuestion), futureOrNone(stringQuestion));
|
||||
_check(parseType('FutureOr<String?>?'), parseType('FutureOr<String?>'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_check(intNone, intNone);
|
||||
_check(intQuestion, intNone);
|
||||
_check(parseType('int'), parseType('int'));
|
||||
_check(parseType('int?'), parseType('int'));
|
||||
|
||||
// NonNull(C<T1, ... , Tn>) = C<T1, ... , Tn>
|
||||
_check(listQuestion(intQuestion), listNone(intQuestion));
|
||||
_check(parseType('List<int?>?'), parseType('List<int?>'));
|
||||
}
|
||||
|
||||
test_interfaceType_function() {
|
||||
_check(functionQuestion, functionNone);
|
||||
_check(parseType('Function?'), parseType('Function'));
|
||||
}
|
||||
|
||||
test_invalidType() {
|
||||
_check(invalidType, invalidType);
|
||||
_check(parseType('InvalidType'), parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_check(neverNone, neverNone);
|
||||
_check(neverQuestion, neverNone);
|
||||
_check(parseType('Never'), parseType('Never'));
|
||||
_check(parseType('Never?'), parseType('Never'));
|
||||
}
|
||||
|
||||
test_null() {
|
||||
_check(nullNone, neverNone);
|
||||
_check(parseType('Null'), parseType('Never'));
|
||||
}
|
||||
|
||||
test_typeParameter_bound_dynamic() {
|
||||
var element = typeParameter('T', bound: dynamicType);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeNone(element),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
withTypeParameterScope('T extends dynamic', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T'),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_invalidType() {
|
||||
var element = typeParameter('T', bound: invalidType);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeNone(element),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
withTypeParameterScope('T extends InvalidType', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T'),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_none() {
|
||||
var element = typeParameter('T', bound: intNone);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeNone(element),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeQuestion(element),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T'),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T?'),
|
||||
element: element,
|
||||
promotedBound: null,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_null() {
|
||||
var element = typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeNone(element),
|
||||
element: element,
|
||||
promotedBound: objectNone,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T'),
|
||||
element: element,
|
||||
promotedBound: parseType('Object'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_question() {
|
||||
var element = typeParameter('T', bound: intQuestion);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeNone(element),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
|
||||
_checkTypeParameter(
|
||||
typeParameterTypeQuestion(element),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T?'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound_none() {
|
||||
var element = typeParameter('T', bound: numQuestion);
|
||||
|
||||
_checkTypeParameter(
|
||||
promotedTypeParameterTypeNone(element, intNone),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
|
||||
_checkTypeParameter(
|
||||
promotedTypeParameterTypeQuestion(element, intNone),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
withTypeParameterScope('T extends num?', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T & int'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('(T & int)?'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound_question() {
|
||||
var element = typeParameter('T', bound: numQuestion);
|
||||
|
||||
_checkTypeParameter(
|
||||
promotedTypeParameterTypeNone(element, intQuestion),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
|
||||
_checkTypeParameter(
|
||||
promotedTypeParameterTypeQuestion(element, intQuestion),
|
||||
element: element,
|
||||
promotedBound: intNone,
|
||||
);
|
||||
withTypeParameterScope('T extends num?', (scope) {
|
||||
var element = scope.typeParameter('T');
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('T & int?'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
_checkTypeParameter(
|
||||
scope.parseTypeParameterType('(T & int?)?'),
|
||||
element: element,
|
||||
promotedBound: parseType('int'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_check(voidNone, voidNone);
|
||||
_check(parseType('void'), parseType('void'));
|
||||
}
|
||||
|
||||
void _check(TypeImpl type, TypeImpl expected) {
|
||||
|
||||
@@ -21,63 +21,42 @@ main() {
|
||||
class ReplaceTopBottomTest extends AbstractTypeSystemTest {
|
||||
test_contravariant_bottom() {
|
||||
// Not contravariant.
|
||||
_check(neverNone, 'Never');
|
||||
_check(parseType('Never'), 'Never');
|
||||
|
||||
void checkContravariant(TypeImpl type, String expectedStr) {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: intNone,
|
||||
formalParameters: [requiredParameter(type: type)],
|
||||
),
|
||||
'int Function($expectedStr)',
|
||||
);
|
||||
}
|
||||
_check(parseFunctionType('int Function(Never)'), 'int Function(Object?)');
|
||||
|
||||
checkContravariant(neverNone, 'Object?');
|
||||
|
||||
checkContravariant(
|
||||
typeParameterTypeNone(typeParameter('T', bound: neverNone)),
|
||||
'Object?',
|
||||
);
|
||||
withTypeParameterScope('T extends Never', (scope) {
|
||||
_check(scope.parseType('int Function(T)'), 'int Function(Object?)');
|
||||
});
|
||||
}
|
||||
|
||||
test_notContravariant_covariant_top() {
|
||||
_check(objectQuestion, 'Never');
|
||||
_check(dynamicType, 'Never');
|
||||
_check(voidNone, 'Never');
|
||||
_check(parseType('Object?'), 'Never');
|
||||
_check(parseType('dynamic'), 'Never');
|
||||
_check(parseType('void'), 'Never');
|
||||
|
||||
_check(listNone(objectQuestion), 'List<Never>');
|
||||
_check(listNone(dynamicType), 'List<Never>');
|
||||
_check(listNone(voidNone), 'List<Never>');
|
||||
_check(parseType('List<Object?>'), 'List<Never>');
|
||||
_check(parseType('List<dynamic>'), 'List<Never>');
|
||||
_check(parseType('List<void>'), 'List<Never>');
|
||||
|
||||
_check(futureOrNone(objectQuestion), 'Never');
|
||||
_check(futureOrNone(dynamicType), 'Never');
|
||||
_check(futureOrNone(voidNone), 'Never');
|
||||
_check(futureOrNone(futureOrNone(voidNone)), 'Never');
|
||||
_check(parseType('FutureOr<Object?>'), 'Never');
|
||||
_check(parseType('FutureOr<dynamic>'), 'Never');
|
||||
_check(parseType('FutureOr<void>'), 'Never');
|
||||
_check(parseType('FutureOr<FutureOr<void>>'), 'Never');
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: intNone,
|
||||
formalParameters: [
|
||||
requiredParameter(
|
||||
type: functionTypeNone(
|
||||
returnType: intNone,
|
||||
formalParameters: [requiredParameter(type: objectQuestion)],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
parseType('int Function(int Function(Object?))'),
|
||||
'int Function(int Function(Never))',
|
||||
typeStr: 'int Function(int Function(Object?))',
|
||||
);
|
||||
|
||||
_check(intNone, 'int');
|
||||
_check(intQuestion, 'int?');
|
||||
_check(parseType('int'), 'int');
|
||||
_check(parseType('int?'), 'int?');
|
||||
|
||||
_check(listNone(intNone), 'List<int>');
|
||||
_check(listNone(intQuestion), 'List<int?>');
|
||||
_check(listQuestion(intNone), 'List<int>?');
|
||||
_check(listQuestion(intQuestion), 'List<int?>?');
|
||||
_check(parseType('List<int>'), 'List<int>');
|
||||
_check(parseType('List<int?>'), 'List<int?>');
|
||||
_check(parseType('List<int>?'), 'List<int>?');
|
||||
_check(parseType('List<int?>?'), 'List<int?>?');
|
||||
}
|
||||
|
||||
test_notContravariant_invariant() {
|
||||
@@ -88,7 +67,7 @@ class ReplaceTopBottomTest extends AbstractTypeSystemTest {
|
||||
var F = typeAliasElement('F');
|
||||
|
||||
var F_dynamic = F.instantiateImpl(
|
||||
typeArguments: [dynamicType],
|
||||
typeArguments: [parseType('dynamic')],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
_check(F_dynamic, 'Never Function(Never)');
|
||||
|
||||
@@ -18,105 +18,94 @@ main() {
|
||||
@reflectiveTest
|
||||
class ResolveToBoundTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_check(dynamicType, 'dynamic');
|
||||
_check(parseType('dynamic'), 'dynamic');
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_check(functionTypeNone(returnType: voidNone), 'void Function()');
|
||||
_check(parseType('void Function()'), 'void Function()');
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_check(intNone, 'int');
|
||||
_check(intQuestion, 'int?');
|
||||
_check(parseType('int'), 'int');
|
||||
_check(parseType('int?'), 'int?');
|
||||
}
|
||||
|
||||
test_typeParameter_bound() {
|
||||
_check(typeParameterTypeNone(typeParameter('T', bound: intNone)), 'int');
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_check(scope.parseType('T'), 'int');
|
||||
});
|
||||
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: intQuestion)),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
_check(scope.parseType('T'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_functionType() {
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T', bound: functionTypeNone(returnType: voidNone)),
|
||||
),
|
||||
'void Function()',
|
||||
);
|
||||
withTypeParameterScope('T extends void Function()', (scope) {
|
||||
_check(scope.parseType('T'), 'void Function()');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nested_noBound() {
|
||||
var T = typeParameter('T');
|
||||
var U = typeParameter('U', bound: typeParameterTypeNone(T));
|
||||
_check(typeParameterTypeNone(U), 'Object?');
|
||||
withTypeParameterScope('T, U extends T', (scope) {
|
||||
_check(scope.parseType('U'), 'Object?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nested_none() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var U = typeParameter('U', bound: typeParameterTypeNone(T));
|
||||
_check(typeParameterTypeNone(U), 'int');
|
||||
withTypeParameterScope('T extends int, U extends T', (scope) {
|
||||
_check(scope.parseType('U'), 'int');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nested_none_outerNullable() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var U = typeParameter('U', bound: typeParameterTypeQuestion(T));
|
||||
_check(typeParameterTypeNone(U), 'int?');
|
||||
withTypeParameterScope('T extends int, U extends T?', (scope) {
|
||||
_check(scope.parseType('U'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nested_question() {
|
||||
var T = typeParameter('T', bound: intQuestion);
|
||||
var U = typeParameter('U', bound: typeParameterTypeNone(T));
|
||||
_check(typeParameterTypeNone(U), 'int?');
|
||||
withTypeParameterScope('T extends int?, U extends T', (scope) {
|
||||
_check(scope.parseType('U'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nullableInner() {
|
||||
_check(
|
||||
typeParameterTypeNone(typeParameter('T', bound: intQuestion)),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
_check(scope.parseType('T'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nullableInnerOuter() {
|
||||
_check(
|
||||
typeParameterTypeQuestion(typeParameter('T', bound: intQuestion)),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends int?', (scope) {
|
||||
_check(scope.parseType('T?'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_bound_nullableOuter() {
|
||||
_check(
|
||||
typeParameterTypeQuestion(typeParameter('T', bound: intNone)),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_check(scope.parseType('T?'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_noBound() {
|
||||
_check(typeParameterTypeNone(typeParameter('T')), 'Object?');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_check(scope.parseType('T'), 'Object?');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_promotedBound() {
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T', bound: numNone),
|
||||
promotedBound: intNone,
|
||||
),
|
||||
'int',
|
||||
);
|
||||
withTypeParameterScope('T extends num', (scope) {
|
||||
_check(scope.parseType('T & int'), 'int');
|
||||
});
|
||||
|
||||
_check(
|
||||
typeParameterTypeNone(
|
||||
typeParameter('T', bound: numQuestion),
|
||||
promotedBound: intQuestion,
|
||||
),
|
||||
'int?',
|
||||
);
|
||||
withTypeParameterScope('T extends num?', (scope) {
|
||||
_check(scope.parseType('T & int?'), 'int?');
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_check(voidNone, 'void');
|
||||
_check(parseType('void'), 'void');
|
||||
}
|
||||
|
||||
void _check(TypeImpl type, String expectedStr) {
|
||||
|
||||
@@ -2,7 +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.
|
||||
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
@@ -26,225 +26,168 @@ class RuntimeTypeEqualityTypeTest extends AbstractTypeSystemTest
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
_equal(dynamicType, dynamicType);
|
||||
_notEqual(dynamicType, voidNone);
|
||||
_notEqual(dynamicType, intNone);
|
||||
_equal(parseType('dynamic'), parseType('dynamic'));
|
||||
_notEqual(parseType('dynamic'), parseType('void'));
|
||||
_notEqual(parseType('dynamic'), parseType('int'));
|
||||
|
||||
_notEqual(dynamicType, neverNone);
|
||||
_notEqual(dynamicType, neverQuestion);
|
||||
_notEqual(parseType('dynamic'), parseType('Never'));
|
||||
_notEqual(parseType('dynamic'), parseType('Never?'));
|
||||
}
|
||||
|
||||
test_functionType_parameters() {
|
||||
void check(
|
||||
FormalParameterElementImpl T1_parameter,
|
||||
FormalParameterElementImpl T2_parameter,
|
||||
bool expected,
|
||||
) {
|
||||
var T1 = functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [T1_parameter],
|
||||
);
|
||||
var T2 = functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [T2_parameter],
|
||||
);
|
||||
_check(T1, T2, expected);
|
||||
void check(String T1, String T2, bool expected) {
|
||||
_check(parseFunctionType(T1), parseFunctionType(T2), expected);
|
||||
}
|
||||
|
||||
{
|
||||
void checkRequiredParameter(
|
||||
TypeImpl T1_type,
|
||||
TypeImpl T2_type,
|
||||
bool expected,
|
||||
) {
|
||||
check(
|
||||
requiredParameter(type: T1_type),
|
||||
requiredParameter(type: T2_type),
|
||||
expected,
|
||||
);
|
||||
void checkRequiredParameter(String T1, String T2, bool expected) {
|
||||
check('void Function($T1)', 'void Function($T2)', expected);
|
||||
}
|
||||
|
||||
checkRequiredParameter(intNone, intNone, true);
|
||||
checkRequiredParameter(intNone, intQuestion, false);
|
||||
checkRequiredParameter('int', 'int', true);
|
||||
checkRequiredParameter('int', 'int?', false);
|
||||
|
||||
checkRequiredParameter(intQuestion, intNone, false);
|
||||
checkRequiredParameter(intQuestion, intQuestion, true);
|
||||
checkRequiredParameter('int?', 'int', false);
|
||||
checkRequiredParameter('int?', 'int?', true);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone, name: 'a'),
|
||||
requiredParameter(type: intNone, name: 'b'),
|
||||
true,
|
||||
);
|
||||
check('void Function(int a)', 'void Function(int b)', true);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
positionalParameter(type: intNone),
|
||||
false,
|
||||
);
|
||||
check('void Function(int)', 'void Function([int])', false);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
check('void Function(int)', 'void Function({int a})', false);
|
||||
|
||||
check(
|
||||
requiredParameter(type: intNone),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
check('void Function(int)', 'void Function({required int a})', false);
|
||||
}
|
||||
|
||||
{
|
||||
check('void Function({int a})', 'void Function({int a})', true);
|
||||
|
||||
check('void Function({int a})', 'void Function({bool a})', false);
|
||||
|
||||
check('void Function({int a})', 'void Function({int b})', false);
|
||||
|
||||
check('void Function({int a})', 'void Function({required int a})', false);
|
||||
}
|
||||
|
||||
{
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
'void Function({required int a})',
|
||||
'void Function({required int a})',
|
||||
true,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: boolNone, name: 'a'),
|
||||
'void Function({required int a})',
|
||||
'void Function({required bool a})',
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'b'),
|
||||
'void Function({required int a})',
|
||||
'void Function({required int b})',
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
true,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: boolNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedRequiredParameter(type: intNone, name: 'b'),
|
||||
false,
|
||||
);
|
||||
|
||||
check(
|
||||
namedRequiredParameter(type: intNone, name: 'a'),
|
||||
namedParameter(type: intNone, name: 'a'),
|
||||
false,
|
||||
);
|
||||
check('void Function({required int a})', 'void Function({int a})', false);
|
||||
}
|
||||
}
|
||||
|
||||
test_functionType_returnType() {
|
||||
void check(TypeImpl T1_returnType, TypeImpl T2_returnType, bool expected) {
|
||||
var T1 = functionTypeNone(returnType: T1_returnType);
|
||||
var T2 = functionTypeNone(returnType: T2_returnType);
|
||||
_check(T1, T2, expected);
|
||||
void check(String T1, String T2, bool expected) {
|
||||
_check(parseFunctionType(T1), parseFunctionType(T2), expected);
|
||||
}
|
||||
|
||||
check(intNone, intNone, true);
|
||||
check(intNone, intQuestion, false);
|
||||
check('int Function()', 'int Function()', true);
|
||||
check('int Function()', 'int? Function()', false);
|
||||
}
|
||||
|
||||
test_functionType_typeParameters() {
|
||||
{
|
||||
var T1_T = typeParameter('T', bound: numNone);
|
||||
_check(
|
||||
functionTypeNone(typeParameters: [T1_T], returnType: voidNone),
|
||||
functionTypeNone(returnType: voidNone),
|
||||
parseType('void Function<T extends num>()'),
|
||||
parseType('void Function()'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var T1_T = typeParameter('T', bound: numNone);
|
||||
var T2_U = typeParameter('U');
|
||||
_check(
|
||||
functionTypeNone(typeParameters: [T1_T], returnType: voidNone),
|
||||
functionTypeNone(typeParameters: [T2_U], returnType: voidNone),
|
||||
parseType('void Function<T extends num>()'),
|
||||
parseType('void Function<U>()'),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var T1_T = typeParameter('T');
|
||||
var T2_U = typeParameter('U');
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeParameters: [T1_T],
|
||||
returnType: typeParameterTypeNone(T1_T),
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T1_T)),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
typeParameters: [T2_U],
|
||||
returnType: typeParameterTypeNone(T2_U),
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(T2_U)),
|
||||
],
|
||||
),
|
||||
parseType('T Function<T>(T)'),
|
||||
parseType('U Function<U>(U)'),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_notEqual(intNone, boolNone);
|
||||
_notEqual(parseType('int'), parseType('bool'));
|
||||
|
||||
_equal(intNone, intNone);
|
||||
_notEqual(intNone, intQuestion);
|
||||
_equal(parseType('int'), parseType('int'));
|
||||
_notEqual(parseType('int'), parseType('int?'));
|
||||
|
||||
_notEqual(intQuestion, intNone);
|
||||
_equal(intQuestion, intQuestion);
|
||||
_notEqual(parseType('int?'), parseType('int'));
|
||||
_equal(parseType('int?'), parseType('int?'));
|
||||
}
|
||||
|
||||
test_interfaceType_typeArguments() {
|
||||
void equal(TypeImpl T1, TypeImpl T2) {
|
||||
_equal(listNone(T1), listNone(T2));
|
||||
_equal(
|
||||
typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: [T1],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: [T2],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void notEqual(TypeImpl T1, TypeImpl T2) {
|
||||
_notEqual(listNone(T1), listNone(T2));
|
||||
_notEqual(
|
||||
typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: [T1],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
typeProvider.listElement.instantiateImpl(
|
||||
typeArguments: [T2],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
notEqual(intNone, boolNone);
|
||||
notEqual(parseType('int'), parseType('bool'));
|
||||
|
||||
equal(intNone, intNone);
|
||||
notEqual(intNone, intQuestion);
|
||||
equal(parseType('int'), parseType('int'));
|
||||
notEqual(parseType('int'), parseType('int?'));
|
||||
|
||||
notEqual(intQuestion, intNone);
|
||||
equal(intQuestion, intQuestion);
|
||||
notEqual(parseType('int?'), parseType('int'));
|
||||
equal(parseType('int?'), parseType('int?'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_equal(neverNone, neverNone);
|
||||
_notEqual(neverNone, neverQuestion);
|
||||
_notEqual(neverNone, intNone);
|
||||
_equal(parseType('Never'), parseType('Never'));
|
||||
_notEqual(parseType('Never'), parseType('Never?'));
|
||||
_notEqual(parseType('Never'), parseType('int'));
|
||||
|
||||
_notEqual(neverQuestion, neverNone);
|
||||
_equal(neverQuestion, neverQuestion);
|
||||
_notEqual(neverQuestion, intNone);
|
||||
_equal(neverQuestion, nullNone);
|
||||
_notEqual(parseType('Never?'), parseType('Never'));
|
||||
_equal(parseType('Never?'), parseType('Never?'));
|
||||
_notEqual(parseType('Never?'), parseType('int'));
|
||||
_equal(parseType('Never?'), parseType('Null'));
|
||||
}
|
||||
|
||||
test_norm() {
|
||||
_equal(futureOrNone(objectNone), objectNone);
|
||||
_equal(futureOrNone(neverNone), futureNone(neverNone));
|
||||
_equal(neverQuestion, nullNone);
|
||||
_equal(parseType('FutureOr<Object>'), parseType('Object'));
|
||||
_equal(parseType('FutureOr<Never>'), parseType('Future<Never>'));
|
||||
_equal(parseType('Never?'), parseType('Null'));
|
||||
}
|
||||
|
||||
test_recordType_andNot() {
|
||||
@@ -275,12 +218,12 @@ class RuntimeTypeEqualityTypeTest extends AbstractTypeSystemTest
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_equal(voidNone, voidNone);
|
||||
_notEqual(voidNone, dynamicType);
|
||||
_notEqual(voidNone, intNone);
|
||||
_equal(parseType('void'), parseType('void'));
|
||||
_notEqual(parseType('void'), parseType('dynamic'));
|
||||
_notEqual(parseType('void'), parseType('int'));
|
||||
|
||||
_notEqual(voidNone, neverNone);
|
||||
_notEqual(voidNone, neverQuestion);
|
||||
_notEqual(parseType('void'), parseType('Never'));
|
||||
_notEqual(parseType('void'), parseType('Never?'));
|
||||
}
|
||||
|
||||
void _check(TypeImpl T1, TypeImpl T2, bool expected) {
|
||||
|
||||
@@ -22,62 +22,20 @@ mixin StringTypes on AbstractTypeSystemTest {
|
||||
}
|
||||
|
||||
void defineStringTypes() {
|
||||
_defineType('dynamic', dynamicType);
|
||||
_defineType('InvalidType', invalidType);
|
||||
_defineType('void', voidNone);
|
||||
|
||||
_defineType('Never', neverNone);
|
||||
_defineType('Never?', neverQuestion);
|
||||
|
||||
_defineType('Null', nullNone);
|
||||
|
||||
_defineType('Object', objectNone);
|
||||
_defineType('Object?', objectQuestion);
|
||||
|
||||
_defineType('Comparable<Object>', comparableNone(objectNone));
|
||||
_defineType('Comparable<num>', comparableNone(numNone));
|
||||
_defineType('Comparable<int>', comparableNone(intNone));
|
||||
|
||||
_defineType('num', numNone);
|
||||
_defineType('num?', numQuestion);
|
||||
|
||||
_defineType('int', intNone);
|
||||
_defineType('int?', intQuestion);
|
||||
|
||||
_defineType('double', doubleNone);
|
||||
_defineType('double?', doubleQuestion);
|
||||
|
||||
_defineType('List<Object>', listNone(objectNone));
|
||||
_defineType('List<num>', listNone(numNone));
|
||||
_defineType('List<int>', listNone(intNone));
|
||||
_defineType('List<int>?', listQuestion(intNone));
|
||||
_defineType('List<int?>', listNone(intQuestion));
|
||||
|
||||
_defineType(
|
||||
'List<Comparable<Object>>',
|
||||
listNone(comparableNone(objectNone)),
|
||||
);
|
||||
_defineType('List<Comparable<num>>', listNone(comparableNone(numNone)));
|
||||
_defineType(
|
||||
'List<Comparable<Comparable<num>>>',
|
||||
listNone(comparableNone(comparableNone(numNone))),
|
||||
);
|
||||
|
||||
_defineType('Iterable<Object>', iterableNone(objectNone));
|
||||
_defineType('Iterable<num>', iterableNone(numNone));
|
||||
_defineType('Iterable<int>', iterableNone(intNone));
|
||||
|
||||
_defineFunctionTypes();
|
||||
_defineFutureTypes();
|
||||
_defineRecordTypes();
|
||||
_types.clear();
|
||||
}
|
||||
|
||||
TypeImpl typeOfString(String str) {
|
||||
var type = _types[str];
|
||||
if (type == null) {
|
||||
fail('No TypeImpl for: $str');
|
||||
}
|
||||
return type;
|
||||
return _types.putIfAbsent(str, () {
|
||||
var type = parseType(str);
|
||||
|
||||
var typeStr = typeString(type);
|
||||
if (typeStr != str) {
|
||||
fail('Expected: $str\nActual: $typeStr');
|
||||
}
|
||||
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
String typesString(List<TypeImpl> types) {
|
||||
@@ -89,309 +47,6 @@ mixin StringTypes on AbstractTypeSystemTest {
|
||||
return type.getDisplayString() + _typeParametersStr(type);
|
||||
}
|
||||
|
||||
void _defineFunctionTypes() {
|
||||
_defineType('Function', functionNone);
|
||||
_defineType('Function?', functionQuestion);
|
||||
|
||||
_defineType('void Function()', functionTypeNone(returnType: voidNone));
|
||||
|
||||
_defineType('int Function()', functionTypeNone(returnType: intNone));
|
||||
_defineType('int Function()?', functionTypeQuestion(returnType: intNone));
|
||||
|
||||
_defineType(
|
||||
'num Function(num)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num Function(num)?',
|
||||
functionTypeQuestion(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'num Function(int)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num Function(int)?',
|
||||
functionTypeQuestion(
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'int Function(num)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: intNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'int Function(int)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
returnType: intNone,
|
||||
),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'num Function(num?)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numQuestion)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function(num)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function(num?)',
|
||||
functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: numQuestion)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'num Function({num x})',
|
||||
functionTypeNone(
|
||||
formalParameters: [namedParameter(name: 'x', type: numNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num Function({num? x})',
|
||||
functionTypeNone(
|
||||
formalParameters: [namedParameter(name: 'x', type: numQuestion)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function({num x})',
|
||||
functionTypeNone(
|
||||
formalParameters: [namedParameter(name: 'x', type: numNone)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function({num? x})',
|
||||
functionTypeNone(
|
||||
formalParameters: [namedParameter(name: 'x', type: numQuestion)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'num Function([num])',
|
||||
functionTypeNone(
|
||||
formalParameters: [positionalParameter(type: numNone)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num Function([num?])',
|
||||
functionTypeNone(
|
||||
formalParameters: [positionalParameter(type: numQuestion)],
|
||||
returnType: numNone,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function([num])',
|
||||
functionTypeNone(
|
||||
formalParameters: [positionalParameter(type: numNone)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
_defineType(
|
||||
'num? Function([num?])',
|
||||
functionTypeNone(
|
||||
formalParameters: [positionalParameter(type: numQuestion)],
|
||||
returnType: numQuestion,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _defineFutureTypes() {
|
||||
_defineType('FutureOr<Object>', futureOrNone(objectNone));
|
||||
_defineType('FutureOr<Object>?', futureOrQuestion(objectNone));
|
||||
_defineType('FutureOr<Object?>', futureOrNone(objectQuestion));
|
||||
_defineType('FutureOr<Object?>?', futureOrQuestion(objectQuestion));
|
||||
|
||||
_defineType('FutureOr<num>', futureOrNone(numNone));
|
||||
_defineType('FutureOr<num?>', futureOrNone(numQuestion));
|
||||
_defineType('FutureOr<num>?', futureOrQuestion(numNone));
|
||||
_defineType('FutureOr<num?>?', futureOrQuestion(numQuestion));
|
||||
|
||||
_defineType('Future<num>', futureNone(numNone));
|
||||
_defineType('Future<num>?', futureQuestion(numNone));
|
||||
_defineType('Future<num?>', futureNone(numQuestion));
|
||||
_defineType('Future<num?>?', futureQuestion(numQuestion));
|
||||
|
||||
_defineType('FutureOr<int>', futureOrNone(intNone));
|
||||
_defineType('FutureOr<int>?', futureOrQuestion(intNone));
|
||||
_defineType('FutureOr<int?>', futureOrNone(intQuestion));
|
||||
_defineType('FutureOr<int?>?', futureOrQuestion(intQuestion));
|
||||
|
||||
_defineType('Future<int>', futureNone(intNone));
|
||||
_defineType('Future<int>?', futureQuestion(intNone));
|
||||
_defineType('Future<int?>', futureNone(intQuestion));
|
||||
_defineType('Future<int?>?', futureQuestion(intQuestion));
|
||||
|
||||
_defineType('Future<Object>', futureNone(objectNone));
|
||||
_defineType(
|
||||
'FutureOr<Future<Object>>',
|
||||
futureOrNone(futureNone(objectNone)),
|
||||
);
|
||||
_defineType(
|
||||
'FutureOr<Future<Object>>?',
|
||||
futureOrQuestion(futureNone(objectNone)),
|
||||
);
|
||||
_defineType(
|
||||
'FutureOr<Future<Object>?>',
|
||||
futureOrNone(futureQuestion(objectNone)),
|
||||
);
|
||||
_defineType(
|
||||
'FutureOr<Future<Object>?>?',
|
||||
futureOrQuestion(futureQuestion(objectNone)),
|
||||
);
|
||||
|
||||
_defineType('Future<Future<num>>?', futureQuestion(futureNone(numNone)));
|
||||
_defineType(
|
||||
'Future<Future<num?>?>?',
|
||||
futureQuestion(futureQuestion(numQuestion)),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'Future<Future<Future<num>>>?',
|
||||
futureQuestion(futureNone(futureNone(numNone))),
|
||||
);
|
||||
_defineType(
|
||||
'Future<Future<Future<num?>?>?>?',
|
||||
futureQuestion(futureQuestion(futureQuestion(numQuestion))),
|
||||
);
|
||||
|
||||
_defineType(
|
||||
'FutureOr<FutureOr<FutureOr<num>>?>',
|
||||
futureOrNone(futureOrQuestion(futureOrNone(numNone))),
|
||||
);
|
||||
_defineType(
|
||||
'FutureOr<FutureOr<FutureOr<num?>>>',
|
||||
futureOrNone(futureOrNone(futureOrNone(numQuestion))),
|
||||
);
|
||||
}
|
||||
|
||||
void _defineRecordTypes() {
|
||||
_defineType('Record', recordNone);
|
||||
|
||||
void mixed(
|
||||
String str,
|
||||
List<TypeImpl> positionalTypes,
|
||||
Map<String, TypeImpl> namedTypes,
|
||||
) {
|
||||
var type = recordTypeNone(
|
||||
positionalTypes: positionalTypes,
|
||||
namedTypes: namedTypes,
|
||||
);
|
||||
_defineType(str, type);
|
||||
}
|
||||
|
||||
void allPositional(String str, List<TypeImpl> types) {
|
||||
mixed(str, types, const {});
|
||||
}
|
||||
|
||||
void allPositionalQuestion(String str, List<TypeImpl> types) {
|
||||
var type = recordTypeQuestion(positionalTypes: types);
|
||||
_defineType(str, type);
|
||||
}
|
||||
|
||||
allPositional('(double,)', [doubleNone]);
|
||||
allPositional('(int,)', [intNone]);
|
||||
allPositional('(int?,)', [intQuestion]);
|
||||
allPositional('(num,)', [numNone]);
|
||||
allPositional('(Never,)', [neverNone]);
|
||||
|
||||
allPositionalQuestion('(int,)?', [intNone]);
|
||||
allPositionalQuestion('(int?,)?', [intQuestion]);
|
||||
|
||||
allPositional('(double, int)', [doubleNone, intNone]);
|
||||
allPositional('(int, double)', [intNone, doubleNone]);
|
||||
allPositional('(int, int)', [intNone, intNone]);
|
||||
allPositional('(int, Object)', [intNone, objectNone]);
|
||||
allPositional('(int, String)', [intNone, stringNone]);
|
||||
allPositional('(num, num)', [numNone, numNone]);
|
||||
allPositional('(num, Object)', [numNone, objectNone]);
|
||||
allPositional('(num, String)', [numNone, stringNone]);
|
||||
allPositional('(Never, Never)', [neverNone, neverNone]);
|
||||
|
||||
void allNamed(String str, Map<String, TypeImpl> types) {
|
||||
mixed(str, const [], types);
|
||||
}
|
||||
|
||||
void allNamedQuestion(String str, Map<String, TypeImpl> types) {
|
||||
var type = recordTypeQuestion(namedTypes: types);
|
||||
_defineType(str, type);
|
||||
}
|
||||
|
||||
allNamed('({double f1})', {'f1': doubleNone});
|
||||
allNamed('({int f1})', {'f1': intNone});
|
||||
allNamed('({int? f1})', {'f1': intQuestion});
|
||||
allNamed('({num f1})', {'f1': numNone});
|
||||
allNamed('({int f2})', {'f2': intNone});
|
||||
allNamed('({Never f1})', {'f1': neverNone});
|
||||
allNamed(r'({int $1})', {r'$1': intNone});
|
||||
|
||||
allNamedQuestion('({int f1})?', {'f1': intNone});
|
||||
allNamedQuestion('({int? f1})?', {'f1': intQuestion});
|
||||
|
||||
allNamed('({double f1, int f2})', {'f1': doubleNone, 'f2': intNone});
|
||||
allNamed('({int f1, double f2})', {'f1': intNone, 'f2': doubleNone});
|
||||
allNamed('({int f1, int f2})', {'f1': intNone, 'f2': intNone});
|
||||
allNamed('({int f1, Object f2})', {'f1': intNone, 'f2': objectNone});
|
||||
allNamed('({int f1, String f2})', {'f1': intNone, 'f2': stringNone});
|
||||
allNamed('({num f1, num f2})', {'f1': numNone, 'f2': numNone});
|
||||
allNamed('({num f1, Object f2})', {'f1': numNone, 'f2': objectNone});
|
||||
allNamed('({num f1, String f2})', {'f1': numNone, 'f2': stringNone});
|
||||
allNamed('({Never f1, Never f2})', {'f1': neverNone, 'f2': neverNone});
|
||||
|
||||
mixed('(int, {Object f2})', [intNone], {'f2': objectNone});
|
||||
mixed('(int, {String f2})', [intNone], {'f2': stringNone});
|
||||
}
|
||||
|
||||
void _defineType(String str, TypeImpl type) {
|
||||
if (typeString(type) != str) {
|
||||
fail('Expected: $str\nActual: ${typeString(type)}');
|
||||
}
|
||||
|
||||
for (var entry in _types.entries) {
|
||||
var key = entry.key;
|
||||
if (key == 'Never' || typeString(type) == 'Never') {
|
||||
// We have aliases for Never.
|
||||
} else {
|
||||
var value = entry.value;
|
||||
if (key == str) {
|
||||
fail('Duplicate type: $str; existing: $value; new: $type');
|
||||
}
|
||||
if (typeString(value) == typeString(type)) {
|
||||
fail('Duplicate type: $str');
|
||||
}
|
||||
}
|
||||
}
|
||||
_types[str] = type;
|
||||
}
|
||||
|
||||
String _typeParametersStr(TypeImpl type) {
|
||||
var typeStr = '';
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,331 +17,231 @@ main() {
|
||||
@reflectiveTest
|
||||
class TopMergeTest extends AbstractTypeSystemTest {
|
||||
test_differentStructure() {
|
||||
_checkThrows(intNone, functionTypeNone(returnType: voidNone));
|
||||
_checkThrows(parseType('int'), parseType('void Function()'));
|
||||
|
||||
_checkThrows(intNone, typeParameterTypeNone(typeParameter('T')));
|
||||
|
||||
_checkThrows(
|
||||
functionTypeNone(returnType: voidNone),
|
||||
typeParameterTypeNone(typeParameter('T')),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_checkThrows(parseType('int'), scope.parseType('T'));
|
||||
_checkThrows(parseType('void Function()'), scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic() {
|
||||
// NNBD_TOP_MERGE(dynamic, dynamic) = dynamic
|
||||
_check(dynamicType, dynamicType, dynamicType);
|
||||
_check(parseType('dynamic'), parseType('dynamic'), parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_function_formalParameters_differentCount() {
|
||||
_checkThrows(
|
||||
functionTypeNone(returnType: voidNone, formalParameters: []),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
),
|
||||
parseFunctionType('void Function()'),
|
||||
parseFunctionType('void Function(int)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_covariant() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
requiredParameter(type: objectQuestion, isCovariant: true),
|
||||
],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: dynamicType)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [
|
||||
requiredParameter(type: objectQuestion, isCovariant: true),
|
||||
],
|
||||
),
|
||||
parseFunctionType('void Function(covariant Object?)'),
|
||||
parseFunctionType('void Function(dynamic)'),
|
||||
parseFunctionType('void Function(covariant Object?)'),
|
||||
);
|
||||
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone, isCovariant: true)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: numNone)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: numNone, isCovariant: true)],
|
||||
),
|
||||
parseFunctionType('void Function(covariant int)'),
|
||||
parseFunctionType('void Function(num)'),
|
||||
parseFunctionType('void Function(covariant num)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_kind_optionalPositional_optionalPositional() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: intNone)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: intNone)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: intNone)],
|
||||
),
|
||||
parseFunctionType('void Function([int])'),
|
||||
parseFunctionType('void Function([int])'),
|
||||
parseFunctionType('void Function([int])'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_kind_requiredNamed_optionalNamed() {
|
||||
_checkThrows(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedRequiredParameter(type: intNone, name: 'a')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedParameter(type: intNone, name: 'a')],
|
||||
),
|
||||
parseFunctionType('void Function({required int a})'),
|
||||
parseFunctionType('void Function({int a})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_kind_requiredPositional_optionalPositional() {
|
||||
_checkThrows(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [positionalParameter(type: intNone)],
|
||||
),
|
||||
parseFunctionType('void Function(int)'),
|
||||
parseFunctionType('void Function([int])'),
|
||||
);
|
||||
|
||||
_checkThrows(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedParameter(type: intNone, name: 'a')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [namedParameter(type: intNone, name: 'b')],
|
||||
),
|
||||
parseFunctionType('void Function({int a})'),
|
||||
parseFunctionType('void Function({int b})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_mismatch() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone, name: 'a')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone, name: 'b')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: intNone, name: 'a')],
|
||||
),
|
||||
parseFunctionType('void Function(int a)'),
|
||||
parseFunctionType('void Function(int b)'),
|
||||
parseFunctionType('void Function(int a)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_parameters_type() {
|
||||
_check(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: objectQuestion, name: 'a')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: dynamicType, name: 'a')],
|
||||
),
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: objectQuestion, name: 'a')],
|
||||
),
|
||||
parseFunctionType('void Function(Object? a)'),
|
||||
parseFunctionType('void Function(dynamic a)'),
|
||||
parseFunctionType('void Function(Object? a)'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_returnType() {
|
||||
_check(
|
||||
functionTypeNone(returnType: voidNone),
|
||||
functionTypeNone(returnType: objectQuestion),
|
||||
functionTypeNone(returnType: objectQuestion),
|
||||
parseFunctionType('void Function()'),
|
||||
parseFunctionType('Object? Function()'),
|
||||
parseFunctionType('Object? Function()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_typeParameters_boundsMerge() {
|
||||
var T1 = typeParameter('T', bound: dynamicType);
|
||||
var T2 = typeParameter('T', bound: objectQuestion);
|
||||
var TR = typeParameter('T', bound: objectQuestion);
|
||||
_check(
|
||||
functionTypeNone(
|
||||
typeParameters: [T1],
|
||||
returnType: typeParameterTypeNone(T1),
|
||||
),
|
||||
functionTypeNone(
|
||||
typeParameters: [T2],
|
||||
returnType: typeParameterTypeNone(T2),
|
||||
),
|
||||
functionTypeNone(
|
||||
typeParameters: [TR],
|
||||
returnType: typeParameterTypeNone(TR),
|
||||
),
|
||||
parseFunctionType('T Function<T extends dynamic>()'),
|
||||
parseFunctionType('T Function<T extends Object?>()'),
|
||||
parseFunctionType('T Function<T extends Object?>()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_typeParameters_boundsMismatch() {
|
||||
var T1 = typeParameter('T', bound: intNone);
|
||||
var T2 = typeParameter('T');
|
||||
_checkThrows(
|
||||
functionTypeNone(
|
||||
typeParameters: [T1],
|
||||
returnType: typeParameterTypeNone(T1),
|
||||
),
|
||||
functionTypeNone(
|
||||
typeParameters: [T2],
|
||||
returnType: typeParameterTypeNone(T2),
|
||||
),
|
||||
parseFunctionType('T Function<T extends int>()'),
|
||||
parseFunctionType('T Function<T>()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_function_typeParameters_differentCount() {
|
||||
var T = typeParameter('T');
|
||||
var S = typeParameter('S');
|
||||
_checkThrows(
|
||||
functionTypeNone(returnType: voidNone),
|
||||
functionTypeNone(typeParameters: [T, S], returnType: voidNone),
|
||||
parseFunctionType('void Function()'),
|
||||
parseFunctionType('void Function<T, S>()'),
|
||||
);
|
||||
}
|
||||
|
||||
test_interface() {
|
||||
_check(
|
||||
listNone(dynamicType),
|
||||
listNone(objectQuestion),
|
||||
listNone(objectQuestion),
|
||||
parseType('List<dynamic>'),
|
||||
parseType('List<Object?>'),
|
||||
parseType('List<Object?>'),
|
||||
);
|
||||
|
||||
_check(
|
||||
listNone(voidNone),
|
||||
listNone(objectQuestion),
|
||||
listNone(objectQuestion),
|
||||
parseType('List<void>'),
|
||||
parseType('List<Object?>'),
|
||||
parseType('List<Object?>'),
|
||||
);
|
||||
|
||||
_checkThrows(iterableNone(intNone), listNone(intNone));
|
||||
_checkThrows(parseType('Iterable<int>'), parseType('List<int>'));
|
||||
}
|
||||
|
||||
test_invalid() {
|
||||
_check(invalidType, intNone, invalidType);
|
||||
_check(intNone, invalidType, invalidType);
|
||||
_check(
|
||||
parseType('InvalidType'),
|
||||
parseType('int'),
|
||||
parseType('InvalidType'),
|
||||
);
|
||||
_check(
|
||||
parseType('int'),
|
||||
parseType('InvalidType'),
|
||||
parseType('InvalidType'),
|
||||
);
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_check(neverNone, neverNone, neverNone);
|
||||
_check(parseType('Never'), parseType('Never'), parseType('Never'));
|
||||
}
|
||||
|
||||
test_nullability() {
|
||||
// NNBD_TOP_MERGE(T?, S?) = NNBD_TOP_MERGE(T, S)?
|
||||
_check(intQuestion, intQuestion, intQuestion);
|
||||
_check(parseType('int?'), parseType('int?'), parseType('int?'));
|
||||
}
|
||||
|
||||
test_nullability_mismatch() {
|
||||
_checkThrows(intQuestion, intNone);
|
||||
_checkThrows(parseType('int?'), parseType('int'));
|
||||
}
|
||||
|
||||
test_objectQuestion() {
|
||||
// NNBD_TOP_MERGE(Object?, Object?) = Object?
|
||||
_check(objectQuestion, objectQuestion, objectQuestion);
|
||||
_check(parseType('Object?'), parseType('Object?'), parseType('Object?'));
|
||||
|
||||
// NNBD_TOP_MERGE(Object?, void) = Object?
|
||||
// NNBD_TOP_MERGE(void, Object?) = Object?
|
||||
_check(objectQuestion, voidNone, objectQuestion);
|
||||
_check(parseType('Object?'), parseType('void'), parseType('Object?'));
|
||||
|
||||
// NNBD_TOP_MERGE(Object?, dynamic) = Object?
|
||||
// NNBD_TOP_MERGE(dynamic, Object?) = Object?
|
||||
_check(objectQuestion, dynamicType, objectQuestion);
|
||||
_check(parseType('Object?'), parseType('dynamic'), parseType('Object?'));
|
||||
}
|
||||
|
||||
test_record() {
|
||||
_check(
|
||||
recordTypeNone(positionalTypes: [dynamicType]),
|
||||
recordTypeNone(positionalTypes: [objectQuestion]),
|
||||
recordTypeNone(positionalTypes: [objectQuestion]),
|
||||
parseRecordType('(dynamic,)'),
|
||||
parseRecordType('(Object?,)'),
|
||||
parseRecordType('(Object?,)'),
|
||||
);
|
||||
|
||||
_check(
|
||||
recordTypeNone(positionalTypes: [voidNone]),
|
||||
recordTypeNone(positionalTypes: [objectQuestion]),
|
||||
recordTypeNone(positionalTypes: [objectQuestion]),
|
||||
parseRecordType('(void,)'),
|
||||
parseRecordType('(Object?,)'),
|
||||
parseRecordType('(Object?,)'),
|
||||
);
|
||||
|
||||
_check(
|
||||
recordTypeNone(namedTypes: {'f': dynamicType}),
|
||||
recordTypeNone(namedTypes: {'f': objectQuestion}),
|
||||
recordTypeNone(namedTypes: {'f': objectQuestion}),
|
||||
parseRecordType('({dynamic f})'),
|
||||
parseRecordType('({Object? f})'),
|
||||
parseRecordType('({Object? f})'),
|
||||
);
|
||||
|
||||
_check(
|
||||
recordTypeNone(
|
||||
positionalTypes: [dynamicType],
|
||||
namedTypes: {'f': voidNone},
|
||||
),
|
||||
recordTypeNone(
|
||||
positionalTypes: [objectQuestion],
|
||||
namedTypes: {'f': objectQuestion},
|
||||
),
|
||||
recordTypeNone(
|
||||
positionalTypes: [objectQuestion],
|
||||
namedTypes: {'f': objectQuestion},
|
||||
),
|
||||
parseRecordType('(dynamic, {void f})'),
|
||||
parseRecordType('(Object?, {Object? f})'),
|
||||
parseRecordType('(Object?, {Object? f})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_record_namedFields_differentCount() {
|
||||
_checkThrows(
|
||||
recordTypeNone(namedTypes: {'a': intNone}),
|
||||
recordTypeNone(namedTypes: {'a': intNone, 'b': intNone}),
|
||||
parseRecordType('({int a})'),
|
||||
parseRecordType('({int a, int b})'),
|
||||
);
|
||||
}
|
||||
|
||||
test_record_namedFields_differentNames() {
|
||||
_checkThrows(
|
||||
recordTypeNone(namedTypes: {'a': intNone}),
|
||||
recordTypeNone(namedTypes: {'b': intNone}),
|
||||
);
|
||||
_checkThrows(parseRecordType('({int a})'), parseRecordType('({int b})'));
|
||||
}
|
||||
|
||||
test_record_positionalFields_differentCount() {
|
||||
_checkThrows(
|
||||
recordTypeNone(positionalTypes: [intNone]),
|
||||
recordTypeNone(positionalTypes: [intNone, intNone]),
|
||||
);
|
||||
_checkThrows(parseRecordType('(int,)'), parseRecordType('(int, int)'));
|
||||
}
|
||||
|
||||
test_typeParameter() {
|
||||
var T = typeParameter('T');
|
||||
withTypeParameterScope('T', (scope1) {
|
||||
_check(
|
||||
scope1.parseType('T'),
|
||||
scope1.parseType('T'),
|
||||
scope1.parseType('T'),
|
||||
);
|
||||
|
||||
_check(
|
||||
typeParameterTypeNone(T),
|
||||
typeParameterTypeNone(T),
|
||||
typeParameterTypeNone(T),
|
||||
);
|
||||
|
||||
var S = typeParameter('T');
|
||||
_checkThrows(typeParameterTypeNone(T), typeParameterTypeNone(S));
|
||||
_checkThrows(typeParameterTypeNone(S), typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope2) {
|
||||
_checkThrows(scope1.parseType('T'), scope2.parseType('T'));
|
||||
_checkThrows(scope2.parseType('T'), scope1.parseType('T'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
// NNBD_TOP_MERGE(void, void) = void
|
||||
_check(voidNone, voidNone, voidNone);
|
||||
_check(parseType('void'), parseType('void'), parseType('void'));
|
||||
|
||||
// NNBD_TOP_MERGE(void, dynamic) = Object?
|
||||
// NNBD_TOP_MERGE(dynamic, void) = Object?
|
||||
_check(voidNone, dynamicType, objectQuestion);
|
||||
_check(parseType('void'), parseType('dynamic'), parseType('Object?'));
|
||||
}
|
||||
|
||||
void _check(TypeImpl T, TypeImpl S, TypeImpl expected) {
|
||||
|
||||
@@ -47,31 +47,36 @@ DartType substitute(
|
||||
@reflectiveTest
|
||||
class MapSubstitutionTest extends _Base {
|
||||
test_andThen_empty_andThenNotEmpty() {
|
||||
var T = typeParameter('T');
|
||||
var after = Substitution.fromMap({T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var after = Substitution.fromMap({T: scope.parseType('int')});
|
||||
|
||||
var combined = Substitution.empty.andThen(after);
|
||||
expect(combined, same(Substitution.empty));
|
||||
var combined = Substitution.empty.andThen(after);
|
||||
expect(combined, same(Substitution.empty));
|
||||
});
|
||||
}
|
||||
|
||||
test_andThen_notEmpty_andThenEmpty() {
|
||||
var T = typeParameter('T');
|
||||
var inner = Substitution.fromMap({T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var inner = Substitution.fromMap({T: scope.parseType('int')});
|
||||
|
||||
var combined = inner.andThen(Substitution.empty);
|
||||
expect(combined, same(inner));
|
||||
var combined = inner.andThen(Substitution.empty);
|
||||
expect(combined, same(inner));
|
||||
});
|
||||
}
|
||||
|
||||
test_andThen_notEmpty_andThenNotEmpty() {
|
||||
var T = typeParameter('T');
|
||||
var G = typeParameter('G');
|
||||
withTypeParameterScope('T, G', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var G = scope.typeParameter('G');
|
||||
var inner = Substitution.fromMap({T: scope.parseType('List<G>')});
|
||||
var after = Substitution.fromMap({G: parseType('String')});
|
||||
|
||||
var inner = Substitution.fromMap({T: listNone(typeParameterTypeNone(G))});
|
||||
var after = Substitution.fromMap({G: stringNone});
|
||||
|
||||
var combined = inner.andThen(after);
|
||||
var result = combined.substituteType(typeParameterTypeNone(T));
|
||||
assertType(result, 'List<String>');
|
||||
var combined = inner.andThen(after);
|
||||
var result = combined.substituteType(scope.parseType('T'));
|
||||
assertType(result, 'List<String>');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,9 +85,8 @@ class SubstituteEmptyTest extends _Base {
|
||||
test_interface() async {
|
||||
// class A<T> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var type = interfaceTypeNone(A, typeArguments: [intNone]);
|
||||
var type = parseType('A<int>');
|
||||
|
||||
var result = Substitution.empty.substituteType(type);
|
||||
expect(result, same(type));
|
||||
@@ -91,61 +95,66 @@ class SubstituteEmptyTest extends _Base {
|
||||
|
||||
@reflectiveTest
|
||||
class SubstituteFromInterfaceTypeTest extends _Base {
|
||||
test_interface() async {
|
||||
// class A<T> {}
|
||||
test_methodReturnType() async {
|
||||
buildTestLibrary(
|
||||
classes: [ClassSpec('class A<T>'), ClassSpec('class B<U>')],
|
||||
classes: [
|
||||
ClassSpec('class A<T>', methods: [MethodSpec('List<T> foo()')]),
|
||||
],
|
||||
);
|
||||
var A = classElement('A');
|
||||
|
||||
// class B<U> {}
|
||||
var B = classElement('B');
|
||||
var U = B.typeParameters.single;
|
||||
var substitution = Substitution.fromInterfaceType(
|
||||
parseInterfaceType('A<int>'),
|
||||
);
|
||||
|
||||
var BofInt = interfaceTypeNone(B, typeArguments: [intNone]);
|
||||
var substitution = Substitution.fromInterfaceType(BofInt);
|
||||
|
||||
// A<U>
|
||||
var type = interfaceTypeNone(A, typeArguments: [typeParameterTypeNone(U)]);
|
||||
assertType(type, 'A<U>');
|
||||
var type = classElement('A').getMethod('foo')!.returnType;
|
||||
assertType(type, 'List<T>');
|
||||
|
||||
var result = substitution.substituteType(type);
|
||||
assertType(result, 'A<int>');
|
||||
assertType(result, 'List<int>');
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class SubstituteFromPairsTest extends _Base {
|
||||
test_interface() async {
|
||||
// class A<T, U> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T, U>')]);
|
||||
test_methodReturnType() async {
|
||||
buildTestLibrary(
|
||||
classes: [
|
||||
ClassSpec('class A<T, U>', methods: [MethodSpec('Map<T, U> foo()')]),
|
||||
],
|
||||
);
|
||||
var A = classElement('A');
|
||||
var T = A.typeParameters[0];
|
||||
var U = A.typeParameters[1];
|
||||
|
||||
var type = interfaceTypeNone(
|
||||
A,
|
||||
typeArguments: [typeParameterTypeNone(T), typeParameterTypeNone(U)],
|
||||
);
|
||||
var type = A.getMethod('foo')!.returnType;
|
||||
assertType(type, 'Map<T, U>');
|
||||
|
||||
var result = Substitution.fromPairs2(
|
||||
[T, U],
|
||||
[intNone, doubleNone],
|
||||
[parseType('int'), parseType('double')],
|
||||
).substituteType(type);
|
||||
assertType(result, 'A<int, double>');
|
||||
assertType(result, 'Map<int, double>');
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class SubstituteTest extends _Base {
|
||||
test_bottom() async {
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.bottomType, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.bottomType, {
|
||||
T: scope.parseType('int'),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic() async {
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.dynamicType, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.dynamicType, {
|
||||
T: scope.parseType('int'),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_function_fromAlias_hasRef() async {
|
||||
@@ -153,15 +162,15 @@ class SubstituteTest extends _Base {
|
||||
buildTestLibrary(
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = void Function()')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = typeAliasTypeNone(
|
||||
Alias,
|
||||
typeArguments: [typeParameterTypeNone(U)],
|
||||
);
|
||||
assertType(type, 'void Function() via Alias<U>');
|
||||
_assertSubstitution(type, {U: intNone}, 'void Function() via Alias<int>');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('Alias<U>');
|
||||
assertType(type, 'void Function() via Alias<U>');
|
||||
_assertSubstitution(type, {
|
||||
U: parseType('int'),
|
||||
}, 'void Function() via Alias<int>');
|
||||
});
|
||||
}
|
||||
|
||||
test_function_fromAlias_noRef() async {
|
||||
@@ -169,13 +178,14 @@ class SubstituteTest extends _Base {
|
||||
buildTestLibrary(
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = void Function()')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var type = typeAliasTypeNone(Alias, typeArguments: [doubleNone]);
|
||||
var type = parseType('Alias<double>');
|
||||
assertType(type, 'void Function() via Alias<double>');
|
||||
|
||||
var U = typeParameter('U');
|
||||
_assertIdenticalType(type, {U: intNone});
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
_assertIdenticalType(type, {U: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_function_fromAlias_noTypeParameters() async {
|
||||
@@ -183,141 +193,123 @@ class SubstituteTest extends _Base {
|
||||
buildTestLibrary(
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = void Function()')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var type = typeAliasTypeNone(Alias, typeArguments: [intNone]);
|
||||
var type = parseType('Alias<int>');
|
||||
assertType(type, 'void Function() via Alias<int>');
|
||||
|
||||
var U = typeParameter('U');
|
||||
_assertIdenticalType(type, {U: intNone});
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
_assertIdenticalType(type, {U: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_function_noSubstitutions() async {
|
||||
var type = functionTypeNone(
|
||||
formalParameters: [requiredParameter(type: intNone)],
|
||||
returnType: boolNone,
|
||||
);
|
||||
var type = parseType('bool Function(int)');
|
||||
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(type, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(type, {T: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_function_parameters_returnType() async {
|
||||
// typedef F<T, U> = T Function(U u, bool);
|
||||
var T = typeParameter('T');
|
||||
var U = typeParameter('U');
|
||||
var type = functionTypeNone(
|
||||
formalParameters: [
|
||||
requiredParameter(type: typeParameterTypeNone(U)),
|
||||
requiredParameter(type: boolNone),
|
||||
],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
withTypeParameterScope('T, U', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('T Function(U, bool)');
|
||||
|
||||
assertType(type, 'T Function(U, bool)');
|
||||
_assertSubstitution(type, {T: intNone}, 'int Function(U, bool)');
|
||||
_assertSubstitution(type, {
|
||||
T: intNone,
|
||||
U: doubleNone,
|
||||
}, 'int Function(double, bool)');
|
||||
assertType(type, 'T Function(U, bool)');
|
||||
_assertSubstitution(type, {T: parseType('int')}, 'int Function(U, bool)');
|
||||
_assertSubstitution(type, {
|
||||
T: parseType('int'),
|
||||
U: parseType('double'),
|
||||
}, 'int Function(double, bool)');
|
||||
});
|
||||
}
|
||||
|
||||
test_function_typeFormals() async {
|
||||
// typedef F<T> = T Function<U extends T>(U);
|
||||
var T = typeParameter('T');
|
||||
var U = typeParameter('U', bound: typeParameterTypeNone(T));
|
||||
var type = functionTypeNone(
|
||||
typeParameters: [U],
|
||||
formalParameters: [requiredParameter(type: typeParameterTypeNone(U))],
|
||||
returnType: typeParameterTypeNone(T),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var type = scope.parseType('T Function<U extends T>(U)');
|
||||
|
||||
assertType(type, 'T Function<U extends T>(U)');
|
||||
_assertSubstitution(type, {T: intNone}, 'int Function<U extends int>(U)');
|
||||
assertType(type, 'T Function<U extends T>(U)');
|
||||
_assertSubstitution(type, {
|
||||
T: parseType('int'),
|
||||
}, 'int Function<U extends int>(U)');
|
||||
});
|
||||
}
|
||||
|
||||
test_function_typeFormals_bounds() async {
|
||||
// class Triple<X, Y, Z> {}
|
||||
// typedef F<V> = bool Function<T extends Triple<T, U, V>, U>();
|
||||
buildTestLibrary(classes: [ClassSpec('class Triple<X, Y, Z>')]);
|
||||
var classTriple = classElement('Triple');
|
||||
|
||||
var T = typeParameter('T');
|
||||
var U = typeParameter('U');
|
||||
var V = typeParameter('V');
|
||||
withTypeParameterScope('V', (scope) {
|
||||
var V = scope.typeParameter('V');
|
||||
var type = scope.parseType(
|
||||
'bool Function<T extends Triple<T, U, V>, U>()',
|
||||
);
|
||||
|
||||
T.bound = interfaceTypeNone(
|
||||
classTriple,
|
||||
typeArguments: [
|
||||
typeParameterTypeNone(T),
|
||||
typeParameterTypeNone(U),
|
||||
typeParameterTypeNone(V),
|
||||
],
|
||||
);
|
||||
assertType(type, 'bool Function<T extends Triple<T, U, V>, U>()');
|
||||
|
||||
var type = functionTypeNone(typeParameters: [T, U], returnType: boolNone);
|
||||
|
||||
assertType(type, 'bool Function<T extends Triple<T, U, V>, U>()');
|
||||
|
||||
var result = substitute(type, {V: intNone}) as FunctionType;
|
||||
assertType(result, 'bool Function<T extends Triple<T, U, int>, U>()');
|
||||
var T2 = result.typeParameters[0];
|
||||
var U2 = result.typeParameters[1];
|
||||
var T2boundArgs = (T2.bound as InterfaceType).typeArguments;
|
||||
expect((T2boundArgs[0] as TypeParameterType).element, same(T2));
|
||||
expect((T2boundArgs[1] as TypeParameterType).element, same(U2));
|
||||
var result = substitute(type, {V: parseType('int')}) as FunctionType;
|
||||
assertType(result, 'bool Function<T extends Triple<T, U, int>, U>()');
|
||||
var T2 = result.typeParameters[0];
|
||||
var U2 = result.typeParameters[1];
|
||||
var T2boundArgs = (T2.bound as InterfaceType).typeArguments;
|
||||
expect((T2boundArgs[0] as TypeParameterType).element, same(T2));
|
||||
expect((T2boundArgs[1] as TypeParameterType).element, same(U2));
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_arguments() async {
|
||||
// class A<T> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = interfaceTypeNone(A, typeArguments: [typeParameterTypeNone(U)]);
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('A<U>');
|
||||
|
||||
assertType(type, 'A<U>');
|
||||
_assertSubstitution(type, {U: intNone}, 'A<int>');
|
||||
assertType(type, 'A<U>');
|
||||
_assertSubstitution(type, {U: parseType('int')}, 'A<int>');
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_arguments_deep() async {
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = interfaceTypeNone(
|
||||
A,
|
||||
typeArguments: [
|
||||
interfaceTypeNone(
|
||||
typeProvider.listElement,
|
||||
typeArguments: [typeParameterTypeNone(U)],
|
||||
),
|
||||
],
|
||||
);
|
||||
assertType(type, 'A<List<U>>');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('A<List<U>>');
|
||||
assertType(type, 'A<List<U>>');
|
||||
|
||||
_assertSubstitution(type, {U: intNone}, 'A<List<int>>');
|
||||
_assertSubstitution(type, {U: parseType('int')}, 'A<List<int>>');
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_noArguments() async {
|
||||
// class A {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var type = interfaceTypeNone(A);
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(type, {T: intNone});
|
||||
var type = parseInterfaceType('A');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(type, {T: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_noArguments_inArguments() async {
|
||||
// class A<T> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var type = interfaceTypeNone(A, typeArguments: [intNone]);
|
||||
var type = parseInterfaceType('A<int>');
|
||||
|
||||
var U = typeParameter('U');
|
||||
_assertIdenticalType(type, {U: doubleNone});
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
_assertIdenticalType(type, {U: scope.parseType('double')});
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_noTypeParameters_fromAlias_hasRef() async {
|
||||
@@ -326,15 +318,13 @@ class SubstituteTest extends _Base {
|
||||
classes: [ClassSpec('class A')],
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = A')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = typeAliasTypeNone(
|
||||
Alias,
|
||||
typeArguments: [typeParameterTypeNone(U)],
|
||||
);
|
||||
assertType(type, 'A via Alias<U>');
|
||||
_assertSubstitution(type, {U: intNone}, 'A via Alias<int>');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('Alias<U>');
|
||||
assertType(type, 'A via Alias<U>');
|
||||
_assertSubstitution(type, {U: parseType('int')}, 'A via Alias<int>');
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_noTypeParameters_fromAlias_noRef() async {
|
||||
@@ -343,13 +333,14 @@ class SubstituteTest extends _Base {
|
||||
classes: [ClassSpec('class A')],
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = A')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var type = typeAliasTypeNone(Alias, typeArguments: [doubleNone]);
|
||||
var type = parseType('Alias<double>');
|
||||
assertType(type, 'A via Alias<double>');
|
||||
|
||||
var U = typeParameter('U');
|
||||
_assertIdenticalType(type, {U: intNone});
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
_assertIdenticalType(type, {U: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_noTypeParameters_fromAlias_noTypeParameters() async {
|
||||
@@ -358,27 +349,34 @@ class SubstituteTest extends _Base {
|
||||
classes: [ClassSpec('class A')],
|
||||
typeAliases: [TypeAliasSpec('typedef Alias = A')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var type = typeAliasTypeNone(Alias);
|
||||
var type = parseType('Alias');
|
||||
assertType(type, 'A via Alias');
|
||||
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(type, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(type, {T: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_invalid() async {
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(InvalidTypeImpl.instance, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(InvalidTypeImpl.instance, {
|
||||
T: scope.parseType('int'),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_record_doesNotUseTypeParameter2() async {
|
||||
var T = typeParameter('T');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
var type = recordTypeNone(positionalTypes: [intNone]);
|
||||
var type = parseRecordType('(int,)');
|
||||
assertType(type, '(int,)');
|
||||
|
||||
assertType(type, '(int,)');
|
||||
_assertIdenticalType(type, {T: intNone});
|
||||
_assertIdenticalType(type, {T: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_record_fromAlias() async {
|
||||
@@ -386,15 +384,15 @@ class SubstituteTest extends _Base {
|
||||
buildTestLibrary(
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = (int, String)')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = typeAliasTypeNone(
|
||||
Alias,
|
||||
typeArguments: [typeParameterTypeNone(U)],
|
||||
);
|
||||
assertType(type, '(int, String) via Alias<U>');
|
||||
_assertSubstitution(type, {U: intNone}, '(int, String) via Alias<int>');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('Alias<U>');
|
||||
assertType(type, '(int, String) via Alias<U>');
|
||||
_assertSubstitution(type, {
|
||||
U: parseType('int'),
|
||||
}, '(int, String) via Alias<int>');
|
||||
});
|
||||
}
|
||||
|
||||
test_record_fromAlias2() async {
|
||||
@@ -402,68 +400,70 @@ class SubstituteTest extends _Base {
|
||||
buildTestLibrary(
|
||||
typeAliases: [TypeAliasSpec('typedef Alias<T> = (T, List<T>)')],
|
||||
);
|
||||
var Alias = typeAliasElement('Alias');
|
||||
|
||||
var type = typeAliasTypeNone(Alias, typeArguments: [intNone]);
|
||||
var type = parseType('Alias<int>');
|
||||
assertType(type, '(int, List<int>) via Alias<int>');
|
||||
}
|
||||
|
||||
test_record_named() async {
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var type = scope.parseType('({T f1, List<T> f2})');
|
||||
|
||||
var type = recordTypeNone(
|
||||
namedTypes: {'f1': T_none, 'f2': listNone(T_none)},
|
||||
);
|
||||
|
||||
assertType(type, '({T f1, List<T> f2})');
|
||||
_assertSubstitution(type, {T: intNone}, '({int f1, List<int> f2})');
|
||||
assertType(type, '({T f1, List<T> f2})');
|
||||
_assertSubstitution(type, {
|
||||
T: parseType('int'),
|
||||
}, '({int f1, List<int> f2})');
|
||||
});
|
||||
}
|
||||
|
||||
test_record_positional() async {
|
||||
var T = typeParameter('T');
|
||||
var T_none = typeParameterTypeNone(T);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
var type = scope.parseType('(T, List<T>)');
|
||||
|
||||
var type = recordTypeNone(positionalTypes: [T_none, listNone(T_none)]);
|
||||
|
||||
assertType(type, '(T, List<T>)');
|
||||
_assertSubstitution(type, {T: intNone}, '(int, List<int>)');
|
||||
assertType(type, '(T, List<T>)');
|
||||
_assertSubstitution(type, {T: parseType('int')}, '(int, List<int>)');
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_nullability() async {
|
||||
var tElement = typeParameter('T');
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
void check(
|
||||
NullabilitySuffix typeParameterNullability,
|
||||
InterfaceType typeArgument,
|
||||
InterfaceType expectedType,
|
||||
) {
|
||||
var result = Substitution.fromMap({tElement: typeArgument})
|
||||
.substituteType(
|
||||
tElement.instantiate(nullabilitySuffix: typeParameterNullability),
|
||||
);
|
||||
expect(result, expectedType);
|
||||
}
|
||||
void check(String type, DartType typeArgument, DartType expectedType) {
|
||||
var result = Substitution.fromMap({
|
||||
T: typeArgument,
|
||||
}).substituteType(scope.parseType(type));
|
||||
expect(result, expectedType);
|
||||
}
|
||||
|
||||
check(NullabilitySuffix.none, intNone, intNone);
|
||||
check(NullabilitySuffix.none, intQuestion, intQuestion);
|
||||
check('T', parseType('int'), parseType('int'));
|
||||
check('T', parseType('int?'), parseType('int?'));
|
||||
|
||||
check(NullabilitySuffix.question, intNone, intQuestion);
|
||||
check(NullabilitySuffix.question, intQuestion, intQuestion);
|
||||
check('T?', parseType('int'), parseType('int?'));
|
||||
check('T?', parseType('int?'), parseType('int?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_unknownInferredType() async {
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(UnknownInferredType.instance, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(UnknownInferredType.instance, {
|
||||
T: scope.parseType('int'),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_void() async {
|
||||
var T = typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.voidType, {T: intNone});
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
_assertIdenticalType(typeProvider.voidType, {T: scope.parseType('int')});
|
||||
});
|
||||
}
|
||||
|
||||
test_void_emptyMap() async {
|
||||
_assertIdenticalType(intNone, {});
|
||||
_assertIdenticalType(parseType('int'), {});
|
||||
}
|
||||
|
||||
void _assertIdenticalType(
|
||||
@@ -482,27 +482,23 @@ class SubstituteWithNullabilityTest extends _Base {
|
||||
test_interface_none() async {
|
||||
// class A<T> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = A.instantiateImpl(
|
||||
typeArguments: [U.instantiate(nullabilitySuffix: NullabilitySuffix.none)],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
_assertSubstitution(type, {U: intNone}, 'A<int>');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('A<U>');
|
||||
_assertSubstitution(type, {U: parseType('int')}, 'A<int>');
|
||||
});
|
||||
}
|
||||
|
||||
test_interface_question() async {
|
||||
// class A<T> {}
|
||||
buildTestLibrary(classes: [ClassSpec('class A<T>')]);
|
||||
var A = classElement('A');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = A.instantiateImpl(
|
||||
typeArguments: [U.instantiate(nullabilitySuffix: NullabilitySuffix.none)],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
_assertSubstitution(type, {U: intNone}, 'A<int>?');
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var U = scope.typeParameter('U');
|
||||
var type = scope.parseType('A<U>?');
|
||||
_assertSubstitution(type, {U: parseType('int')}, 'A<int>?');
|
||||
});
|
||||
}
|
||||
|
||||
test_withNullability_updatesAlias_function() {
|
||||
@@ -550,15 +546,16 @@ class SubstituteWithNullabilityTest extends _Base {
|
||||
buildTestLibrary(typeAliases: [TypeAliasSpec('typedef A<T> = T')]);
|
||||
var alias = typeAliasElement('A');
|
||||
|
||||
var U = typeParameter('U');
|
||||
var type = alias.instantiateImpl(
|
||||
typeArguments: [typeParameterTypeNone(U)],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
withTypeParameterScope('U', (scope) {
|
||||
var type = alias.instantiateImpl(
|
||||
typeArguments: [scope.parseType('U')],
|
||||
nullabilitySuffix: NullabilitySuffix.question,
|
||||
);
|
||||
|
||||
var result = type.withNullability(NullabilitySuffix.none);
|
||||
expect(result.alias, isNotNull);
|
||||
expect(result.alias?.nullabilitySuffix, NullabilitySuffix.none);
|
||||
var result = type.withNullability(NullabilitySuffix.none);
|
||||
expect(result.alias, isNotNull);
|
||||
expect(result.alias?.nullabilitySuffix, NullabilitySuffix.none);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,57 +19,57 @@ main() {
|
||||
@reflectiveTest
|
||||
class DynamicBoundedTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_assertDynamicBounded(dynamicType);
|
||||
_assertDynamicBounded(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasBound_dynamic() {
|
||||
var T = typeParameter('T', bound: dynamicType);
|
||||
|
||||
_assertDynamicBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends dynamic', (scope) {
|
||||
_assertDynamicBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasBound_notDynamic() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
_assertNotDynamicBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_assertNotDynamicBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasPromotedBound_dynamic() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertDynamicBounded(typeParameterTypeNone(T, promotedBound: dynamicType));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertDynamicBounded(scope.parseType('T & dynamic'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasPromotedBound_notDynamic() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotDynamicBounded(typeParameterTypeNone(T, promotedBound: intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotDynamicBounded(scope.parseType('T & int'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_noBound() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotDynamicBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotDynamicBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_assertNotDynamicBounded(functionTypeNone(returnType: voidNone));
|
||||
_assertNotDynamicBounded(parseType('void Function()'));
|
||||
|
||||
_assertNotDynamicBounded(functionTypeNone(returnType: dynamicType));
|
||||
_assertNotDynamicBounded(parseType('dynamic Function()'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_assertNotDynamicBounded(intNone);
|
||||
_assertNotDynamicBounded(intQuestion);
|
||||
_assertNotDynamicBounded(parseType('int'));
|
||||
_assertNotDynamicBounded(parseType('int?'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_assertNotDynamicBounded(neverNone);
|
||||
_assertNotDynamicBounded(neverQuestion);
|
||||
_assertNotDynamicBounded(parseType('Never'));
|
||||
_assertNotDynamicBounded(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_assertNotDynamicBounded(voidNone);
|
||||
_assertNotDynamicBounded(parseType('void'));
|
||||
}
|
||||
|
||||
void _assertDynamicBounded(DartType type) {
|
||||
@@ -84,83 +84,70 @@ class DynamicBoundedTest extends AbstractTypeSystemTest {
|
||||
@reflectiveTest
|
||||
class FunctionBoundedTest extends AbstractTypeSystemTest {
|
||||
test_dynamic() {
|
||||
_assertNotFunctionBounded(dynamicType);
|
||||
_assertNotFunctionBounded(parseType('dynamic'));
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasBound_functionType_none() {
|
||||
var T = typeParameter('T', bound: functionTypeNone(returnType: voidNone));
|
||||
|
||||
_assertFunctionBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends void Function()', (scope) {
|
||||
_assertFunctionBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasBound_functionType_question() {
|
||||
var T = typeParameter(
|
||||
'T',
|
||||
bound: functionTypeQuestion(returnType: voidNone),
|
||||
);
|
||||
|
||||
_assertNotFunctionBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends void Function()?', (scope) {
|
||||
_assertNotFunctionBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasBound_notFunction() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
_assertNotFunctionBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_assertNotFunctionBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasPromotedBound_functionType_none() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertFunctionBounded(
|
||||
typeParameterTypeNone(
|
||||
T,
|
||||
promotedBound: functionTypeNone(returnType: voidNone),
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertFunctionBounded(scope.parseType('T & void Function()'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasPromotedBound_functionType_question() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotFunctionBounded(
|
||||
typeParameterTypeNone(
|
||||
T,
|
||||
promotedBound: functionTypeQuestion(returnType: voidNone),
|
||||
),
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotFunctionBounded(scope.parseType('T & void Function()?'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_hasPromotedBound_notFunction() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotFunctionBounded(typeParameterTypeNone(T, promotedBound: intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotFunctionBounded(scope.parseType('T & int'));
|
||||
});
|
||||
}
|
||||
|
||||
test_dynamic_typeParameter_noBound() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotFunctionBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotFunctionBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_assertFunctionBounded(functionTypeNone(returnType: voidNone));
|
||||
_assertNotFunctionBounded(functionTypeQuestion(returnType: voidNone));
|
||||
_assertFunctionBounded(parseType('void Function()'));
|
||||
_assertNotFunctionBounded(parseType('void Function()?'));
|
||||
|
||||
_assertFunctionBounded(functionTypeNone(returnType: dynamicType));
|
||||
_assertFunctionBounded(parseType('dynamic Function()'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_assertNotFunctionBounded(intNone);
|
||||
_assertNotFunctionBounded(intQuestion);
|
||||
_assertNotFunctionBounded(parseType('int'));
|
||||
_assertNotFunctionBounded(parseType('int?'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_assertNotFunctionBounded(neverNone);
|
||||
_assertNotFunctionBounded(neverQuestion);
|
||||
_assertNotFunctionBounded(parseType('Never'));
|
||||
_assertNotFunctionBounded(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_assertNotFunctionBounded(voidNone);
|
||||
_assertNotFunctionBounded(parseType('void'));
|
||||
}
|
||||
|
||||
void _assertFunctionBounded(DartType type) {
|
||||
@@ -175,57 +162,57 @@ class FunctionBoundedTest extends AbstractTypeSystemTest {
|
||||
@reflectiveTest
|
||||
class InvalidBoundedTest extends AbstractTypeSystemTest {
|
||||
test_dynamic_typeParameter_hasPromotedBound_notDynamic() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotInvalidBounded(typeParameterTypeNone(T, promotedBound: intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotInvalidBounded(scope.parseType('T & int'));
|
||||
});
|
||||
}
|
||||
|
||||
test_functionType() {
|
||||
_assertNotInvalidBounded(functionTypeNone(returnType: voidNone));
|
||||
_assertNotInvalidBounded(parseType('void Function()'));
|
||||
|
||||
_assertNotInvalidBounded(functionTypeNone(returnType: invalidType));
|
||||
_assertNotInvalidBounded(parseType('InvalidType Function()'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_assertNotInvalidBounded(intNone);
|
||||
_assertNotInvalidBounded(intQuestion);
|
||||
_assertNotInvalidBounded(parseType('int'));
|
||||
_assertNotInvalidBounded(parseType('int?'));
|
||||
}
|
||||
|
||||
test_invalid() {
|
||||
_assertInvalidBounded(invalidType);
|
||||
_assertInvalidBounded(parseType('InvalidType'));
|
||||
}
|
||||
|
||||
test_never() {
|
||||
_assertNotInvalidBounded(neverNone);
|
||||
_assertNotInvalidBounded(neverQuestion);
|
||||
_assertNotInvalidBounded(parseType('Never'));
|
||||
_assertNotInvalidBounded(parseType('Never?'));
|
||||
}
|
||||
|
||||
test_typeParameter_hasBound_invalid() {
|
||||
var T = typeParameter('T', bound: invalidType);
|
||||
|
||||
_assertInvalidBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends InvalidType', (scope) {
|
||||
_assertInvalidBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_hasBound_notInvalid() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
|
||||
_assertNotInvalidBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T extends int', (scope) {
|
||||
_assertNotInvalidBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_hasPromotedBound_invalidType() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertInvalidBounded(typeParameterTypeNone(T, promotedBound: invalidType));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertInvalidBounded(scope.parseType('T & InvalidType'));
|
||||
});
|
||||
}
|
||||
|
||||
test_typeParameter_noBound() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertNotInvalidBounded(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotInvalidBounded(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
test_void() {
|
||||
_assertNotInvalidBounded(voidNone);
|
||||
_assertNotInvalidBounded(parseType('void'));
|
||||
}
|
||||
|
||||
void _assertInvalidBounded(DartType type) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,76 +18,51 @@ main() {
|
||||
@reflectiveTest
|
||||
class TypeParameterElementTest extends AbstractTypeSystemTest {
|
||||
test_equal() {
|
||||
var T1 = typeParameter('T');
|
||||
var T2 = typeParameter('T');
|
||||
withTypeParameterScope('T', (scope1) {
|
||||
var T1 = scope1.typeParameter('T');
|
||||
scope1.withTypeParameterScope('T', (scope2) {
|
||||
var T2 = scope2.typeParameter('T');
|
||||
|
||||
expect(T1 == T1, isTrue);
|
||||
expect(T2 == T2, isTrue);
|
||||
expect(T1 == T1, isTrue);
|
||||
expect(T2 == T2, isTrue);
|
||||
|
||||
expect(T1 == T2, isFalse);
|
||||
expect(T2 == T1, isFalse);
|
||||
expect(T1 == T2, isFalse);
|
||||
expect(T2 == T1, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class TypeParameterTypeTest extends AbstractTypeSystemTest {
|
||||
test_equal_differentElements() {
|
||||
var T1 = typeParameter('T');
|
||||
var T2 = typeParameter('T');
|
||||
|
||||
_assertEqual(typeParameterTypeNone(T1), typeParameterTypeNone(T2), isFalse);
|
||||
withTypeParameterScope('T', (scope1) {
|
||||
var T1 = scope1.parseType('T');
|
||||
scope1.withTypeParameterScope('T', (scope2) {
|
||||
var T2 = scope2.parseType('T');
|
||||
_assertEqual(T1, T2, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test_equal_sameElement() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertEqual(typeParameterTypeNone(T), typeParameterTypeNone(T), isTrue);
|
||||
|
||||
_assertEqual(
|
||||
typeParameterTypeNone(T),
|
||||
typeParameterTypeQuestion(T),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
_assertEqual(
|
||||
typeParameterTypeQuestion(T),
|
||||
typeParameterTypeNone(T),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
_assertEqual(
|
||||
typeParameterTypeQuestion(T),
|
||||
typeParameterTypeQuestion(T),
|
||||
isTrue,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.parseType('T');
|
||||
_assertEqual(T, T, isTrue);
|
||||
_assertEqual(T, scope.parseType('T?'), isFalse);
|
||||
_assertEqual(scope.parseType('T?'), T, isFalse);
|
||||
_assertEqual(scope.parseType('T?'), scope.parseType('T?'), isTrue);
|
||||
});
|
||||
}
|
||||
|
||||
test_equal_sameElement_promotedBounds() {
|
||||
var T = typeParameter('T');
|
||||
|
||||
_assertEqual(
|
||||
promotedTypeParameterTypeNone(T, intNone),
|
||||
promotedTypeParameterTypeNone(T, intNone),
|
||||
isTrue,
|
||||
);
|
||||
|
||||
_assertEqual(
|
||||
promotedTypeParameterTypeNone(T, intNone),
|
||||
promotedTypeParameterTypeNone(T, doubleNone),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
_assertEqual(
|
||||
promotedTypeParameterTypeNone(T, intNone),
|
||||
typeParameterTypeNone(T),
|
||||
isFalse,
|
||||
);
|
||||
|
||||
_assertEqual(
|
||||
typeParameterTypeNone(T),
|
||||
promotedTypeParameterTypeNone(T, intNone),
|
||||
isFalse,
|
||||
);
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.parseType('T & int');
|
||||
_assertEqual(T, T, isTrue);
|
||||
_assertEqual(T, scope.parseType('T & double'), isFalse);
|
||||
_assertEqual(T, scope.parseType('T'), isFalse);
|
||||
_assertEqual(scope.parseType('T'), T, isFalse);
|
||||
});
|
||||
}
|
||||
|
||||
void _assertEqual(DartType T1, DartType T2, matcher) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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.
|
||||
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
@@ -17,55 +16,39 @@ main() {
|
||||
|
||||
@reflectiveTest
|
||||
class TypeReferencesAnyTest extends AbstractTypeSystemTest {
|
||||
late TypeParameterElementImpl T;
|
||||
late TypeParameterTypeImpl T_none;
|
||||
|
||||
@override
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
|
||||
T = typeParameter('T');
|
||||
T_none = typeParameterTypeNone(T);
|
||||
}
|
||||
|
||||
test_false() {
|
||||
_checkFalse(dynamicType);
|
||||
_checkFalse(intNone);
|
||||
_checkFalse(neverNone);
|
||||
_checkFalse(voidNone);
|
||||
_checkFalse(listNone(intNone));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
void checkFalse(TypeImpl type) {
|
||||
var actual = type.referencesAny({T});
|
||||
expect(actual, isFalse);
|
||||
}
|
||||
|
||||
checkFalse(parseType('dynamic'));
|
||||
checkFalse(parseType('int'));
|
||||
checkFalse(parseType('Never'));
|
||||
checkFalse(parseType('void'));
|
||||
checkFalse(parseType('List<int>'));
|
||||
});
|
||||
}
|
||||
|
||||
test_true() {
|
||||
_checkTrue(T_none);
|
||||
_checkTrue(listNone(T_none));
|
||||
_checkTrue(mapNone(T_none, intNone));
|
||||
_checkTrue(mapNone(intNone, T_none));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
var T = scope.typeParameter('T');
|
||||
|
||||
_checkTrue(functionTypeNone(returnType: T_none));
|
||||
void checkTrue(TypeImpl type) {
|
||||
var actual = type.referencesAny({T});
|
||||
expect(actual, isTrue);
|
||||
}
|
||||
|
||||
_checkTrue(
|
||||
functionTypeNone(
|
||||
returnType: voidNone,
|
||||
formalParameters: [requiredParameter(type: T_none)],
|
||||
),
|
||||
);
|
||||
|
||||
_checkTrue(
|
||||
functionTypeNone(
|
||||
typeParameters: [typeParameter('U', bound: T_none)],
|
||||
returnType: voidNone,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _checkFalse(TypeImpl type) {
|
||||
var actual = type.referencesAny({T});
|
||||
expect(actual, isFalse);
|
||||
}
|
||||
|
||||
void _checkTrue(TypeImpl type) {
|
||||
var actual = type.referencesAny({T});
|
||||
expect(actual, isTrue);
|
||||
checkTrue(scope.parseType('T'));
|
||||
checkTrue(scope.parseType('List<T>'));
|
||||
checkTrue(scope.parseType('Map<T, int>'));
|
||||
checkTrue(scope.parseType('Map<int, T>'));
|
||||
checkTrue(scope.parseType('T Function()'));
|
||||
checkTrue(scope.parseType('void Function(T)'));
|
||||
checkTrue(scope.parseType('void Function<U extends T>()'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,54 +18,54 @@ main() {
|
||||
@reflectiveTest
|
||||
class IsValidExtensionTypeSuperinterfaceTest extends AbstractTypeSystemTest {
|
||||
test_functionType() {
|
||||
_assertNotValid(functionTypeNone(returnType: voidNone));
|
||||
_assertNotValid(parseType('void Function()'));
|
||||
}
|
||||
|
||||
test_interfaceType() {
|
||||
_assertValid(numNone);
|
||||
_assertValid(parseType('num'));
|
||||
}
|
||||
|
||||
test_interfaceType_extensionType() {
|
||||
buildTestLibrary(
|
||||
extensionTypes: [ExtensionTypeSpec('extension type A(int it)')],
|
||||
);
|
||||
var element = extensionTypeElement('A');
|
||||
_assertValid(interfaceTypeNone(element));
|
||||
_assertValid(parseType('A'));
|
||||
}
|
||||
|
||||
test_interfaceType_function() {
|
||||
_assertNotValid(functionNone);
|
||||
_assertNotValid(parseType('Function'));
|
||||
}
|
||||
|
||||
test_interfaceType_futureOr() {
|
||||
_assertNotValid(futureOrNone(intNone));
|
||||
_assertNotValid(parseType('FutureOr<int>'));
|
||||
}
|
||||
|
||||
test_interfaceType_null() {
|
||||
_assertNotValid(nullNone);
|
||||
_assertNotValid(parseType('Null'));
|
||||
}
|
||||
|
||||
test_interfaceType_nullable() {
|
||||
_assertNotValid(numQuestion);
|
||||
_assertNotValid(parseType('num?'));
|
||||
}
|
||||
|
||||
test_interfaceType_record() {
|
||||
_assertNotValid(recordNone);
|
||||
_assertNotValid(parseType('Record'));
|
||||
}
|
||||
|
||||
test_recordType() {
|
||||
_assertNotValid(recordTypeNone(positionalTypes: [intNone, stringNone]));
|
||||
_assertNotValid(parseType('(int, String)'));
|
||||
}
|
||||
|
||||
test_topType() {
|
||||
_assertNotValid(dynamicType);
|
||||
_assertNotValid(voidNone);
|
||||
_assertNotValid(objectQuestion);
|
||||
_assertNotValid(parseType('dynamic'));
|
||||
_assertNotValid(parseType('void'));
|
||||
_assertNotValid(parseType('Object?'));
|
||||
}
|
||||
|
||||
test_typeParameterType() {
|
||||
var T = typeParameter('T');
|
||||
_assertNotValid(typeParameterTypeNone(T));
|
||||
withTypeParameterScope('T', (scope) {
|
||||
_assertNotValid(scope.parseType('T'));
|
||||
});
|
||||
}
|
||||
|
||||
void _assertNotValid(DartType type) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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.
|
||||
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/element/type_visitor.dart';
|
||||
import 'package:test/test.dart';
|
||||
@@ -29,181 +28,144 @@ class RecursiveTypeVisitorTest extends AbstractTypeSystemTest with StringTypes {
|
||||
}
|
||||
|
||||
void test_callsDefaultBehavior() {
|
||||
expect(intNone.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
expect(parseType('int').accept(visitor), true);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_functionType_complex() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var K = typeParameter('K', bound: stringNone);
|
||||
var a = positionalParameter(type: numNone);
|
||||
var b = positionalParameter(type: doubleNone);
|
||||
var c = namedParameter(name: 'c', type: voidNone);
|
||||
var d = namedParameter(name: 'd', type: objectNone);
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [T, K],
|
||||
formalParameters: [a, b, c, d],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
var type = parseFunctionType(
|
||||
'dynamic Function<T extends int, K extends String>('
|
||||
'num, double, {void c, Object d})',
|
||||
);
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedTypes([
|
||||
dynamicType,
|
||||
intNone,
|
||||
stringNone,
|
||||
numNone,
|
||||
doubleNone,
|
||||
voidNone,
|
||||
objectNone,
|
||||
parseType('dynamic'),
|
||||
parseType('int'),
|
||||
parseType('String'),
|
||||
parseType('num'),
|
||||
parseType('double'),
|
||||
parseType('void'),
|
||||
parseType('Object'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_functionType_positionalParameter() {
|
||||
var a = positionalParameter(type: intNone);
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [],
|
||||
formalParameters: [a],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
var type = parseFunctionType('dynamic Function([int])');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_functionType_returnType() {
|
||||
var type = functionType(
|
||||
returnType: intNone,
|
||||
typeParameters: [],
|
||||
formalParameters: [],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
var type = parseFunctionType('int Function()');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_functionType_typeFormal_bound() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [T],
|
||||
formalParameters: [],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
var type = parseFunctionType('dynamic Function<T extends int>()');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedTypes([dynamicType, intNone]);
|
||||
visitor.assertVisitedTypes([parseType('dynamic'), parseType('int')]);
|
||||
}
|
||||
|
||||
void test_functionType_typeFormal_noBound() {
|
||||
var T = typeParameter('T');
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [T],
|
||||
formalParameters: [],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
var type = parseFunctionType('dynamic Function<T>()');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(dynamicType);
|
||||
visitor.assertVisitedType(parseType('dynamic'));
|
||||
}
|
||||
|
||||
void test_interfaceType_typeParameter() {
|
||||
var type = typeProvider.listType(intNone);
|
||||
var type = typeProvider.listType(parseType('int'));
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_interfaceType_typeParameters() {
|
||||
var type = typeProvider.mapType(intNone, stringNone);
|
||||
var type = typeProvider.mapType(parseType('int'), parseType('String'));
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedTypes([intNone, stringNone]);
|
||||
visitor.assertVisitedTypes([parseType('int'), parseType('String')]);
|
||||
}
|
||||
|
||||
void test_interfaceType_typeParameters_nested() {
|
||||
var innerList = typeProvider.listType(intNone);
|
||||
var innerList = typeProvider.listType(parseType('int'));
|
||||
var outerList = typeProvider.listType(innerList);
|
||||
expect(outerList.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_recordType_named() {
|
||||
var type = typeOfString('({int f1, double f2})');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(doubleNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
visitor.assertVisitedType(parseType('double'));
|
||||
}
|
||||
|
||||
void test_recordType_named_dollarIdentifier() {
|
||||
var type = typeOfString(r'({int $1})');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
}
|
||||
|
||||
void test_recordType_positional() {
|
||||
var type = typeOfString('(int, double)');
|
||||
expect(type.accept(visitor), true);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertVisitedType(doubleNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
visitor.assertVisitedType(parseType('double'));
|
||||
}
|
||||
|
||||
void test_stopVisiting_first() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var K = typeParameter('K', bound: stringNone);
|
||||
var a = positionalParameter(type: numNone);
|
||||
var b = positionalParameter(type: doubleNone);
|
||||
var c = namedParameter(name: 'c', type: voidNone);
|
||||
var d = namedParameter(name: 'd', type: objectNone);
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [T, K],
|
||||
formalParameters: [a, b, c, d],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
var type = parseFunctionType(
|
||||
'dynamic Function<T extends int, K extends String>('
|
||||
'num, double, {void c, Object d})',
|
||||
);
|
||||
visitor.stopOnType = dynamicType;
|
||||
visitor.stopOnType = parseType('dynamic');
|
||||
expect(type.accept(visitor), false);
|
||||
visitor.assertNotVisitedTypes([
|
||||
intNone,
|
||||
stringNone,
|
||||
numNone,
|
||||
doubleNone,
|
||||
voidNone,
|
||||
objectNone,
|
||||
parseType('int'),
|
||||
parseType('String'),
|
||||
parseType('num'),
|
||||
parseType('double'),
|
||||
parseType('void'),
|
||||
parseType('Object'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_stopVisiting_halfway() {
|
||||
var T = typeParameter('T', bound: intNone);
|
||||
var K = typeParameter('K', bound: stringNone);
|
||||
var a = positionalParameter(type: numNone);
|
||||
var b = positionalParameter(type: doubleNone);
|
||||
var c = namedParameter(name: 'c', type: voidNone);
|
||||
var d = namedParameter(name: 'd', type: objectNone);
|
||||
var type = functionType(
|
||||
returnType: dynamicType,
|
||||
typeParameters: [T, K],
|
||||
formalParameters: [a, b, c, d],
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
var type = parseFunctionType(
|
||||
'dynamic Function<T extends int, K extends String>('
|
||||
'num, double, {void c, Object d})',
|
||||
);
|
||||
visitor.stopOnType = intNone;
|
||||
visitor.stopOnType = parseType('int');
|
||||
expect(type.accept(visitor), false);
|
||||
visitor.assertNotVisitedTypes([stringNone, voidNone, objectNone]);
|
||||
visitor.assertNotVisitedTypes([
|
||||
parseType('String'),
|
||||
parseType('void'),
|
||||
parseType('Object'),
|
||||
]);
|
||||
}
|
||||
|
||||
void test_stopVisiting_nested() {
|
||||
var innerType = typeProvider.mapType(intNone, stringNone);
|
||||
var innerType = typeProvider.mapType(parseType('int'), parseType('String'));
|
||||
var outerList = typeProvider.listType(innerType);
|
||||
visitor.stopOnType = intNone;
|
||||
visitor.stopOnType = parseType('int');
|
||||
expect(outerList.accept(visitor), false);
|
||||
visitor.assertNotVisitedType(stringNone);
|
||||
visitor.assertNotVisitedType(parseType('String'));
|
||||
}
|
||||
|
||||
void test_stopVisiting_nested_parent() {
|
||||
var innerTypeStop = typeProvider.listType(intNone);
|
||||
var innerTypeSkipped = typeProvider.listType(stringNone);
|
||||
var innerTypeStop = typeProvider.listType(parseType('int'));
|
||||
var innerTypeSkipped = typeProvider.listType(parseType('String'));
|
||||
var outerType = typeProvider.mapType(innerTypeStop, innerTypeSkipped);
|
||||
visitor.stopOnType = intNone;
|
||||
visitor.stopOnType = parseType('int');
|
||||
expect(outerType.accept(visitor), false);
|
||||
visitor.assertNotVisitedType(stringNone);
|
||||
visitor.assertNotVisitedType(parseType('String'));
|
||||
}
|
||||
|
||||
void test_stopVisiting_typeParameters() {
|
||||
var type = typeProvider.mapType(intNone, stringNone);
|
||||
visitor.stopOnType = intNone;
|
||||
var type = typeProvider.mapType(parseType('int'), parseType('String'));
|
||||
visitor.stopOnType = parseType('int');
|
||||
expect(type.accept(visitor), false);
|
||||
visitor.assertVisitedType(intNone);
|
||||
visitor.assertNotVisitedType(stringNone);
|
||||
visitor.assertVisitedType(parseType('int'));
|
||||
visitor.assertNotVisitedType(parseType('String'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user