Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/10.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* F# Scripts: Fix default reference paths resolving when an SDK directory is specified. ([PR #19270](https://github.com/dotnet/fsharp/pull/19270))
* Improve static compilation of state machines. ([PR #19297](https://github.com/dotnet/fsharp/pull/19297))
* Fix a bug where `let!` and `use!` were incorrectly allowed outside computation expressions. [PR #19347](https://github.com/dotnet/fsharp/pull/19347)
* Fix incorrect type reported for RHS of pattern binding when there's a type annotation on the pattern. ([PR #19284](https://github.com/dotnet/fsharp/pull/19284))
* Fix TypeLoadException when creating delegate with voidptr parameter. (Issue [#11132](https://github.com/dotnet/fsharp/issues/11132), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Suppress tail calls when localloc (NativePtr.stackalloc) is used. (Issue [#13447](https://github.com/dotnet/fsharp/issues/13447), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
* Fix TypeLoadException in Release builds with inline constraints. (Issue [#14492](https://github.com/dotnet/fsharp/issues/14492), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
Expand Down
14 changes: 14 additions & 0 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11361,6 +11361,20 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt
// If binding a ctor then set the ugly counter that permits us to write ctor expressions on the r.h.s.
let isCtor = (match memberFlagsOpt with Some memberFlags -> memberFlags.MemberKind = SynMemberKind.Constructor | _ -> false)

// For bindings with a type annotation, the parser wraps the RHS in SynExpr.Typed
// (see mkSynBindingRhs in SyntaxTreeOps.fs). Unwrap it and unify the annotation
// with the binding type separately so that type errors on the RHS report the actual
// expression type, not the annotation type.
let rhsExpr =
match rtyOpt, rhsExpr with
| Some (SynBindingReturnInfo(typeName = retInfoTy; range = mRetTy)), SynExpr.Typed(innerExpr, _, _) when spatsL.IsEmpty ->
Comment thread
T-Gro marked this conversation as resolved.
let retTy, _ = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurrence.UseInType WarnOnIWSAM.Yes envinner tpenv retInfoTy
try UnifyTypes cenv envinner pat.Range retTy overallExprTy
with RecoverableException exn -> errorRecovery exn mRetTy
innerExpr
| _ ->
Comment on lines +11370 to +11375

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider

let a: T = b

If I understand it correctly, during the analysis the compiler rewrites it to

let a = (b: T)

T may be a partially annotated type, e.g. _ list in the source, and then it can be inferred to something like int list after the type checking of the b expression. Can we propagate this inferred type here instead of type checking T from scratch? Would there be downsides?

@travv0 travv0 Feb 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry if I'm misunderstanding what you're saying here, but the problem this addresses is that when it's rewritten to let a = (b: T), if a is a pattern and b doesn't typecheck, it reports the annotated type of a as the type of b instead of the actual type of b (in the specific scenario where the type annotation doesn't fit the pattern).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a test for the partially inferred scenario?

rhsExpr

// Now check the right of the binding.
//
// At each module binding, dive into the expression to check for syntax errors and suppress them if they show.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,63 @@ let main args =
(Error 1, Line 8, Col 25, Line 8, Col 37, "The tuples have differing lengths of 3 and 2")
]

[<Fact>]
Comment thread
T-Gro marked this conversation as resolved.
let ``Binding with type annotation and tuple pattern reports correct type``() =
FSharp """
let a, b: int = ()
"""
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 1, Line 2, Col 5, Line 2, Col 9,
"This expression was expected to have type\n 'int' \nbut here has type\n ''a * 'b' ")
(Error 1, Line 2, Col 17, Line 2, Col 19,
"This expression was expected to have type\n ''a * 'b' \nbut here has type\n 'unit' ")
]

[<Fact>]
let ``Binding with correct type annotation and tuple pattern compiles``() =
FSharp """
let a, b: int * string = (1, "hello")
"""
|> typecheck
|> shouldSucceed

[<Fact>]
let ``Non-tuple binding with wrong type annotation reports correct type``() =
FSharp """
let x: int = "hello"
"""
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 1, Line 2, Col 14, Line 2, Col 21,
"This expression was expected to have type\n 'int' \nbut here has type\n 'string' ")
]

[<Fact>]
let ``Wildcard binding with wrong type annotation reports correct type``() =
FSharp """
let _: int = ()
"""
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 1, Line 2, Col 14, Line 2, Col 16,
"This expression was expected to have type\n 'int' \nbut here has type\n 'unit' ")
]

[<Fact>]
let ``Tuple pattern with correct annotation but wrong RHS reports RHS error``() =
FSharp """
let a, b: int * int = ()
"""
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 1, Line 2, Col 23, Line 2, Col 25,
"This expression was expected to have type\n 'int * int' \nbut here has type\n 'unit' ")
]
module ``Not a function`` =

[<Theory>]
Expand Down
Loading