mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[kernel] Add sealed classes GenericDeclaration and GenericFunction
This adds a typed `TypeParameter.declaration` property to be used instead of the `parent` property. The `declaration` property holds the declaration (Class, Method, Extension, etc.) that introduced the type parameter. `GenericFunction` is the subset of `GenericDeclaration` that is defined through a `FunctionNode`. TEST=existing Change-Id: Ie89e7f5fa12a7966507a250cacc098eb0ce6b30b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323160 Reviewed-by: Mayank Patke <fishythefish@google.com> Reviewed-by: Jens Johansen <jensj@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
parent
5b44717c63
commit
e401b6f18a
|
@ -344,41 +344,35 @@ class TypeVariableTypeWithContext implements ir.Node {
|
|||
factory TypeVariableTypeWithContext(
|
||||
ir.TypeParameterType type, ir.TreeNode? context) {
|
||||
TypeVariableKind kind;
|
||||
ir.TreeNode? typeDeclaration = type.parameter.parent;
|
||||
ir.GenericDeclaration? typeDeclaration = type.parameter.declaration;
|
||||
// TODO(fishythefish): Use exhaustive pattern switch.
|
||||
if (typeDeclaration == null) {
|
||||
// We have a function type variable, like `T` in `void Function<T>(int)`.
|
||||
kind = TypeVariableKind.function;
|
||||
} else if (typeDeclaration is ir.Class) {
|
||||
// We have a class type variable, like `T` in `class Class<T> { ... }`.
|
||||
kind = TypeVariableKind.cls;
|
||||
} else {
|
||||
final parent = typeDeclaration.parent;
|
||||
if (parent is ir.Member) {
|
||||
ir.Member member = parent;
|
||||
if (member is ir.Constructor ||
|
||||
(member is ir.Procedure && member.isFactory)) {
|
||||
// We have a synthesized generic method type variable for a class type
|
||||
// variable.
|
||||
// TODO(johnniwinther): Handle constructor/factory type variables as
|
||||
// method type variables.
|
||||
kind = TypeVariableKind.cls;
|
||||
typeDeclaration = member.enclosingClass;
|
||||
} else {
|
||||
// We have a generic method type variable, like `T` in
|
||||
// `m<T>() { ... }`.
|
||||
kind = TypeVariableKind.method;
|
||||
typeDeclaration = parent;
|
||||
context = typeDeclaration;
|
||||
}
|
||||
} else if (typeDeclaration is ir.Procedure) {
|
||||
if (typeDeclaration.isFactory) {
|
||||
// We have a synthesized generic method type variable for a class type
|
||||
// variable.
|
||||
// TODO(johnniwinther): Handle constructor/factory type variables as
|
||||
// method type variables.
|
||||
kind = TypeVariableKind.cls;
|
||||
typeDeclaration = typeDeclaration.enclosingClass;
|
||||
} else {
|
||||
// We have a generic local function type variable, like `T` in
|
||||
// `m() { local<T>() { ... } ... }`.
|
||||
assert(parent is ir.LocalFunction,
|
||||
"Unexpected type declaration: $typeDeclaration");
|
||||
kind = TypeVariableKind.local;
|
||||
typeDeclaration = parent;
|
||||
// We have a generic method type variable, like `T` in
|
||||
// `m<T>() { ... }`.
|
||||
kind = TypeVariableKind.method;
|
||||
context = typeDeclaration;
|
||||
}
|
||||
} else {
|
||||
// We have a generic local function type variable, like `T` in
|
||||
// `m() { local<T>() { ... } ... }`.
|
||||
assert(typeDeclaration is ir.LocalFunction,
|
||||
"Unexpected type declaration: $typeDeclaration");
|
||||
kind = TypeVariableKind.local;
|
||||
context = typeDeclaration;
|
||||
}
|
||||
return TypeVariableTypeWithContext.internal(
|
||||
type, context, kind, typeDeclaration);
|
||||
|
|
|
@ -416,10 +416,10 @@ class ScopeModelBuilder extends ir.Visitor<EvaluationComplexity>
|
|||
TypeVariableTypeWithContext(
|
||||
ir.TypeParameterType.withDefaultNullabilityForLibrary(
|
||||
typeParameter, library),
|
||||
// If this typeParameter is part of a typedef then its parent is
|
||||
// null because it has no context. Just pass in null for the
|
||||
// context in that case.
|
||||
typeParameter.parent?.parent);
|
||||
// If this typeParameter is part of a function type then its
|
||||
// declaration is null because it has no context. Just pass in null
|
||||
// for the context in that case.
|
||||
typeParameter.declaration);
|
||||
|
||||
ir.TreeNode? context = _executableContext;
|
||||
if (_isInsideClosure && context is ir.Procedure && context.isFactory) {
|
||||
|
|
|
@ -103,7 +103,7 @@ class DartTypeConverter extends ir.DartTypeVisitor<DartType> {
|
|||
if (typeParameter != null) {
|
||||
return _convertNullability(typeParameter, node);
|
||||
}
|
||||
if (node.parameter.parent is ir.Typedef) {
|
||||
if (node.parameter.declaration is ir.Typedef) {
|
||||
// Typedefs are only used in type literals so we never need their type
|
||||
// variables.
|
||||
return _dartTypes.dynamicType();
|
||||
|
|
|
@ -1592,20 +1592,13 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap {
|
|||
TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node) {
|
||||
TypeVariableEntity? typeVariable = typeVariableMap[node];
|
||||
if (typeVariable == null) {
|
||||
final parent = node.parent;
|
||||
if (parent is ir.FunctionNode) {
|
||||
final member = parent.parent;
|
||||
int index = parent.typeParameters.indexOf(node);
|
||||
if (member is ir.Constructor) {
|
||||
ir.Class cls = member.enclosingClass;
|
||||
final declaration = node.declaration;
|
||||
if (declaration is ir.Procedure) {
|
||||
int index = declaration.typeParameters.indexOf(node);
|
||||
if (declaration.kind == ir.ProcedureKind.Factory) {
|
||||
ir.Class cls = declaration.enclosingClass!;
|
||||
typeVariableMap[node] =
|
||||
typeVariable = getTypeVariableInternal(cls.typeParameters[index]);
|
||||
} else if (member is ir.Procedure) {
|
||||
if (member.kind == ir.ProcedureKind.Factory) {
|
||||
ir.Class cls = member.enclosingClass!;
|
||||
typeVariableMap[node] = typeVariable =
|
||||
getTypeVariableInternal(cls.typeParameters[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1613,7 +1606,7 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap {
|
|||
throw failedAt(
|
||||
CURRENT_ELEMENT_SPANNABLE,
|
||||
"No type variable entity for $node on "
|
||||
"${node.parent is ir.FunctionNode ? node.parent!.parent : node.parent}");
|
||||
"${node.declaration}");
|
||||
}
|
||||
return typeVariable;
|
||||
}
|
||||
|
|
|
@ -1234,41 +1234,28 @@ class KernelToElementMap implements IrToElementMap {
|
|||
!envIsClosed,
|
||||
"Environment of $this is closed. Trying to create "
|
||||
"type variable for $node.");
|
||||
final parent = node.parent;
|
||||
if (parent is ir.Class) {
|
||||
ir.Class cls = parent;
|
||||
int index = cls.typeParameters.indexOf(node);
|
||||
final declaration = node.declaration;
|
||||
// TODO(fishythefish): Use exhaustive pattern switch.
|
||||
if (declaration is ir.Class) {
|
||||
int index = declaration.typeParameters.indexOf(node);
|
||||
return typeVariables.register(
|
||||
createTypeVariable(getClassInternal(cls), node.name!, index),
|
||||
createTypeVariable(getClassInternal(declaration), node.name!, index),
|
||||
KTypeVariableData(node));
|
||||
}
|
||||
if (parent is ir.FunctionNode) {
|
||||
ir.FunctionNode func = parent;
|
||||
int index = func.typeParameters.indexOf(node);
|
||||
final funcParent = func.parent;
|
||||
if (funcParent is ir.Constructor) {
|
||||
ir.Constructor constructor = funcParent;
|
||||
ir.Class cls = constructor.enclosingClass;
|
||||
} else if (declaration is ir.Procedure) {
|
||||
int index = declaration.typeParameters.indexOf(node);
|
||||
if (declaration.kind == ir.ProcedureKind.Factory) {
|
||||
ir.Class cls = declaration.enclosingClass!;
|
||||
return getTypeVariableInternal(cls.typeParameters[index]);
|
||||
} else if (funcParent is ir.Procedure) {
|
||||
ir.Procedure procedure = funcParent;
|
||||
if (procedure.kind == ir.ProcedureKind.Factory) {
|
||||
ir.Class cls = procedure.enclosingClass!;
|
||||
return getTypeVariableInternal(cls.typeParameters[index]);
|
||||
} else {
|
||||
return typeVariables.register(
|
||||
createTypeVariable(
|
||||
getMethodInternal(procedure), node.name!, index),
|
||||
KTypeVariableData(node));
|
||||
}
|
||||
} else if (funcParent is ir.LocalFunction) {
|
||||
// Ensure that local function type variables have been created.
|
||||
getLocalFunction(funcParent);
|
||||
return typeVariableMap[node];
|
||||
} else {
|
||||
throw UnsupportedError('Unsupported function type parameter parent '
|
||||
'node ${func.parent}.');
|
||||
return typeVariables.register(
|
||||
createTypeVariable(
|
||||
getMethodInternal(declaration), node.name!, index),
|
||||
KTypeVariableData(node));
|
||||
}
|
||||
} else if (declaration is ir.LocalFunction) {
|
||||
// Ensure that local function type variables have been created.
|
||||
getLocalFunction(declaration);
|
||||
return typeVariableMap[node];
|
||||
}
|
||||
throw UnsupportedError('Unsupported type parameter type node $node.');
|
||||
}
|
||||
|
|
|
@ -595,18 +595,23 @@ class DataSinkWriter {
|
|||
}
|
||||
|
||||
void _writeTypeParameter(ir.TypeParameter value, MemberData? memberData) {
|
||||
ir.TreeNode parent = value.parent!;
|
||||
if (parent is ir.Class) {
|
||||
ir.GenericDeclaration declaration = value.declaration!;
|
||||
// TODO(fishythefish): Use exhaustive pattern switch.
|
||||
if (declaration is ir.Class) {
|
||||
_sinkWriter.writeEnum(_TypeParameterKind.cls);
|
||||
_writeClassNode(parent);
|
||||
_sinkWriter.writeInt(parent.typeParameters.indexOf(value));
|
||||
} else if (parent is ir.FunctionNode) {
|
||||
_writeClassNode(declaration);
|
||||
_sinkWriter.writeInt(declaration.typeParameters.indexOf(value));
|
||||
} else if (declaration is ir.Procedure) {
|
||||
_sinkWriter.writeEnum(_TypeParameterKind.functionNode);
|
||||
_writeFunctionNode(parent, memberData);
|
||||
_sinkWriter.writeInt(parent.typeParameters.indexOf(value));
|
||||
_writeFunctionNode(declaration.function, memberData);
|
||||
_sinkWriter.writeInt(declaration.typeParameters.indexOf(value));
|
||||
} else if (declaration is ir.LocalFunction) {
|
||||
_sinkWriter.writeEnum(_TypeParameterKind.functionNode);
|
||||
_writeFunctionNode(declaration.function, memberData);
|
||||
_sinkWriter.writeInt(declaration.typeParameters.indexOf(value));
|
||||
} else {
|
||||
throw UnsupportedError(
|
||||
"Unsupported TypeParameter parent ${parent.runtimeType}");
|
||||
"Unsupported TypeParameter declaration ${declaration.runtimeType}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1131,7 +1131,7 @@ class CaptureFinder extends RecursiveVisitor {
|
|||
|
||||
@override
|
||||
void visitTypeParameter(TypeParameter node) {
|
||||
if (node.parent is FunctionNode) {
|
||||
if (node.declaration is GenericFunction) {
|
||||
if (depth > 0) {
|
||||
variableDepth[node] = depth;
|
||||
}
|
||||
|
@ -1196,10 +1196,10 @@ class CaptureFinder extends RecursiveVisitor {
|
|||
void visitTypeParameterType(TypeParameterType node) {
|
||||
if (member is Constructor) {
|
||||
_visitVariableUse(node.parameter);
|
||||
} else if (node.parameter.parent != null &&
|
||||
node.parameter.parent == member.enclosingClass) {
|
||||
} else if (node.parameter.declaration != null &&
|
||||
node.parameter.declaration == member.enclosingClass) {
|
||||
_visitThis();
|
||||
} else if (node.parameter.parent is FunctionNode) {
|
||||
} else if (node.parameter.declaration is GenericFunction) {
|
||||
_visitVariableUse(node.parameter);
|
||||
}
|
||||
super.visitTypeParameterType(node);
|
||||
|
|
|
@ -3057,7 +3057,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
w.ValueType resultType;
|
||||
|
||||
// `this` will not be initialized yet for constructor initializer lists
|
||||
if (parameter.parent is FunctionNode || reference.isInitializerReference) {
|
||||
if (parameter.declaration is GenericFunction ||
|
||||
reference.isInitializerReference) {
|
||||
// Type argument to function
|
||||
w.Local? local = typeLocals[parameter];
|
||||
if (local != null) {
|
||||
|
@ -3071,7 +3072,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
}
|
||||
} else {
|
||||
// Type argument of class
|
||||
Class cls = parameter.parent as Class;
|
||||
Class cls = parameter.declaration as Class;
|
||||
ClassInfo info = translator.classInfo[cls]!;
|
||||
int fieldIndex = translator.typeParameterIndex[parameter]!;
|
||||
visitThis(info.nonNullableType);
|
||||
|
|
|
@ -334,7 +334,7 @@ class Types {
|
|||
}
|
||||
|
||||
bool isFunctionTypeParameter(TypeParameterType type) =>
|
||||
type.parameter.parent == null;
|
||||
type.parameter.declaration == null;
|
||||
|
||||
bool _isTypeConstant(DartType type) {
|
||||
return type is DynamicType ||
|
||||
|
|
|
@ -223,7 +223,7 @@ class TypeTable {
|
|||
// readability to little or no benefit. It would be good to do this
|
||||
// when we know that we can hoist it to an outer scope, but for
|
||||
// now we just disable it.
|
||||
if (freeVariables.any((i) => i.parent is FunctionNode)) {
|
||||
if (freeVariables.any((i) => i.declaration is GenericFunction)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -9007,8 +9007,9 @@ class BodyBuilder extends StackListenerImpl
|
|||
TypeVariableBuilder typeParameterBuilder =
|
||||
declaration as TypeVariableBuilder;
|
||||
TypeParameter typeParameter = typeParameterBuilder.parameter;
|
||||
if (typeParameter.parent is Class ||
|
||||
typeParameter.parent is Extension) {
|
||||
if (typeParameter.declaration is Class ||
|
||||
typeParameter.declaration is Extension ||
|
||||
typeParameter.declaration is ExtensionTypeDeclaration) {
|
||||
if (constantContext != ConstantContext.none &&
|
||||
(!inConstructorInitializer || !allowPotentiallyConstantType)) {
|
||||
LocatedMessage message =
|
||||
|
|
|
@ -159,7 +159,7 @@ Component createExpressionEvaluationComponent(Procedure procedure) {
|
|||
Map<TypeParameter, DartType> typeSubstitution = <TypeParameter, DartType>{};
|
||||
for (TypeParameter typeParam in realClass.typeParameters) {
|
||||
TypeParameter newNode = new TypeParameter(typeParam.name)
|
||||
..parent = fakeClass;
|
||||
..declaration = fakeClass;
|
||||
typeParams[typeParam] = newNode;
|
||||
typeSubstitution[typeParam] =
|
||||
new TypeParameterType.forAlphaRenaming(typeParam, newNode);
|
||||
|
|
|
@ -404,7 +404,12 @@ class DeclaredSourceConstructorBuilder
|
|||
super.classBuilder as SourceClassBuilder;
|
||||
|
||||
@override
|
||||
Member get readTarget => _constructorTearOff ?? _constructor;
|
||||
Member get readTarget =>
|
||||
_constructorTearOff ??
|
||||
// The case is need to ensure that the upper bound is [Member] and not
|
||||
// [GenericFunction].
|
||||
// ignore: unnecessary_cast
|
||||
_constructor as Member;
|
||||
|
||||
@override
|
||||
Member? get writeTarget => null;
|
||||
|
|
|
@ -1316,6 +1316,7 @@ severity: $severity
|
|||
builder,
|
||||
dietListener.memberScope,
|
||||
thisVariable: extensionThis);
|
||||
builder.procedure.function = parameters..parent = builder.procedure;
|
||||
for (VariableDeclaration variable in parameters.positionalParameters) {
|
||||
listener.typeInferrer.assignedVariables.declare(variable);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
|
||||
/*library: nnbd=true*/
|
||||
|
||||
T id<T>(T /*T%*/ t) => t;
|
||||
T id<T>(
|
||||
T /*normal|limited.id.T%*/ /*verbose.library org-dartlang-test:///a/b/c/main.dart::id.T%*/
|
||||
t) =>
|
||||
t;
|
||||
|
||||
class Class1<T> {
|
||||
const Class1();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/*library: nnbd=false*/
|
||||
library test;
|
||||
|
||||
T id<T>(T /*T**/ t) => t;
|
||||
T id<T>(T /*normal|limited.id.T**/ /*verbose.test::id.T**/ t) => t;
|
||||
|
||||
class Class1<T> {
|
||||
const Class1();
|
||||
|
|
|
@ -70,8 +70,16 @@ get topLevelGetter => 42;
|
|||
set topLevelSetter(/*dynamic*/ _) {}
|
||||
topLevelMethod() {}
|
||||
|
||||
T genericTopLevelMethod1<T>(T /*T%*/ t) => t;
|
||||
T genericTopLevelMethod2<T, S>(T /*T%*/ t, S /*S%*/ s) => t;
|
||||
T genericTopLevelMethod1<T>(
|
||||
T /*normal|limited.genericTopLevelMethod1.T%*/ /*verbose.expressions::genericTopLevelMethod1.T%*/
|
||||
t) =>
|
||||
t;
|
||||
T genericTopLevelMethod2<T, S>(
|
||||
T /*normal|limited.genericTopLevelMethod2.T%*/ /*verbose.expressions::genericTopLevelMethod2.T%*/
|
||||
t,
|
||||
S /*normal|limited.genericTopLevelMethod2.S%*/ /*verbose.expressions::genericTopLevelMethod2.S%*/
|
||||
s) =>
|
||||
t;
|
||||
|
||||
/*member: exprNullLiteral:null*/
|
||||
exprNullLiteral() => null;
|
||||
|
|
|
@ -71,14 +71,44 @@ futureOrType(
|
|||
/*normal|limited.FutureOr<int?>?*/
|
||||
/*verbose.FutureOr<dart.core::int?>?*/
|
||||
o4) {}
|
||||
typeVariableType1<T>(T /*T%*/ o1, T? /*T?*/ o2) {}
|
||||
typeVariableType2<T extends num>(T /*T*/ o1, T? /*T?*/ o2) {}
|
||||
typeVariableType1<T>(
|
||||
T /*normal|limited.typeVariableType1.T%*/ /*verbose.test::typeVariableType1.T%*/
|
||||
o1,
|
||||
T? /*normal|limited.typeVariableType1.T?*/ /*verbose.test::typeVariableType1.T?*/
|
||||
o2) {}
|
||||
typeVariableType2<T extends num>(
|
||||
T /*normal|limited.typeVariableType2.T*/ /*verbose.test::typeVariableType2.T*/
|
||||
o1,
|
||||
T? /*normal|limited.typeVariableType2.T?*/ /*verbose.test::typeVariableType2.T?*/
|
||||
o2) {}
|
||||
typeVariableType3<T extends S, S>(
|
||||
T /*T%*/ o1, S /*S%*/ p1, T? /*T?*/ o2, S? /*S?*/ p2) {}
|
||||
T /*normal|limited.typeVariableType3.T%*/ /*verbose.test::typeVariableType3.T%*/
|
||||
o1,
|
||||
S /*normal|limited.typeVariableType3.S%*/ /*verbose.test::typeVariableType3.S%*/
|
||||
p1,
|
||||
T? /*normal|limited.typeVariableType3.T?*/ /*verbose.test::typeVariableType3.T?*/
|
||||
o2,
|
||||
S? /*normal|limited.typeVariableType3.S?*/ /*verbose.test::typeVariableType3.S?*/
|
||||
p2) {}
|
||||
typeVariableType4<T, S extends T>(
|
||||
T /*T%*/ o1, S /*S%*/ p1, T? /*T?*/ o2, S? /*S?*/ p2) {}
|
||||
typeVariableType5<T extends Object>(T /*T*/ o1, T? /*T?*/ o2) {}
|
||||
typeVariableType6<T extends Object?>(T /*T%*/ o1, T? /*T?*/ o2) {}
|
||||
T /*normal|limited.typeVariableType4.T%*/ /*verbose.test::typeVariableType4.T%*/
|
||||
o1,
|
||||
S /*normal|limited.typeVariableType4.S%*/ /*verbose.test::typeVariableType4.S%*/
|
||||
p1,
|
||||
T? /*normal|limited.typeVariableType4.T?*/ /*verbose.test::typeVariableType4.T?*/
|
||||
o2,
|
||||
S? /*normal|limited.typeVariableType4.S?*/ /*verbose.test::typeVariableType4.S?*/
|
||||
p2) {}
|
||||
typeVariableType5<T extends Object>(
|
||||
T /*normal|limited.typeVariableType5.T*/ /*verbose.test::typeVariableType5.T*/
|
||||
o1,
|
||||
T? /*normal|limited.typeVariableType5.T?*/ /*verbose.test::typeVariableType5.T?*/
|
||||
o2) {}
|
||||
typeVariableType6<T extends Object?>(
|
||||
T /*normal|limited.typeVariableType6.T%*/ /*verbose.test::typeVariableType6.T%*/
|
||||
o1,
|
||||
T? /*normal|limited.typeVariableType6.T?*/ /*verbose.test::typeVariableType6.T?*/
|
||||
o2) {}
|
||||
functionType1(void Function() /*void Function()*/ o1,
|
||||
void Function()? /*void Function()?*/ o2) {}
|
||||
functionType2(
|
||||
|
|
|
@ -42,11 +42,25 @@ futureOrType(
|
|||
/*normal|limited.FutureOr<int*>**/
|
||||
/*verbose.FutureOr<dart.core::int*>**/
|
||||
o) {}
|
||||
typeVariableType1<T>(T /*T**/ o) {}
|
||||
typeVariableType2<T extends num>(T /*T**/ o) {}
|
||||
typeVariableType3<T extends S, S>(T /*T**/ o, S /*S**/ p) {}
|
||||
typeVariableType4<T, S extends T>(T /*T**/ o, S /*S**/ p) {}
|
||||
typeVariableType5<T extends Object>(T /*T**/ o) {}
|
||||
typeVariableType1<T>(
|
||||
T /*normal|limited.typeVariableType1.T**/ /*verbose.test::typeVariableType1.T**/
|
||||
o) {}
|
||||
typeVariableType2<T extends num>(
|
||||
T /*normal|limited.typeVariableType2.T**/ /*verbose.test::typeVariableType2.T**/
|
||||
o) {}
|
||||
typeVariableType3<T extends S, S>(
|
||||
T /*normal|limited.typeVariableType3.T**/ /*verbose.test::typeVariableType3.T**/
|
||||
o,
|
||||
S /*normal|limited.typeVariableType3.S**/ /*verbose.test::typeVariableType3.S**/
|
||||
p) {}
|
||||
typeVariableType4<T, S extends T>(
|
||||
T /*normal|limited.typeVariableType4.T**/ /*verbose.test::typeVariableType4.T**/
|
||||
o,
|
||||
S /*normal|limited.typeVariableType4.S**/ /*verbose.test::typeVariableType4.S**/
|
||||
p) {}
|
||||
typeVariableType5<T extends Object>(
|
||||
T /*normal|limited.typeVariableType5.T**/ /*verbose.test::typeVariableType5.T**/
|
||||
o) {}
|
||||
functionType1(void Function() /*void Function()**/ o) {}
|
||||
functionType2(
|
||||
int Function(int)
|
||||
|
|
|
@ -846,7 +846,8 @@ class Combinator extends TreeNode {
|
|||
}
|
||||
|
||||
/// Declaration of a type alias.
|
||||
class Typedef extends NamedNode implements FileUriNode, Annotatable {
|
||||
class Typedef extends NamedNode
|
||||
implements FileUriNode, Annotatable, GenericDeclaration {
|
||||
/// The URI of the source file that contains the declaration of this typedef.
|
||||
@override
|
||||
Uri fileUri;
|
||||
|
@ -855,7 +856,10 @@ class Typedef extends NamedNode implements FileUriNode, Annotatable {
|
|||
List<Expression> annotations = const <Expression>[];
|
||||
|
||||
String name;
|
||||
|
||||
@override
|
||||
final List<TypeParameter> typeParameters;
|
||||
|
||||
// TODO(johnniwinther): Make this non-nullable.
|
||||
DartType? type;
|
||||
|
||||
|
@ -974,13 +978,26 @@ class DirtifyingList<E> extends ListBase<E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Declaration that can introduce [TypeParameter]s.
|
||||
sealed class GenericDeclaration implements TreeNode {
|
||||
/// The type parameters introduced by this declaration.
|
||||
List<TypeParameter> get typeParameters;
|
||||
}
|
||||
|
||||
/// Functions that can introduce [TypeParameter]s.
|
||||
sealed class GenericFunction implements GenericDeclaration {
|
||||
/// The [FunctionNode] that holds the introduced [typeParameters].
|
||||
FunctionNode get function;
|
||||
}
|
||||
|
||||
/// Declaration of a regular class or a mixin application.
|
||||
///
|
||||
/// Mixin applications may not contain fields or procedures, as they implicitly
|
||||
/// use those from its mixed-in type. However, the IR does not enforce this
|
||||
/// rule directly, as doing so can obstruct transformations. It is possible to
|
||||
/// transform a mixin application to become a regular class, and vice versa.
|
||||
class Class extends NamedNode implements Annotatable, FileUriNode {
|
||||
class Class extends NamedNode
|
||||
implements Annotatable, FileUriNode, GenericDeclaration {
|
||||
/// Start offset of the class in the source file it comes from.
|
||||
///
|
||||
/// Note that this includes annotations if any.
|
||||
|
@ -1168,6 +1185,7 @@ class Class extends NamedNode implements Annotatable, FileUriNode {
|
|||
@override
|
||||
Uri fileUri;
|
||||
|
||||
@override
|
||||
final List<TypeParameter> typeParameters;
|
||||
|
||||
/// The immediate super type, or `null` if this is the root class.
|
||||
|
@ -1517,7 +1535,8 @@ class Class extends NamedNode implements Annotatable, FileUriNode {
|
|||
///
|
||||
/// The members are converted into top-level procedures and only accessible
|
||||
/// by reference in the [Extension] node.
|
||||
class Extension extends NamedNode implements Annotatable, FileUriNode {
|
||||
class Extension extends NamedNode
|
||||
implements Annotatable, FileUriNode, GenericDeclaration {
|
||||
/// Name of the extension.
|
||||
///
|
||||
/// If unnamed, the extension will be given a synthesized name by the
|
||||
|
@ -1529,6 +1548,7 @@ class Extension extends NamedNode implements Annotatable, FileUriNode {
|
|||
Uri fileUri;
|
||||
|
||||
/// Type parameters declared on the extension.
|
||||
@override
|
||||
final List<TypeParameter> typeParameters;
|
||||
|
||||
/// The type in the 'on clause' of the extension declaration.
|
||||
|
@ -1731,7 +1751,7 @@ class ExtensionMemberDescriptor {
|
|||
/// The members are converted into top-level procedures and only accessible
|
||||
/// by reference in the [ExtensionTypeDeclaration] node.
|
||||
class ExtensionTypeDeclaration extends NamedNode
|
||||
implements Annotatable, FileUriNode {
|
||||
implements Annotatable, FileUriNode, GenericDeclaration {
|
||||
/// Name of the extension type declaration.
|
||||
String name;
|
||||
|
||||
|
@ -1740,6 +1760,7 @@ class ExtensionTypeDeclaration extends NamedNode
|
|||
Uri fileUri;
|
||||
|
||||
/// Type parameters declared on the extension.
|
||||
@override
|
||||
final List<TypeParameter> typeParameters;
|
||||
|
||||
/// The type in the underlying representation of the extension type
|
||||
|
@ -2801,7 +2822,7 @@ enum ProcedureStubKind {
|
|||
/// For index-getters/setters, this is `[]` and `[]=`.
|
||||
/// For operators, this is the token for the operator, e.g. `+` or `==`,
|
||||
/// except for the unary minus operator, whose name is `unary-`.
|
||||
class Procedure extends Member {
|
||||
class Procedure extends Member implements GenericFunction {
|
||||
/// Start offset of the function in the source file it comes from.
|
||||
///
|
||||
/// Note that this includes annotations if any.
|
||||
|
@ -2909,6 +2930,9 @@ class Procedure extends Member {
|
|||
"$memberSignatureOrigin for $this.");
|
||||
}
|
||||
|
||||
@override
|
||||
List<TypeParameter> get typeParameters => function.typeParameters;
|
||||
|
||||
// The function node's body might be lazily loaded, meaning that this value
|
||||
// might not be set correctly yet. Make sure the body is loaded before
|
||||
// returning anything.
|
||||
|
@ -8402,7 +8426,8 @@ class AwaitExpression extends Expression {
|
|||
}
|
||||
|
||||
/// Common super-interface for [FunctionExpression] and [FunctionDeclaration].
|
||||
abstract class LocalFunction implements TreeNode {
|
||||
abstract class LocalFunction implements GenericFunction {
|
||||
@override
|
||||
FunctionNode get function;
|
||||
}
|
||||
|
||||
|
@ -8417,6 +8442,9 @@ class FunctionExpression extends Expression implements LocalFunction {
|
|||
function.parent = this;
|
||||
}
|
||||
|
||||
@override
|
||||
List<TypeParameter> get typeParameters => function.typeParameters;
|
||||
|
||||
@override
|
||||
DartType getStaticTypeInternal(StaticTypeContext context) {
|
||||
return function.computeFunctionType(context.nonNullable);
|
||||
|
@ -10597,6 +10625,9 @@ class FunctionDeclaration extends Statement implements LocalFunction {
|
|||
function.parent = this;
|
||||
}
|
||||
|
||||
@override
|
||||
List<TypeParameter> get typeParameters => function.typeParameters;
|
||||
|
||||
@override
|
||||
R accept<R>(StatementVisitor<R> v) => v.visitFunctionDeclaration(this);
|
||||
|
||||
|
@ -12237,7 +12268,7 @@ class TypeParameterType extends DartType {
|
|||
} else if (other is TypeParameterType) {
|
||||
if (nullability != other.nullability) return false;
|
||||
if (parameter != other.parameter) {
|
||||
if (parameter.parent == null) {
|
||||
if (parameter.isFunctionTypeTypeParameter) {
|
||||
// Function type parameters are also equal by assumption.
|
||||
if (assumptions == null) {
|
||||
return false;
|
||||
|
@ -12632,6 +12663,46 @@ class TypeParameter extends TreeNode implements Annotatable {
|
|||
// Must match serialized bit positions.
|
||||
static const int FlagCovariantByClass = 1 << 0;
|
||||
|
||||
@Deprecated("Used TypeParameter.declaration instead.")
|
||||
@override
|
||||
TreeNode? get parent;
|
||||
|
||||
@Deprecated("Used TypeParameter.declaration instead.")
|
||||
@override
|
||||
void set parent(TreeNode? value);
|
||||
|
||||
GenericDeclaration? get declaration {
|
||||
// TODO(johnniwinther): Store the declaration directly when [parent] is
|
||||
// removed.
|
||||
TreeNode? parent = super.parent;
|
||||
if (parent is GenericDeclaration) {
|
||||
return parent;
|
||||
} else if (parent is FunctionNode) {
|
||||
return parent.parent as GenericDeclaration;
|
||||
}
|
||||
assert(
|
||||
parent == null,
|
||||
"Unexpected type parameter parent node "
|
||||
"${parent} (${parent.runtimeType}).");
|
||||
return null;
|
||||
}
|
||||
|
||||
void set declaration(GenericDeclaration? value) {
|
||||
switch (value) {
|
||||
case Typedef():
|
||||
case Class():
|
||||
case Extension():
|
||||
case ExtensionTypeDeclaration():
|
||||
super.parent = value;
|
||||
case Procedure():
|
||||
super.parent = value.function;
|
||||
case LocalFunction():
|
||||
super.parent = value.function;
|
||||
case null:
|
||||
super.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// If this [TypeParameter] is a type parameter of a generic method, indicates
|
||||
/// whether the method implementation needs to contain a runtime type check to
|
||||
/// deal with generic covariance.
|
||||
|
@ -12693,7 +12764,7 @@ class TypeParameter extends TreeNode implements Annotatable {
|
|||
printer.writeTypeParameterName(this);
|
||||
}
|
||||
|
||||
bool get isFunctionTypeTypeParameter => parent == null;
|
||||
bool get isFunctionTypeTypeParameter => declaration == null;
|
||||
}
|
||||
|
||||
class Supertype extends Node {
|
||||
|
|
|
@ -3936,7 +3936,7 @@ class BinaryBuilder {
|
|||
}
|
||||
|
||||
List<TypeParameter> readAndPushTypeParameterList(
|
||||
[List<TypeParameter>? list, TreeNode? parent]) {
|
||||
[List<TypeParameter>? list, GenericDeclaration? declaration]) {
|
||||
int length = readUInt30();
|
||||
if (length == 0) {
|
||||
if (list != null) return list;
|
||||
|
@ -3947,12 +3947,12 @@ class BinaryBuilder {
|
|||
}
|
||||
}
|
||||
if (list == null) {
|
||||
list = new List<TypeParameter>.generate(
|
||||
length, (_) => new TypeParameter(null, null)..parent = parent,
|
||||
list = new List<TypeParameter>.generate(length,
|
||||
(_) => new TypeParameter(null, null)..declaration = declaration,
|
||||
growable: useGrowableLists);
|
||||
} else if (list.length != length) {
|
||||
for (int i = 0; i < length; ++i) {
|
||||
list.add(new TypeParameter(null, null)..parent = parent);
|
||||
list.add(new TypeParameter(null, null)..declaration = declaration);
|
||||
}
|
||||
}
|
||||
typeParameterStack.addAll(list);
|
||||
|
|
|
@ -267,24 +267,37 @@ String memberNameToString(Member node) {
|
|||
|
||||
String qualifiedTypeParameterNameToString(TypeParameter node,
|
||||
{bool includeLibraryName = false}) {
|
||||
TreeNode? parent = node.parent;
|
||||
if (parent is Class) {
|
||||
return qualifiedClassNameToString(parent,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
} else if (parent is Extension) {
|
||||
return qualifiedExtensionNameToString(parent,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
} else if (parent is Member) {
|
||||
return qualifiedMemberNameToString(parent,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
GenericDeclaration? declaration = node.declaration;
|
||||
switch (declaration) {
|
||||
case Class():
|
||||
return qualifiedClassNameToString(declaration,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
case Extension():
|
||||
return qualifiedExtensionNameToString(declaration,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
case ExtensionTypeDeclaration():
|
||||
return qualifiedExtensionTypeDeclarationNameToString(declaration,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
case Typedef():
|
||||
return qualifiedTypedefNameToString(declaration,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
case Procedure():
|
||||
return qualifiedMemberNameToString(declaration,
|
||||
includeLibraryName: includeLibraryName) +
|
||||
'.' +
|
||||
typeParameterNameToString(node);
|
||||
case LocalFunction():
|
||||
case null:
|
||||
return typeParameterNameToString(node);
|
||||
}
|
||||
return typeParameterNameToString(node);
|
||||
}
|
||||
|
||||
String typeParameterNameToString(TypeParameter node) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import '../ast.dart';
|
|||
import '../import_table.dart';
|
||||
import '../src/text_util.dart';
|
||||
|
||||
abstract class Namer<T> {
|
||||
abstract mixin class Namer<T> {
|
||||
int index = 0;
|
||||
final Map<T, String> map = <T, String>{};
|
||||
|
||||
|
@ -143,18 +143,24 @@ String debugTypeParameterName(TypeParameter node) {
|
|||
}
|
||||
|
||||
String debugQualifiedTypeParameterName(TypeParameter node) {
|
||||
TreeNode? parent = node.parent;
|
||||
if (parent is Class) {
|
||||
return debugQualifiedClassName(parent) +
|
||||
'::' +
|
||||
debugTypeParameterName(node);
|
||||
GenericDeclaration? declaration = node.declaration;
|
||||
switch (declaration) {
|
||||
case Class():
|
||||
return debugQualifiedClassName(declaration) +
|
||||
'::' +
|
||||
debugTypeParameterName(node);
|
||||
case Procedure():
|
||||
return debugQualifiedMemberName(declaration) +
|
||||
'::' +
|
||||
debugTypeParameterName(node);
|
||||
case Typedef():
|
||||
case Extension():
|
||||
case ExtensionTypeDeclaration():
|
||||
// TODO(johnniwinther): Support these cases directly?
|
||||
case LocalFunction():
|
||||
case null:
|
||||
return debugTypeParameterName(node);
|
||||
}
|
||||
if (parent is Member) {
|
||||
return debugQualifiedMemberName(parent) +
|
||||
'::' +
|
||||
debugTypeParameterName(node);
|
||||
}
|
||||
return debugTypeParameterName(node);
|
||||
}
|
||||
|
||||
String debugVariableDeclarationName(VariableDeclaration node) {
|
||||
|
@ -396,15 +402,21 @@ class Printer extends Visitor<void> with VisitorVoidMixin {
|
|||
|
||||
String getTypeParameterReference(TypeParameter node) {
|
||||
String name = getTypeParameterName(node);
|
||||
TreeNode? parent = node.parent;
|
||||
if (parent is FunctionNode && parent.parent is Member) {
|
||||
String member = getMemberReference(parent.parent as Member);
|
||||
return '$member::$name';
|
||||
} else if (parent is Class) {
|
||||
String className = getClassReference(parent);
|
||||
return '$className::$name';
|
||||
} else {
|
||||
return name; // Bound inside a function type.
|
||||
GenericDeclaration? declaration = node.declaration;
|
||||
switch (declaration) {
|
||||
case Class():
|
||||
String className = getClassReference(declaration);
|
||||
return '$className::$name';
|
||||
case Procedure():
|
||||
String member = getMemberReference(declaration);
|
||||
return '$member::$name';
|
||||
case Typedef():
|
||||
case Extension():
|
||||
case ExtensionTypeDeclaration():
|
||||
case LocalFunction():
|
||||
// TODO(johnniwinther): Support these cases correctly.
|
||||
case null:
|
||||
return name; // Bound inside a function type.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
/// Indentation utility class. Should be used as a mixin in most cases.
|
||||
class Indentation {
|
||||
mixin class Indentation {
|
||||
/// The current indentation string.
|
||||
String get indentation {
|
||||
// Lazily add new indentation strings as required.
|
||||
|
@ -50,7 +50,7 @@ class Indentation {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class Tagging<N> implements Indentation {
|
||||
abstract mixin class Tagging<N> implements Indentation {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
List<String> tagStack = [];
|
||||
|
||||
|
|
|
@ -463,7 +463,7 @@ class _ClassBottomSubstitution extends Substitution {
|
|||
|
||||
@override
|
||||
DartType? getSubstitute(TypeParameter parameter, bool upperBound) {
|
||||
if (parameter.parent == class_) {
|
||||
if (parameter.declaration == class_) {
|
||||
return upperBound ? const NeverType.nonNullable() : const DynamicType();
|
||||
}
|
||||
return null;
|
||||
|
@ -1044,7 +1044,8 @@ class _FreeFunctionTypeVariableVisitor implements DartTypeVisitor<bool> {
|
|||
|
||||
@override
|
||||
bool visitTypeParameterType(TypeParameterType node) {
|
||||
return node.parameter.parent == null && !variables.contains(node.parameter);
|
||||
return node.parameter.declaration == null &&
|
||||
!variables.contains(node.parameter);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -747,7 +747,7 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
|
|||
void visitFunctionType(FunctionType node) {
|
||||
if (node.typeParameters.isNotEmpty) {
|
||||
for (TypeParameter typeParameter in node.typeParameters) {
|
||||
if (typeParameter.parent != null) {
|
||||
if (typeParameter.declaration != null) {
|
||||
problem(
|
||||
localContext,
|
||||
"Type parameters of function types shouldn't have parents: "
|
||||
|
@ -1188,20 +1188,18 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
|
|||
@override
|
||||
void visitTypeParameterType(TypeParameterType node) {
|
||||
TypeParameter parameter = node.parameter;
|
||||
GenericDeclaration? declaration = parameter.declaration;
|
||||
if (!typeParametersInScope.contains(parameter)) {
|
||||
TreeNode? owner = parameter.parent is FunctionNode
|
||||
? parameter.parent!.parent
|
||||
: parameter.parent;
|
||||
problem(
|
||||
currentParent,
|
||||
"Type parameter '$parameter' referenced out of"
|
||||
" scope, owner is: '${owner}'.");
|
||||
" scope, declaration is: '${declaration}'.");
|
||||
}
|
||||
if (parameter.parent is Class && !classTypeParametersAreInScope) {
|
||||
if (declaration is Class && !classTypeParametersAreInScope) {
|
||||
problem(
|
||||
currentParent,
|
||||
"Type parameter '$parameter' referenced from"
|
||||
" static context, parent is: '${parameter.parent}'.");
|
||||
" static context, declaration is: '${parameter.declaration}'.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ name: kernel
|
|||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: '>=2.19.0 <3.0.0'
|
||||
sdk: ^3.0.0
|
||||
|
||||
# Use 'any' constraints here; we get our versions from the DEPS file.
|
||||
dev_dependencies:
|
||||
|
|
|
@ -144,7 +144,7 @@ void main() {
|
|||
},
|
||||
(Node? node, Node? parent) =>
|
||||
"${errorPrefix}Type parameter '$node' referenced out of scope,"
|
||||
" owner is: '$parent'.",
|
||||
" declaration is: '$parent'.",
|
||||
);
|
||||
negative2Test(
|
||||
'Class type parameter from another class',
|
||||
|
@ -156,7 +156,7 @@ void main() {
|
|||
},
|
||||
(Node? node, Node? parent) =>
|
||||
"${errorPrefix}Type parameter '$node' referenced out of scope,"
|
||||
" owner is: '$parent'.",
|
||||
" declaration is: '$parent'.",
|
||||
);
|
||||
negative2Test(
|
||||
'Class type parameter in static method',
|
||||
|
@ -175,7 +175,7 @@ void main() {
|
|||
},
|
||||
(Node? node, Node? parent) =>
|
||||
"${errorPrefix}Type parameter '$node' referenced from static context,"
|
||||
" parent is: '$parent'.",
|
||||
" declaration is: '$parent'.",
|
||||
);
|
||||
negative2Test(
|
||||
'Class type parameter in static field',
|
||||
|
@ -191,7 +191,7 @@ void main() {
|
|||
},
|
||||
(Node? node, Node? parent) =>
|
||||
"${errorPrefix}Type parameter '$node' referenced from static context,"
|
||||
" parent is: '$parent'.",
|
||||
" declaration is: '$parent'.",
|
||||
);
|
||||
negative2Test(
|
||||
'Method type parameter out of scope',
|
||||
|
@ -221,7 +221,7 @@ void main() {
|
|||
},
|
||||
(Node? node, Node? parent) =>
|
||||
"${errorPrefix}Type parameter '$node' referenced out of scope,"
|
||||
" owner is: '${(parent as TreeNode).parent}'.",
|
||||
" declaration is: '${(parent as TreeNode).parent}'.",
|
||||
);
|
||||
negative1Test(
|
||||
'Interface type arity too low',
|
||||
|
@ -745,7 +745,7 @@ void main() {
|
|||
return foo;
|
||||
},
|
||||
(Node? foo) => "${errorPrefix}"
|
||||
"Unset bound on type parameter TypeParameter(T)",
|
||||
"Unset bound on type parameter TypeParameter(Foo.T)",
|
||||
);
|
||||
negative1Test(
|
||||
'Unset default type typedef Foo<T> = dynamic',
|
||||
|
@ -759,7 +759,7 @@ void main() {
|
|||
return foo;
|
||||
},
|
||||
(Node? foo) => "${errorPrefix}"
|
||||
"Unset default type on type parameter TypeParameter(T)",
|
||||
"Unset default type on type parameter TypeParameter(Foo.T)",
|
||||
);
|
||||
negative1Test(
|
||||
'Non-static top-level field',
|
||||
|
|
|
@ -2657,8 +2657,8 @@ class RuntimeTypeTranslatorImpl extends DartTypeVisitor<TypeExpr>
|
|||
return result;
|
||||
}
|
||||
}
|
||||
if (type.parameter.parent is! Class) return unknownType;
|
||||
final interfaceClass = type.parameter.parent as Class;
|
||||
final interfaceClass = type.parameter.declaration;
|
||||
if (interfaceClass is! Class) return unknownType;
|
||||
// Undetermined nullability is equivalent to nonNullable when
|
||||
// instantiating type parameter, so convert it right away.
|
||||
Nullability nullability = type.nullability;
|
||||
|
|
|
@ -1033,9 +1033,9 @@ class _TreeShakerTypeVisitor extends RecursiveVisitor {
|
|||
|
||||
@override
|
||||
visitTypeParameterType(TypeParameterType node) {
|
||||
final parent = node.parameter.parent;
|
||||
if (parent is Class) {
|
||||
shaker.addClassUsedInType(parent);
|
||||
final declaration = node.parameter.declaration;
|
||||
if (declaration is Class) {
|
||||
shaker.addClassUsedInType(declaration);
|
||||
}
|
||||
node.visitChildren(this);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue