diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md index 5fd7be2081..aa2551e024 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.200.md @@ -23,6 +23,7 @@ * Shim/file system: fix leaks of the shim [PR #18144](https://github.com/dotnet/fsharp/pull/18144) * fsi: fix auto-loading of script file inside NuGet package ([PR #18177](https://github.com/dotnet/fsharp/pull/18177)) * Fix for `Obsolete` attribute warning/error not taken into account when used with a unit of measure [PR #18182](https://github.com/dotnet/fsharp/pull/18182) +* 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) ### Added diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index c0d2935926..e6605655cf 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -11152,6 +11152,19 @@ 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. + // 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 -> + 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 + | _ -> + 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. diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index d645f4d5a9..9f2abf6d52 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -370,3 +370,17 @@ let main args = (Error 1, Line 8, Col 25, Line 8, Col 37, "The tuples have differing lengths of 3 and 2") ] + [] + 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' ") + ] +