| // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:typed_data'; |
| |
| import 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'; |
| import 'package:analyzer/dart/analysis/features.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/field_name_non_promotability_info.dart'; |
| import 'package:analyzer/src/dart/element/member.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/type_algebra.dart'; |
| import 'package:analyzer/src/error/inference_error.dart'; |
| import 'package:analyzer/src/summary2/ast_binary_tag.dart'; |
| import 'package:analyzer/src/summary2/ast_binary_writer.dart'; |
| import 'package:analyzer/src/summary2/data_writer.dart'; |
| import 'package:analyzer/src/summary2/export.dart'; |
| import 'package:analyzer/src/summary2/reference.dart'; |
| |
| class BundleWriter { |
| late final _BundleWriterReferences _references; |
| |
| /// The declaration sink - any data that can be read without a need to |
| /// have any other elements to be available. For example declarations of |
| /// classes, methods, functions, etc. But not supertypes of classes, or |
| /// return types of methods - these might reference other classes that we |
| /// have not read yet. Such resolution data is stored into [_resolutionSink]. |
| /// |
| /// Some resolution data is still written into this sink, if it does not |
| /// require any other declaration read it later. For example type inference |
| /// errors, or whether a parameter inherits `covariant`, or a class is |
| /// simply bounded. |
| late _SummaryDataWriter _sink = _SummaryDataWriter( |
| stringIndexer: _stringIndexer, |
| ); |
| |
| /// The resolution sink - any data that references elements, so can only |
| /// be read after elements are created and available via its [Reference]s. |
| late final ResolutionSink _resolutionSink = ResolutionSink( |
| stringIndexer: _stringIndexer, |
| references: _references, |
| ); |
| |
| /// We fill this map before writing the library. |
| /// |
| /// When we write getter / setter fragments, we write non-synthetic |
| /// fragments as full data objects. But for synthetic getter / setter |
| /// fragments we write only the ID of the non-synthetic variable fragment, |
| /// from this map. |
| /// |
| /// When we write property fragments, we write non-synthetic fragments as |
| /// full data objects. But for synthetic property fragments we write the |
| /// pair of getter / setter fragments IDs, from this map. |
| final Map<FragmentImpl, int> _fragmentIds = Map.identity(); |
| |
| final StringIndexer _stringIndexer = StringIndexer(); |
| |
| final List<_Library> _libraries = []; |
| |
| BundleWriter() { |
| _references = _BundleWriterReferences(); |
| } |
| |
| BundleWriterResult finish() { |
| var baseResolutionOffset = _sink.offset; |
| _sink.writeBytes(_resolutionSink.takeBytes()); |
| |
| var librariesOffset = _sink.offset; |
| _sink.writeList<_Library>(_libraries, (library) { |
| _sink._writeStringReference(library.uriStr); |
| _sink.writeUInt30(library.offset); |
| }); |
| |
| var referencesOffset = _sink.offset; |
| _sink.writeUint30List(_references._referenceParents); |
| _sink._writeStringList(_references._referenceNames); |
| _references._clearIndexes(); |
| |
| var stringTableOffset = _stringIndexer.write(_sink); |
| |
| // Write as Uint32 so that we know where it is. |
| _sink.writeUInt32(baseResolutionOffset); |
| _sink.writeUInt32(librariesOffset); |
| _sink.writeUInt32(referencesOffset); |
| _sink.writeUInt32(stringTableOffset); |
| |
| var bytes = _sink.takeBytes(); |
| return BundleWriterResult(resolutionBytes: bytes); |
| } |
| |
| void writeLibraryElement(LibraryElementImpl libraryElement) { |
| var libraryOffset = _sink.offset; |
| |
| // Write non-resolution data for the library. |
| _sink._writeStringReference(libraryElement.name); |
| _writeFeatureSet(libraryElement.featureSet); |
| libraryElement.writeModifiers(_sink); |
| _writeLanguageVersion(libraryElement.languageVersion); |
| _writeExportedReferences(libraryElement.exportedReferences); |
| _sink.writeUint30List(libraryElement.nameUnion.mask); |
| _writeLoadLibraryFunctionReferences(libraryElement); |
| |
| // Write the library units. |
| // This will write also resolution data, e.g. for classes. |
| _writeUnitElement(libraryElement.definingCompilationUnit); |
| |
| _writeClassElements(libraryElement.classes); |
| _writeEnumElements(libraryElement.enums); |
| _writeExtensionElements(libraryElement.extensions); |
| _writeExtensionTypeElements(libraryElement.extensionTypes); |
| _writeTopLevelFunctionElements(libraryElement.topLevelFunctions); |
| _writeMixinElements(libraryElement.mixins); |
| _writeTypeAliasElements(libraryElement.typeAliases); |
| |
| // TODO(scheglov): extract |
| _sink.writeList(libraryElement.topLevelVariables, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| _writeElementResolution(() { |
| _resolutionSink.writeType(element.type); |
| }); |
| }); |
| |
| _writeGetterElements(libraryElement.getters); |
| _writeSetterElements(libraryElement.setters); |
| _writeVariableGetterSetterLinking(libraryElement.topLevelVariables); |
| |
| // Write resolution data for the library. |
| _writeResolutionOffset(); |
| _resolutionSink._writeMetadata(libraryElement.metadata); |
| _resolutionSink.writeElement(libraryElement.entryPoint); |
| _writeFieldNameNonPromotabilityInfo( |
| libraryElement.fieldNameNonPromotabilityInfo, |
| ); |
| |
| _libraries.add( |
| _Library(uriStr: '${libraryElement.source.uri}', offset: libraryOffset), |
| ); |
| } |
| |
| void _writeClassElements(List<ClassElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| |
| // We read members lazily. |
| _writeForLazyRead(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _writeFieldElements(element.fields); |
| _writeGetterElements(element.getters); |
| _writeSetterElements(element.setters); |
| _writeVariableGetterSetterLinking(element.fields); |
| _writeMethodElements(element.methods); |
| if (!element.isMixinApplication) { |
| _writeConstructorElements(element.constructors); |
| } |
| }); |
| }); |
| |
| _writeElementResolution(() { |
| // TODO(scheglov): write any element resolution |
| }); |
| }); |
| } |
| |
| void _writeClassFragment(ClassFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink.writeType(fragment.supertype); |
| _resolutionSink._writeTypeList(fragment.mixins); |
| _resolutionSink._writeTypeList(fragment.interfaces); |
| |
| _writeForLazyRead(() { |
| _sink.writeList(fragment.fields, _writeFieldFragment); |
| _sink.writeList(fragment.getters, _writeGetterFragment); |
| _sink.writeList(fragment.setters, _writeSetterFragment); |
| _sink.writeList(fragment.methods, _writeMethodFragment); |
| if (!fragment.isMixinApplication) { |
| _sink.writeList(fragment.constructors, _writeConstructorFragment); |
| } |
| }); |
| }); |
| }); |
| } |
| |
| void _writeConstructorElements(List<ConstructorElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| |
| _writeElementResolution(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _resolutionSink.writeType(element.returnType); |
| _resolutionSink.writeElement(element.superConstructor); |
| _resolutionSink.writeElement(element.redirectedConstructor); |
| // TODO(scheglov): formal parameters |
| }); |
| }); |
| }); |
| } |
| |
| void _writeConstructorFragment(ConstructorFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _sink._writeOptionalStringReference(fragment.typeName); |
| _writeTypeParameters(fragment.typeParameters, () { |
| _sink.writeList(fragment.formalParameters, _writeParameterElement); |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink.writeList( |
| fragment.constantInitializers, |
| _resolutionSink._writeNode, |
| ); |
| }); |
| }); |
| } |
| |
| void _writeDirectiveUri(DirectiveUri element) { |
| void writeWithUriString(DirectiveUriWithRelativeUriString element) { |
| _sink._writeStringReference(element.relativeUriString); |
| } |
| |
| void writeWithRelativeUri(DirectiveUriWithRelativeUri element) { |
| writeWithUriString(element); |
| _sink._writeStringReference('${element.relativeUri}'); |
| } |
| |
| void writeWithSource(DirectiveUriWithSource element) { |
| writeWithRelativeUri(element); |
| _sink._writeStringReference('${element.source.uri}'); |
| } |
| |
| if (element is DirectiveUriWithLibrary) { |
| _sink.writeByte(DirectiveUriKind.withLibrary.index); |
| writeWithSource(element); |
| } else if (element is DirectiveUriWithUnitImpl) { |
| _sink.writeByte(DirectiveUriKind.withUnit.index); |
| writeWithSource(element); |
| _writeUnitElement(element.libraryFragment); |
| } else if (element is DirectiveUriWithSource) { |
| _sink.writeByte(DirectiveUriKind.withSource.index); |
| writeWithSource(element); |
| } else if (element is DirectiveUriWithRelativeUri) { |
| _sink.writeByte(DirectiveUriKind.withRelativeUri.index); |
| writeWithRelativeUri(element); |
| } else if (element is DirectiveUriWithRelativeUriString) { |
| _sink.writeByte(DirectiveUriKind.withRelativeUriString.index); |
| writeWithUriString(element); |
| } else { |
| _sink.writeByte(DirectiveUriKind.withNothing.index); |
| } |
| } |
| |
| void _writeElementResolution(void Function() operation) { |
| _writeResolutionOffset(); |
| operation(); |
| } |
| |
| void _writeEnumElements(List<EnumElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| |
| // TODO(scheglov): consider reading lazily |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _writeFieldElements(element.fields); |
| _writeGetterElements(element.getters); |
| _writeSetterElements(element.setters); |
| _writeVariableGetterSetterLinking(element.fields); |
| _writeConstructorElements(element.constructors); |
| _writeMethodElements(element.methods); |
| }); |
| |
| _writeElementResolution(() { |
| // TODO(scheglov): write any element resolution |
| }); |
| }); |
| } |
| |
| void _writeEnumFragment(EnumFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink.writeType(fragment.supertype); |
| _resolutionSink._writeTypeList(fragment.mixins); |
| _resolutionSink._writeTypeList(fragment.interfaces); |
| |
| // TODO(scheglov): consider reading lazily |
| _sink.writeList(fragment.fields, _writeFieldFragment); |
| _sink.writeList(fragment.getters, _writeGetterFragment); |
| _sink.writeList(fragment.setters, _writeSetterFragment); |
| _sink.writeList(fragment.constructors, _writeConstructorFragment); |
| _sink.writeList(fragment.methods, _writeMethodFragment); |
| }); |
| }); |
| } |
| |
| void _writeExportedReferences(List<ExportedReference> elements) { |
| _sink.writeList(elements, (exported) { |
| var index = _references._indexOfReference(exported.reference); |
| if (exported is ExportedReferenceDeclared) { |
| _sink.writeByte(0); |
| _sink.writeUInt30(index); |
| } else if (exported is ExportedReferenceExported) { |
| _sink.writeByte(1); |
| _sink.writeUInt30(index); |
| _sink.writeList(exported.locations, _writeExportLocation); |
| } else { |
| throw UnimplementedError('(${exported.runtimeType}) $exported'); |
| } |
| }); |
| } |
| |
| void _writeExportLocation(ExportLocation location) { |
| _sink.writeUInt30(location.fragmentIndex); |
| _sink.writeUInt30(location.exportIndex); |
| } |
| |
| void _writeExtensionElements(List<ExtensionElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| |
| // TODO(scheglov): consider reading lazily |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _writeFieldElements(element.fields); |
| _writeGetterElements(element.getters); |
| _writeSetterElements(element.setters); |
| _writeVariableGetterSetterLinking(element.fields); |
| _writeMethodElements(element.methods); |
| }); |
| |
| _writeElementResolution(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _resolutionSink.writeType(element.extendedType); |
| }); |
| }); |
| }); |
| } |
| |
| void _writeExtensionFragment(ExtensionFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _sink.writeList(fragment.fields, _writeFieldFragment); |
| _sink.writeList(fragment.getters, _writeGetterFragment); |
| _sink.writeList(fragment.setters, _writeSetterFragment); |
| _sink.writeList(fragment.methods, _writeMethodFragment); |
| }); |
| }); |
| } |
| |
| void _writeExtensionTypeElements(List<ExtensionTypeElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| |
| // TODO(scheglov): consider reading lazily |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _writeFieldElements(element.fields); |
| _writeGetterElements(element.getters); |
| _writeSetterElements(element.setters); |
| _writeVariableGetterSetterLinking(element.fields); |
| _writeConstructorElements(element.constructors); |
| _writeMethodElements(element.methods); |
| }); |
| |
| _writeElementResolution(() { |
| // TODO(scheglov): write any element resolution |
| }); |
| }); |
| } |
| |
| void _writeExtensionTypeFragment(ExtensionTypeFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| // TODO(fshcheglov): Put these separate flags into modifiers |
| _sink.writeBool(fragment.hasRepresentationSelfReference); |
| _sink.writeBool(fragment.hasImplementsSelfReference); |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink._writeTypeList(fragment.interfaces); |
| _resolutionSink.writeType(fragment.typeErasure); |
| |
| // TODO(scheglov): consider reading lazily |
| _sink.writeList(fragment.fields, _writeFieldFragment); |
| _sink.writeList(fragment.getters, _writeGetterFragment); |
| _sink.writeList(fragment.setters, _writeSetterFragment); |
| _sink.writeList(fragment.constructors, _writeConstructorFragment); |
| _sink.writeList(fragment.methods, _writeMethodFragment); |
| }); |
| }); |
| } |
| |
| void _writeFeatureSet(FeatureSet featureSet) { |
| var experimentStatus = featureSet as ExperimentStatus; |
| var encoded = experimentStatus.toStorage(); |
| _sink.writeUint8List(encoded); |
| } |
| |
| void _writeFieldElements(List<FieldElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| _writeElementResolution(() { |
| _resolutionSink.writeType(element.type); |
| }); |
| }); |
| } |
| |
| void _writeFieldFragment(FieldFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink._writeOptionalNode(fragment.constantInitializer); |
| }); |
| } |
| |
| void _writeFieldNameNonPromotabilityInfo( |
| Map<String, FieldNameNonPromotabilityInfo>? info, |
| ) { |
| _resolutionSink.writeOptionalObject(info, (info) { |
| _resolutionSink.writeMap( |
| info, |
| writeKey: (key) { |
| _resolutionSink._writeStringReference(key); |
| }, |
| writeValue: (value) { |
| _resolutionSink._writeElementList(value.conflictingFields); |
| _resolutionSink._writeElementList(value.conflictingGetters); |
| _resolutionSink._writeElementList(value.conflictingNsmClasses); |
| }, |
| ); |
| }); |
| } |
| |
| /// Support for writing data that can be read lazily. |
| /// |
| /// Resulting state of [_sink]. |
| /// - length of data to read lazily |
| /// - data to read lazily, written by [operation] |
| /// - after return new data is written here |
| void _writeForLazyRead(void Function() operation) { |
| var newSink = _sink.clone(); |
| |
| var savedSink = _sink; |
| _sink = newSink; |
| operation(); |
| _sink = savedSink; |
| |
| var bytes = newSink.takeBytes(); |
| _sink.writeUInt30(bytes.length); |
| _sink.writeBytes(bytes); |
| } |
| |
| void _writeFragmentId(FragmentImpl fragment) { |
| var id = _fragmentIds.getId(fragment); |
| _sink.writeUInt30(id); |
| } |
| |
| void _writeFragmentName(Fragment fragment) { |
| _sink._writeOptionalStringReference(fragment.name); |
| } |
| |
| void _writeFragments(List<FragmentImpl> fragments) { |
| _sink.writeList(fragments, _writeFragmentId); |
| } |
| |
| void _writeGetterElements(List<GetterElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| |
| _writeElementResolution(() { |
| _resolutionSink.writeType(element.returnType); |
| }); |
| }); |
| } |
| |
| void _writeGetterFragment(GetterFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _sink.writeList(fragment.formalParameters, _writeParameterElement); |
| _resolutionSink._writeMetadata(fragment.metadata); |
| }); |
| }); |
| } |
| |
| void _writeLanguageVersion(LibraryLanguageVersion version) { |
| _sink.writeUInt30(version.package.major); |
| _sink.writeUInt30(version.package.minor); |
| |
| var override = version.override; |
| if (override != null) { |
| _sink.writeBool(true); |
| _sink.writeUInt30(override.major); |
| _sink.writeUInt30(override.minor); |
| } else { |
| _sink.writeBool(false); |
| } |
| } |
| |
| void _writeLibraryExport(LibraryExportImpl element) { |
| _resolutionSink._writeMetadata(element.metadata); |
| _sink.writeList(element.combinators, _writeNamespaceCombinator); |
| _writeDirectiveUri(element.uri); |
| } |
| |
| void _writeLibraryImport(LibraryImportImpl element) { |
| _resolutionSink._writeMetadata(element.metadata); |
| _sink.writeBool(element.isSynthetic); |
| _sink.writeList(element.combinators, _writeNamespaceCombinator); |
| _writeLibraryImportPrefixFragment(element.prefix); |
| _writeDirectiveUri(element.uri); |
| } |
| |
| void _writeLibraryImportPrefixFragment(PrefixFragmentImpl? fragment) { |
| _sink.writeOptionalObject(fragment, (fragment) { |
| _writeFragmentName(fragment); |
| _writeReference(fragment.element.reference); |
| _sink.writeBool(fragment.isDeferred); |
| }); |
| } |
| |
| void _writeLoadLibraryFunctionReferences(LibraryElementImpl library) { |
| var element = library.loadLibraryFunction; |
| _writeReference(element.reference); |
| } |
| |
| void _writeMethodElements(List<MethodElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| _sink._writeTopLevelInferenceError(element.typeInferenceError); |
| |
| _writeElementResolution(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _resolutionSink.writeType(element.returnType); |
| // TODO(scheglov): formal parameters |
| }); |
| }); |
| }); |
| } |
| |
| void _writeMethodFragment(MethodFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _sink.writeList(fragment.formalParameters, _writeParameterElement); |
| _resolutionSink._writeMetadata(fragment.metadata); |
| }); |
| }); |
| } |
| |
| void _writeMixinElements(List<MixinElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| |
| // TODO(scheglov): consider reading lazily |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _writeFieldElements(element.fields); |
| _writeGetterElements(element.getters); |
| _writeSetterElements(element.setters); |
| _writeVariableGetterSetterLinking(element.fields); |
| _writeConstructorElements(element.constructors); |
| _writeMethodElements(element.methods); |
| }); |
| |
| _writeElementResolution(() { |
| // TODO(scheglov): write any element resolution |
| // _resolutionSink._writeTypeList(element.superclassConstraints); |
| // _resolutionSink._writeTypeList(element.interfaces); |
| }); |
| }); |
| } |
| |
| void _writeMixinFragment(MixinFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _sink._writeStringList(fragment.superInvokedNames); |
| |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink._writeTypeList(fragment.superclassConstraints); |
| _resolutionSink._writeTypeList(fragment.interfaces); |
| |
| // TODO(scheglov): consider reading lazily |
| _sink.writeList(fragment.fields, _writeFieldFragment); |
| _sink.writeList(fragment.getters, _writeGetterFragment); |
| _sink.writeList(fragment.setters, _writeSetterFragment); |
| _sink.writeList(fragment.constructors, _writeConstructorFragment); |
| _sink.writeList(fragment.methods, _writeMethodFragment); |
| }); |
| }); |
| } |
| |
| void _writeNamespaceCombinator(NamespaceCombinator combinator) { |
| switch (combinator) { |
| case HideElementCombinator(): |
| _sink.writeByte(Tag.HideCombinator); |
| _sink.writeList<String>(combinator.hiddenNames, (name) { |
| _sink._writeStringReference(name); |
| }); |
| case ShowElementCombinator(): |
| _sink.writeByte(Tag.ShowCombinator); |
| _sink.writeList<String>(combinator.shownNames, (name) { |
| _sink._writeStringReference(name); |
| }); |
| } |
| } |
| |
| void _writeOptionalReference(Reference? reference) { |
| _sink.writeOptionalObject(reference, _writeReference); |
| } |
| |
| // TODO(scheglov): Deduplicate parameter writing implementation. |
| void _writeParameterElement(FormalParameterFragmentImpl element) { |
| _writeFragmentId(element); |
| _writeFragmentName(element); |
| _sink.writeBool(element.isInitializingFormal); |
| _sink.writeBool(element.isSuperFormal); |
| _sink._writeFormalParameterKind(element); |
| element.writeModifiers(_sink); |
| |
| _resolutionSink._writeMetadata(element.metadata); |
| |
| _writeTypeParameters(element.typeParameters, () { |
| _sink.writeList(element.formalParameters, _writeParameterElement); |
| _resolutionSink.writeBool(element.element.inheritsCovariant); |
| _resolutionSink.writeType(element.element.type); |
| _resolutionSink._writeOptionalNode(element.constantInitializer); |
| |
| if (element is FieldFormalParameterFragmentImpl) { |
| // TODO(scheglov): formal parameter types? Anything else? |
| // _resolutionSink.writeFragmentOrMember(element.field); |
| _resolutionSink.writeElement(element.field?.element); |
| } |
| }); |
| } |
| |
| /// We write metadata here, to keep it inside [unitElement] resolution |
| /// data, because [_writePartInclude] recursively writes included unit |
| /// elements. But the bundle reader wants all metadata for `parts` |
| /// sequentially. |
| void _writePartElementsMetadata(LibraryFragmentImpl unitElement) { |
| for (var element in unitElement.parts) { |
| _resolutionSink._writeMetadata(element.metadata); |
| } |
| } |
| |
| void _writePartInclude(PartIncludeImpl element) { |
| _writeDirectiveUri(element.uri); |
| } |
| |
| void _writeReference(Reference reference) { |
| var index = _references._indexOfReference(reference); |
| _sink.writeUInt30(index); |
| } |
| |
| /// Invoke this after writing enough information to create an element, but |
| /// before writing any resolution data. |
| void _writeResolutionOffset() { |
| _sink.writeUInt30(_resolutionSink.offset); |
| } |
| |
| void _writeSetterElements(List<SetterElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| element.writeModifiers(_sink); |
| |
| _writeElementResolution(() { |
| _resolutionSink.writeType(element.returnType); |
| // TODO(scheglov): formal parameter types? Anything else? |
| }); |
| }); |
| } |
| |
| void _writeSetterFragment(SetterFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _sink.writeList(fragment.formalParameters, _writeParameterElement); |
| _resolutionSink._writeMetadata(fragment.metadata); |
| }); |
| }); |
| } |
| |
| void _writeTemplateFragment<T extends FragmentImpl>( |
| T fragment, |
| void Function() writeFragmentBody, |
| ) { |
| _writeFragmentId(fragment); |
| _writeFragmentName(fragment); |
| _writeResolutionOffset(); |
| fragment.writeModifiers(_sink); |
| writeFragmentBody(); |
| } |
| |
| void _writeTopLevelFunctionElements( |
| List<TopLevelFunctionElementImpl> elements, |
| ) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| |
| _writeElementResolution(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _resolutionSink.writeType(element.returnType); |
| }); |
| }); |
| }); |
| } |
| |
| void _writeTopLevelFunctionFragment(TopLevelFunctionFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _writeTypeParameters(fragment.typeParameters, () { |
| _sink.writeList(fragment.formalParameters, _writeParameterElement); |
| _resolutionSink._writeMetadata(fragment.metadata); |
| }); |
| }); |
| } |
| |
| void _writeTopLevelVariableFragment(TopLevelVariableFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink._writeOptionalNode(fragment.constantInitializer); |
| }); |
| } |
| |
| void _writeTypeAliasElements(List<TypeAliasElementImpl> elements) { |
| _sink.writeList(elements, (element) { |
| _writeReference(element.reference); |
| _writeFragments(element.fragments); |
| |
| _writeElementResolution(() { |
| _resolutionSink.withTypeParameters(element.typeParameters, () { |
| _resolutionSink.writeType(element.aliasedType); |
| }); |
| }); |
| }); |
| } |
| |
| void _writeTypeAliasFragment(TypeAliasFragmentImpl fragment) { |
| _writeTemplateFragment(fragment, () { |
| _sink.writeBool(fragment.isFunctionTypeAliasBased); |
| _writeTypeParameters(fragment.typeParameters, () { |
| _resolutionSink._writeMetadata(fragment.metadata); |
| _resolutionSink._writeAliasedElement(fragment.aliasedElement); |
| }); |
| }); |
| } |
| |
| void _writeTypeParameterElement(TypeParameterFragmentImpl element) { |
| _writeFragmentName(element); |
| _sink.writeByte(_encodeVariance(element).index); |
| _resolutionSink._writeMetadata(element.metadata); |
| _resolutionSink.writeType(element.bound); |
| _resolutionSink.writeType(element.defaultType); |
| } |
| |
| /// Add [typeParameters] to the indexing scope, so make them available |
| /// when writing types that might reference them, and write the elements. |
| void _writeTypeParameters( |
| List<TypeParameterFragmentImpl> typeParameterFragments, |
| void Function() f, |
| ) { |
| // TODO(scheglov): review |
| var typeParameters = typeParameterFragments.map((f) => f.element).toList(); |
| _resolutionSink.localElements.withElements(typeParameters, () { |
| _sink.writeList(typeParameterFragments, _writeTypeParameterElement); |
| f(); |
| }); |
| } |
| |
| void _writeUnitElement(LibraryFragmentImpl unitElement) { |
| _writeResolutionOffset(); |
| |
| _sink.writeBool(unitElement.isSynthetic); |
| |
| _sink.writeList(unitElement.libraryImports, _writeLibraryImport); |
| _sink.writeList(unitElement.libraryExports, _writeLibraryExport); |
| |
| // Write the metadata for parts here, even though we write parts below. |
| // The reason is that resolution data must be in a single chunk. |
| _writePartElementsMetadata(unitElement); |
| |
| _sink.writeList(unitElement.classes, _writeClassFragment); |
| _sink.writeList(unitElement.enums, _writeEnumFragment); |
| _sink.writeList(unitElement.extensions, _writeExtensionFragment); |
| _sink.writeList(unitElement.extensionTypes, _writeExtensionTypeFragment); |
| _sink.writeList(unitElement.functions, _writeTopLevelFunctionFragment); |
| _sink.writeList(unitElement.mixins, _writeMixinFragment); |
| _sink.writeList(unitElement.typeAliases, _writeTypeAliasFragment); |
| |
| _sink.writeList( |
| unitElement.topLevelVariables, |
| _writeTopLevelVariableFragment, |
| ); |
| _sink.writeList(unitElement.getters, _writeGetterFragment); |
| _sink.writeList(unitElement.setters, _writeSetterFragment); |
| |
| // Write parts after this library fragment, so that when we read, we |
| // process fragments of declarations in the same order as we build them. |
| _sink.writeList(unitElement.parts, _writePartInclude); |
| } |
| |
| void _writeVariableGetterSetterLinking( |
| List<PropertyInducingElementImpl> variables, |
| ) { |
| _sink.writeList(variables, (variable) { |
| _writeReference(variable.reference); |
| _writeOptionalReference(variable.getter?.reference); |
| _writeOptionalReference(variable.setter?.reference); |
| }); |
| } |
| |
| static TypeParameterVarianceTag _encodeVariance( |
| TypeParameterFragmentImpl element, |
| ) { |
| if (element.isLegacyCovariant) { |
| return TypeParameterVarianceTag.legacy; |
| } |
| |
| var variance = element.variance; |
| if (variance == Variance.unrelated) { |
| return TypeParameterVarianceTag.unrelated; |
| } else if (variance == Variance.covariant) { |
| return TypeParameterVarianceTag.covariant; |
| } else if (variance == Variance.contravariant) { |
| return TypeParameterVarianceTag.contravariant; |
| } else if (variance == Variance.invariant) { |
| return TypeParameterVarianceTag.invariant; |
| } else { |
| throw UnimplementedError('$variance'); |
| } |
| } |
| } |
| |
| class BundleWriterResult { |
| final Uint8List resolutionBytes; |
| |
| BundleWriterResult({required this.resolutionBytes}); |
| } |
| |
| class ResolutionSink extends _SummaryDataWriter { |
| final _BundleWriterReferences _references; |
| final _LocalElementIndexer localElements = _LocalElementIndexer(); |
| |
| ResolutionSink({ |
| required super.stringIndexer, |
| required _BundleWriterReferences references, |
| }) : _references = references; |
| |
| void withTypeParameters( |
| List<TypeParameterElementImpl> typeParameters, |
| void Function() operation, |
| ) { |
| localElements.withElements(typeParameters, operation); |
| } |
| |
| void writeElement(Element? element) { |
| switch (element) { |
| case null: |
| writeEnum(ElementTag.null_); |
| case DynamicElementImpl(): |
| writeEnum(ElementTag.dynamic_); |
| case NeverElementImpl(): |
| writeEnum(ElementTag.never_); |
| case MultiplyDefinedElementImpl(): |
| writeEnum(ElementTag.multiplyDefined); |
| case SubstitutedElementImpl element: |
| writeEnum(ElementTag.memberWithTypeArguments); |
| |
| var baseElement = element.baseElement; |
| writeElement(baseElement); |
| |
| var typeArguments = _enclosingClassTypeArguments( |
| baseElement, |
| element.substitution.map, |
| ); |
| _writeTypeList(typeArguments); |
| case TypeParameterElementImpl(): |
| writeEnum(ElementTag.typeParameter); |
| var localIndex = localElements[element]; |
| writeUInt30(localIndex); |
| case FormalParameterElementImpl(): |
| writeEnum(ElementTag.formalParameter); |
| var enclosingElement = element.enclosingElement; |
| enclosingElement as ExecutableElement; |
| writeElement(enclosingElement); |
| var index = enclosingElement.formalParameters.indexOf(element); |
| assert(index >= 0); |
| writeUInt30(index); |
| case ElementImpl(): |
| writeEnum(ElementTag.elementImpl); |
| var reference = element.reference!; |
| var referenceIndex = _references._indexOfReference(reference); |
| writeUInt30(referenceIndex); |
| default: |
| throw StateError('${element.runtimeType}'); |
| } |
| } |
| |
| void writeOptionalTypeList(List<DartType>? types) { |
| if (types != null) { |
| writeBool(true); |
| _writeTypeList(types); |
| } else { |
| writeBool(false); |
| } |
| } |
| |
| void writeType(DartType? type) { |
| if (type == null) { |
| writeEnum(TypeTag.NullType); |
| } else if (type is DynamicTypeImpl) { |
| writeEnum(TypeTag.DynamicType); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is FunctionTypeImpl) { |
| _writeFunctionType(type); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is InterfaceTypeImpl) { |
| var typeArguments = type.typeArguments; |
| var nullabilitySuffix = type.nullabilitySuffix; |
| if (typeArguments.isEmpty) { |
| if (nullabilitySuffix == NullabilitySuffix.none) { |
| writeEnum(TypeTag.InterfaceType_noTypeArguments_none); |
| } else if (nullabilitySuffix == NullabilitySuffix.question) { |
| writeEnum(TypeTag.InterfaceType_noTypeArguments_question); |
| } |
| // TODO(scheglov): Write raw |
| writeElement(type.element); |
| } else { |
| writeEnum(TypeTag.InterfaceType); |
| // TODO(scheglov): Write raw |
| writeElement(type.element); |
| _writeTypeList(typeArguments); |
| _writeNullabilitySuffix(nullabilitySuffix); |
| } |
| _writeTypeAliasElementArguments(type); |
| } else if (type is InvalidTypeImpl) { |
| writeEnum(TypeTag.InvalidType); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is NeverTypeImpl) { |
| writeEnum(TypeTag.NeverType); |
| _writeNullabilitySuffix(type.nullabilitySuffix); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is RecordTypeImpl) { |
| _writeRecordType(type); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is TypeParameterTypeImpl) { |
| writeEnum(TypeTag.TypeParameterType); |
| writeElement(type.element); |
| _writeNullabilitySuffix(type.nullabilitySuffix); |
| _writeTypeAliasElementArguments(type); |
| } else if (type is VoidTypeImpl) { |
| writeEnum(TypeTag.VoidType); |
| _writeTypeAliasElementArguments(type); |
| } else { |
| throw UnimplementedError('${type.runtimeType}'); |
| } |
| } |
| |
| void _writeAliasedElement(FragmentImpl? element) { |
| if (element == null) { |
| writeByte(AliasedElementTag.nothing); |
| } else if (element is GenericFunctionTypeFragmentImpl) { |
| writeByte(AliasedElementTag.genericFunctionElement); |
| _writeTypeParameters(element.typeParameters, () { |
| _writeFormalParameters(element.formalParameters, withAnnotations: true); |
| writeType(element.returnType); |
| }, withAnnotations: true); |
| } else { |
| throw UnimplementedError('${element.runtimeType}'); |
| } |
| } |
| |
| void _writeElementList(List<Element> elements) { |
| writeList(elements, writeElement); |
| } |
| |
| void _writeElementName(Element element) { |
| _writeOptionalStringReference(element.name); |
| } |
| |
| void _writeFormalParameters( |
| List<FormalParameterFragmentImpl> parameters, { |
| required bool withAnnotations, |
| }) { |
| writeList(parameters, (parameter) { |
| _writeFormalParameterKind(parameter); |
| writeBool(parameter.hasImplicitType); |
| writeBool(parameter.isInitializingFormal); |
| _writeTypeParameters(parameter.typeParameters, () { |
| writeType(parameter.element.type); |
| _writeFragmentName(parameter); |
| _writeFormalParameters( |
| parameter.formalParameters, |
| withAnnotations: withAnnotations, |
| ); |
| }, withAnnotations: withAnnotations); |
| if (withAnnotations) { |
| _writeMetadata(parameter.metadata); |
| } |
| }); |
| } |
| |
| void _writeFormalParameters2( |
| List<InternalFormalParameterElement> parameters, { |
| required bool withAnnotations, |
| }) { |
| writeList(parameters, (parameter) { |
| _writeFormalParameterKind2(parameter); |
| writeBool(parameter.hasImplicitType); |
| writeBool(parameter.isInitializingFormal); |
| _writeTypeParameters2(parameter.typeParameters, () { |
| writeType(parameter.type); |
| _writeElementName(parameter); |
| _writeFormalParameters2( |
| parameter.formalParameters.cast(), |
| withAnnotations: withAnnotations, |
| ); |
| }, withAnnotations: withAnnotations); |
| if (withAnnotations) { |
| _writeMetadata(parameter.metadata as MetadataImpl); |
| } |
| }); |
| } |
| |
| void _writeFragmentName(Fragment fragment) { |
| _writeOptionalStringReference(fragment.name); |
| } |
| |
| void _writeFunctionType(FunctionTypeImpl type) { |
| type = _toSyntheticFunctionType(type); |
| |
| writeEnum(TypeTag.FunctionType); |
| |
| _writeTypeParameters2(type.typeParameters, () { |
| writeType(type.returnType); |
| _writeFormalParameters2(type.formalParameters, withAnnotations: false); |
| }, withAnnotations: false); |
| _writeNullabilitySuffix(type.nullabilitySuffix); |
| } |
| |
| void _writeMetadata(MetadataImpl metadata) { |
| writeList(metadata.annotations, (annotation) { |
| _writeNode(annotation.annotationAst); |
| }); |
| } |
| |
| void _writeNode(AstNode node) { |
| var astWriter = AstBinaryWriter(sink: this, stringIndexer: _stringIndexer); |
| node.accept(astWriter); |
| } |
| |
| void _writeNullabilitySuffix(NullabilitySuffix suffix) { |
| writeByte(suffix.index); |
| } |
| |
| void _writeOptionalNode(Expression? node) { |
| if (node != null) { |
| writeBool(true); |
| _writeNode(node); |
| } else { |
| writeBool(false); |
| } |
| } |
| |
| void _writeRecordType(RecordTypeImpl type) { |
| writeEnum(TypeTag.RecordType); |
| |
| writeList<RecordTypePositionalField>(type.positionalFields, (field) { |
| writeType(field.type); |
| }); |
| |
| writeList<RecordTypeNamedField>(type.namedFields, (field) { |
| _writeStringReference(field.name); |
| writeType(field.type); |
| }); |
| |
| _writeNullabilitySuffix(type.nullabilitySuffix); |
| } |
| |
| void _writeTypeAliasElementArguments(TypeImpl type) { |
| var alias = type.alias; |
| writeElement(alias?.element); |
| if (alias != null) { |
| _writeTypeList(alias.typeArguments); |
| } |
| } |
| |
| void _writeTypeList(List<DartType> types) { |
| writeList(types, writeType); |
| } |
| |
| void _writeTypeParameters( |
| List<TypeParameterFragmentImpl> typeParameterFragments, |
| void Function() f, { |
| required bool withAnnotations, |
| }) { |
| var typeParameters = typeParameterFragments.map((f) => f.element).toList(); |
| localElements.withElements(typeParameters, () { |
| writeList(typeParameterFragments, _writeFragmentName); |
| for (var typeParameter in typeParameterFragments) { |
| writeType(typeParameter.bound); |
| if (withAnnotations) { |
| _writeMetadata(typeParameter.metadata); |
| } |
| } |
| f(); |
| }); |
| } |
| |
| void _writeTypeParameters2( |
| List<TypeParameterElementImpl> typeParameters, |
| void Function() f, { |
| required bool withAnnotations, |
| }) { |
| localElements.withElements(typeParameters, () { |
| writeList(typeParameters, _writeElementName); |
| for (var typeParameter in typeParameters) { |
| writeType(typeParameter.bound); |
| if (withAnnotations) { |
| _writeMetadata(typeParameter.metadata); |
| } |
| } |
| f(); |
| }); |
| } |
| |
| static List<DartType> _enclosingClassTypeArguments( |
| Element declaration, |
| Map<TypeParameterElement, DartType> substitution, |
| ) { |
| // TODO(scheglov): Just keep it null in class Member? |
| if (substitution.isEmpty) { |
| return const []; |
| } |
| |
| var enclosing = declaration.enclosingElement; |
| if (enclosing is InstanceElement) { |
| var typeParameters = enclosing.typeParameters; |
| if (typeParameters.isEmpty) { |
| return const <DartType>[]; |
| } |
| |
| return typeParameters |
| .map((typeParameter) => substitution[typeParameter]) |
| .nonNulls |
| .toList(growable: false); |
| } |
| |
| return const <DartType>[]; |
| } |
| |
| static FunctionTypeImpl _toSyntheticFunctionType(FunctionTypeImpl type) { |
| var typeParameters = type.typeParameters; |
| if (typeParameters.isEmpty) return type; |
| |
| var fresh = getFreshTypeParameters(typeParameters); |
| return fresh.applyToFunctionType(type); |
| } |
| } |
| |
| class StringIndexer { |
| final Map<String, int> _index = {}; |
| |
| int operator [](String string) { |
| var result = _index[string]; |
| |
| if (result == null) { |
| result = _index.length; |
| _index[string] = result; |
| } |
| |
| return result; |
| } |
| |
| int write(BufferedSink sink) { |
| var bytesOffset = sink.offset; |
| |
| var length = _index.length; |
| var lengths = Uint32List(length); |
| var lengthsIndex = 0; |
| for (var key in _index.keys) { |
| var stringStart = sink.offset; |
| _writeWtf8(sink, key); |
| lengths[lengthsIndex++] = sink.offset - stringStart; |
| } |
| |
| var resultOffset = sink.offset; |
| |
| var lengthOfBytes = sink.offset - bytesOffset; |
| sink.writeUInt30(lengthOfBytes); |
| sink.writeUint30List(lengths); |
| |
| return resultOffset; |
| } |
| |
| /// Write [source] string into [sink]. |
| static void _writeWtf8(BufferedSink sink, String source) { |
| var end = source.length; |
| if (end == 0) { |
| return; |
| } |
| |
| int i = 0; |
| do { |
| var codeUnit = source.codeUnitAt(i++); |
| if (codeUnit < 128) { |
| // ASCII. |
| sink.writeByte(codeUnit); |
| } else if (codeUnit < 0x800) { |
| // Two-byte sequence (11-bit unicode value). |
| sink.writeByte(0xC0 | (codeUnit >> 6)); |
| sink.writeByte(0x80 | (codeUnit & 0x3f)); |
| } else if ((codeUnit & 0xFC00) == 0xD800 && |
| i < end && |
| (source.codeUnitAt(i) & 0xFC00) == 0xDC00) { |
| // Surrogate pair -> four-byte sequence (non-BMP unicode value). |
| int codeUnit2 = source.codeUnitAt(i++); |
| int unicode = |
| 0x10000 + ((codeUnit & 0x3FF) << 10) + (codeUnit2 & 0x3FF); |
| sink.writeByte(0xF0 | (unicode >> 18)); |
| sink.writeByte(0x80 | ((unicode >> 12) & 0x3F)); |
| sink.writeByte(0x80 | ((unicode >> 6) & 0x3F)); |
| sink.writeByte(0x80 | (unicode & 0x3F)); |
| } else { |
| // Three-byte sequence (16-bit unicode value), including lone |
| // surrogates. |
| sink.writeByte(0xE0 | (codeUnit >> 12)); |
| sink.writeByte(0x80 | ((codeUnit >> 6) & 0x3f)); |
| sink.writeByte(0x80 | (codeUnit & 0x3f)); |
| } |
| } while (i < end); |
| } |
| } |
| |
| class UnitToWriteAst { |
| final CompilationUnit node; |
| |
| UnitToWriteAst({required this.node}); |
| } |
| |
| class _BundleWriterReferences { |
| /// References used in all libraries being linked. |
| /// Element references in nodes are indexes in this list. |
| final List<Reference?> _references = [null]; |
| |
| final List<int> _referenceParents = [0]; |
| final List<String> _referenceNames = ['']; |
| |
| /// We need indexes for references during linking, but once we are done, |
| /// we must clear indexes to make references ready for linking a next bundle. |
| void _clearIndexes() { |
| for (var reference in _references) { |
| if (reference != null) { |
| reference.index = null; |
| } |
| } |
| } |
| |
| int _indexOfReference(Reference reference) { |
| var index = reference.index; |
| if (index != null) return index; |
| |
| if (reference.parent case var parent?) { |
| var parentIndex = _indexOfReference(parent); |
| _referenceParents.add(parentIndex); |
| _referenceNames.add(reference.name); |
| |
| index = _references.length; |
| reference.index = index; |
| _references.add(reference); |
| return index; |
| } else { |
| return 0; |
| } |
| } |
| } |
| |
| class _Library { |
| final String uriStr; |
| final int offset; |
| |
| _Library({required this.uriStr, required this.offset}); |
| } |
| |
| class _LocalElementIndexer { |
| final Map<ElementImpl, int> _index = Map.identity(); |
| int _stackHeight = 0; |
| |
| int operator [](ElementImpl element) { |
| return _index[element] ?? |
| (throw ArgumentError('Unexpectedly not indexed: $element')); |
| } |
| |
| void withElements(List<ElementImpl> elements, void Function() f) { |
| for (var element in elements) { |
| _index[element] = _stackHeight++; |
| } |
| |
| f(); |
| |
| _stackHeight -= elements.length; |
| for (var element in elements) { |
| _index.remove(element); |
| } |
| } |
| } |
| |
| class _SummaryDataWriter extends BufferedSink { |
| final StringIndexer _stringIndexer; |
| |
| _SummaryDataWriter({required StringIndexer stringIndexer}) |
| : _stringIndexer = stringIndexer; |
| |
| _SummaryDataWriter clone() { |
| return _SummaryDataWriter(stringIndexer: _stringIndexer); |
| } |
| |
| void _writeFormalParameterKind(FormalParameterFragmentImpl p) { |
| if (p.isRequiredPositional) { |
| writeByte(Tag.ParameterKindRequiredPositional); |
| } else if (p.isOptionalPositional) { |
| writeByte(Tag.ParameterKindOptionalPositional); |
| } else if (p.isRequiredNamed) { |
| writeByte(Tag.ParameterKindRequiredNamed); |
| } else if (p.isOptionalNamed) { |
| writeByte(Tag.ParameterKindOptionalNamed); |
| } else { |
| throw StateError('Unexpected parameter kind: $p'); |
| } |
| } |
| |
| void _writeFormalParameterKind2(InternalFormalParameterElement p) { |
| if (p.isRequiredPositional) { |
| writeByte(Tag.ParameterKindRequiredPositional); |
| } else if (p.isOptionalPositional) { |
| writeByte(Tag.ParameterKindOptionalPositional); |
| } else if (p.isRequiredNamed) { |
| writeByte(Tag.ParameterKindRequiredNamed); |
| } else if (p.isOptionalNamed) { |
| writeByte(Tag.ParameterKindOptionalNamed); |
| } else { |
| throw StateError('Unexpected parameter kind: $p'); |
| } |
| } |
| |
| void _writeOptionalStringReference(String? value) { |
| if (value != null) { |
| writeBool(true); |
| _writeStringReference(value); |
| } else { |
| writeBool(false); |
| } |
| } |
| |
| void _writeStringList(List<String> values) { |
| writeList(values, _writeStringReference); |
| } |
| |
| void _writeStringReference(String string) { |
| var index = _stringIndexer[string]; |
| writeUInt30(index); |
| } |
| |
| void _writeTopLevelInferenceError(TopLevelInferenceError? error) { |
| if (error != null) { |
| writeByte(error.kind.index); |
| _writeStringList(error.arguments); |
| } else { |
| writeByte(TopLevelInferenceErrorKind.none.index); |
| } |
| } |
| } |
| |
| extension on Map<FragmentImpl, int> { |
| int getId(FragmentImpl fragment) { |
| return this[fragment] ??= length; |
| } |
| } |