44
55import 'package:kernel/ast.dart' ;
66import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
7+ import 'package:kernel/core_types.dart' show CoreTypes;
78import 'package:kernel/library_index.dart' show LibraryIndex;
89import 'package:yaml/yaml.dart' ;
910import '../source/source_loader.dart' show SourceLoader;
@@ -28,15 +29,18 @@ void validateDynamicModule(
2829 String dynamicInterfaceSpecification,
2930 Uri dynamicInterfaceSpecificationUri,
3031 Component component,
32+ CoreTypes coreTypes,
3133 ClassHierarchy hierarchy,
3234 List <Library > libraries,
3335 SourceLoader loader) {
3436 final DynamicInterfaceSpecification spec = new DynamicInterfaceSpecification (
3537 dynamicInterfaceSpecification,
3638 dynamicInterfaceSpecificationUri,
3739 component);
40+ final DynamicInterfaceLanguageImplPragmas languageImplPragmas =
41+ new DynamicInterfaceLanguageImplPragmas (coreTypes);
3842 final _DynamicModuleValidator validator = new _DynamicModuleValidator (
39- spec, new Set .of (libraries), hierarchy, loader);
43+ spec, languageImplPragmas, new Set .of (libraries), hierarchy, loader);
4044 for (Library library in libraries) {
4145 library.accept (validator);
4246 }
@@ -183,17 +187,73 @@ class DynamicInterfaceSpecification {
183187 }
184188}
185189
190+ /// Recognizes dyn-module:language-impl:* pragmas which can be used
191+ /// to annotate classes and members in core libraries to include
192+ /// them to the dynamic interface automatically.
193+ class DynamicInterfaceLanguageImplPragmas {
194+ static const String extendablePragmaName =
195+ "dyn-module:language-impl:extendable" ;
196+ static const String canBeOverriddenPragmaName =
197+ "dyn-module:language-impl:can-be-overridden" ;
198+ static const String callablePragmaName = "dyn-module:language-impl:callable" ;
199+
200+ final CoreTypes coreTypes;
201+ DynamicInterfaceLanguageImplPragmas (this .coreTypes);
202+
203+ bool isPlatformLibrary (Library library) => library.importUri.isScheme ('dart' );
204+
205+ bool isExtendable (Class node) =>
206+ isPlatformLibrary (node.enclosingLibrary) &&
207+ // Coverage-ignore(suite): Not run.
208+ isAnnotatedWith (node, extendablePragmaName);
209+
210+ bool canBeOverridden (Member node) =>
211+ isPlatformLibrary (node.enclosingLibrary) &&
212+ // Coverage-ignore(suite): Not run.
213+ isAnnotatedWith (node, canBeOverriddenPragmaName);
214+
215+ bool isCallable (TreeNode node) => switch (node) {
216+ Member () => isPlatformLibrary (node.enclosingLibrary) &&
217+ // Coverage-ignore(suite): Not run.
218+ (isAnnotatedWith (node, callablePragmaName) ||
219+ (! node.name.isPrivate &&
220+ node.enclosingClass != null &&
221+ isAnnotatedWith (node.enclosingClass! , callablePragmaName))),
222+ Class () => isPlatformLibrary (node.enclosingLibrary) &&
223+ isAnnotatedWith (node, callablePragmaName),
224+ _ => // Coverage-ignore(suite): Not run.
225+ throw 'Unexpected node ${node .runtimeType } $node '
226+ };
227+
228+ bool isAnnotatedWith (Annotatable node, String pragmaName) {
229+ for (Expression annotation in node.annotations) {
230+ if (annotation case ConstantExpression (: var constant)) {
231+ if (constant case InstanceConstant (: var classNode, : var fieldValues)
232+ when classNode == coreTypes.pragmaClass) {
233+ // Coverage-ignore-block(suite): Not run.
234+ if (fieldValues[coreTypes.pragmaName.fieldReference]
235+ case StringConstant (: var value) when value == pragmaName) {
236+ return true ;
237+ }
238+ }
239+ }
240+ }
241+ return false ;
242+ }
243+ }
244+
186245class _DynamicModuleValidator extends RecursiveVisitor {
187246 final DynamicInterfaceSpecification spec;
247+ final DynamicInterfaceLanguageImplPragmas languageImplPragmas;
188248 final Set <Library > moduleLibraries;
189249 final ClassHierarchy hierarchy;
190250 final SourceLoader loader;
191251 final Set <Constant > _visitedConstants = new Set <Constant >.identity ();
192252
193253 TreeNode ? _enclosingTreeNode;
194254
195- _DynamicModuleValidator (
196- this .spec, this . moduleLibraries, this .hierarchy, this .loader) {
255+ _DynamicModuleValidator (this .spec, this .languageImplPragmas,
256+ this .moduleLibraries, this .hierarchy, this .loader) {
197257 _addLibraryExports (spec.callable);
198258 _addLibraryExports (spec.extendable);
199259 _addLibraryExports (spec.canBeOverridden);
@@ -493,7 +553,9 @@ class _DynamicModuleValidator extends RecursiveVisitor {
493553 if (target is Procedure ) {
494554 target = _unwrapMixinStubs (target);
495555 }
496- if (! _isFromDynamicModule (target) && ! _isSpecified (target, spec.callable)) {
556+ if (! _isFromDynamicModule (target) &&
557+ ! _isSpecified (target, spec.callable) &&
558+ ! languageImplPragmas.isCallable (target)) {
497559 switch (target) {
498560 case Constructor ():
499561 String name = target.enclosingClass.name;
@@ -534,7 +596,8 @@ class _DynamicModuleValidator extends RecursiveVisitor {
534596 void _verifyExtendable (Supertype base , Class node) {
535597 final Class baseClass = base .classNode;
536598 if (! _isFromDynamicModule (baseClass) &&
537- ! _isSpecified (baseClass, spec.extendable)) {
599+ ! _isSpecified (baseClass, spec.extendable) &&
600+ ! languageImplPragmas.isExtendable (baseClass)) {
538601 loader.addProblem (
539602 templateClassShouldBeListedAsExtendableInDynamicInterface
540603 .withArguments (baseClass.name),
@@ -578,7 +641,8 @@ class _DynamicModuleValidator extends RecursiveVisitor {
578641
579642 void _verifyOverride (Member ownMember, Member superMember) {
580643 if (! _isFromDynamicModule (superMember) &&
581- ! _isSpecified (superMember, spec.canBeOverridden)) {
644+ ! _isSpecified (superMember, spec.canBeOverridden) &&
645+ ! languageImplPragmas.canBeOverridden (superMember)) {
582646 loader.addProblem (
583647 templateMemberShouldBeListedAsCanBeOverriddenInDynamicInterface
584648 .withArguments (
0 commit comments