diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md index b69621fc79..f7f572652f 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md @@ -21,6 +21,7 @@ * Fix SRTP nullness constraint resolution for types imported from older assemblies. AmbivalentToNull types now use legacy F# nullness rules instead of always satisfying `'T : null` constraints. ([Issue #18390](https://github.com/dotnet/fsharp/issues/18390), [Issue #18344](https://github.com/dotnet/fsharp/issues/18344)) * Fix Show XML doc for enum fields in external metadata ([Issue #17939](https://github.com/dotnet/fsharp/issues/17939#issuecomment-3137410105), [PR #18800](https://github.com/dotnet/fsharp/pull/18800)) +* TypeMismatchDiagnosticExtendedData: fix expected and actual types calculation. ([Issue ](https://github.com/dotnet/fsharp/pull/18851)) ### Changed * Use `errorR` instead of `error` in `CheckDeclarations.fs` when possible. ([PR #18645](https://github.com/dotnet/fsharp/pull/18645)) diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fs b/src/Compiler/Symbols/FSharpDiagnostic.fs index 131e49845c..3aa7a26ac4 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fs +++ b/src/Compiler/Symbols/FSharpDiagnostic.fs @@ -9,7 +9,6 @@ namespace FSharp.Compiler.Diagnostics open System -open FSharp.Compiler.AttributeChecking open FSharp.Compiler.CheckExpressions open FSharp.Compiler.ConstraintSolver open FSharp.Compiler.SignatureConformance @@ -26,7 +25,6 @@ open FSharp.Compiler.CompilerDiagnostics open FSharp.Compiler.Diagnostics open FSharp.Compiler.DiagnosticsLogger open FSharp.Compiler.Text -open FSharp.Compiler.Text.Position open FSharp.Compiler.Text.Range module ExtendedData = @@ -199,11 +197,21 @@ type FSharpDiagnostic(m: range, severity: FSharpDiagnosticSeverity, message: str match diagnostic.Exception with | ErrorFromAddingTypeEquation(_, displayEnv, expectedType, actualType, ConstraintSolverTupleDiffLengths(contextInfo = contextInfo), _) - | ErrorFromAddingTypeEquation(_, displayEnv, expectedType, actualType, ConstraintSolverTypesNotInEqualityRelation(_, _, _, _, _, contextInfo), _) | ErrorsFromAddingSubsumptionConstraint(_, displayEnv, expectedType, actualType, _, contextInfo, _) -> let context = DiagnosticContextInfo.From(contextInfo) Some(TypeMismatchDiagnosticExtendedData(symbolEnv, displayEnv, expectedType, actualType, context)) + | ErrorFromAddingTypeEquation(g, displayEnv, ty1, ty2, ConstraintSolverTypesNotInEqualityRelation(_, ty1b, ty2b, _, _, contextInfo), _) -> + let expectedType, actualType = + if typeEquiv g ty1 ty1b && typeEquiv g ty2 ty2b then + ty1, ty2 + elif not (typeEquiv g ty1 ty2) then + ty1, ty2 + else ty2b, ty1b + + let context = DiagnosticContextInfo.From(contextInfo) + Some(TypeMismatchDiagnosticExtendedData(symbolEnv, displayEnv, expectedType, actualType, context)) + | ErrorFromAddingTypeEquation(_, displayEnv, expectedType, actualType, _, _)-> Some(TypeMismatchDiagnosticExtendedData(symbolEnv, displayEnv, expectedType, actualType, DiagnosticContextInfo.NoContext)) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs index 1c6003de00..e2615a4da6 100755 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ExtendedDiagnosticDataTests.fs @@ -4,7 +4,6 @@ open FSharp.Compiler.Text open FSharp.Compiler.Diagnostics open FSharp.Compiler.Diagnostics.ExtendedData -open FSharp.Test open FSharp.Test.Compiler open Xunit @@ -144,6 +143,50 @@ if true then 1 else "a" Assert.Equal("int", typeMismatch.ExpectedType.Format(displayContext)) Assert.Equal("string", typeMismatch.ActualType.Format(displayContext))) +[] +let ``TypeMismatchDiagnosticExtendedData 08`` () = + FSharp """ +type R = { Field1: int } +let f (x: R) = "" + x.Field1 +""" + |> typecheckResults + |> checkDiagnostic + (1, "The type 'int' does not match the type 'string'") + (fun (typeMismatch: TypeMismatchDiagnosticExtendedData) -> + let displayContext = typeMismatch.DisplayContext + Assert.Equal(DiagnosticContextInfo.NoContext, typeMismatch.ContextInfo) + Assert.Equal("string", typeMismatch.ExpectedType.Format(displayContext)) + Assert.Equal("int", typeMismatch.ActualType.Format(displayContext))) + +[] +let ``TypeMismatchDiagnosticExtendedData 09`` () = + FSharp """ +let x: string = 1 +""" + |> typecheckResults + |> checkDiagnostic + (1, "This expression was expected to have type\n 'string' \nbut here has type\n 'int' ") + (fun (typeMismatch: TypeMismatchDiagnosticExtendedData) -> + let displayContext = typeMismatch.DisplayContext + Assert.Equal(DiagnosticContextInfo.NoContext, typeMismatch.ContextInfo) + Assert.Equal("string", typeMismatch.ExpectedType.Format(displayContext)) + Assert.Equal("int", typeMismatch.ActualType.Format(displayContext))) + +[] +let ``TypeMismatchDiagnosticExtendedData 10`` () = + FSharp """ +let f1 (x: outref<'T>) = 1 +let f2 (x: inref<'T>) = f1 &x +""" + |> typecheckResults + |> checkDiagnostic + (1, "Type mismatch. Expecting a\n 'outref<'T>' \nbut given a\n 'inref<'T>' \nThe type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In'") + (fun (typeMismatch: TypeMismatchDiagnosticExtendedData) -> + let displayContext = typeMismatch.DisplayContext + Assert.Equal(DiagnosticContextInfo.NoContext, typeMismatch.ContextInfo) + Assert.Equal("outref<'T>", typeMismatch.ExpectedType.Format(displayContext)) + Assert.Equal("inref<'T>", typeMismatch.ActualType.Format(displayContext))) + [] [] []