[cfe] Initial support for view methods

TEST=pkg/front_end/testcases/views/procedures.dart

Change-Id: I62c26183d8160a3841b74381a256d0a4b5bb9365
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272624
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2022-12-01 09:54:40 +00:00 committed by Commit Queue
parent b7aa26710a
commit 5994c04ef4
23 changed files with 263 additions and 57 deletions

View file

@ -194,6 +194,29 @@ abstract class Builder {
///
bool get isExtensionInstanceMember;
/// Returns `true` if this builder is an instance member of an extension
/// declaration.
///
/// For instance `method3a` in:
///
/// class A {
/// A.constructor(); // Not a view instance member.
/// method1a() {} // Not a view instance member.
/// static method1b() {} // Not a view instance member.
/// }
/// mixin B {
/// method2a() {} // Not a view instance member.
/// static method2b() {} // Not a view instance member.
/// }
/// view C {
/// final A it;
/// A(this.is); // Not a view instance member.
/// method3a() {}
/// static method3b() {} // Not a view instance member.
/// }
///
bool get isViewInstanceMember;
bool get isLocal;
bool get isPatch;
@ -276,6 +299,9 @@ abstract class BuilderImpl implements Builder {
@override
bool get isExtensionInstanceMember => false;
@override
bool get isViewInstanceMember => false;
@override
bool get isLocal => false;

View file

@ -32,6 +32,8 @@ class NameScheme {
bool get isExtensionMember => containerType == ContainerType.Extension;
bool get isViewMember => containerType == ContainerType.View;
MemberName getFieldMemberName(FieldNameType fieldNameType, String name,
{required bool isSynthesized}) {
bool hasSynthesizedName;
@ -118,31 +120,34 @@ class NameScheme {
required bool isStatic,
required ProcedureKind kind,
required String name}) {
if (containerType == ContainerType.Extension) {
String extensionName = containerName!.name;
String kindInfix = '';
if (!isStatic) {
// Instance getter and setter are converted to methods so we use an
// infix to make their names unique.
switch (kind) {
case ProcedureKind.Getter:
kindInfix = 'get#';
break;
case ProcedureKind.Setter:
kindInfix = 'set#';
break;
case ProcedureKind.Method:
case ProcedureKind.Operator:
kindInfix = '';
break;
case ProcedureKind.Factory:
throw new UnsupportedError(
'Unexpected extension method kind ${kind}');
switch (containerType) {
case ContainerType.Extension:
case ContainerType.View:
String extensionName = containerName!.name;
String kindInfix = '';
if (!isStatic) {
// Instance getter and setter are converted to methods so we use an
// infix to make their names unique.
switch (kind) {
case ProcedureKind.Getter:
kindInfix = 'get#';
break;
case ProcedureKind.Setter:
kindInfix = 'set#';
break;
case ProcedureKind.Method:
case ProcedureKind.Operator:
kindInfix = '';
break;
case ProcedureKind.Factory:
throw new UnsupportedError(
'Unexpected extension method kind ${kind}');
}
}
}
return '${extensionName}|${kindInfix}${name}';
} else {
return name;
return '${extensionName}|${kindInfix}${name}';
case ContainerType.Library:
case ContainerType.Class:
return name;
}
}

View file

@ -390,8 +390,6 @@ class SourceEnumBuilder extends SourceClassBuilder {
containerName: new ClassName(name),
containerType: ContainerType.Class,
libraryName: new LibraryName(coreLibrary.library.reference)),
isExtensionMember: false,
isInstanceMember: true,
isSynthetic: true);
members["_enumToString"] = toStringBuilder;
String className = name;

View file

@ -122,6 +122,12 @@ class SourceExtensionBuilder extends ExtensionBuilderImpl
case BuiltMemberKind.RedirectingFactory:
case BuiltMemberKind.Field:
case BuiltMemberKind.Method:
case BuiltMemberKind.ViewMethod:
case BuiltMemberKind.ViewGetter:
case BuiltMemberKind.ViewSetter:
case BuiltMemberKind.ViewOperator:
case BuiltMemberKind.ViewTearOff:
case BuiltMemberKind.ViewFactory:
unhandled("${member.runtimeType}:${memberKind}", "buildMembers",
memberBuilder.charOffset, memberBuilder.fileUri);
case BuiltMemberKind.ExtensionField:

View file

@ -2859,8 +2859,6 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
tearOffReference,
asyncModifier,
nameScheme,
isExtensionMember: isExtensionMember,
isInstanceMember: isInstanceMember,
nativeMethodName: nativeMethodName);
checkTypeVariables(typeVariables, procedureBuilder);
addBuilder(name, procedureBuilder, charOffset,

View file

@ -1325,9 +1325,7 @@ severity: $severity
containerName: null,
containerType: ContainerType.Library,
isInstanceMember: false,
libraryName: libraryBuilder.libraryName),
isInstanceMember: false,
isExtensionMember: false)
libraryName: libraryBuilder.libraryName))
..parent = parent;
BodyBuilder listener = dietListener.createListener(
builder, dietListener.memberScope,

View file

@ -178,6 +178,12 @@ enum BuiltMemberKind {
ExtensionSetter,
ExtensionOperator,
ExtensionTearOff,
ViewMethod,
ViewGetter,
ViewSetter,
ViewOperator,
ViewTearOff,
ViewFactory,
LateIsSetField,
LateGetter,
LateSetter,

View file

@ -7,7 +7,6 @@ import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart';
import '../builder/builder.dart';
import '../builder/extension_builder.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/member_builder.dart';
import '../builder/metadata_builder.dart';
@ -22,9 +21,12 @@ import '../kernel/member_covariance.dart';
import '../source/name_scheme.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
import '../source/source_loader.dart' show SourceLoader;
import 'source_builder_mixins.dart';
import 'source_class_builder.dart';
import 'source_extension_builder.dart';
import 'source_function_builder.dart';
import 'source_member_builder.dart';
import 'source_view_builder.dart';
class SourceProcedureBuilder extends SourceFunctionBuilderImpl
implements ProcedureBuilder {
@ -35,6 +37,9 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
@override
final bool isExtensionInstanceMember;
@override
final bool isViewInstanceMember;
@override
final TypeBuilder returnType;
@ -85,21 +90,20 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
this._tearOffReference,
AsyncMarker asyncModifier,
NameScheme nameScheme,
{required bool isExtensionMember,
required bool isInstanceMember,
String? nativeMethodName,
{String? nativeMethodName,
bool isSynthetic = false})
// ignore: unnecessary_null_comparison
: assert(isExtensionMember != null),
// ignore: unnecessary_null_comparison
assert(isInstanceMember != null),
assert(kind != ProcedureKind.Factory),
this.isExtensionInstanceMember = isInstanceMember && isExtensionMember,
: assert(kind != ProcedureKind.Factory),
this.isExtensionInstanceMember =
nameScheme.isInstanceMember && nameScheme.isExtensionMember,
this.isViewInstanceMember =
nameScheme.isInstanceMember && nameScheme.isViewMember,
super(metadata, modifiers, name, typeVariables, formals, libraryBuilder,
charOffset, nativeMethodName) {
_procedure = new Procedure(
dummyName,
isExtensionInstanceMember ? ProcedureKind.Method : kind,
isExtensionInstanceMember || isViewInstanceMember
? ProcedureKind.Method
: kind,
new FunctionNode(null),
fileUri: libraryBuilder.fileUri,
reference: procedureReference,
@ -110,7 +114,10 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
..isNonNullableByDefault = libraryBuilder.isNonNullableByDefault;
nameScheme.getProcedureMemberName(kind, name).attachMember(_procedure);
this.asyncModifier = asyncModifier;
if (isExtensionMember && isInstanceMember && kind == ProcedureKind.Method) {
if ((isExtensionInstanceMember
// TODO(johnniwinther): Support view tear offs.
/* || isViewInstanceMember*/) &&
kind == ProcedureKind.Method) {
_extensionTearOff = new Procedure(
dummyName, ProcedureKind.Method, new FunctionNode(null),
isStatic: true,
@ -144,7 +151,11 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
}
bool get isExtensionMethod {
return parent is ExtensionBuilder;
return parent is SourceExtensionBuilder;
}
bool get isViewMethod {
return parent is SourceViewBuilder;
}
@override
@ -266,6 +277,27 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
if (extensionTearOff != null) {
f(extensionTearOff!, BuiltMemberKind.ExtensionTearOff);
}
} else if (isViewMethod) {
switch (kind) {
case ProcedureKind.Method:
f(_procedure, BuiltMemberKind.ViewMethod);
break;
case ProcedureKind.Getter:
f(_procedure, BuiltMemberKind.ViewGetter);
break;
case ProcedureKind.Setter:
f(_procedure, BuiltMemberKind.ViewSetter);
break;
case ProcedureKind.Operator:
f(_procedure, BuiltMemberKind.ViewOperator);
break;
case ProcedureKind.Factory:
f(_procedure, BuiltMemberKind.ViewFactory);
break;
}
if (extensionTearOff != null) {
f(extensionTearOff!, BuiltMemberKind.ViewTearOff);
}
} else {
f(member, BuiltMemberKind.Method);
}
@ -284,11 +316,18 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
if (isExtensionInstanceMember) {
assert(_procedure.kind == ProcedureKind.Method);
}
} else if (isViewMethod) {
_procedure.isViewMember = true;
_procedure.isStatic = true;
if (isViewInstanceMember) {
assert(_procedure.kind == ProcedureKind.Method);
}
} else {
_procedure.isStatic = isStatic;
}
if (extensionTearOff != null) {
_buildExtensionTearOff(libraryBuilder, parent as ExtensionBuilder);
_buildExtensionTearOff(
libraryBuilder, parent as SourceDeclarationBuilderMixin);
}
}
@ -312,7 +351,7 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
/// }
///
void _buildExtensionTearOff(SourceLibraryBuilder sourceLibraryBuilder,
ExtensionBuilder extensionBuilder) {
SourceDeclarationBuilderMixin declarationBuilder) {
assert(
_extensionTearOff != null, "No extension tear off created for $this.");
@ -322,7 +361,7 @@ class SourceProcedureBuilder extends SourceFunctionBuilderImpl
int fileEndOffset = _procedure.fileEndOffset;
int extensionTypeParameterCount =
extensionBuilder.typeParameters?.length ?? 0;
declarationBuilder.typeParameters?.length ?? 0;
List<TypeParameter> typeParameters = <TypeParameter>[];

View file

@ -114,29 +114,37 @@ class SourceViewBuilder extends ViewBuilderImpl
case BuiltMemberKind.RedirectingFactory:
case BuiltMemberKind.Field:
case BuiltMemberKind.Method:
case BuiltMemberKind.ExtensionMethod:
case BuiltMemberKind.ExtensionGetter:
case BuiltMemberKind.ExtensionSetter:
case BuiltMemberKind.ExtensionOperator:
case BuiltMemberKind.ExtensionTearOff:
unhandled("${member.runtimeType}:${memberKind}", "buildMembers",
memberBuilder.charOffset, memberBuilder.fileUri);
case BuiltMemberKind.ExtensionField:
case BuiltMemberKind.LateIsSetField:
kind = ViewMemberKind.Field;
break;
case BuiltMemberKind.ExtensionMethod:
case BuiltMemberKind.ViewMethod:
kind = ViewMemberKind.Method;
break;
case BuiltMemberKind.ExtensionGetter:
case BuiltMemberKind.ViewGetter:
case BuiltMemberKind.LateGetter:
kind = ViewMemberKind.Getter;
break;
case BuiltMemberKind.ExtensionSetter:
case BuiltMemberKind.ViewSetter:
case BuiltMemberKind.LateSetter:
kind = ViewMemberKind.Setter;
break;
case BuiltMemberKind.ExtensionOperator:
case BuiltMemberKind.ViewOperator:
kind = ViewMemberKind.Operator;
break;
case BuiltMemberKind.ExtensionTearOff:
case BuiltMemberKind.ViewTearOff:
kind = ViewMemberKind.TearOff;
break;
case BuiltMemberKind.ViewFactory:
kind = ViewMemberKind.Factory;
break;
}
// ignore: unnecessary_null_comparison
assert(kind != null);

View file

@ -214,5 +214,6 @@ variance/class_type_parameter_modifier: FormatterCrash
variance/generic_covariance_sound_variance: FormatterCrash
variance/mixin_type_parameter_modifier: FormatterCrash
variance/unconstrained_inference: FormatterCrash
views/procedures: FormatterCrash
views/representation: FormatterCrash
views/view_class_declaration: FormatterCrash

View file

@ -0,0 +1,10 @@
// Copyright (c) 2022, 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.
view class Class {
final int it;
void instanceMethod() {}
static void staticMethod() {}
}

View file

@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void {}
static method Class|staticMethod() → void {}

View file

@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void {}
static method Class|staticMethod() → void {}

View file

@ -0,0 +1,6 @@
view
class Class {
final int it;
void instanceMethod() {}
static void staticMethod() {}
}

View file

@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void {}
static method Class|staticMethod() → void {}

View file

@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void {}
static method Class|staticMethod() → void {}

View file

@ -0,0 +1,12 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void
;
static method Class|staticMethod() → void
;

View file

@ -0,0 +1,10 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
view Class /* representationType = core::int */ {
method instanceMethod = self::Class|instanceMethod;
static method staticMethod = self::Class|staticMethod;
}
static method Class|instanceMethod() → void {}
static method Class|staticMethod() → void {}

View file

@ -147,7 +147,7 @@ type CanonicalName {
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
UInt32 formatVersion = 89;
UInt32 formatVersion = 90;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
@ -411,7 +411,7 @@ type Field extends Member {
UInt flags (isFinal, isConst, isStatic, isCovariantByDeclaration,
isCovariantByClass, isLate, isExtensionMember,
isNonNullableByDefault, isInternalImplementation,
isEnumElement);
isEnumElement, isViewMember);
Name name;
List<Expression> annotations;
DartType type;
@ -466,7 +466,8 @@ type Procedure extends Member {
Byte stubKind; // Index into the ProcedureStubKind enum above.
UInt flags (isStatic, isAbstract, isExternal, isConst,
isRedirectingFactory, isExtensionMember,
isNonNullableByDefault, isSynthetic, isInternalImplementation);
isNonNullableByDefault, isSynthetic, isInternalImplementation,
isViewMember);
Name name;
List<Expression> annotations;
MemberReference stubTarget; // May be NullReference.

View file

@ -2239,6 +2239,21 @@ abstract class Member extends NamedNode implements Annotatable, FileUriNode {
///
bool get isExtensionMember;
/// If `true` this member is compiled from a member declared in a view class
/// declaration.
///
/// For instance `field`, `method1` and `method2` in:
///
/// view class A {
/// final B it;
/// A(this.it);
/// static var field;
/// B method1() => this;
/// static B method2() => new B();
/// }
///
bool get isViewMember;
/// If `true` this member is defined in a library for which non-nullable by
/// default is enabled.
bool get isNonNullableByDefault;
@ -2474,6 +2489,7 @@ class Field extends Member {
static const int FlagNonNullableByDefault = 1 << 7;
static const int FlagInternalImplementation = 1 << 8;
static const int FlagEnumElement = 1 << 9;
static const int FlagViewMember = 1 << 10;
/// Whether the field is declared with the `covariant` keyword.
bool get isCovariantByDeclaration => flags & FlagCovariant != 0;
@ -2488,6 +2504,9 @@ class Field extends Member {
@override
bool get isExtensionMember => flags & FlagExtensionMember != 0;
@override
bool get isViewMember => flags & FlagViewMember != 0;
/// Indicates whether the implicit setter associated with this field needs to
/// contain a runtime type check to deal with generic covariance.
///
@ -2559,6 +2578,10 @@ class Field extends Member {
flags = value ? (flags | FlagEnumElement) : (flags & ~FlagEnumElement);
}
void set isViewMember(bool value) {
flags = value ? (flags | FlagViewMember) : (flags & ~FlagViewMember);
}
@override
bool get isInstanceMember => !isStatic;
@ -2735,6 +2758,9 @@ class Constructor extends Member {
@override
bool get isExtensionMember => false;
@override
bool get isViewMember => false;
@override
bool get isNonNullableByDefault => flags & FlagNonNullableByDefault != 0;
@ -2898,6 +2924,9 @@ class RedirectingFactory extends Member {
@override
bool get isExtensionMember => false;
@override
bool get isViewMember => false;
bool get isUnresolved => targetReference == null;
@override
@ -3313,6 +3342,7 @@ class Procedure extends Member {
static const int FlagSynthetic = 1 << 7;
static const int FlagInternalImplementation = 1 << 8;
static const int FlagIsAbstractFieldAccessor = 1 << 9;
static const int FlagViewMember = 1 << 10;
bool get isStatic => flags & FlagStatic != 0;
@ -3392,6 +3422,9 @@ class Procedure extends Member {
@override
bool get isExtensionMember => flags & FlagExtensionMember != 0;
@override
bool get isViewMember => flags & FlagViewMember != 0;
void set isStatic(bool value) {
flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
}
@ -3420,6 +3453,10 @@ class Procedure extends Member {
value ? (flags | FlagExtensionMember) : (flags & ~FlagExtensionMember);
}
void set isViewMember(bool value) {
flags = value ? (flags | FlagViewMember) : (flags & ~FlagViewMember);
}
void set isSynthetic(bool value) {
flags = value ? (flags | FlagSynthetic) : (flags & ~FlagSynthetic);
}

View file

@ -195,7 +195,7 @@ class Tag {
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
static const int BinaryFormatVersion = 89;
static const int BinaryFormatVersion = 90;
}
abstract class ConstantTag {

View file

@ -495,6 +495,7 @@ class FieldHelper {
kNonNullableByDefault = 1 << 7,
kInternalImplementation = 1 << 8,
kEnumElement = 1 << 9,
kViewMember = 1 << 10,
};
explicit FieldHelper(KernelReaderHelper* helper)
@ -520,6 +521,7 @@ class FieldHelper {
}
bool IsLate() const { return (flags_ & kIsLate) != 0; }
bool IsExtensionMember() const { return (flags_ & kExtensionMember) != 0; }
bool IsViewMember() const { return (flags_ & kViewMember) != 0; }
NameIndex canonical_name_field_;
NameIndex canonical_name_getter_;
@ -593,6 +595,8 @@ class ProcedureHelper {
kExtensionMember = 1 << 5,
kSyntheticProcedure = 1 << 7,
kInternalImplementation = 1 << 8,
kIsAbstractFieldAccessor = 1 << 9,
kViewMember = 1 << 10,
};
explicit ProcedureHelper(KernelReaderHelper* helper)
@ -626,6 +630,7 @@ class ProcedureHelper {
return stub_kind_ == kNoSuchMethodForwarderStubKind;
}
bool IsExtensionMember() const { return (flags_ & kExtensionMember) != 0; }
bool IsViewMember() const { return (flags_ & kViewMember) != 0; }
bool IsMemberSignature() const {
return stub_kind_ == kMemberSignatureStubKind;
}

View file

@ -18,7 +18,7 @@ namespace kernel {
// package:kernel/binary.md.
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
static const uint32_t kSupportedKernelFormatVersion = 89;
static const uint32_t kSupportedKernelFormatVersion = 90;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \