Support OverloadResolutionPriority and a most-concrete tiebreaker - #19277
Open
T-Gro wants to merge 139 commits into
Open
Support OverloadResolutionPriority and a most-concrete tiebreaker#19277T-Gro wants to merge 139 commits into
T-Gro wants to merge 139 commits into
Conversation
- Create OverloadResolutionRules.fs with TiebreakRule record type - Extract all 12 existing rules from better() function into DSL format - Add placeholder for new 'MoreConcrete' rule at priority 13 - Include evaluateTiebreakRules function for rule evaluation - Add import of OverloadResolutionRules module to ConstraintSolver.fs - Update FSharp.Compiler.Service.fsproj with new files Rules documented with priority, name, and description: 1. NoTDC - Prefer no type-directed conversions 2. LessTDC - Prefer less type-directed conversion 3. NullableTDC - Prefer nullable TDC only 4. NoWarnings - Prefer no 'less generic' warnings 5. NoParamArray - Prefer no param array usage 6. PreciseParamArray - Prefer more precise param array type 7. NoOutArgs - Prefer no out args 8. NoOptionalArgs - Prefer no optional args 9. UnnamedArgs - Compare unnamed args by subsumption 10. PreferNonExtension - Prefer intrinsic over extension 11. ExtensionPriority - Prefer recently opened extension 12. PreferNonGeneric - Prefer non-generic methods 13. MoreConcrete (placeholder) - Most concrete tiebreaker from RFC 14. NullableOptionalInterop - F# 5.0 all args comparison 15. PropertyOverride - Prefer more derived property type
Add the core type concreteness comparison algorithm as specified in section-algorithm.md: - compareTypeConcreteness: Compares types under the 'more concrete' partial ordering - aggregateComparisons: Implements dominance rule for pairwise comparisons - countTyparConstraints: Helper to count constraints on type parameters Handles all 8 TType cases: - TType_var: Compares by constraint count - TType_app: Compares type arguments pairwise when constructors match - TType_tuple: Compares elements pairwise - TType_fun: Compares domain and range - TType_anon: Compares anonymous record fields - TType_measure: Measures are equal or incomparable - TType_forall: Compares body with aligned bound variables - Default: Different structural forms are incomparable Implements subtask 4 of the RFC FS-XXXX: Most Concrete Tiebreaker.
- Add new tiebreaker rule after 'prefer non-generic methods' (rule 12) - Only activates when BOTH candidates have non-empty CalledTyArgs - Uses compareTypeConcreteness to compare type arguments - Applies dominance rule: better in at least one position, not worse in any - Positioned before F# 5.0 NullableOptionalInterop rule - Update DSL placeholder documentation to reflect implementation
- Create tests/FSharp.Compiler.ComponentTests/Conformance/Tiebreakers/ directory - Add TiebreakerTests.fs with module structure and helper functions - Include placeholder test and RFC example tests - Configure for Debug build and net10 TFM - All 3 tests pass
- Example 1: Option<'t> vs Option<int> - resolves to more concrete - Example 2: 't vs Option<'t> - expects ambiguity (structural comparison not yet implemented) - Example 3: Option<Option<'t>> vs Option<Option<int>> - resolves to nested int - Example 4: list<Option<Result<'t,exn>>> vs list<Option<Result<int,exn>>> - deep nesting works All 7 tiebreaker tests pass with dotnet test --filter Tiebreakers -c Debug
- Add test for Result<int,string> selecting fully concrete overload (Example 5) - Add test for incomparable types (Result<int,'e> vs Result<'t,string>) producing FS0041 (Example 6) - Add tests verifying partial order behavior with helpful error messages - Document current limitation: partial concreteness comparison between fully generic and partially concrete types remains ambiguous - Add additional tests for tuple-like scenarios and three-way comparisons All 14 tiebreaker tests pass.
Implement tests for the primary motivating use cases:
- Example 7: ValueTask constructor scenario (Task<'T> vs 'T disambiguation)
- Example 8: CE Source overloads (FsToolkit AsyncResult pattern)
- Example 9: CE Bind with Task types (TaskBuilder pattern)
Tests document both working cases (Task<'a> vs 't with wrapped types)
and cases that remain ambiguous pending structural comparison implementation
('T vs Task<'T> when type shapes differ).
Additional real-world pattern tests:
- Source with Result types vs generic
- Nested Task<Result<...>> types
All 22 tiebreaker tests pass.
- Example 10: Verify existing Rule 8 (prefer no optional) takes priority over the 'more concrete' tiebreaker - Example 11: When both overloads have optional params, concreteness breaks the tie (Option<int> vs Option<'t>) - Example 12: ParamArray with generic element types - concreteness resolves Option<int>[] vs Option<'t>[] Additional coverage: - Multiple optional params test - Nested generics with optional params - ParamArray with Result element types - Combined optional and ParamArray scenarios - ParamArray vs explicit array ambiguity documentation All 33 Tiebreaker tests pass.
Tests covering: - Intrinsic methods ALWAYS preferred over extensions (Rule 8) - Less concrete intrinsic still wins over more concrete extension - Same-module extensions resolved by concreteness - SRTP resolution following same rules - C# style extensions in F# - Extension priority precedence over concreteness - Incomparable concreteness remains ambiguous - FsToolkit pattern documentation
Implements subtask 12: byref and Span tests from section-byref-span.md Tests added: - Span<byte> vs Span<'T> selecting concrete element type - ReadOnlySpan element type comparison (concrete vs generic) - T > inref<T> adhoc rule verification - Span with nested generics (Option<int> vs Option<'T>) - inref with nested generics (Result<int,exn> vs Result<'T,exn>) - Adhoc rule priority over concreteness test All 53 tiebreaker tests pass.
Implements subtask 13: Adds tests for constraint and TDC interaction: - Example 15 constrained type variable tests (documents FS0438 limitation) - TDC priority tests (no TDC > less TDC > concreteness) - Func adhoc rule interaction tests - Nullable adhoc rule interaction tests (T > Nullable<T>) Tests verify TDC rules have higher priority than concreteness tiebreaker, and adhoc rules (Func, inref, Nullable) apply before concreteness. All 65 tiebreaker tests pass.
Adds 27 new test scenarios beyond RFC examples, covering: - SRTPs with generic vs concrete (3 tests) - Byref/inref/outref combinations (4 tests) - Anonymous record types (3 tests) - Units of measure (4 tests) - F#-specific types: Async, MailboxProcessor, Lazy, Choice, ValueOption, ValueTask (8 tests) - Computation expressions: seq, list, async (3 tests) - Discriminated unions: Result, custom Tree (2 tests) All 91 tiebreaker tests pass.
…ameter types Sprint 1: The core algorithm fix Changes: - Compare formal (uninstantiated) parameter types using FormalMethodInst instead of comparing CalledTyArgs (which are already instantiated after type inference) - This enables proper comparison for cases like: - 't vs Option<'t> (Option wins - more concrete structure) - Task<'T> vs 'T (Task wins for Task<int> argument) - Async<Result<'ok,'e>> vs Async<'t> (Result wins for Result argument) - Result<int,'e> vs Result<'ok,'e> (partial concreteness - int wins) The fix correctly resolves overloads where one method's parameter type has more concrete structure than another, even when both methods are generic. Updated 7 tests from shouldFail to shouldSucceed: - Example 2: 't vs Option<'t> - Example 5: Partial concreteness (int ok, string error) - Example 7: ValueTask Task<T> vs T - Example 8: CE Source FsToolkit pattern - Real-world pattern: Source with Result types - FsToolkit pattern: same module extensions All 95 tiebreaker tests pass.
…gured Verified DoD: - Build succeeds with 0 errors - All 91 tiebreaker tests pass - Example 2,5,7,8: use shouldSucceed (correctly) - Example 6: uses shouldFail for incomparable case (correctly) No code changes needed - Sprint 1 already configured expectations properly.
- Add FSComp.txt entries for FS3575 (tcMoreConcreteTiebreakerUsed) and FS3576 (tcGenericOverloadBypassed) - Register both warnings as off by default in CompilerDiagnostics.fs - Add wasConcretenessTiebreaker helper in ConstraintSolver.fs to detect when concreteness rule decided - Emit warning when concreteness tiebreaker is used and --warnon:3575 is enabled - Add tests verifying warning is emitted when enabled and not emitted by default
- Add MoreConcreteTiebreaker to LanguageFeature enum (F# 10.0) - Gate concreteness tiebreaker logic in better() with SupportsFeature check - Gate wasConcretenessTiebreaker helper similarly - Add feature string to FSComp.txt
Sprint 2 audit: Verified all 14 implementable RFC examples from section-examples.md have corresponding tests in TiebreakerTests.fs. Coverage mapping: - Examples 1-14: All tested with explicit test names and line numbers - Example 15: Confirmed deferred (FS0438 language limitation) 93/93 tiebreaker tests passing.
Sprint 3: Documentation-only changes to track deferred future work: 1. TiebreakerTests.fs: Enhanced comment block for Example 15 test explaining F# language limitation (FS0438 prevents constraint-only overloading) 2. ConstraintSolver.fs: Added TODO comment at aggregateComparisons function for future enhanced FS0041 error message that explains why types are incomparable 3. VISION.md: Updated deferred items with code location cross-references No functional changes - all 93 tiebreaker tests pass.
- Remove .ralph/ folder (workflow artifacts not needed in final PR) - Add docs/TIEBREAKERS_DESIGN.md with comprehensive feature documentation - Release notes have PR number placeholders (to be updated when PR is created)
…utionRules Sprint 1 deliverables: - Add aggregateComparisons helper for dominance-based comparison - Add compareTypeConcreteness function for type concreteness ordering - Export both functions in signature file - OverloadResolutionContext already has all needed fields (g, amap, m, ndeep) These functions are now available for use by the rule engine in future sprints. The implementation matches the existing algorithm in ConstraintSolver.fs but is now accessible from OverloadResolutionRules.fs.
- Replace ~140 lines of duplicated if-then-else chains in ConstraintSolver.fs with calls to evaluateTiebreakRules() and wasDecidedByRule() from OverloadResolutionRules module - Fix moreConcreteRule to actually perform the comparison (was placeholder returning 0) - Add wasDecidedByRule helper to check if a specific rule was the deciding factor - Remove unused local helper functions from ConstraintSolver.fs - All 93 tiebreaker tests pass This eliminates the code duplication identified in VISION.md between better() and wasConcretenessTiebreaker().
This function computes position-by-position comparison results when two types are incomparable under the concreteness ordering. It returns Some with a list of (position, ty1Arg, ty2Arg, comparison) tuples when types have mixed results (incomparable), or None when one type dominates or they are equal. This is Sprint 1 of the enhanced FS0041 error message implementation.
- Add IncomparableConcretenessInfo type and explainIncomparableMethodConcreteness function - Extend PossibleCandidates to carry incomparable concreteness details - Format enhanced message in CompilerDiagnostics.fs showing which type args favor each method - Add csIncomparableConcreteness message resource to FSComp.txt - Update test to verify enhanced message content When overload resolution fails due to incomparable type concreteness, the error message now explains: 'Neither candidate is strictly more concrete than the other: - Compare is more concrete at position 1 - Compare is more concrete at position 2'
All DoD items verified: - Build succeeds with 0 errors - Enhanced FS0041 message shows per-position concreteness details - FSComp.txt string resource csIncomparableConcreteness added - All 93 TiebreakerTests pass The functionality was already implemented in earlier sprints.
DoD verified: - Build succeeds with 0 errors - Test at TiebreakerTests.fs:252-268 verifies enhanced FS0041 message - Test checks for 'Neither candidate is strictly more concrete' - Test checks for position-specific concreteness explanation - All 93 TiebreakerTests pass
… 15) - Add countTypeParamConstraints helper to count effective constraints (CoercesTo, IsNonNullableStruct, IsReferenceType, MayResolveMember, etc.) - Update compareTypeConcreteness to compare constraint counts when both types are type variables (RFC section-algorithm.md lines 136-146) - Remove 'deferred' comments as constraint comparison is now implemented - Update Example 15 test to expect success (constrained overload wins) All 97 tiebreaker tests pass.
…dings CI fix (net472 Desktop jobs): - TiebreakerTests: mark "overload resolution priority still wins over concreteness" [<FactForNETCOREAPP>]; its body uses [<OverloadResolutionPriority>], a .NET 9+ BCL type that cannot be authored on net472, so it must skip there like its siblings. Quality (3 cross-model rubber ducks: clarity/compactness/no-fluff): - OverloadResolutionRules: extract shared methodMentionsSRTP helper used by both moreConcreteRule's firing gate and the FS0041 diagnostic explainer, so their SRTP exclusion can no longer drift (the explainer previously only checked parameter-type SRTP, missing method type params / called type args). Behaviour-identical for the rule; strictly narrows the diagnostic to cases the rule actually ranks. - OverloadResolutionRules(.fsi): correct the TiebreakRuleId doc — the integer values are report-only conceptual identifiers; evaluation order is the list order of allTiebreakRules (which runs MoreConcrete last). - infos: document that GetOverloadResolutionPriority returns 0 for F# override members (priority is fixed by the base declaration, matching C#). - Tests: hoist the two duplicated embedded sources (incomparable- concreteness pair; ORPA-on-override pair) into shared bindings; strip leftover hypothesis/phase tags from comments. Verified: build 0/0; ORPA 16/16; Tiebreaker 123/123; fantomas clean; differential default-vs-preview safety gate 65 snippets, 0 flips. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bring in main (incl. .NET 11 migration #20080). Two auto-merge fixes: - FSharp.Compiler.Service.fsproj + ComponentTests.fsproj: git dropped main's new <Compile Include> entries (EncMethodDebugInformation, GeneratedNames, CompilerGeneratedNameMapState, SynthesizedTypeMaps, Spreads, + 11 test files). Rebased both ItemGroups on main and re-inserted this branch's additions. - FSComp.txt.*.xlf (13): regenerated via XliffTasks so each is the union of main's strings and this branch's 9 new trans-units (+9 vs main, nothing removed). Validated on net11: full Arcade build 0/0; ORPA 16/16; Tiebreaker 123/123; fantomas --check clean. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…aging The merge commit took main's raw fsprojs (staged by 'git checkout main --') but my re-inserted <Compile Include> entries were only in the working tree, never git add-ed. CI's clean build failed (OverloadResolutionRules module 'not defined' from ConstraintSolver.fs). Local build passed because it used the working tree. Stage the 2 compiler + 3 test entries. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The "more concrete at position N" breakdown named the wrong candidate whenever the two ambiguous parameters shared a top-level type constructor (e.g. Result<int,'e> vs Result<'o,string>). collectComparisons' same- constructor branch used `args1 |> List.mapi2 f args2`, which the pipe evaluates as `List.mapi2 f args2 args1`, swapping the two candidates' type-arguments inside the lambda and inverting the c>0 => meth1 convention used just below. Overload selection was unaffected (moreConcreteRule and compareTypeConcreteness pass their lists in the correct order); only this diagnostic detail was wrong. Use `(args1, args2) ||> List.mapi2 f` so arg1 comes from meth1 and arg2 from meth2, matching the different-constructor branch and the winner logic. Strengthen Example 6 to pin the correct type-argument positions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…oads The enhanced FS0041 "neither is strictly more concrete" breakdown flattened per-type-argument indices across all formal parameters, so a method with several parameters printed ambiguous, duplicated position numbers such as "is more concrete at positions 1, 1" — where one "1" meant parameter 1 and the other meant type argument 1 of a later same-constructor parameter. Report positions at the granularity moreConcreteRule itself compares: - single parameter: decompose a same-constructor application into its type-argument positions (the flagship Result<int,'e> vs Result<'o,string> case), unambiguous because every position is that one parameter's type args; - multiple parameters: one comparison per formal parameter, reporting the parameter index. A same-constructor parameter that is internally incomparable is neutral and drops out. Add a regression test pinning clean per-parameter positions for a 3-parameter incomparable pair; the single-parameter flagship output is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rework the two draft RFC documents in this PR into publishable form and assign their fslang-design FS numbers: - FS-1340 "most concrete" tiebreaker (was FS-XXXX-most-concrete-tiebreaker.md) - FS-1338 OverloadResolutionPriorityAttribute (new) Both were iterated through four adversarial, cross-model review rounds (accuracy / completeness / clarity) with every normative claim grounded in the compiler implementation and, where behavioural, a compiled repro. The rounds also surfaced two real diagnostic defects, fixed separately earlier in this PR. Notable accuracy corrections in this pass: - Tiebreak ordering: type-directed-conversion preferences run ahead of the published rules 1-8; the nullable/optional-interop and property-override rules run after rule 8; most-concrete is last. - ORPA prunes only among *applicable* candidates, so an inapplicable high-priority overload never shadows an applicable lower-priority one; the Drawbacks text now matches the body and the tests. - Cross-language parity holds for method and constructor calls; indexers diverge on an identical applicable set (F# resolves by specificity), while a C#-only conversion diverges because the applicable set itself differs. - Portability example: an argument type annotation does not make a call portable (still FS0041 pre-preview), only an explicit type argument does. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rewrite FS-1340 (258->131) and FS-1338 (255->118) in the concise FS-1137 register: one example per point, near-empty Pragmatics, and no re-quoting of published spec rules 1-8. Every normative claim and all prior accuracy fixes (rule ordering, applicable-set pruning, indexer vs C#-conversion parity split, portability) are preserved; verified by a claim-by-claim accuracy pass. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rewrite both RFCs in a plainer, more declarative register: flatter sentences, far fewer em-dashes (34 -> 0) and semicolons, no internal compiler identifiers in the prose, and no meta-asides. All normative content and prior accuracy fixes are preserved. Also close the two gaps found by the standalone RFC review: - FS-1340 now states multi-candidate selection (a candidate wins only if strictly preferred over every other applicable candidate; otherwise FS0041). - FS-1338 reconciles override priority: an F# override is always 0 (the attribute on it is FS3586), while a C#/IL override takes the priority of its least-derived declaration. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Nine cross-model reviewers (voice, compactness, clarity; three model
families each) audited the RFCs standalone, without the implementation.
Voice (2/3): drop the enumeration of internal, non-published betterness
rules from both RFCs and describe the ordering by observable behaviour;
remove two meta asides ("intentionally narrow", "the author makes
visibly").
Compactness (3/3): remove the duplicated "constructor has no C# analogue"
sentence in FS-1340; tighten the SRTP/rule-ordering gloss; collapse the
FS-1338 prior-art corner-case list and the triple out-of-scope note.
Clarity (3/3, verified against OverloadResolutionRules.fs): FS-1340 now
states that parameter counting uses the declared arity (params array
counts once, optionals count once) on the uninstantiated formal
signatures, and that extension members take part only after the existing
extension preferences. FS-1338 now notes the single override divergence
(an F# override of an already-prioritized base member stays 0).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
T-Gro
added a commit
to fsharp/fslang-design
that referenced
this pull request
Aug 4, 2026
Replace the earlier draft with the compacted, reviewed version aligned with the implementation in dotnet/fsharp#19277. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The branch's copies of the FCS 11.0.100 and Language preview release notes had dropped ~13 unrelated entries (Spread operator, NotNullIfNotNull, reflectionfree ToString, StructLayout, module-rec attrs, the SynInterpolatedStringPart breaking change, etc.). Restore both files from the merge-base and re-add only the two intended ORPA/tiebreaker entries, now linked to their fslang-design RFC PRs (#834, #828). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The ORPA read path hand-rolled three option-taking helpers (TryFindFSharpAttributeOpt, TryFindFSharpInt32AttributeOpt, TryDecodeILAttributeOpt) that scanned a method's full attribute list on every candidate on every overload resolution — a hot path. Adopt the existing O(1) cached WellKnownAttribs bitflag mechanism instead: - Add OverloadResolutionPriorityAttribute to WellKnownILAttributes (il) and WellKnownValAttributes, with the matching classify cases. - Rewrite MethInfo.GetOverloadResolutionPriority to gate on the cached HasWellKnownAttribute / ValHasWellKnownAttribute flag, decoding the Int32 only on the rare present case via the existing (|ILAttribDecoded|_|) and (|ValAttribInt|_|). - Route the FS3586 override diagnostic through attribsHaveValFlag. - Delete the three bespoke helpers and the now-unused TcGlobals attrib_OverloadResolutionPriorityAttribute slot. Recognition is now by attribute name/path rather than gated on the type being resolvable in a framework assembly, matching C#'s name-based ORPA recognition (a referenced polyfilled attribute on a down-level target is now honored). Net -11 LOC; behaviour unchanged on targets whose BCL carries the attribute (ORPA 16/16 + Tiebreaker 124/124 + SurfaceArea green). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The WellKnownAttribs adoption recognises OverloadResolutionPriority by name instead of gating on the framework-resolved TcGlobals slot, so it now honours the attribute even when the target framework lacks it (a referenced polyfill), matching Roslyn. This case is unreachable by the existing net-core tests (their framework always resolves the slot). The guard uses an F# polyfill library and consumer both targeting netstandard2.0 (slot = None) with return-type-divergent overloads, so the selection is observable at compile time. Verified RED on the pre-adoption commit (picks the concrete int overload -> string annotation fails) and GREEN after it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Source (OverloadResolutionRules.fs, behavior-preserving):
- extract a getCached HOF so getCachedParamData/getCachedHasSRTP stop
duplicating the cache dance
- add a preferFlagRule factory and collapse the 9 simple projection rules
(NoTDC/LessTDC/NullableTDC/NoWarnings/NoParamArray/NoOutArgs/NoOptionalArgs/
PreferNonExtension/PreferNonGeneric) onto it
- reuse resolveAggregation in compareTypeConcreteness' TType_fun branch
- drop decorative section-banner comments and war-story parentheticals
Tests:
- hoist the copy-pasted per-sequence 'case' helper to one module-level def
- replace the three non-exercising 'Example 13' typecheck-only tests (whose
extension members had different names, so no overload competition ever
happened) with one runtime-observed test: an intrinsic Process('t) vs a
same-named more-concrete extension Process(int), asserting the intrinsic
executes -- pinning that the last-running most-concrete tiebreaker does not
override the earlier PreferNonExtension choice
- strip decorative divider banners from ORPTestRunner.fs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Split the single down-level ORPA recognition test into a shared consumer helper plus two branch-specific polyfill libraries -- a C# lib (exercises the ILMeth classification path) and an F# lib (exercises the FSMeth/Val path) -- each defining its own netstandard2.0 OverloadResolutionPriorityAttribute so the TcGlobals slot is None and name-based recognition must fire. Enable C# libs at netstandard2.0 (Compiler.fs asNetStandard20). Also drop the standalone 'override uses least-derived base priority' Fact: its single assertion is a strict subset of ORPTestRunner.testVirtualBaseOrpa, which already covers the base, derived-object, and negative-priority-int cases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
abonie
approved these changes
Aug 5, 2026
…bmodules Restructure TiebreakerTests.fs into three sibling modules that make the langversion gating of the most-concrete tiebreaker self-documenting: - TiebreakerFixtures: source fixtures shared across the modules (the case helper, the incomparable/warning sources, and the flip source lists/ builders extracted from the former inline Facts). - AgnosticOfTieBreakerFeature: tests whose outcome is identical with or without the feature - either an earlier rule decides them, or they stay ambiguous even under preview (incomparable / SRTP-only differences). - WithTieBreakerFeature: flip sources at --langversion:preview -> resolve. - WithoutTieBreakerFeature: the EXACT same flip sources pinned to langversion 10.0 (feature off) -> FS0041. Every With test has a 1:1 Without mirror over a shared source, so the pair proves the resolution is feature-gated rather than incidental. The suite is the classification oracle: all Without mirrors produce FS0041 at 10.0 and all With tests resolve at preview, empirically confirming each moved source genuinely flips. No agnostic coverage was dropped. Tiebreakers 148/148, ORPA 17/17 green. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… overload won) Three adversarial reviews found that 5 WithTieBreakerFeature tests only asserted 'typecheck |> shouldSucceed' - they proved the call became unambiguous under preview but NOT that the most-concrete overload was the one selected. An inverted tiebreaker that picked the generic overload would have left them green. Strengthen each to discriminate the winner, downstream of the already-generalized binding so the feature-off FS0041 mirrors stay intact: - moreConcretDisabledAmbiguousCases / realWorldSource: append a runtime guard (if result <> <concrete-marker> then failwith ...) and run via asExe/compileAndRun. - example7Source (Task<'T> vs 'T): match the DU result - FromTask expected, FromResult fails. - example8Source / fsToolkitSource (CE Source): RunSynchronously and match Ok 42, which only type-checks/evaluates when the concrete Async<Result<_,_>> overload was chosen. - 'Multiple bypassed' warning: assert BOTH bypassed generic signatures are named (Process: value: 't -> and Process: value: Option<'t> ->), so 'multiple' is verified, not just 'at least one FS3576'. Verified the harness enforces these: an unhandled exception from failwith is caught as Outcome.Failure (CompilerAssert.executeAssemblyEntryPoint) -> CompilationResult.Failure -> shouldSucceed throws. Mutation-tested every new discriminator: flipping each expected value turns exactly its own With-test red (7 cases) while all Without mirrors stay green, proving the oracles have teeth and remain inert at langversion 10.0. Tiebreakers 148/148, ORPA 17/17 green. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
T-Gro
enabled auto-merge (squash)
August 6, 2026 12:42
abonie
approved these changes
Aug 6, 2026
# Conflicts: # src/Compiler/xlf/FSComp.txt.cs.xlf # src/Compiler/xlf/FSComp.txt.de.xlf # src/Compiler/xlf/FSComp.txt.es.xlf # src/Compiler/xlf/FSComp.txt.fr.xlf # src/Compiler/xlf/FSComp.txt.it.xlf # src/Compiler/xlf/FSComp.txt.ja.xlf # src/Compiler/xlf/FSComp.txt.ko.xlf # src/Compiler/xlf/FSComp.txt.pl.xlf # src/Compiler/xlf/FSComp.txt.pt-BR.xlf # src/Compiler/xlf/FSComp.txt.ru.xlf # src/Compiler/xlf/FSComp.txt.tr.xlf # src/Compiler/xlf/FSComp.txt.zh-Hans.xlf # src/Compiler/xlf/FSComp.txt.zh-Hant.xlf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two overload-resolution features, both gated behind
--langversion:preview.Most-concrete tiebreaker — when candidates are otherwise equally ranked, the overload with more concrete parameter types is chosen, so
Api.Call(Some 42)resolves toCall(x: 'T option)instead of failing with FS0041 (ambiguous). Implements fslang-suggestions #905; design in RFC FS-1340.OverloadResolutionPriorityAttribute(.NET 9) — candidates marked with a higher priority are preferred over lower-priority ones, matching C#'s behavior for steering callers toward newer library overloads. Implements fslang-suggestions #821; design in RFC FS-1338.The tiebreaker is transparent: opt into
--warnon:3575to see which concrete overload was selected and--warnon:3576for each generic overload it bypassed.