Skip to content

Get types from type tree in async-related rules#843

Merged
knocte merged 7 commits intofsprojects:masterfrom
webwarrior-ws:async-related-rules-types
Feb 12, 2026
Merged

Get types from type tree in async-related rules#843
knocte merged 7 commits intofsprojects:masterfrom
webwarrior-ws:async-related-rules-types

Conversation

@webwarrior-ws
Copy link
Contributor

If output type of function/method is not specified, get it from typed syntax tree.

This affects the following rules:

  • SynchronousFunctionNames
  • AsynchronousFunctionNames
  • SimpleAsyncComplementaryHelpers

Contributes to #517.

For functions without explicit return types.
@greptile-apps
Copy link

greptile-apps bot commented Feb 11, 2026

Greptile Overview

Confidence Score: 3/5

  • This PR is directionally correct but has correctness risks in typed-tree inference and suggestion text rendering that should be addressed before merging.
  • The new typed-tree fallback improves rule coverage, but (1) SimpleAsyncComplementaryHelpers can produce incorrect suggested signatures by dropping generic arguments when formatting inferred type params, and (2) the shared symbol-lookup helper may resolve the wrong symbol for qualified/overloaded identifiers, which would misclassify async-ness and change lint results unexpectedly. Tests added cover basic cases but don’t protect against these mis-resolution/formatting issues.
  • src/FSharpLint.Core/Rules/Utilities.fs, src/FSharpLint.Core/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs

Important Files Changed

Filename Overview
src/FSharpLint.Core/Rules/Conventions/Naming/AsynchronousFunctionNames.fs Refactors naming checks and, when no explicit return type is present, infers Async/Task return type via typed tree lookup (FSharpCheckFileResults).
src/FSharpLint.Core/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs Switches return-type-param rendering from AST SynType to strings and adds typed-tree inference for missing return annotations; current typed-tree rendering can drop generic arguments and produce incorrect suggested signatures.
src/FSharpLint.Core/Rules/Conventions/Naming/SynchronousFunctionNames.fs Adds typed-tree inference for missing return annotations to detect non-async functions named with Async prefix/suffix; refactors identifier check into helper.
src/FSharpLint.Core/Rules/NamingHelper.fs Updates async prefix/suffix active pattern to ignore double-backticked identifiers; adds FSharpType active pattern to classify Async/Task based on BasicQualifiedName.
src/FSharpLint.Core/Rules/Utilities.fs Introduces TypedTree helper (GetSymbolUseAtLocation + FullType traversal) to infer function return types; current symbol location/ident selection can mis-resolve for qualified/overloaded members.
tests/FSharpLint.Core.Tests/Rules/Conventions/AsyncExceptionWithoutReturn.fs Renames test methods for clarity; no behavioral change.
tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/AsynchronousFunctionNames.fs Adds coverage for typed-tree inference when return type annotation is omitted (Async/Task functions and methods).
tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs Adds tests for complementary helper suggestions when return annotations are missing; assumes suggestion includes correct type parameter rendering.
tests/FSharpLint.Core.Tests/Rules/Conventions/Naming/SynchronousFunctionNames.fs Adds tests ensuring non-async functions without explicit return types still trigger naming violations and async ones don’t.

Sequence Diagram

sequenceDiagram
    participant Rule as Naming rule
    participant AST as Parsed AST
    participant TTC as Utilities.TypedTree
    participant Check as FSharpCheckFileResults
    participant Sym as FCS Symbol

    Rule->>AST: Visit SynBinding
    Rule->>AST: Read returnInfo
    alt returnInfo present
        Rule->>Rule: Classify via ReturnsAsync/ReturnsTask/ReturnsNonAsync
        Rule->>Rule: Emit warning if naming mismatches
    else returnInfo missing
        Rule->>TTC: getFunctionReturnType(checkInfo, lines, funcIdent)
        TTC->>Check: GetSymbolUseAtLocation(line,col,lineText,identIsland)
        Check-->>TTC: SymbolUse (option)
        alt function symbol resolved
            TTC->>Sym: Read FullType and compute return type
            Sym-->>TTC: FSharpType
            TTC-->>Rule: FSharpType (option)
            Rule->>Rule: Classify via FSharpTypeAsync/FSharpTypeTask/...
            Rule->>Rule: Emit warning if naming mismatches
        else not resolved
            TTC-->>Rule: None
            Rule->>Rule: Skip (no warning)
        end
    end
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link

greptile-apps bot commented Feb 11, 2026

Additional Comments (1)

src/FSharpLint.Core/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs
Typed return type may lose generics

When returnInfo is missing, this builds Task<'T>/Async<'T> text using paramType.TypeDefinition.DisplayName, which drops generic arguments (e.g., Map<string,int> becomes just Map). That makes the suggested signature incorrect and can produce misleading fix text.

This also affects any nested generics (e.g., Task<Result<int,string>>). Prefer using a full display string for the generic argument type (e.g., Format/ToString-style display from compiler services) rather than TypeDefinition.DisplayName.

Also appears in the same file where FSharpTypeTaskNonGeneric is forced to "unit" even though Task return type should be represented without a type parameter.

@webwarrior-ws webwarrior-ws force-pushed the async-related-rules-types branch from c378757 to c18ce72 Compare February 12, 2026 08:42
@webwarrior-ws
Copy link
Contributor Author

Additional Comments (1)
src/FSharpLint.Core/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs Typed return type may lose generics

When returnInfo is missing, this builds Task<'T>/Async<'T> text using paramType.TypeDefinition.DisplayName, which drops generic arguments (e.g., Map<string,int> becomes just Map). That makes the suggested signature incorrect and can produce misleading fix text.

This also affects any nested generics (e.g., Task<Result<int,string>>). Prefer using a full display string for the generic argument type (e.g., Format/ToString-style display from compiler services) rather than TypeDefinition.DisplayName.

I added a test that uses return type Async<Map<int,string>> and the code works perfectly fine.

@webwarrior-ws
Copy link
Contributor Author

Also appears in the same file where FSharpTypeTaskNonGeneric is forced to "unit" even though Task return type should be represented without a type parameter.

This is by design. Function that returns Task should prompt creation of function that returns Async<unit>.

If there is no explicit return type.
For functions without explicit return types.
If there is no explicit return type.
For functions without explicit return types.
If there is no explicit return type.
@webwarrior-ws webwarrior-ws force-pushed the async-related-rules-types branch from 40d54e5 to 240ffd6 Compare February 12, 2026 09:36
@webwarrior-ws
Copy link
Contributor Author

Additional Comments (1)
src/FSharpLint.Core/Rules/Conventions/Naming/SimpleAsyncComplementaryHelpers.fs Typed return type may lose generics
When returnInfo is missing, this builds Task<'T>/Async<'T> text using paramType.TypeDefinition.DisplayName, which drops generic arguments (e.g., Map<string,int> becomes just Map). That makes the suggested signature incorrect and can produce misleading fix text.
This also affects any nested generics (e.g., Task<Result<int,string>>). Prefer using a full display string for the generic argument type (e.g., Format/ToString-style display from compiler services) rather than TypeDefinition.DisplayName.

I added a test that uses return type Async<Map<int,string>> and the code works perfectly fine.

Upon further examination, that test I added was testing the wrong thing. Modified the test. Switched to using Format with FSharpDisplayContext obtained from checkInfo instead of DisplayName.

@knocte knocte merged commit 8e20e0b into fsprojects:master Feb 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants