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:
Konstantin Shcheglov
2026-04-24 09:21:11 -07:00
parent 7b337624fb
commit bf0f72ae14
35 changed files with 6094 additions and 9208 deletions
@@ -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,
]),
);
}
@@ -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