[cfe] Move ExtensionType into pkg/kernel/lib/ast.dart

Change-Id: I2e8231dad00accafb09d1ec88416242d3d5815a4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190483
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Dmitry Stefantsov
2021-03-12 19:02:27 +00:00
committed by commit-bot@chromium.org
parent cf7e990233
commit 8ddc7465a8
24 changed files with 388 additions and 255 deletions
+5
View File
@@ -207,6 +207,11 @@ class _FreeVariableVisitor implements ir.DartTypeVisitor<bool> {
return visitList(node.typeArguments);
}
@override
bool visitExtensionType(ir.ExtensionType node) {
return visitList(node.typeArguments);
}
@override
bool visitFutureOrType(ir.FutureOrType node) {
return visit(node.typeArgument);
+6
View File
@@ -97,6 +97,12 @@ class TypeTextVisitor implements ir.DartTypeVisitor1<void, StringBuffer> {
_writeTypeArguments(node.typeArguments, sb);
}
@override
void visitExtensionType(ir.ExtensionType node, StringBuffer sb) {
sb.write(node.extension.name);
_writeTypeArguments(node.typeArguments, sb);
}
@override
void visitFutureOrType(ir.FutureOrType node, StringBuffer sb) {
sb.write('FutureOr<');
@@ -2745,6 +2745,10 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
js_ast.Expression visitInterfaceType(InterfaceType type) =>
_emitInterfaceType(type);
@override
js_ast.Expression visitExtensionType(ExtensionType type) =>
type.onType.accept(this);
@override
js_ast.Expression visitFutureOrType(FutureOrType type) =>
_normalizeFutureOr(type);
@@ -9,7 +9,6 @@ import 'package:kernel/core_types.dart';
import '../fasta_codes.dart'
show templateInternalProblemNotFoundIn, templateTypeArgumentMismatch;
import '../kernel/internal_ast.dart';
import '../scope.dart';
import '../source/source_library_builder.dart';
import '../problems.dart';
@@ -21,13 +21,9 @@
/// with the same kind of root node.
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_to_binary.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/src/assumptions.dart';
import 'package:kernel/src/printer.dart';
import 'package:kernel/src/text_util.dart';
import 'package:kernel/text/ast_to_text.dart' show Precedence, Printer;
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../builder/type_alias_builder.dart';
@@ -54,8 +50,6 @@ import '../type_inference/type_schema_environment.dart'
import 'inference_visitor.dart';
import 'type_labeler.dart';
/// Computes the return type of a (possibly factory) constructor.
InterfaceType computeConstructorReturnType(
Member constructor, CoreTypes coreTypes) {
@@ -4232,170 +4226,3 @@ Expression clonePureExpression(Expression node) {
}
throw new UnsupportedError("Clone not supported for ${node.runtimeType}.");
}
class ExtensionType extends DartType {
final Reference extensionName;
@override
final Nullability declaredNullability;
final List<DartType> typeArguments;
final DartType onType;
ExtensionType(Extension extensionNode, Nullability declaredNullability,
[List<DartType> typeArguments])
: this.byReference(extensionNode.reference, declaredNullability,
typeArguments ?? _defaultTypeArguments(extensionNode));
ExtensionType.byReference(
this.extensionName, this.declaredNullability, this.typeArguments)
: assert(declaredNullability != null),
onType = _computeOnType(extensionName, typeArguments);
Extension get extensionNode => extensionName.asExtension;
@override
Nullability get nullability {
return uniteNullabilities(
declaredNullability, extensionNode.onType.nullability);
}
static List<DartType> _defaultTypeArguments(Extension extensionNode) {
if (extensionNode.typeParameters.length == 0) {
// Avoid allocating a list in this very common case.
return const <DartType>[];
} else {
return new List<DartType>.filled(
extensionNode.typeParameters.length, const DynamicType());
}
}
static DartType _computeOnType(
Reference extensionName, List<DartType> typeArguments) {
Extension extensionNode = extensionName.asExtension;
if (extensionNode.typeParameters.isEmpty) {
return extensionNode.onType;
} else {
assert(extensionNode.typeParameters.length == typeArguments.length);
return Substitution.fromPairs(extensionNode.typeParameters, typeArguments)
.substituteType(extensionNode.onType);
}
}
@override
R accept<R>(DartTypeVisitor<R> v) {
if (v is Printer) {
// TODO(dmitryas): Move this guarded code into Printer.visitExtensionType
// when it's available.
Printer printer = v as Printer;
printer.writeExtensionReferenceFromReference(extensionName);
if (typeArguments.isNotEmpty) {
printer.writeSymbol('<');
printer.writeList(typeArguments, printer.writeType);
printer.writeSymbol('>');
printer.state = Printer.WORD;
}
printer.writeNullability(declaredNullability);
// The following line is needed to supply the return value and make the
// compiler happy. It should go away once ExtensionType is moved to
// ast.dart.
return null;
} else if (v is BinaryPrinter) {
// TODO(dmitryas): Remove the following line and implement
// BinaryPrinter.visitExtensionType when it's available.
return onType.accept(v);
} else if (v is TypeLabeler) {
// TODO(dmitryas): Move this guarded code into
// TypeLabeler.visitExtensionType when it's available.
TypeLabeler typeLabeler = v as TypeLabeler;
typeLabeler.result.add(typeLabeler.nameForEntity(
extensionNode,
extensionNode.name,
extensionNode.enclosingLibrary.importUri,
extensionNode.enclosingLibrary.fileUri));
if (typeArguments.isNotEmpty) {
typeLabeler.result.add("<");
bool first = true;
for (DartType typeArg in typeArguments) {
if (!first) typeLabeler.result.add(", ");
typeArg.accept(typeLabeler);
first = false;
}
typeLabeler.result.add(">");
}
typeLabeler.addNullability(declaredNullability);
// The following line is needed to supply the return value and make the
// compiler happy. It should go away once ExtensionType is moved to
// ast.dart.
return null;
}
// TODO(dmitryas): Change this to `v.visitExtensionType(this)` when
// ExtensionType is moved to ast.dart.
return v.defaultDartType(this);
}
@override
R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
// TODO(dmitryas): Change this to `v.visitExtensionType(this, arg)` when
// ExtensionType is moved to ast.dart.
return v.defaultDartType(this, arg);
}
@override
void visitChildren(Visitor v) {
// TODO(dmitryas): Uncomment the following line when ExtensionType is moved
// to ast.dart.
//extensionNode.acceptReference(v);
visitList(typeArguments, v);
}
@override
bool equals(Object other, Assumptions assumptions) {
if (identical(this, other)) return true;
if (other is ExtensionType) {
if (nullability != other.nullability) return false;
if (extensionName != other.extensionName) return false;
if (typeArguments.length != other.typeArguments.length) return false;
for (int i = 0; i < typeArguments.length; ++i) {
if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
return false;
}
}
return true;
} else {
return false;
}
}
@override
int get hashCode {
int hash = 0x3fffffff & extensionName.hashCode;
for (int i = 0; i < typeArguments.length; ++i) {
hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
}
int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
return hash;
}
@override
ExtensionType withDeclaredNullability(Nullability declaredNullability) {
return declaredNullability == this.declaredNullability
? this
: new ExtensionType.byReference(
extensionName, declaredNullability, typeArguments);
}
@override
String toString() {
return "ExtensionType(${toStringInternal()})";
}
@override
void toTextInternal(AstPrinter printer) {
printer.writeExtensionName(extensionName);
printer.writeTypeArguments(typeArguments);
printer.write(nullabilityToString(declaredNullability));
}
}
@@ -9,8 +9,6 @@ import 'package:kernel/visitor.dart';
import '../type_inference/type_schema.dart';
import 'internal_ast.dart';
/// Check if [type] contains [InvalidType] as its part.
///
/// The helper function is intended for stopping cascading errors because of
@@ -59,6 +57,15 @@ class _InvalidTypeFinder implements DartTypeVisitor1<bool, Set<TypedefType>> {
return false;
}
@override
bool visitExtensionType(
ExtensionType node, Set<TypedefType> visitedTypedefs) {
for (DartType typeArgument in node.typeArguments) {
if (typeArgument.accept1(this, visitedTypedefs)) return true;
}
return false;
}
@override
bool visitFutureOrType(FutureOrType node, Set<TypedefType> visitedTypedefs) {
return node.typeArgument.accept1(this, visitedTypedefs);
@@ -4,23 +4,7 @@
// @dart = 2.9
import 'package:kernel/ast.dart'
show
DartType,
DartTypeVisitor,
DynamicType,
FunctionType,
FutureOrType,
InterfaceType,
InvalidType,
NamedType,
NeverType,
NullType,
TypeParameter,
TypeParameterType,
TypedefType,
Variance,
VoidType;
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart' show containsTypeVariable;
@@ -1029,24 +1013,37 @@ class TypeVariableSearch implements DartTypeVisitor<bool> {
return false;
}
@override
bool visitInvalidType(InvalidType node) => false;
@override
bool visitDynamicType(DynamicType node) => false;
@override
bool visitVoidType(VoidType node) => false;
@override
bool visitNeverType(NeverType node) => false;
@override
bool visitNullType(NullType node) => false;
@override
bool visitInterfaceType(InterfaceType node) {
return anyTypeVariables(node.typeArguments);
}
@override
bool visitExtensionType(ExtensionType node) {
return anyTypeVariables(node.typeArguments);
}
@override
bool visitFutureOrType(FutureOrType node) {
return node.typeArgument.accept(this);
}
@override
bool visitFunctionType(FunctionType node) {
if (anyTypeVariables(node.positionalParameters)) return true;
for (TypeParameter variable in node.typeParameters) {
@@ -1058,8 +1055,10 @@ class TypeVariableSearch implements DartTypeVisitor<bool> {
return false;
}
@override
bool visitTypeParameterType(TypeParameterType node) => true;
@override
bool visitTypedefType(TypedefType node) {
return anyTypeVariables(node.typeArguments);
}
@@ -9,26 +9,7 @@ library fasta.type_builder_computer;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show FormalParameterKind;
import 'package:kernel/ast.dart'
show
Class,
DartType,
DartTypeVisitor,
DynamicType,
FunctionType,
FutureOrType,
InterfaceType,
InvalidType,
Library,
NamedType,
NeverType,
NullType,
TreeNode,
TypeParameter,
TypeParameterType,
Typedef,
TypedefType,
VoidType;
import 'package:kernel/ast.dart';
import '../builder/class_builder.dart';
import '../builder/dynamic_type_declaration_builder.dart';
@@ -130,6 +111,11 @@ class TypeBuilderComputer implements DartTypeVisitor<TypeBuilder> {
..bind(cls);
}
@override
TypeBuilder visitExtensionType(ExtensionType node) {
throw "Not implemented";
}
@override
TypeBuilder visitFutureOrType(FutureOrType node) {
TypeBuilder argument = node.typeArgument.accept(this);
@@ -6,43 +6,7 @@
import 'dart:convert' show json;
import 'package:kernel/ast.dart'
show
BoolConstant,
Class,
Constant,
ConstantMapEntry,
DartType,
DoubleConstant,
DynamicType,
Field,
FunctionType,
FutureOrType,
InvalidType,
InstanceConstant,
IntConstant,
InterfaceType,
Library,
ListConstant,
MapConstant,
NeverType,
NullConstant,
NullType,
Nullability,
PartialInstantiationConstant,
Procedure,
SetConstant,
StringConstant,
SymbolConstant,
TearOffConstant,
TreeNode,
Typedef,
TypedefType,
TypeLiteralConstant,
TypeParameter,
TypeParameterType,
UnevaluatedConstant,
VoidType;
import 'package:kernel/ast.dart';
import 'package:kernel/visitor.dart' show ConstantVisitor, DartTypeVisitor;
@@ -286,6 +250,25 @@ class TypeLabeler implements DartTypeVisitor<void>, ConstantVisitor<void> {
addNullability(node.declaredNullability);
}
void visitExtensionType(ExtensionType node) {
result.add(nameForEntity(
node.extension,
node.extension.name,
node.extension.enclosingLibrary.importUri,
node.extension.enclosingLibrary.fileUri));
if (node.typeArguments.isNotEmpty) {
result.add("<");
bool first = true;
for (DartType typeArg in node.typeArguments) {
if (!first) result.add(", ");
typeArg.accept(this);
first = false;
}
result.add(">");
}
addNullability(node.declaredNullability);
}
void defaultConstant(Constant node) {}
void visitNullConstant(NullConstant node) {
@@ -896,7 +896,7 @@ class TypeInferrerImpl implements TypeInferrer {
Member targetTearoff;
ProcedureKind targetKind;
for (ExtensionMemberDescriptor descriptor
in receiverType.extensionNode.members) {
in receiverType.extension.members) {
if (descriptor.name == name) {
switch (descriptor.kind) {
case ExtensionMemberKind.Method:
@@ -17,8 +17,6 @@ import 'package:kernel/type_environment.dart';
import 'package:kernel/src/hierarchy_based_type_environment.dart'
show HierarchyBasedTypeEnvironment;
import '../kernel/internal_ast.dart' show ExtensionType;
import 'standard_bounds.dart' show TypeSchemaStandardBounds;
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
@@ -373,7 +371,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
if (coreTypes.isTop(supertype)) {
return const IsSubtypeOf.always();
} else if (supertype is ExtensionType &&
subtype.extensionNode == supertype.extensionNode) {
subtype.extension == supertype.extension) {
assert(subtype.typeArguments.length == supertype.typeArguments.length);
IsSubtypeOf result = const IsSubtypeOf.always();
for (int i = 0; i < subtype.typeArguments.length; ++i) {
@@ -399,7 +397,7 @@ class TypeSchemaEnvironment extends HierarchyBasedTypeEnvironment
if (coreTypes.isBottom(subtype)) {
return const IsSubtypeOf.always();
} else if (subtype is ExtensionType &&
subtype.extensionNode == unwrappedSupertype.extensionNode) {
subtype.extension == unwrappedSupertype.extension) {
assert(subtype.typeArguments.length ==
unwrappedSupertype.typeArguments.length);
IsSubtypeOf result = const IsSubtypeOf.always();
@@ -570,6 +570,16 @@ class DartTypeToTextVisitor implements DartTypeVisitor<void> {
}
sb.write(nullabilityToText(node.nullability, typeRepresentation));
}
void visitExtensionType(ExtensionType node) {
sb.write(node.extension.name);
if (node.typeArguments.isNotEmpty) {
sb.write('<');
visitList(node.typeArguments);
sb.write('>');
}
sb.write(nullabilityToText(node.declaredNullability, typeRepresentation));
}
}
/// Returns `true` if [type] is `Object` from `dart:core`.
@@ -345,6 +345,11 @@ class BenchMaker implements DartTypeVisitor1<void, StringBuffer> {
throw "not implemented";
}
@override
void visitExtensionType(ExtensionType node, StringBuffer sb) {
throw "not implemented";
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
"classes": classes,
+119
View File
@@ -1466,6 +1466,8 @@ class Extension extends NamedNode implements FileUriNode {
@override
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitExtension(this, arg);
R acceptReference<R>(Visitor<R> v) => v.visitExtensionReference(this);
@override
void visitChildren(Visitor v) {
visitList(typeParameters, v);
@@ -11150,6 +11152,123 @@ class FutureOrType extends DartType {
}
}
class ExtensionType extends DartType {
final Reference extensionReference;
@override
final Nullability declaredNullability;
final List<DartType> typeArguments;
final DartType onType;
ExtensionType(Extension extensionNode, Nullability declaredNullability,
[List<DartType>? typeArguments])
: this.byReference(extensionNode.reference, declaredNullability,
typeArguments ?? _defaultTypeArguments(extensionNode));
ExtensionType.byReference(
this.extensionReference, this.declaredNullability, this.typeArguments)
// ignore: unnecessary_null_comparison
: assert(declaredNullability != null),
onType = _computeOnType(extensionReference, typeArguments);
Extension get extension => extensionReference.asExtension;
@override
Nullability get nullability {
return uniteNullabilities(
declaredNullability, extension.onType.nullability);
}
static List<DartType> _defaultTypeArguments(Extension extensionNode) {
if (extensionNode.typeParameters.length == 0) {
// Avoid allocating a list in this very common case.
return const <DartType>[];
} else {
return new List<DartType>.filled(
extensionNode.typeParameters.length, const DynamicType());
}
}
static DartType _computeOnType(
Reference extensionName, List<DartType> typeArguments) {
Extension extensionNode = extensionName.asExtension;
if (extensionNode.typeParameters.isEmpty) {
return extensionNode.onType;
} else {
assert(extensionNode.typeParameters.length == typeArguments.length);
return Substitution.fromPairs(extensionNode.typeParameters, typeArguments)
.substituteType(extensionNode.onType);
}
}
@override
R accept<R>(DartTypeVisitor<R> v) {
return v.visitExtensionType(this);
}
@override
R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
return v.visitExtensionType(this, arg);
}
@override
void visitChildren(Visitor v) {
extension.acceptReference(v);
visitList(typeArguments, v);
}
@override
bool equals(Object other, Assumptions? assumptions) {
if (identical(this, other)) return true;
if (other is ExtensionType) {
if (nullability != other.nullability) return false;
if (extensionReference != other.extensionReference) return false;
if (typeArguments.length != other.typeArguments.length) return false;
for (int i = 0; i < typeArguments.length; ++i) {
if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
return false;
}
}
return true;
} else {
return false;
}
}
@override
int get hashCode {
int hash = 0x3fffffff & extensionReference.hashCode;
for (int i = 0; i < typeArguments.length; ++i) {
hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
}
int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
return hash;
}
@override
ExtensionType withDeclaredNullability(Nullability declaredNullability) {
return declaredNullability == this.declaredNullability
? this
: new ExtensionType.byReference(
extensionReference, declaredNullability, typeArguments);
}
@override
String toString() {
return "ExtensionType(${toStringInternal()})";
}
@override
void toTextInternal(AstPrinter printer) {
printer.writeExtensionName(extensionReference);
printer.writeTypeArguments(typeArguments);
printer.write(nullabilityToString(declaredNullability));
}
}
/// A named parameter in [FunctionType].
class NamedType extends Node implements Comparable<NamedType> {
// Flag used for serialization if [isRequired].
+11
View File
@@ -2287,6 +2287,12 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
}
}
@override
void visitExtensionType(ExtensionType node) {
// TODO(dmitryas): Serialize ExtensionType.
node.onType.accept(this);
}
@override
void visitFutureOrType(FutureOrType node) {
// TODO(dmitryas): Remove special treatment of FutureOr when the VM supports
@@ -2524,6 +2530,11 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
throw new UnsupportedError('serialization of Class references');
}
@override
void visitExtensionReference(Extension node) {
throw new UnsupportedError('serialization of Class references');
}
@override
void visitConstructorReference(Constructor node) {
throw new UnsupportedError('serialization of Constructor references');
+15
View File
@@ -738,6 +738,21 @@ class VarianceCalculator
return result;
}
@override
int visitExtensionType(ExtensionType node,
Map<TypeParameter, Map<DartType, int>> computedVariances) {
int result = Variance.unrelated;
for (int i = 0; i < node.typeArguments.length; ++i) {
result = Variance.meet(
result,
Variance.combine(
node.extension.typeParameters[i].variance,
computeVariance(typeParameter, node.typeArguments[i],
computedVariances: computedVariances)));
}
return result;
}
@override
int visitFutureOrType(FutureOrType node,
Map<TypeParameter, Map<DartType, int>> computedVariances) {
@@ -170,6 +170,32 @@ class DartTypeEquivalence implements DartTypeVisitor1<bool, DartType> {
return false;
}
@override
bool visitExtensionType(ExtensionType node, DartType other) {
// First, check Object*, Object?.
if (equateTopTypes && coreTypes.isTop(node)) {
return coreTypes.isTop(other);
}
if (other is ExtensionType) {
if (!_checkAndRegisterNullabilities(
node.declaredNullability, other.declaredNullability)) {
return false;
}
if (node.extension != other.extension) {
return false;
}
assert(node.typeArguments.length == other.typeArguments.length);
for (int i = 0; i < node.typeArguments.length; ++i) {
if (!node.typeArguments[i].accept1(this, other.typeArguments[i])) {
return false;
}
}
return true;
}
return false;
}
@override
bool visitFutureOrType(FutureOrType node, DartType other) {
// First, check FutureOr<dynamic>, FutureOr<Object?>, etc.
@@ -93,6 +93,12 @@ class FutureValueTypeVisitor implements DartTypeVisitor1<DartType, CoreTypes> {
return coreTypes.objectNullableRawType;
}
@override
DartType visitExtensionType(DartType node, CoreTypes coreTypes) {
// Otherwise, for all S, futureValueType(S) = Object?.
return coreTypes.objectNullableRawType;
}
@override
DartType visitVoidType(DartType node, CoreTypes coreTypes) {
// futureValueType(void) = void.
+35
View File
@@ -174,6 +174,41 @@ class MergeVisitor implements DartTypeVisitor1<DartType?, DartType> {
return new InterfaceType(a.classNode, nullability, newTypeArguments);
}
@override
DartType? visitExtensionType(ExtensionType a, DartType b) {
if (b is ExtensionType &&
a.extension == b.extension &&
a.typeArguments.length == b.typeArguments.length) {
Nullability? nullability = mergeNullability(a.nullability, b.nullability);
if (nullability != null) {
return mergeExtensionTypes(a, b, nullability);
}
}
if (b is InvalidType) {
return b;
}
return null;
}
DartType? mergeExtensionTypes(
ExtensionType a, ExtensionType b, Nullability nullability) {
assert(a.extension == b.extension);
assert(a.typeArguments.length == b.typeArguments.length);
if (a.typeArguments.isEmpty) {
return new ExtensionType(a.extension, nullability);
}
List<DartType> newTypeArguments =
new List<DartType>.filled(a.typeArguments.length, dummyDartType);
for (int i = 0; i < a.typeArguments.length; i++) {
DartType? newType = a.typeArguments[i].accept1(this, b.typeArguments[i]);
if (newType == null) {
return null;
}
newTypeArguments[i] = newType;
}
return new ExtensionType(a.extension, nullability, newTypeArguments);
}
@override
DartType? visitFutureOrType(FutureOrType a, DartType b) {
if (b is FutureOrType) {
+8
View File
@@ -52,6 +52,14 @@ class _NonNullVisitor implements DartTypeVisitor<DartType?> {
return node.withDeclaredNullability(Nullability.nonNullable);
}
@override
DartType? visitExtensionType(ExtensionType node) {
if (node.declaredNullability == Nullability.nonNullable) {
return null;
}
return node.withDeclaredNullability(Nullability.nonNullable);
}
@override
DartType? visitInvalidType(InvalidType node) => null;
@@ -267,6 +267,36 @@ class ReplacementVisitor implements DartTypeVisitor1<DartType?, int> {
}
}
@override
DartType? visitExtensionType(ExtensionType node, int variance) {
Nullability? newNullability = visitNullability(node);
List<DartType>? newTypeArguments = null;
for (int i = 0; i < node.typeArguments.length; i++) {
DartType? substitution = node.typeArguments[i].accept1(
this,
Variance.combine(
variance, node.extension.typeParameters[i].variance));
if (substitution != null) {
newTypeArguments ??= node.typeArguments.toList(growable: false);
newTypeArguments[i] = substitution;
}
}
return createExtensionType(node, newNullability, newTypeArguments);
}
DartType? createExtensionType(ExtensionType node, Nullability? newNullability,
List<DartType>? newTypeArguments) {
if (newNullability == null && newTypeArguments == null) {
// No nullability or type arguments needed to be substituted.
return null;
} else {
return new ExtensionType(
node.extension,
newNullability ?? node.nullability,
newTypeArguments ?? node.typeArguments);
}
}
@override
DartType? defaultDartType(DartType node, int variance) => null;
}
+11
View File
@@ -2436,6 +2436,17 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
writeNullability(node.nullability);
}
visitExtensionType(ExtensionType node) {
writeExtensionReferenceFromReference(node.extensionReference);
if (node.typeArguments.isNotEmpty) {
writeSymbol('<');
writeList(node.typeArguments, writeType);
writeSymbol('>');
state = Printer.WORD;
}
writeNullability(node.declaredNullability);
}
visitFutureOrType(FutureOrType node) {
writeWord('FutureOr');
writeSymbol('<');
+29
View File
@@ -675,6 +675,10 @@ class _OccurrenceVisitor implements DartTypeVisitor<bool> {
return node.typeArguments.any(visit);
}
bool visitExtensionType(ExtensionType node) {
return node.typeArguments.any(visit);
}
bool visitFutureOrType(FutureOrType node) {
return visit(node.typeArgument);
}
@@ -727,6 +731,10 @@ class _FreeFunctionTypeVariableVisitor implements DartTypeVisitor<bool> {
return node.typeArguments.any(visit);
}
bool visitExtensionType(ExtensionType node) {
return node.typeArguments.any(visit);
}
bool visitFutureOrType(FutureOrType node) {
return visit(node.typeArgument);
}
@@ -782,6 +790,10 @@ class _FreeTypeVariableVisitor implements DartTypeVisitor<bool> {
return node.typeArguments.any(visit);
}
bool visitExtensionType(ExtensionType node) {
return node.typeArguments.any(visit);
}
bool visitFutureOrType(FutureOrType node) {
return visit(node.typeArgument);
}
@@ -880,6 +892,11 @@ class _PrimitiveTypeVerifier implements DartTypeVisitor<bool> {
return node.typeArguments.isEmpty;
}
@override
bool visitExtensionType(ExtensionType node) {
return node.typeArguments.isEmpty;
}
@override
bool visitInvalidType(InvalidType node) {
throw new UnsupportedError(
@@ -949,6 +966,11 @@ class _NullabilityConstructorUnwrapper
return node.withDeclaredNullability(Nullability.nonNullable);
}
@override
DartType visitExtensionType(ExtensionType node, CoreTypes coreTypes) {
return node.withDeclaredNullability(Nullability.nonNullable);
}
@override
DartType visitInvalidType(InvalidType node, CoreTypes coreTypes) => node;
@@ -1162,6 +1184,13 @@ class _NullabilityMarkerDetector implements DartTypeVisitor<bool> {
node.declaredNullability == Nullability.legacy;
}
@override
bool visitExtensionType(ExtensionType node) {
assert(node.declaredNullability != Nullability.undetermined);
return node.declaredNullability == Nullability.nullable ||
node.declaredNullability == Nullability.legacy;
}
@override
bool visitInvalidType(InvalidType node) => false;
+14
View File
@@ -529,6 +529,7 @@ abstract class DartTypeVisitor<R> {
R visitTypedefType(TypedefType node) => defaultDartType(node);
R visitNeverType(NeverType node) => defaultDartType(node);
R visitNullType(NullType node) => defaultDartType(node);
R visitExtensionType(ExtensionType node) => defaultDartType(node);
}
abstract class DartTypeVisitor1<R, T> {
@@ -545,6 +546,7 @@ abstract class DartTypeVisitor1<R, T> {
R visitTypedefType(TypedefType node, T arg) => defaultDartType(node, arg);
R visitNeverType(NeverType node, T arg) => defaultDartType(node, arg);
R visitNullType(NullType node, T arg) => defaultDartType(node, arg);
R visitExtensionType(ExtensionType node, T arg) => defaultDartType(node, arg);
}
/// Visitor for [Constant] nodes.
@@ -783,6 +785,7 @@ abstract class Visitor<R> extends TreeVisitor<R>
R visitTypedefType(TypedefType node) => defaultDartType(node);
R visitNeverType(NeverType node) => defaultDartType(node);
R visitNullType(NullType node) => defaultDartType(node);
R visitExtensionType(ExtensionType node) => defaultDartType(node);
// Constants
R defaultConstant(Constant node) => defaultNode(node);
@@ -807,6 +810,8 @@ abstract class Visitor<R> extends TreeVisitor<R>
R visitTypedefReference(Typedef node);
R visitExtensionReference(Extension node);
// Constant references
R defaultConstantReference(Constant node);
@@ -905,6 +910,9 @@ mixin VisitorNullMixin<R> implements Visitor<R?> {
@override
R? visitTypedefReference(Typedef node) => null;
@override
R? visitExtensionReference(Extension node) => null;
@override
R? defaultConstantReference(Constant node) => null;
@@ -923,6 +931,9 @@ mixin VisitorVoidMixin implements Visitor<void> {
@override
void visitTypedefReference(Typedef node) {}
@override
void visitExtensionReference(Extension node) {}
@override
void defaultConstantReference(Constant node) {}
@@ -943,6 +954,9 @@ mixin VisitorDefaultValueMixin<R> implements Visitor<R> {
@override
R visitTypedefReference(Typedef node) => defaultValue;
@override
R visitExtensionReference(Extension node) => defaultValue;
@override
R defaultConstantReference(Constant node) => defaultValue;