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 b69621fc796..4f5975f3e8d 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.100.md @@ -24,6 +24,7 @@ ### Changed * Use `errorR` instead of `error` in `CheckDeclarations.fs` when possible. ([PR #18645](https://github.com/dotnet/fsharp/pull/18645)) +* Type checker: use inner expr range in upcast constraints errors ([PR #18850](https://github.com/dotnet/fsharp/pull/18850)) ### Breaking Changes diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index a2c1a2d4e92..c5228adeccf 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -3004,20 +3004,19 @@ let TcRuntimeTypeTest isCast isOperator (cenv: cenv) denv m tgtTy srcTy = warning(Error(FSComp.SR.tcTypeTestLossy(NicePrint.minimalStringOfTypeWithNullness denv ety, NicePrint.minimalStringOfType denv (stripTyEqnsWrtErasure EraseAll g ety)), m)) /// Checks, warnings and constraint assertions for upcasts -let TcStaticUpcast (cenv: cenv) denv m tgtTy srcTy = +let TcStaticUpcast (cenv: cenv) denv mSourceExpr mUpcastExpr tgtTy srcTy = let g = cenv.g if isTyparTy g tgtTy then if not (destTyparTy g tgtTy).IsCompatFlex then - error(IndeterminateStaticCoercion(denv, srcTy, tgtTy, m)) - //else warning(UpcastUnnecessary m) + error(IndeterminateStaticCoercion(denv, srcTy, tgtTy, mUpcastExpr)) if isSealedTy g tgtTy && not (isTyparTy g tgtTy) then - warning(CoercionTargetSealed(denv, tgtTy, m)) + warning(CoercionTargetSealed(denv, tgtTy, mUpcastExpr)) if typeEquiv g srcTy tgtTy then - warning(UpcastUnnecessary m) + warning(UpcastUnnecessary mUpcastExpr) - AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css m NoTrace tgtTy srcTy + AddCxTypeMustSubsumeType ContextInfo.NoContext denv cenv.css mSourceExpr NoTrace tgtTy srcTy let BuildPossiblyConditionalMethodCall (cenv: cenv) env isMutable m isProp minfo valUseFlags minst objArgs args staticTyOpt = @@ -6139,7 +6138,7 @@ and TcExprUpcast (cenv: cenv) overallTy env tpenv (synExpr, synInnerExpr, m) = | SynExpr.InferredUpcast _ -> overallTy.Commit, tpenv | _ -> failwith "upcast" - TcStaticUpcast cenv env.DisplayEnv m tgtTy srcTy + TcStaticUpcast cenv env.DisplayEnv synInnerExpr.Range m tgtTy srcTy let expr = mkCoerceExpr(innerExpr, tgtTy, m, srcTy) expr, tpenv diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/Type-relatedExpressions/Type-relatedExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/Type-relatedExpressions/Type-relatedExpressions.fs index b0e0d389b2f..b833530cedc 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/Type-relatedExpressions/Type-relatedExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/Type-relatedExpressions/Type-relatedExpressions.fs @@ -74,4 +74,16 @@ module TyperelatedExpressions = (Warning 20, Line 9, Col 1, Line 9, Col 22, "The result of this expression has type 'obj' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.") ] + [] + let ``Upcast 01`` () = + FSharp """ +module Module +type A() = + class end + +not true :> A |> ignore +""" + |> compile + |> shouldFail + |> withDiagnostics [(Error 193, Line 7, Col 1, Line 7, Col 9, "Type constraint mismatch. The type \n 'bool' \nis not compatible with type\n 'A' \n")] diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UpcastDowncastTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UpcastDowncastTests.fs index a25753fdc7c..ea053cc8bf4 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UpcastDowncastTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/UpcastDowncastTests.fs @@ -17,7 +17,7 @@ let c = orig :> Dictionary """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Error 193, Line 5, Col 9, Line 5, Col 36, + |> withSingleDiagnostic (Error 193, Line 5, Col 9, Line 5, Col 13, "Type constraint mismatch. The type \n 'IDictionary' \nis not compatible with type\n 'Dictionary' \n") [] diff --git a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_impl_iface.fsx b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_impl_iface.fsx index 228904421a6..d3c8b164b46 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_impl_iface.fsx +++ b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_impl_iface.fsx @@ -2,11 +2,11 @@ // Negative tests on :> // Cast to an interface not implemented -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type diff --git a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_subclass.fsx b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_subclass.fsx index 99ed789f347..360093c1b52 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_subclass.fsx +++ b/tests/fsharpqa/Source/Conformance/Expressions/Type-relatedExpressions/E_StaticCoercion_class_not_subclass.fsx @@ -2,11 +2,11 @@ // Negative tests on :> // Cast to a class that is not parent -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type -//Type constraint mismatch\. The type +//Type constraint mismatch\. The type