Skip to content

Commit f80d20f

Browse files
T-GroCopilotabonie
authored
Cache attributes read by compiler— replace repeated string matching with O(1) enum lookups (#19394)
* Define WellKnownILAttributes, WellKnownEntityAttributes, WellKnownValAttributes flag enums Add three [<Flags>] enums for O(1) well-known attribute lookups: - WellKnownILAttributes (uint32) in AbstractIL/il.fs/.fsi - WellKnownEntityAttributes (uint64) in TypedTree/TypedTree.fs/.fsi - WellKnownValAttributes (uint64) in TypedTree/TypedTree.fs/.fsi Each enum uses power-of-2 bit values with NotComputed at the sign bit. Purely additive — no existing code modified. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add computeILWellKnownFlags and migrate IL attribute check sites - Add computeILWellKnownFlags function in TypedTreeOps.fs that maps all 19 WellKnownILAttributes enum values to their TcGlobals attrib_* fields - Add HasWellKnownAttribute extension members on ILAttributesStored, ILTypeDef, ILMethodDef, and ILFieldDef - Migrate 12 IL-domain existence-only check sites from O(N) TryFindILAttribute scans to O(1) HasWellKnownAttribute calls - Fix pre-existing ILAttributesStored sealed class callers (Given -> CreateGiven, customAttrsReader -> CreateReader pattern in ilread.fs) - Keep 3 data-extracting sites (ReflectedDefinition, AutoOpen, InternalsVisibleTo) and 2 individual-attribute iteration sites unchanged - TypeHierarchy.fs sites use TryFindILAttribute on storedAttrs.CustomAttrs (scope comparison prevents full HasWellKnownAttribute migration) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix IL Compute And Migration: scope-safe comparison, TypeHierarchy migration, remove dead enums - Fix computeILWellKnownFlags to use name+enclosing comparison (not full ILTypeRef equality with scope) matching isILAttrib semantics. This fixes silent failures when BCL reference assemblies use ILScopeRef.Local while TcGlobals uses ILScopeRef.Assembly. - Migrate TypeHierarchy.fs sites #6 and #7 (IsReadOnlyAttribute, RequiresLocationAttribute) to use HasWellKnownAttribute. - Remove unused WellKnownEntityAttributes and WellKnownValAttributes enums from TypedTree.fs/TypedTree.fsi (dead code not part of this sprint). - Update surface area baseline. - Run dotnet fantomas on all changed files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add WellKnownEntityAttribs struct and migrate Entity.entity_attribs Sprint 2: Entity Container And Infrastructure - Add WellKnownEntityAttributes flags enum (27 flags + NotComputed sentinel) - Add WellKnownEntityAttribs struct wrapper with O(1) attribute lookup - Change Entity.entity_attribs field type from Attribs to WellKnownEntityAttribs - Entity.Attribs still returns Attrib list via .AsList() - Add Entity.EntityAttribs and Entity.SetEntityAttribs members - Fix Entity.IsLinked for struct field (null check on AsList()) - Add computeEntityWellKnownFlags and EntityHasWellKnownAttribute in TypedTreeOps - Update TypedTreePickle.fs to pickle/unpickle through the wrapper - Update all entity_attribs assignments across the compiler Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 30 entity-level existence checks to EntityHasWellKnownAttribute Replace O(N) HasFSharpAttribute calls with O(1) EntityHasWellKnownAttribute bit tests for entity-level existence-only attribute checks across: - AugmentWithHashCompare.fs (1 site) - CheckDeclarations.fs (12 sites) - ConstraintSolver.fs (4 sites) - CheckExpressions.fs (1 site) - NameResolution.fs (9 sites) - PostInferenceChecks.fs (2 sites) - IlxGen.fs (2 sites) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 4: Val Container And Infrastructure - WellKnownValAttribs - Add WellKnownValAttributes flags enum (25 flags + NotComputed sentinel) - Add WellKnownValAttribs wrapper struct mirroring WellKnownEntityAttribs - Change ValOptionalData.val_attribs field type to WellKnownValAttribs - Add Val.ValAttribs property returning WellKnownValAttribs - Add Val.SetValAttribs accepting WellKnownValAttribs - Val.Attribs still returns Attrib list, Val.SetAttribs still accepts Attribs - Change ArgReprInfo.Attribs field type to WellKnownValAttribs - Add computeValWellKnownFlags covering all 25 enum flags - Add ValHasWellKnownAttribute helper in TypedTreeOps - Update TypedTreePickle for val_attribs and ArgReprInfo serialization - Fix all downstream usage sites across compiler Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 05: Migrate Val/ArgReprInfo-level existence checks to well-known attribute flags - Add ArgReprInfoHasWellKnownAttribute helper in TypedTreeOps.fs/.fsi - Migrate 11 Val sites to ValHasWellKnownAttribute (O(1) flag test) - Migrate 19 ArgReprInfo sites to ArgReprInfoHasWellKnownAttribute - Migrate 7 Attrib list sites using computeValWellKnownFlags - Migrate 2 Entity sites to EntityHasWellKnownAttribute - Total: 39 existence-only attribute check sites migrated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 6: Hybrid mapping functions and TyconRef migration Add mapILFlagToEntityFlag and mapILFlagToValFlag mapping functions to TypedTreeOps.fs for translating WellKnownILAttributes flags to their Entity and Val equivalents. Add TyconRefHasWellKnownAttribute unified hybrid check function that dispatches on IL vs F# vs provided type metadata using O(1) flag tests. Migrate 5 existence-only TyconRef hybrid sites: - NameResolution.fs: ExtensionAttribute check - PostInferenceChecks.fs: IsByRefLikeAttribute and IsReadOnlyAttribute checks - TypedTreeOps.fs: IsByRefLikeAttribute (isByrefLikeTyconRef) and IsReadOnlyAttribute (isTyconRefReadOnly) checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 7: Final validation fixes - conditional compile mapILFlagToAttribInfo - Wrap mapILFlagToAttribInfo in #if !NO_TYPEPROVIDERS to fix FS1182 unused value error on netstandard2.0 target - Simplify ProvidedTypeMetadata case in TyconRefHasWellKnownAttribute to reuse TyconRefHasAttribute via the new helper - All component tests pass (6630/6630) - All import tests pass (63/63) - All CompilerCompat cross-version tests pass (6/6) - All service tests pass (2089/2089) - All scripting tests pass (99/99) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 7: Fix isByrefLikeTyconRef to use name-based attribute matching Revert isByrefLikeTyconRef from TyconRefHasWellKnownAttribute (type-identity) back to TyconRefHasAttributeByName (name-based) to preserve RFC FS-1053 compatibility. User code can define its own IsByRefLikeAttribute, so this function must match by attribute name, not by type identity. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Sprint 7: Fix PostInferenceChecks IsByRefLike to use name-based matching per RFC FS-1053 The IsByRefLikeAttribute check in CheckEntityDefn was incorrectly changed to type-identity matching (TyconRefHasWellKnownAttribute) during Sprint 6. This breaks user-defined IsByRefLikeAttribute per RFC FS-1053. Reverted to name-based matching (TyconRefHasAttributeByName) for consistency with isByrefLikeTyconRef in TypedTreeOps.fs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rewrite computeEntityWellKnownFlags with multi-level path dispatch Replace flat if/elif chain of 27 tyconRefEq comparisons with a two-phase dispatch: first check assembly identity (ccuEq), then array pattern match on the namespace path. User-defined attributes from unrelated assemblies are rejected in 1-2 cheap checks instead of 27 comparisons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rewrite computeValWellKnownFlags with multi-level path dispatch Replace flat if/elif chain of tyconRefEq calls with two-phase assembly/path routing and array pattern matching, matching the approach used in computeEntityWellKnownFlags. User attributes are rejected in 1-2 cheap checks instead of O(N×K) comparisons. All 25 well-known val attributes are covered. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rewrite computeILWellKnownFlags with prefix + string match dispatch Replace flat if/elif chain of nameMatch calls against 16 AttribInfo references with a prefix-based dispatch on ILTypeRef.Name. User-defined attributes bail out after 1-2 prefix checks instead of scanning all 16+ comparisons. Key changes: - Remove 16 AttribInfo extractions from TcGlobals at function top - Remove inline nameMatch helper - Group by StartsWith prefix: System.Runtime.CompilerServices (13), Microsoft.FSharp.Core (4), then remaining (3) - Cover SetsRequiredMembersAttribute from both CompilerServices and CodeAnalysis namespaces Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate getAugmentationAttribs to cached WellKnownEntityAttributes flags Replace 7 TryFindFSharpBoolAttribute linear scans with cached EntityHasWellKnownAttribute lookups. Update all pattern match sites in CheckAugmentationAttribs, TyconIsCandidateForAugmentationWithCompare, and TyconIsCandidateForAugmentationWithEquals from bool option to bool. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate remaining existence-only attribute call sites to cached flags Replace TryFindFSharpBoolAttribute/HasFSharpAttribute/TryFindFSharpAttribute calls with EntityHasWellKnownAttribute/ValHasWellKnownAttribute at 10 sites: - CheckDeclarations.fs: StructuralComparison, StructuralEquality - NameResolution.fs: AutoOpen (CanAutoOpenTyconRef, module auto-open) - Optimizer.fs: CLIMutable - IlxGen.fs: CLIMutable, ComVisible (fast negative guard), LiteralAttribute, EntryPoint - fsi.fs: EntryPoint (fast negative guard) GeneralizableValueAttribute site left as-is (enum case is on Entity, not Val). ComVisible uses conservative fast negative guard to preserve exact semantics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add missing enum cases to WellKnownEntityAttributes and WellKnownValAttributes Add ClassAttribute, InterfaceAttribute, StructAttribute, MeasureAttribute to WellKnownEntityAttributes enum (bits 0x8000000u-0x40000000u). Add NoCompilerInliningAttribute to WellKnownValAttributes enum (0x2000000uL). Update computeEntityWellKnownFlags and computeValWellKnownFlags to recognize the new attribute names in FSharp.Core paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Bool TrueFalse encoding for three-state attributes Add _True/_False flag pairs for attributes that carry boolean semantics: Entity enum: DefaultAugmentationAttribute_True/_False, AutoSerializableAttribute_True/_False (widened enum to uint64) Val enum: ReflectedDefinitionAttribute_True/_False, DefaultValueAttribute_True/_False, NoDynamicInvocationAttribute_True/_False Compute functions now extract bool args from attribute constructors and set the appropriate flag. Added EntityTryGetBoolAttribute and ValTryGetBoolAttribute helpers. Migrated all TODO WELLKNOWN_ATTRIB bool extraction call sites: - TypedTreeOps.fs: HasDefaultAugmentationAttribute, isSealedTy - IlxGen.fs: DefaultAugmentation, NoDynamicInvocation, AutoSerializable - PostInferenceChecks.fs: DefaultAugmentation - infos.fs: ReflectedDefinition on ArgReprInfo Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix NoDynamicInvocation/ReflectedDefinition default to false (AssumeFalse semantics) The original code used TryFindFSharpBoolAttributeAssumeFalse for these two attributes, which defaults to false when no explicit bool argument is present. The | _ -> fallback incorrectly set _True; corrected to _False. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix ReflectedDefinitionAttribute existence check to include _False flag The existence check at PostInferenceChecks.fs line 2122 must check both _True and _False flags since [<ReflectedDefinition>] without explicit bool arg sets _False (matching TryFindFSharpBoolAttributeAssumeFalse semantics). Without this fix, bare [<ReflectedDefinition>] on struct members would not trigger the FS1220 error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Flatten ILAttributesStored: eliminate Computed DU case Replace the Computed(ILAttributes * WellKnownILAttributes) DU case with a separate mutable wellKnownFlags field on ILAttributesStored. This avoids allocating a new DU case on every GetOrComputeWellKnownFlags call, reducing GC pressure for IL type definitions, methods, and fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fast negative guards and perf improvements for attribute checks - Add fast negative guard for StructLayoutAttribute in IlxGen.fs - Add fast negative guard for AttributeUsageAttribute in CheckExpressions.fs - Optimize CombineCcuContentFragments to avoid list concat when one side is empty - Use WellKnownEntityAttribs.Add for extension attribute additions - Remove TODO: WELLKNOWN_ATTRIB comments from guarded sites Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use WellKnownValAttribs.Empty instead of WellKnownValAttribs.Create([]) Replace WellKnownValAttribs.Create([]) with WellKnownValAttribs.Empty in NicePrint.fs, CompilerDiagnostics.fs, Symbols.fs, and TypedTreeBasics.fs. This avoids unnecessary list allocations. Also remove findings.yaml leftover artifact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * deduplicate logic for bool arg attrs * Refactor WellKnownEntityAttribs and WellKnownValAttribs into generic WellKnownAttribs<'TItem, 'TFlags> Extract the near-identical struct implementations into a single generic struct WellKnownAttribs<'TItem, 'TFlags> defined in a separate file (WellKnownAttribs.fs/fsi) outside the module rec context. The two flag enums (WellKnownEntityAttributes, WellKnownValAttributes) are also moved to the new file to avoid FS0073 bootstrap compiler limitations with enum<uint64> constraints in module rec. WellKnownEntityAttribs and WellKnownValAttribs become type aliases with companion modules for factory functions (Empty, Create, CreateWithFlags). All instance methods (HasWellKnownAttribute, AsList, Flags, Add, Append, WithRecomputedFlags) live on the generic struct and work through the type aliases unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate 10 additional attribute callsites to cached well-known flags - DllImport: IlxGen.IsValRefIsDllImport and TailCallChecks to ValHasWellKnownAttribute - CLIEventAttribute: Add flag, add ValCompileAsEvent, migrate 4 val-based callers - ComVisibleAttribute: Split into True/False flags, migrate IlxGen bool check - ComImportAttribute: Add True flag, migrate isComInteropTy - CompilationRepresentation: Add ModuleSuffix/PermitNull/Instance/Static entity flags, migrate TyconHasUseNullAsTrueValueAttribute - ObsoleteAttribute: Add to WellKnownILAttributes + WellKnownEntityAttributes, add CheckILAttributesForUnseenStored using O(1) flag check, migrate NameResolution.IsTyconUnseenObsoleteSpec Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove dead TryFindFSharpBoolAttributeAssumeFalse helper All callers migrated to decodeBoolAttribFlag in compute functions. Inline TryFindFSharpBoolAttribute (default=true) directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Phase A: Use already-computed entity flags in Phase1G Replace redundant HasFSharpAttribute/TryFindFSharpBoolAttribute calls with direct flag tests on the entityFlags that are already computed 3 lines above. - SealedAttribute: split into _True/_False flag pair for three-state semantics - MeasureableAttribute: add to WellKnownEntityAttributes enum - hasMeasureAttr, hasMeasureableAttr, hasAllowNullLiteralAttr: test entityFlags bits - structLayoutAttr: kept as TryFindFSharpInt32Attribute (needs LayoutKind int) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Phase B: Compute entity flags ad-hoc in Phase1B and early typar check Replace HasFSharpAttribute with computeEntityWellKnownFlags + bit test in TcTyconDefnCore_Phase1B and TyparsAllHaveMeasureDeclEarlyCheck. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Phase C: Compute val flags ad-hoc in CheckExpressions Replace HasFSharpAttribute/HasFSharpAttributeOpt with computeValWellKnownFlags + bit tests for: LiteralAttribute (3 sites), DllImportAttribute (1 site), NoCompilerInliningAttribute (1 site). ComputeInlineFlag computes flags once for both NoCompilerInlining and DllImport checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Phase D: Compute val flags in GenParamAttribs Replace HasFSharpAttribute/HasFSharpAttributeOpt with computeValWellKnownFlags + bit tests for InAttribute, OutAttribute, OptionalAttribute in GenParamAttribs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Phase E: Compute val flags ad-hoc for field-level attrs - CheckDeclarations field attrs: compute computeValWellKnownFlags once for DefaultValueAttribute, VolatileFieldAttribute, ThreadStatic, ContextStatic - PostInferenceChecks: DefaultValueAttribute_True flag for zero-init check - TypedTreeOps: DefaultValueAttribute_False flag for field filtering - IlxGen NonSerializedAttribute: kept as-is (single site, merged list) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix review findings: MeasureableAttribute name, AllowNullLiteral True/False - Fix MeasureableAttribute: match on 'MeasureAnnotatedAbbreviationAttribute' (the actual FSharp.Core type name) instead of 'MeasureableAttribute' - AllowNullLiteralAttribute: split into _True/_False pair to preserve three-state semantics ([<AllowNullLiteral(false)>] vs absence) - Fix all references to renamed enum cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add attribsHaveEntityFlag/attribsHaveValFlag helpers, refactor callsites Address review findings: extract inline helpers for ad-hoc flag testing on raw Attrib lists. Refactor all verbose computeXWellKnownFlags + bit test patterns to use the new helpers. Fix ThreadStatic/ContextStatic to use combined ||| pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove dead TryFindFSharpBoolAttribute helper (zero callers remain) All bool attribute checks now use cached flags via decodeBoolAttribFlag in compute functions or attribsHaveValFlag ad-hoc helpers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove dead code and migrate remaining CompilationRepresentation/CompileAsEvent Dead code removed: - isThreadOrContextStatic (zero callers) - TryFindILAttributeOpt (zero callers) - enum_CompilationRepresentationAttribute_* constants (all 3, zero callers) Migrated to flags: - CompileAsEvent now uses attribsHaveValFlag internally - ModuleNameIsMangled now uses attribsHaveEntityFlag - MemberIsCompiledAsInstance Instance/Static uses computeEntityWellKnownFlags Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Delete HasFSharpAttributeOpt (zero callers), migrate CheckFSharpAttributesForObsolete Eliminated helpers: - HasFSharpAttributeOpt: last caller inlined, function deleted - TryFindFSharpBoolAttribute: already deleted (prior commit) - TryFindFSharpBoolAttributeAssumeFalse: already deleted (prior commit) Migrated: - CheckFSharpAttributesForObsolete: ObsoleteAttribute + IsByRefLikeAttribute now use attribsHaveEntityFlag instead of HasFSharpAttribute/Opt - IlxGen NonSerialized: inlined HasFSharpAttributeOpt to HasFSharpAttribute Remaining HasFSharpAttribute callers (7): 3 typar-level, 3 assembly-level, 1 NonSerialized fallback — all deliberately deferred. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Prototype: classifyEntityAttrib + tryFindEntityAttribByFlag Factor computeEntityWellKnownFlags into two layers: - classifyEntityAttrib: classify a SINGLE attrib, return its flag - computeEntityWellKnownFlags: OR all flags (uses classifyEntityAttrib) - tryFindEntityAttribByFlag: find first attrib matching a flag This enables enum-powered data extraction: callers use the WellKnownEntityAttributes enum to both check existence (O(1) via cached flags) AND find the actual attrib for data extraction (O(N) only on hit, via classifyEntityAttrib). Demonstrate with 2 migrations: - IlxGen StructLayoutAttribute: tryFindEntityAttribByFlag replaces TryFindFSharpAttribute - CheckExpressions AttributeUsageAttribute: same pattern This commit is isolated and revertable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate NonSerializedAttribute to val flags Add NonSerializedAttribute to WellKnownValAttributes enum + compute function. Replace last HasFSharpAttribute caller with attribsHaveValFlag. HasFSharpAttribute callers now: 6 (3 typar-level, 3 assembly-level — deferred). HasFSharpAttributeOpt callers: 0 (fully deleted). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add tryFindEntityAttribString/Int32, delete TryFindFSharpInt32Attribute Add enum-powered data extraction helpers that use classifyEntityAttrib for O(1) negative guard, then extract string/int data on hit. Migrate StructLayoutAttribute int extraction in CheckDeclarations from TryFindFSharpInt32Attribute to tryFindEntityAttribInt32. TryFindFSharpInt32Attribute now has zero callers and is deleted. This commit is isolated and revertable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add (|EntityAttrib|_|) and (|ValAttrib|_|) active patterns for enum-powered data extraction Factor computeEntityWellKnownFlags into classifyEntityAttrib (per-attrib) + fold. Factor computeValWellKnownFlags into classifyValAttrib (per-attrib) + fold. Active patterns use classifyEntityAttrib/classifyValAttrib to find the matching attrib by flag, then callers destructure the full Attrib in the pattern match — existence check AND data extraction in one expression. Before: match TryFindFSharpAttribute g g.attrib_MethodImplAttribute attrs with | Some(Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> flags | _ -> 0x0 After: match attrs with | ValAttrib g WellKnownValAttributes.MethodImplAttribute (Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> flags | _ -> 0x0 Migrated 7 callsites: - IlxGen: MethodImplAttribute, PreserveSigAttribute, FieldOffsetAttribute, StructLayoutAttribute - CheckExpressions: HasMethodImplNoInliningAttribute, AttributeUsageAttribute - CheckDeclarations: StructAttribute on ArgReprInfo - infos.fs: CallerMemberNameAttribute Added val flags: MethodImplAttribute, PreserveSigAttribute, FieldOffsetAttribute Deleted: TryFindFSharpInt32Attribute (zero callers), g.attrib_CallerMemberNameAttribute This commit is isolated and revertable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add typed extraction APs: EntityAttribInt, EntityAttribString, ValAttribInt, ValAttribString Slim active patterns that extract the common single-arg data directly: Before: | ValAttrib g WellKnownValAttributes.MethodImplAttribute (Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> flags After: | ValAttribInt g WellKnownValAttributes.MethodImplAttribute flags -> flags Migrated: MethodImplAttribute (×2), FieldOffsetAttribute, StructLayoutAttribute. Full (|EntityAttrib|_|) and (|ValAttrib|_|) remain for complex cases needing named args or multiple constructor args. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Make typed APs compose on top of base (|EntityAttrib|_|) / (|ValAttrib|_|) EntityAttribInt/String now match via EntityAttrib internally instead of calling tryFindEntityAttribByFlag independently. Same for Val variants. Proper layering: base AP is the building block, typed APs are sugar. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * A1: Add 7 entity/val flag cases, migrate 11 TryFindFSharpAttribute callers to APs WellKnownEntityAttributes: CompilerMessage, Experimental, Unverifiable, EditorBrowsable, CompiledName added to enum + classifyEntityAttrib. WellKnownValAttributes: CompiledName, WarnOnWithoutNullArgument added. Migrated to EntityAttrib/ValAttrib/EntityAttribString/ValAttribString APs: - AttributeChecking.fs: Obsolete, CompilerMessage(×2), Experimental, Unverifiable, EditorBrowsable - CheckDeclarations.fs: CompiledName - CheckExpressions.fs: CompiledName(×2), WarnOnWithoutNullArgument(×2) - fsi.fs: EntryPoint TryFindFSharpAttribute callers: 15 → 8 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * B1: Add WellKnownAssemblyAttributes, migrate all string attribute callers New enum WellKnownAssemblyAttributes with AutoOpen, InternalsVisibleTo, AssemblyCulture, AssemblyVersion. classifyAssemblyAttrib + (|AssemblyAttribString|_|). Migrated 7 TryFindFSharpStringAttribute callers: - fsc.fs: InternalsVisibleTo - IncrementalBuild.fs: AutoOpen, IVT, AssemblyCulture, AssemblyVersion - TransparentCompiler.fs: AssemblyCulture, AssemblyVersion TryFindFSharpStringAttribute callers: 10 → 0 (can be deleted) TryFindLocalizedFSharpStringAttribute callers: 2 → 0 (can be deleted) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Delete dead helpers and g.attrib_ members after AP migration Dead helpers removed (zero callers): - TryFindFSharpStringAttribute - TryFindLocalizedFSharpStringAttribute Dead g.attrib_ members removed (zero callers outside TcGlobals): - attrib_CompilerMessageAttribute - attrib_ExperimentalAttribute - attrib_UnverifiableAttribute - attrib_InternalsVisibleToAttribute - attrib_WarnOnWithoutNullArgumentAttribute - attrib_ComponentModelEditorBrowsableAttribute Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * C3: Shared combinators tryFindAttribByClassifier + attribsHaveFlag Extract inline combinators parameterized by classify function and zero value. Entity/Val/Assembly tryFind and attribsHave functions become thin wrappers: let tryFindEntityAttribByFlag g flag attribs = tryFindAttribByClassifier classifyEntityAttrib WellKnownEntityAttributes.None g flag attribs let attribsHaveValFlag g flag attribs = attribsHaveFlag classifyValAttrib WellKnownValAttributes.None g flag attribs Eliminates 3×duplicated tryFind + 2×duplicated attribsHave implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Migrate remaining IsMatchingFSharpAttribute/TryFindFSharpAttribute to flag-based APIs - Add DebuggerDisplayAttribute to WellKnownEntityAttributes and classifyEntityAttrib - Add MarshalAsAttribute to WellKnownValAttributes and classifyValAttrib - Export classifyEntityAttrib, classifyValAttrib, filterOutWellKnownAttribs, and tryFindValAttribByFlag from TypedTreeOps.fsi - NicePrint.fs: Replace 13 serial filters with single filterOutWellKnownAttribs call - NicePrint.fs: Replace OptionalArgumentAttribute filter - IlxGen.fs: Migrate 14 filter sites and 4 TryFind data-extraction sites - CheckExpressions.fs: Replace MeasureAttribute filter - CheckDeclarations.fs: Replace ConditionalAttribute tryFind - TypedTreeOps.fs: Replace ExtensionAttribute tryFind - NameResolution.fs: Replace IsMatchingFSharpAttribute for StructAttribute - infos.fs: Replace DefaultParameterValueAttribute TryFindOpt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Filter chain optimization + delete dead helpers and 18 g.attrib_ members Major changes: - filterOutWellKnownAttribs: single-pass filter using classify functions replaces 30+ serial IsMatchingFSharpAttribute filter chains - NicePrint.fs: 13 serial O(N) filters → 1 filterOutWellKnownAttribs call - IlxGen.fs: 12 filter sites migrated to filterOutWellKnownAttribs - Data extraction: TryFindFSharpAttributeOpt callers migrated to ValAttrib APs Dead code removed: - TryFindFSharpAttributeOpt, IsMatchingFSharpAttributeOpt (zero callers) - 18 g.attrib_ TcGlobals members (zero callers) g.attrib_ members: 59 → 41 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add IL-level classifyILAttrib + (|ILAttribDecoded|_|) AP, migrate 9 TryDecodeILAttribute sites Factor computeILWellKnownFlags into classifyILAttrib (per-attrib) + fold. Add tryFindILAttribByFlag and (|ILAttribDecoded|_|) active pattern for enum-powered IL attribute data extraction. New WellKnownILAttributes flags: CompilerFeatureRequired, Experimental, RequiredMember, NullableContext, AttributeUsage. Migrated 9 TryDecodeILAttribute callsites: - AttributeChecking.fs: CompilerFeatureRequired, Experimental, Obsolete(×3), IsByRefLike - import.fs: NullableAttribute, NullableContextAttribute - infos.fs: ReflectedDefinition Also migrated TryFindILAttribute callers: - CheckExpressions.fs: SetsRequiredMembersAttribute → tryFindILAttribByFlag - infos.fs: RequiredMemberAttribute → tryFindILAttribByFlag Deleted 6 g.attrib_ members (zero callers): NullableAttribute_opt, NullableContextAttribute_opt, CompilerFeatureRequiredAttribute, SetsRequiredMembersAttribute, RequiredMemberAttribute, IlExperimentalAttribute. g.attrib_ members: 41 → 35 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Delete attrib_IlExperimentalAttribute (zero callers) g.attrib_ members: 95 → 35 (60 deleted total) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Audit cleanup: hasFlag helper, CheckFlag dedup, ILAttributes extension, docs - Add inline hasFlag helper to replace 37 verbose &&& <> None patterns - Add CheckFlag method to WellKnownAttribs struct, dedup 3 cache functions - Add ILAttributes.HasWellKnownAttribute extension for non-caching checks - Fix ILPropInfo.IsRequired to use cached HasWellKnownAttribute - Simplify CheckRequiredProperties to use ILAttributes extension - Document WellKnownAssemblyAttributes uint32 choice - Update surface area baseline for new WellKnownILAttributes members - Fix DefaultValue(false) regression: zeroInit must match both True and False flags Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add MethInfoHasWellKnownAttribute for O(1) checks on overload resolution hot path Migrate NoEagerConstraintApplicationAttribute (2 callers in MethodCalls + CheckExpressions) and ExtensionAttribute (NameResolution) from linear-scan MethInfoHasAttribute to cached-flag MethInfoHasWellKnownAttribute. The new function dispatches to ILMethodDef.HasWellKnownAttribute (cached IL flags) for ILMeth and ValHasWellKnownAttribute (cached val flags) for FSMeth, with ProvidedMeth fallback to the old API. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Council fixes: resolveAttribPath DU, merge IL maps, private HasWellKnownAttribute, cleanup - Refactor resolveAttribPath from callback to struct(bclPath, fsharpCorePath) return value. Eliminates mutable-captured-by-closure in all 3 classifiers, removes 1 nesting level, makes control flow linear and purely functional. - Merge mapILFlagToAttribInfo + mapILFlagToEntityFlag into single mapILFlag returning struct(EntityFlag * AttribInfo option). One match, no drift risk. - Remove HasWellKnownAttribute from .fsi — callers must use CheckFlag. - Remove dead _g parameter from CheckCompilerFeatureRequiredAttribute. - Add NoEagerConstraintApplicationAttribute to WellKnownValAttributes for complete MethInfoHasWellKnownAttribute coverage on FSMeth path. - Add comment on dual-namespace SetsRequiredMembersAttribute. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Round 2 council fixes: extract WarnOnWithoutNull helper, dedup CheckILUnseen, tryGetAssemblyAttribString - Extract tryGetWarnOnWithoutNullMessage helper from duplicated 8-line decode logic at two CheckExpressions.fs callsites - CheckILAttributesForUnseen now uses ILAttributes.HasWellKnownAttribute (non-caching) — same logic as CheckILAttributesForUnseenStored, no decode - Add tryGetAssemblyAttribString for single-attrib string extraction, eliminating [attr] singleton-list wrapping in IncrementalBuild.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Final cleanup: dead code, encapsulation, AllowNullLiteral migration, IlxGen single-scan Dead code removed: - WellKnownAttribs.Append (zero callers) - ILAttributesStored.CreateGiven(idx,attrs) two-arg overload (zero callers) - ILAttributesStored.GetCustomAttrs(int32) shim (ignored arg, fix import.fs) - MetadataIndex + GetOrComputeWellKnownFlags removed from il.fsi (no external callers) Encapsulation: - CheckFlag now returns needsWriteBack bool, removing need to expose .Flags - .Flags removed from WellKnownAttribs.fsi Migration: - TyconRefAllowsNull replaces 5 TryFindTyconRefBoolAttribute AllowNullLiteral sites with cached flag path (IL: HasWellKnownAttribute, F#: EntityTryGetBoolAttribute) Efficiency: - GenParamAttribs: gate tryFindValAttribByFlag with flag check, merge MarshalAs filter into single pass, pass valFlags to GenMarshal - GenMarshal: accept valFlags, skip all scans when MarshalAs absent - ComputeMethodImplAttribs: compute flags once, gate attribsHave + filterOut Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add ValueAsStaticPropertyAttribute to WellKnownValAttributes for O(1) lookup Replace List.exists with string comparison on hot path in Val.IsCompiledAsStaticPropertyWithoutField and PostInferenceChecks with cached WellKnownValAttributes flag check. - Add ValueAsStaticPropertyAttribute flag at bit 39 in WellKnownValAttributes - Add classifyValAttrib entry for the attribute - Simplify Val.IsCompiledAsStaticPropertyWithoutField to use HasWellKnownAttribute - Replace inline string scan in PostInferenceChecks with ValHasWellKnownAttribute - Expose HasWellKnownAttribute and Flags in WellKnownAttribs.fsi Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add HasWellKnownAttribute members on Entity and Val for transparent caching Add convenience members that encapsulate the CheckFlag + write-back pattern directly on Entity and Val types. This eliminates the need for callers to manually remember the write-back step when checking well-known attribute flags. - Entity.HasWellKnownAttribute(flag, computeFlags) encapsulates cache update - Val.HasWellKnownAttribute(flag, computeFlags) encapsulates cache update - EntityHasWellKnownAttribute now forwards to entity.HasWellKnownAttribute - ValHasWellKnownAttribute now forwards to v.HasWellKnownAttribute - EntityTryGetBoolAttribute uses entity.HasWellKnownAttribute for first check - Both members declared in .fsi signature files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add WellKnownMethAttribute struct to bundle correlated attribute check parameters Introduce WellKnownMethAttribute struct that bundles ILFlag, ValFlag, and AttribInfo for well-known attribute checks on MethInfo. Add MethInfoHasWellKnownAttributeSpec overload that takes the bundled struct, delegating to the original function. Update all 3 callsites to use the new struct-based API, eliminating the risk of passing mismatched flags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add ValTryGetBoolAttribute for three-state bool attribute queries on Val Mirrors EntityTryGetBoolAttribute to provide symmetric API for querying True/False/NotPresent attribute states on Val nodes. Supports flag pairs: ReflectedDefinition, DefaultValue, NoDynamicInvocation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unused parameters from AttributeChecking functions - Remove unused _g from CheckILExperimentalAttributes (private) - Remove unused _m from CheckILAttributesForUnseenStored and update .fsi - Remove unused _m from CheckFSharpAttributesForUnseen and update .fsi - Prefix newly-unused m params with _ in PropInfoIsUnseen and IsValUnseen - Add cross-reference doc comments between CheckILAttributesForUnseen variants - Update all callsites in NameResolution.fs and AttributeChecking.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Rewrite TryFindAutoOpenAttr and TryFindInternalsVisibleToAttr to use classifyILAttrib Replace hand-rolled isILAttribByName checks with the modern classifyILAttrib flag-based API for consistency with the rest of the attribute classification infrastructure. Remove unused tname_AutoOpenAttr binding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add well-known attribute API navigation guide comment block Add a comprehensive navigation comment block before the attribute helpers section in TypedTreeOps.fs. The comment documents all well-known attribute APIs organized by category: existence checks, ad-hoc checks, data extraction active patterns, bool queries, IL-level operations, cross-metadata dispatch, and classification functions. Notes that MethInfoHasWellKnownAttribute lives in AttributeChecking.fs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix verifier issues: BSL baseline, CompilerCompat test bugs, trailing newlines - Commit updated surface area baseline removing stale ILAttributesStored entries - Fix reserved keyword 'sealed' used as variable name in CompilerCompat Program.fs - Fully qualify StructRecord.Y field for cross-project resolution - Add trailing newlines to Library.fs and AttributeUsage.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add TailCallAttribute to WellKnownValAttributes for O(1) flag-based lookup - Add TailCallAttribute = (1uL <<< 40) to WellKnownValAttributes enum (.fs and .fsi) - Add TailCallAttribute classification in classifyValAttrib under Microsoft.FSharp.Core - Remove HasTailCallAttrib from TcGlobals; replace with hasTailCallAttrib helper in TailCallChecks - Helper uses O(1) flag lookup with fallback for user-defined shadow attributes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Consolidate TypeProviderAssemblyAttribute detection into classifyAssemblyAttrib Add WellKnownAssemblyAttributes.TypeProviderAssemblyAttribute flag and classify it under Microsoft.FSharp.Core.CompilerServices in classifyAssemblyAttrib. Fold detection into the existing assembly attribute classification loop in IncrementalBuild.fs and TransparentCompiler.fs, eliminating a duplicate List.exists scan over topAttrs.assemblyAttrs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fast-path DefaultMemberAttribute in indexer resolution Extract shared tryBindTyconRefAttributeCore with WellKnownILAttributes voption parameter. Both TryBindTyconRefAttribute and TryBindTyconRefAttributeWithILFlag delegate to it, eliminating code duplication while preserving the O(1) flag check fast-path on the IL metadata path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove duplicate DefaultAugmentation(false) test The test 'DefaultAugmentation(false) suppresses helpers' in AttributeUsage.fs was a near-duplicate of the more specific 'Is* discriminated union properties are unavailable with DefaultAugmentation(false)' test in DiscriminatedUnionTests.fs. Remove the duplicate per TEST-CODE-QUALITY verifier feedback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * AugmentWishHashCompare - remove 7 bools in matches * Fix MarshalAs regression: don't filter attribute before GenMarshal reads it GenParamAttribs was filtering MarshalAsAttribute from the attribs list before passing it to GenMarshal, which then couldn't find the attribute data (UnmanagedType value). Remove MarshalAs from the pre-filter mask and let GenMarshal handle its own filtering. Fixes: Marshal_fs IL baseline test (all platforms) Fixes: attributes-FSC_OPTIMIZED/FSI (Windows Desktop) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix fantomas formatting in TypedTree.fsi and TypedTreeOps.fsi Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Adam Boniecki <20281641+abonie@users.noreply.github.com>
1 parent 6f6440a commit f80d20f

47 files changed

Lines changed: 2467 additions & 1188 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/Compiler/AbstractIL/il.fs

Lines changed: 84 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,19 +1229,75 @@ type ILAttributes(array: ILAttribute[]) =
12291229

12301230
static member val internal Empty = ILAttributes([||])
12311231

1232-
[<NoEquality; NoComparison>]
1233-
type ILAttributesStored =
1234-
1235-
/// Computed by ilread.fs based on metadata index
1232+
[<Flags>]
1233+
type WellKnownILAttributes =
1234+
| None = 0u
1235+
| IsReadOnlyAttribute = (1u <<< 0)
1236+
| IsUnmanagedAttribute = (1u <<< 1)
1237+
| IsByRefLikeAttribute = (1u <<< 2)
1238+
| ExtensionAttribute = (1u <<< 3)
1239+
| NullableAttribute = (1u <<< 4)
1240+
| ParamArrayAttribute = (1u <<< 5)
1241+
| AllowNullLiteralAttribute = (1u <<< 6)
1242+
| ReflectedDefinitionAttribute = (1u <<< 7)
1243+
| AutoOpenAttribute = (1u <<< 8)
1244+
| InternalsVisibleToAttribute = (1u <<< 9)
1245+
| CallerMemberNameAttribute = (1u <<< 10)
1246+
| CallerFilePathAttribute = (1u <<< 11)
1247+
| CallerLineNumberAttribute = (1u <<< 12)
1248+
| IDispatchConstantAttribute = (1u <<< 13)
1249+
| IUnknownConstantAttribute = (1u <<< 14)
1250+
| RequiresLocationAttribute = (1u <<< 15)
1251+
| SetsRequiredMembersAttribute = (1u <<< 16)
1252+
| NoEagerConstraintApplicationAttribute = (1u <<< 17)
1253+
| DefaultMemberAttribute = (1u <<< 18)
1254+
| ObsoleteAttribute = (1u <<< 19)
1255+
| CompilerFeatureRequiredAttribute = (1u <<< 20)
1256+
| ExperimentalAttribute = (1u <<< 21)
1257+
| RequiredMemberAttribute = (1u <<< 22)
1258+
| NullableContextAttribute = (1u <<< 23)
1259+
| AttributeUsageAttribute = (1u <<< 24)
1260+
| NotComputed = (1u <<< 31)
1261+
1262+
type internal ILAttributesStoredRepr =
12361263
| Reader of (int32 -> ILAttribute[])
1237-
1238-
/// Already computed
12391264
| Given of ILAttributes
12401265

1241-
member x.GetCustomAttrs metadataIndex =
1242-
match x with
1243-
| Reader f -> ILAttributes(f metadataIndex)
1244-
| Given attrs -> attrs
1266+
[<Sealed; NoEquality; NoComparison>]
1267+
type ILAttributesStored private (metadataIndex: int32, initial: ILAttributesStoredRepr) =
1268+
[<VolatileField>]
1269+
let mutable repr = initial
1270+
1271+
[<VolatileField>]
1272+
let mutable wellKnownFlags = WellKnownILAttributes.NotComputed
1273+
1274+
member _.MetadataIndex = metadataIndex
1275+
1276+
member x.CustomAttrs: ILAttributes =
1277+
match repr with
1278+
| Given a -> a
1279+
| Reader f ->
1280+
let r = ILAttributes(f metadataIndex)
1281+
repr <- Given r
1282+
r
1283+
1284+
member x.HasWellKnownAttribute(flag: WellKnownILAttributes, compute: ILAttributes -> WellKnownILAttributes) : bool =
1285+
x.GetOrComputeWellKnownFlags(compute) &&& flag <> WellKnownILAttributes.None
1286+
1287+
member x.GetOrComputeWellKnownFlags(compute: ILAttributes -> WellKnownILAttributes) : WellKnownILAttributes =
1288+
let f = wellKnownFlags
1289+
1290+
if f <> WellKnownILAttributes.NotComputed then
1291+
f
1292+
else
1293+
let a = x.CustomAttrs
1294+
let computed = compute a
1295+
wellKnownFlags <- computed
1296+
computed
1297+
1298+
static member CreateReader(idx: int32, f: int32 -> ILAttribute[]) = ILAttributesStored(idx, Reader f)
1299+
1300+
static member CreateGiven(attrs: ILAttributes) = ILAttributesStored(-1, Given attrs)
12451301

12461302
let emptyILCustomAttrs = ILAttributes [||]
12471303

@@ -1256,18 +1312,18 @@ let mkILCustomAttrs l =
12561312
| [] -> emptyILCustomAttrs
12571313
| _ -> mkILCustomAttrsFromArray (List.toArray l)
12581314

1259-
let emptyILCustomAttrsStored = ILAttributesStored.Given emptyILCustomAttrs
1315+
let emptyILCustomAttrsStored = ILAttributesStored.CreateGiven emptyILCustomAttrs
12601316

12611317
let storeILCustomAttrs (attrs: ILAttributes) =
12621318
if attrs.AsArray().Length = 0 then
12631319
emptyILCustomAttrsStored
12641320
else
1265-
ILAttributesStored.Given attrs
1321+
ILAttributesStored.CreateGiven attrs
12661322

12671323
let mkILCustomAttrsComputed f =
1268-
ILAttributesStored.Reader(fun _ -> f ())
1324+
ILAttributesStored.CreateReader(-1, fun _ -> f ())
12691325

1270-
let mkILCustomAttrsReader f = ILAttributesStored.Reader f
1326+
let mkILCustomAttrsReader f = ILAttributesStored.CreateReader(-1, f)
12711327

12721328
type ILCodeLabel = int
12731329

@@ -1791,7 +1847,7 @@ type ILParameter =
17911847
MetadataIndex: int32
17921848
}
17931849

1794-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
1850+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
17951851

17961852
override x.ToString() =
17971853
x.Name |> Option.defaultValue "<no name>"
@@ -1809,7 +1865,7 @@ type ILReturn =
18091865

18101866
override x.ToString() = "<return>"
18111867

1812-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
1868+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
18131869

18141870
member x.WithCustomAttrs(customAttrs) =
18151871
{ x with
@@ -1870,7 +1926,7 @@ type ILGenericParameterDef =
18701926
MetadataIndex: int32
18711927
}
18721928

1873-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
1929+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
18741930

18751931
/// For debugging
18761932
[<DebuggerBrowsable(DebuggerBrowsableState.Never)>]
@@ -1916,13 +1972,7 @@ type InterfaceImpl =
19161972
mutable CustomAttrsStored: ILAttributesStored
19171973
}
19181974

1919-
member x.CustomAttrs =
1920-
match x.CustomAttrsStored with
1921-
| ILAttributesStored.Reader f ->
1922-
let res = ILAttributes(f x.Idx)
1923-
x.CustomAttrsStored <- ILAttributesStored.Given res
1924-
res
1925-
| ILAttributesStored.Given attrs -> attrs
1975+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
19261976

19271977
static member Create(ilType: ILType, customAttrsStored: ILAttributesStored) =
19281978
{
@@ -2029,7 +2079,7 @@ type ILMethodDef
20292079
| Some attrs -> attrs)
20302080
)
20312081

2032-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs metadataIndex
2082+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
20332083

20342084
member x.SecurityDecls = x.SecurityDeclsStored.GetSecurityDecls x.MetadataIndex
20352085

@@ -2266,7 +2316,7 @@ type ILEventDef
22662316

22672317
member _.MetadataIndex = metadataIndex
22682318

2269-
member x.CustomAttrs = customAttrsStored.GetCustomAttrs x.MetadataIndex
2319+
member x.CustomAttrs = customAttrsStored.CustomAttrs
22702320

22712321
member x.With(?eventType, ?name, ?attributes, ?addMethod, ?removeMethod, ?fireMethod, ?otherMethods, ?customAttrs) =
22722322
ILEventDef(
@@ -2342,7 +2392,7 @@ type ILPropertyDef
23422392
member x.Init = init
23432393
member x.Args = args
23442394
member x.CustomAttrsStored = customAttrsStored
2345-
member x.CustomAttrs = customAttrsStored.GetCustomAttrs x.MetadataIndex
2395+
member x.CustomAttrs = customAttrsStored.CustomAttrs
23462396
member x.MetadataIndex = metadataIndex
23472397

23482398
member x.With(?name, ?attributes, ?setMethod, ?getMethod, ?callingConv, ?propertyType, ?init, ?args, ?customAttrs) =
@@ -2418,7 +2468,7 @@ type ILFieldDef
24182468
member _.Offset = offset
24192469
member _.Marshal = marshal
24202470
member x.CustomAttrsStored = customAttrsStored
2421-
member x.CustomAttrs = customAttrsStored.GetCustomAttrs x.MetadataIndex
2471+
member x.CustomAttrs = customAttrsStored.CustomAttrs
24222472
member x.MetadataIndex = metadataIndex
24232473

24242474
member x.With
@@ -2677,8 +2727,6 @@ type ILTypeDef
26772727
metadataIndex: int32
26782728
) =
26792729

2680-
let mutable customAttrsStored = customAttrsStored
2681-
26822730
let hasFlag flag = additionalFlags &&& flag = flag
26832731

26842732
new
@@ -2829,13 +2877,7 @@ type ILTypeDef
28292877
customAttrs = defaultArg customAttrs x.CustomAttrsStored
28302878
)
28312879

2832-
member x.CustomAttrs: ILAttributes =
2833-
match customAttrsStored with
2834-
| ILAttributesStored.Reader f ->
2835-
let res = ILAttributes(f x.MetadataIndex)
2836-
customAttrsStored <- ILAttributesStored.Given res
2837-
res
2838-
| ILAttributesStored.Given res -> res
2880+
member x.CustomAttrs: ILAttributes = customAttrsStored.CustomAttrs
28392881

28402882
member x.SecurityDecls = x.SecurityDeclsStored.GetSecurityDecls x.MetadataIndex
28412883

@@ -2993,7 +3035,7 @@ type ILNestedExportedType =
29933035
MetadataIndex: int32
29943036
}
29953037

2996-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
3038+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
29973039

29983040
override x.ToString() = "exported type " + x.Name
29993041

@@ -3017,7 +3059,7 @@ and [<NoComparison; NoEquality>] ILExportedTypeOrForwarder =
30173059

30183060
member x.IsForwarder = x.Attributes &&& enum<TypeAttributes> 0x00200000 <> enum 0
30193061

3020-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
3062+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
30213063

30223064
override x.ToString() = "exported type " + x.Name
30233065

@@ -3057,7 +3099,7 @@ type ILResource =
30573099
| ILResourceLocation.Local bytes -> bytes.GetByteMemory()
30583100
| _ -> failwith "GetBytes"
30593101

3060-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
3102+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
30613103

30623104
override x.ToString() = "resource " + x.Name
30633105

@@ -3104,7 +3146,7 @@ type ILAssemblyManifest =
31043146
MetadataIndex: int32
31053147
}
31063148

3107-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
3149+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
31083150

31093151
member x.SecurityDecls = x.SecurityDeclsStored.GetSecurityDecls x.MetadataIndex
31103152

@@ -3151,7 +3193,7 @@ type ILModuleDef =
31513193
| None -> false
31523194
| _ -> true
31533195

3154-
member x.CustomAttrs = x.CustomAttrsStored.GetCustomAttrs x.MetadataIndex
3196+
member x.CustomAttrs = x.CustomAttrsStored.CustomAttrs
31553197

31563198
override x.ToString() = "assembly " + x.Name
31573199

src/Compiler/AbstractIL/il.fsi

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -878,15 +878,45 @@ type ILAttributes =
878878

879879
static member internal Empty: ILAttributes
880880

881+
[<Flags>]
882+
type WellKnownILAttributes =
883+
| None = 0u
884+
| IsReadOnlyAttribute = (1u <<< 0)
885+
| IsUnmanagedAttribute = (1u <<< 1)
886+
| IsByRefLikeAttribute = (1u <<< 2)
887+
| ExtensionAttribute = (1u <<< 3)
888+
| NullableAttribute = (1u <<< 4)
889+
| ParamArrayAttribute = (1u <<< 5)
890+
| AllowNullLiteralAttribute = (1u <<< 6)
891+
| ReflectedDefinitionAttribute = (1u <<< 7)
892+
| AutoOpenAttribute = (1u <<< 8)
893+
| InternalsVisibleToAttribute = (1u <<< 9)
894+
| CallerMemberNameAttribute = (1u <<< 10)
895+
| CallerFilePathAttribute = (1u <<< 11)
896+
| CallerLineNumberAttribute = (1u <<< 12)
897+
| IDispatchConstantAttribute = (1u <<< 13)
898+
| IUnknownConstantAttribute = (1u <<< 14)
899+
| RequiresLocationAttribute = (1u <<< 15)
900+
| SetsRequiredMembersAttribute = (1u <<< 16)
901+
| NoEagerConstraintApplicationAttribute = (1u <<< 17)
902+
| DefaultMemberAttribute = (1u <<< 18)
903+
| ObsoleteAttribute = (1u <<< 19)
904+
| CompilerFeatureRequiredAttribute = (1u <<< 20)
905+
| ExperimentalAttribute = (1u <<< 21)
906+
| RequiredMemberAttribute = (1u <<< 22)
907+
| NullableContextAttribute = (1u <<< 23)
908+
| AttributeUsageAttribute = (1u <<< 24)
909+
| NotComputed = (1u <<< 31)
910+
881911
/// Represents the efficiency-oriented storage of ILAttributes in another item.
882-
[<NoEquality; NoComparison>]
912+
[<Sealed; NoEquality; NoComparison>]
883913
type ILAttributesStored =
884-
/// Computed by ilread.fs based on metadata index
885-
| Reader of (int32 -> ILAttribute[])
886-
/// Already computed
887-
| Given of ILAttributes
914+
member CustomAttrs: ILAttributes
915+
916+
member HasWellKnownAttribute: flag: WellKnownILAttributes * compute: (ILAttributes -> WellKnownILAttributes) -> bool
888917

889-
member GetCustomAttrs: int32 -> ILAttributes
918+
static member CreateReader: idx: int32 * f: (int32 -> ILAttribute[]) -> ILAttributesStored
919+
static member CreateGiven: attrs: ILAttributes -> ILAttributesStored
890920

891921
/// Method parameters and return values.
892922
[<RequireQualifiedAccess; NoEquality; NoComparison>]

0 commit comments

Comments
 (0)