diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 53802cc1153..10f24a3171a 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -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)) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 569f97f22e1..87cd91e6db5 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -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 -> + 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 337a49d5352..4fd480ecb8e 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -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") ] + [] + 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' ") + ] + + [] + let ``Binding with correct type annotation and tuple pattern compiles``() = + FSharp """ +let a, b: int * string = (1, "hello") + """ + |> typecheck + |> shouldSucceed + + [] + 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' ") + ] + + [] + 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' ") + ] + + [] + 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`` = []