Skip to content

Split TypedTreeOps.fs (12,569 lines) into 7 focused files#19521

Open
T-Gro wants to merge 34 commits intomainfrom
refactoring/typedtreeops
Open

Split TypedTreeOps.fs (12,569 lines) into 7 focused files#19521
T-Gro wants to merge 34 commits intomainfrom
refactoring/typedtreeops

Conversation

@T-Gro
Copy link
Copy Markdown
Member

@T-Gro T-Gro commented Mar 30, 2026

Motivation

TypedTreeOps.fs was the 3rd largest file in the compiler at 12,569 lines. Unlike the top 2 (CheckExpressions.fs, IlxGen.fs) which are dominated by monolithic mutual-recursion chains, TypedTreeOps had 23 small independent function groups and ~9,700 standalone functions — making it the best candidate for splitting.

Being a single flat module, it became a natural "catch-all" destination for any utility that touched the typed tree. Over time this led to arbitrary function placement — container type helpers next to XML doc encoding, free variable accumulators next to attribute classification, expression builders next to measure algebra. The lack of internal structure made it hard to discover what is available, understand boundaries, or know where new code should go.

This PR splits it into 7 files organized by compilation phase, with 32 [<AutoOpen>] modules organized by semantic purpose. All 69 files that open FSharp.Compiler.TypedTreeOps require zero changes — the [<AutoOpen>] attribute preserves full API compatibility.

Structure

📁 src/Compiler/TypedTree/
│
├── TypedTreeOps.Remap.fs                    (1,695 lines)
│   Foundation: type-level substitution, construction, equivalence
│   ├── TypeRemapping         — Type parameter substitution (remap*, inst*, copy*)
│   ├── MeasureOps            — Measure unit algebra and normalization
│   ├── TypeBuilders          — Type constructors (mkFunTy, mkByrefTy, mkArrayTy…)
│   ├── TypeAbbreviations     — Type abbreviation reduction and application
│   ├── TypeDecomposition     — Type stripping, destruction, predicates (strip*, dest*, is*, try*)
│   └── TypeEquivalence       — Type equivalence and comparison (*AEquiv*)
│
├── TypedTreeOps.ExprConstruction.fs         (1,563 lines)
│   Expression building, type testing, container type helpers
│   ├── ExprConstruction      — Expression node builders (mkLambda, mkLet, mkBind, mkWhile…)
│   ├── TypedTreeCollections  — Stamp-based collection types (ValHash, ValMultiMap, TyconRefMultiMap)
│   ├── TypeTesters           — Type predicates and metadata (is*Ty, actual*, metadata queries)
│   └── CommonContainers     — Built-in container helpers (Option, RefCell, Nullable, Choice, List…)
│
├── TypedTreeOps.FreeVars.fs                 (1,552 lines)
│   Free variable analysis and display/pretty-printing
│   ├── FreeTypeVars          — Free type variable accumulation (acc*, free*, Collect*, empty*/union*)
│   ├── MemberRepresentation  — Member type shape queries (Get*MemberType*, Partition*, ArgInfos*)
│   ├── PrettyTypes           — Type prettification for diagnostics (Prettify*, fullDisplayText*)
│   └── SimplifyTypes         — Type constraint simplification and hierarchy
│
├── TypedTreeOps.Attributes.fs               (2,547 lines)
│   IL/F# attribute infrastructure and debug printing
│   ├── ILExtensions          — IL attribute decoding and well-known attribute matching
│   ├── AttributeHelpers      — F# attribute classification, entity/val flags, compilation mapping
│   ├── ByrefAndSpanHelpers   — Byref-like and Span type helpers (depend on attribute infra)
│   └── DebugPrint            — Debug layout functions for typed tree nodes (*L, show*)
│
├── TypedTreeOps.Remapping.fs                (2,929 lines)
│   Signature operations and expression-level remapping
│   ├── SignatureOps          — Signature remapping, hiding, module wrapping (Compute*, IsHidden*)
│   ├── ExprFreeVars          — Expression-level free variable analysis (acc*, free*)
│   ├── ExprRemapping         — Expression remapping, copying, instantiation (remap*, copy*, inst*)
│   └── ExprAnalysis          — Expression shape queries, mutability, witness types, mkApps
│
├── TypedTreeOps.ExprOps.fs                  (2,362 lines)
│   Expression operations: address-of, folding, intrinsic makers
│   ├── AddressOps            — Address-of operations and mutability analysis
│   ├── ExprFolding           — Generic expression tree folding (FoldExpr, FoldImplFile)
│   ├── Makers                — Intrinsic expression constructors (179 mk* for calls, boxing, seq…)
│   └── ExprTransforms        — Expression transformations (Adjust*, Make*BetaReduce, eta-expand)
│
└── TypedTreeOps.Transforms.fs               (3,018 lines)
    Late-stage transforms: encoding, nullness, rewriting, lowering patterns
    ├── XmlDocSignatures      — XML documentation signature encoding
    ├── NullnessAnalysis      — Null semantics classification (TypeNull*, nullnessOfTy)
    ├── TypeTestsAndPatterns  — Type test helpers and comparison/equality patterns
    ├── Rewriting             — Generic expression tree rewriting (RewriteExpr, RewriteImplFile)
    ├── TupleCompilation      — Tuple compilation and optimized range loops
    ├── ConstantEvaluation    — Compile-time constant evaluation and IL field init
    ├── ResumableCodePatterns — Active patterns for resumable code lowering
    └── SeqExprPatterns       — Active patterns for seq expression lowering

Key design decisions

  • [<AutoOpen>] on every module — zero caller changes needed. The 69 files that open FSharp.Compiler.TypedTreeOps continue to work unchanged.
  • Compilation order respected — F# requires earlier files to be independent of later ones. The 7-file order follows the dependency graph: types → expressions → free vars → attributes → remapping → operations → transforms.

T-Gro and others added 30 commits March 30, 2026 18:29
Extract lines 1-1230 from TypedTreeOps.fs into a new file pair
using namespace FSharp.Compiler.TypedTreeOps with three AutoOpen modules:

- TypeRemapping: TyparMap, TyconRefMap, ValMap, Remap types and the
  remapTypeAux/remapValRef let-rec chain plus instantiation wrappers
- TypeConstruction: type construction/destruction/query functions,
  Erasure DU, strip/dest/is functions
- TypeEquivalence: TypeEquivEnv, the traitsAEquivAux/typeEquivAux
  let-rec chain, equivalence wrappers, getErasedTypes

Files are not yet added to the fsproj - that happens in a later sprint.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract expression construction primitives, collection types, and
arity/metadata analysis from TypedTreeOps.fs lines ~1231-2260 into
TypedTreeOps.ExprConstruction.fs with matching .fsi file.

Organized into 3 [<AutoOpen>] modules:
- ExprConstruction: orderings, type builders, expr constructors,
  MatchBuilder, lambda/let/bind builders
- CollectionTypes: ValHash, ValMultiMap, TyconRefMultiMap
- ArityAndMetadata: rescoping, field accessors, type testers,
  TypeDefMetadata, free tyvar accumulators

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create File 3 of the TypedTreeOps split: free type variable analysis,
pretty-printing, and display environment.

Structure:
- FreeTypeVars module: FreeVarOptions, collection options, two recursive
  chains (accFreeTycon..accFreeInVal, boundTyparsLeftToRight..accFreeInTypesLeftToRight),
  addFreeInModuleTy, public wrappers, checkMemberVal/checkMemberValRef
- Display module: GetFSharpViewOfReturnType, TraitConstraintInfo extension,
  member type functions, nested PrettyTypes and SimplifyTypes modules,
  GenericParameterStyle, DisplayEnv, display text helpers, superOfTycon

Files are not yet added to the project file (will happen in final integration sprint).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create File 4 of the TypedTreeOps split: IL extensions, attribute helpers,
and debug printing.

Structure:
- ILExtensions module: IL attribute detection functions (isILAttribByName,
  classifyILAttrib, computeILWellKnownFlags, tryFindILAttribByFlag,
  (|ILAttribDecoded|_|)) and type extensions on ILAttributesStored,
  ILTypeDef, ILMethodDef, ILFieldDef, ILAttributes
- AttributeHelpers module: F# attribute discovery (resolveAttribPath,
  classifyEntityAttrib, classifyValAttrib, computeEntityWellKnownFlags,
  EntityHasWellKnownAttribute, etc.), type construction helpers, and
  type ValRef extension members
- DebugPrinting module: nested DebugPrint module with showType, showExpr,
  layout functions (exprL, bindingL, atomL, etc.), and
  wrapModuleOrNamespace* helpers

The DebugPrint module is nested inside DebugPrinting to preserve the
FSharp.Compiler.TypedTreeOps.DebugPrint reference path used by callers.

All let rec ... and chains inside DebugPrint are kept intact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove 12 val declarations from .fsi that have no implementations in the
.fs file. These were from original TypedTreeOps.fs lines outside the
~3523-5462 extraction range:

- isInByrefTy, isOutByrefTy, isByrefTy, isNativePtrTy (original ~L1907-1923)
- EvalLiteralExprOrAttribArg, EvaledAttribExprEquality (original ~L10943-10969)
- IsSimpleSyntacticConstantExpr, ConstToILFieldInit (original ~L10646-10951)
- Int32Expr, SpecialComparableHeadType, SpecialEquatableHeadType,
  SpecialNotEquatableHeadType (original ~L9986-11049)
- TyparTy|NullableTypar|... (incomplete signature causing FS0010 parse error)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create the 5th split file from TypedTreeOps.fs containing:
- SignatureOps: signature repackage/hiding types and operations
- ExprFreeVars: expression-level free variable analysis (24-function chain)
- ExprRemapping: expression remapping and copying (57-function chain)
- ExprShapeQueries: type inference, remark, decision tree simplification

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create File 6 of the TypedTreeOps split: address-of operations, expression
folding, intrinsic call wrappers, and higher-level expression helpers.

Extracts original TypedTreeOps.fs lines ~7651-9599 into 4 modules:
- AddressOps: Mutates DU, address-of helpers, mkExprAddrOfExpr, field gets
- ExprFolding: IterateRecursiveFixups, ExprFolder/ExprFolders, FoldExpr
- IntrinsicCalls: 105 mkCall* wrappers, literal constructors, compilation attrs
- ExprHelpers: MakeApplicationAndBetaReduce, lambda tupling, subsumption, etc.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create the final split file containing type encoding, expression rewriting,
tuple compilation, integral constants, and attribute checking.

Structure:
- TypeEncoding: typeEnc, XML doc encoding, nullness helpers, compiled-as
- Rewriting: ExprRewritingEnv, RewriteExpr, export remapping
- TupleCompilation: mkCompiledTuple, IntegralConst (nested), mkFastForLoop
- AttribChecking: CombineCcuContentFragments, Seq patterns, resumable code

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tions, fix module placement

- Remove duplicate declarations: HasConstraint, IsTyparTyWithConstraint, doesActivePatternHaveFreeTypars
- Remove declarations belonging to other files (FreeVars: GetMemberTypeInMemberForm,
  PartitionValTypars*, CountEnclosingTyparsOfActualParentOfVal, ReturnTypeOfPropertyVal,
  ArgInfosOfPropertyVal, ArgInfosOfMember; ExprOps: mkCallDispose, mkCallSeq, mkCallTypeTest)
- Move GetTypeOfIntrinsicMemberInCompiledForm from TypeEncoding to TupleCompilation
- Move TraitWitnessInfoHashMap/EmptyTraitWitnessInfoHashMap from TupleCompilation to AttribChecking
- Move mkDebugPoint and IfThenElseExpr from AttribChecking to TupleCompilation
- Remove TraitConstraintInfo type extension (belongs to FreeVars, not this file)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ix cross-file deps

Replace the monolithic TypedTreeOps.fs (12,569 lines) and TypedTreeOps.fsi
(3,094 lines) with 7 focused files:

1. TypedTreeOps.Remap - Type remapping, instantiation, equivalence
2. TypedTreeOps.ExprConstruction - Expression/type construction helpers
3. TypedTreeOps.FreeVars - Free variable collection, display helpers
4. TypedTreeOps.Attributes - IL extensions, attribute classification
5. TypedTreeOps.Remapping - Signature ops, expr free vars, expr remapping
6. TypedTreeOps.ExprOps - Address ops, folding, intrinsic calls
7. TypedTreeOps.Transforms - Debug printing, pattern matching, transforms

All files use namespace FSharp.Compiler.TypedTreeOps with [<AutoOpen>]
internal modules, so the 69 callers doing 'open FSharp.Compiler.TypedTreeOps'
required zero modifications.

Integration fixes:
- Added missing opens (FSharp.Compiler, Internal.Utilities.Collections,
  FSharp.Compiler.Syntax, FSharp.Compiler.CompilerGlobalState)
- Fixed .fsi signature mismatches (generic vs concrete type params)
- Exposed cross-file functions in .fsi files
- Fixed type name references (Mutability -> ValMutability, etc.)
- Applied dotnet fantomas formatting to all 14 files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… from file 4

Move container type helpers (Option, RefCell, Nullable, Choice, Byref,
LinqExpression, etc.) from AttributeHelpers in TypedTreeOps.Attributes.fs
to a new CommonContainers module in TypedTreeOps.ExprConstruction.fs.

These functions only depend on tyconRefEq, stripTyEqns, tryTcrefOfAppTy,
argsOfAppTy from file 1, not attribute infrastructure.

Create ByrefAndSpanHelpers module in file 4 for span/byref-like functions
that depend on TyconRefHasAttributeByName (must stay in file 4).

All modules use [<AutoOpen>] so callers need no changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pers

- Rename ArityAndMetadata → TypeTesters (core content is 46 is*Ty predicates)
- Rename IntrinsicCalls → Makers (174 mk* expression constructors)
- Move mkForallTy/mkForallTyIfNeeded/+-> from ExprConstruction to TypeConstruction
- Move commaEncs/angleEnc/typarEnc/ticksAndArgCountTextOfTyconRef from ExprHelpers to TypeEncoding

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Free var accumulators TypeTesters→FreeTypeVars
- Attribute helpers Makers→AttributeHelpers
- mkFunTy/mkIteratedFunTy ExprConstruction→TypeConstruction
- mk*Ty ExprShapeQueries→TypeConstruction
- mk*Type Makers→TypeConstruction
- mk*Test TypeEncoding→Makers (except mkIsInstConditional which
  depends on canUseTypeTestFast in Transforms.fs, compiled after
  ExprOps.fs)
- Linear* APs: kept in SignatureOps (moving to ExprShapeQueries
  impossible - ExprShapeQueries is at end of Remapping.fs but
  Linear* are used in ExprFreeVars and ExprRemapping modules
  which appear earlier in the same file)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The module contains tuple compilation, fast for loops, integral range
detection, constant evaluation, and loop optimization — not just tuples.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- underlyingTypeOfEnumTy/normalizeEnumTy ExprRemapping→TypeTesters
- ClearValReprInfo ExprRemapping→ExprHelpers
- mkArray AddressOps→Makers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ules

- isResumableCodeTy/isReturnsResumableCodeTy/isFSharpExceptionTy → TypeTesters
- serializeEntity + helpers → DebugPrint
- Linear* APs SignatureOps → ExprFreeVars (same file, earlier position)
- mkApps group ExprShapeQueries → Makers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… remapping

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Last 2 cross-model agreed misplacements resolved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… modules

- CompileAsEvent/ValCompileAsEvent/ModuleNameIsMangled/MemberIsCompiledAsInstance → AttributeHelpers
- valOfBind/valsOfBinds → ExprConstruction
- WhileExpr/TryWithExpr/TryFinallyExpr/IntegerForLoopExpr APs → ExprShapeQueries
- mkDebugPoint/(|InnerExprPat|)/(|Int32Expr|_|) → ExprConstruction or earlier

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…AndPatterns

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ensionAndMiscHelpers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ns, TypeDecomposition

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…, split LoopAndConstantOptimization

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…xprShapeQueries→ExprAnalysis

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s, move patterns from TupleCompilation

- Rename CollectionTypes → TypedTreeCollections
- Move destInt32/destThrow/isThrow/isIDelegateEventType/destIDelegateEventType Makers→ExprTransforms
- Move (|Int32Expr|_|)/(|IntegralRange|_|) TupleCompilation→ConstantEvaluation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
70% of vals operate on TType, 12% on Tycon, 5% on Val — 'Testers' better
describes the is*/dest*/strip* nature than 'Queries'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@T-Gro T-Gro requested a review from a team as a code owner March 30, 2026 16:36
@T-Gro T-Gro added the NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes label Mar 30, 2026
@T-Gro T-Gro requested a review from abonie March 30, 2026 16:36
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

⚠️ Release notes required, but author opted out

Warning

Author opted out of release notes, check is disabled for this pull request.
cc @dotnet/fsharp-team-msft

T-Gro and others added 3 commits March 31, 2026 10:53
The [<AutoOpen>] split brought multiple record types with 'stackGuard'
field into scope (FreeVarOptions, RemapContext, cenv). Add type annotation
to resolve ambiguity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

1 participant