Skip to content

Commit acd7cfd

Browse files
improve compiler error message for failed overload resolution (#6596)
* migrate (as a separate copy) fsharpqa tests that are going to be impacted by #6596 the baseline files are empty on purpose, expecting CI failure reporting those tests, I intend to update the baseline and clean up the comments / xml tags from fsharpqa syntax in later commit, and then remove those specific tests altogether from fsharpqa if this is OK with the maintainers. * update the .bsl files * remove comments that are handled by baseline files, update baseline files * remove the migrated tests from fsharpqa tests * need to be more careful when migrating those * testing if running the test with .fs instead of .fsx makes them work on .netcore * exclude migrated fsharpqa from dotnet core run * sample test in fsharpqa (can't run locally for now) * trying to make it green now. * checking if this path is covered by a test, trying to identify how to trigger this other overload related error message * * [MethodCalls.fs] Defining CallerArgs<'T> in, this replaces passing of callerArgsCount, uncurriedCallerArgs and other variants in the overload resolution logic happening in ConstraintSolver & TypeChecker * [TypeChecker.fs] pass CallerArgs instace at call sites for overload resolution + some commented code as we'll be building a list of given argument types (probably moving as a CallerArgs method or property) * [ConstraintSolver.fs/fsi] pipe the overload resolution traced callback to `trace.CollectThenUndoOrCommit` as that expression is long and more important in that context * bit of refactoring of error message building logic during failed overload resolution [ConstraintSolver.fsi] * define OverloadInformation and OverloadResolutionFailure, those replace workflow where `string * ((CalledMeth<_> * exn) list)` values were created at call site mixed with message building and matched later in non obvious fashion in `failOverloading` closure * adjust UnresolvedOverloading and PossibleOverload exceptions [ConstraintSolver.fs] * get rid of `GetPossibleOverloads`, this was used only in `failOverloading` closure, and just being passed the same parameters at call site * give `failOverloading` a more meaningful signature and consolidate the prefix message building logic there * fix `failOverloading` call sites [CompilerOps.fs] adjust pattern matching Expecting behaviour of this code to be identical as before PR ` * (buildfix) harmonizing .fsi/.fs right before commit doesn't always work with simple copy paste. * trying to check what kind of things break loose when I change this I'm trying to identify why we get `(CalledMeth<Expr> * exn list)`, I'm making a cartesian product through getMethodSlotsAndErrors for now, trying to figure out if we can get other than 0 or 1 exception in the list for a given method slot. I may revert that one if it doesn't make sense make from a reviewer standpoint and/or breaks fsharpqa tests surounding overload resolution error messages. * (minor) [ConstraintSolver.fs] revert space mishapps to reduce diff, put back comments where they were * toward displaying the argument names properly (may fail some fsharpqa tests for now) * missing Resharper's Ctrl+Alt+V "introduce variable" refactoring @auduchinok :) * pretty print unresolved overloads without all the type submsumption per overload verbose messages * Overload resolution error messages: things display like I want in fsi, almost like I want in VS2019, this is for the simple non generic method overload case. I want to check if user experience changes wrt dotnet/fsharp#2503 and put some time to add tests. * adjust message for candidates overload * Hijack the split phase for UnresolvedOverloading, remove the match on PossibleOverload. It consolidates some more of the string building logic, and it now shows as a single compact and exhaustive error message in VS Thinking I'll change PossibleOverload to not be an exception if going this way is OK * updating existing failing baseline files that looks correct to me * quickfix for update.base.line.with.actuals.fsx so that it skips missing base line files in the loop * (minor) minimize diff, typos, comments * fix vsintegration tests affected by overload error message changes * merge issue unused variable warning * update the 12 fsharpqa migrated baseline with new error messages * (minor) baseline update script [update.base.line.with.actuals.fsx] * add few directories * error handling (when tests are running, the .err files are locked * move System.Convert.ToString and System.Threading.Tasks.Task.Run tests from QA * * moving 3 fsharpqa tests to new test suite * bring back neg_System.Convert.ToString.OverloadList.fsx which I mistakenly removed during merge * consolidate all string building logic in CompileOps.fs, fix remaining cases with missing \n (the end result code is less whack-a-mole-ish) * update base lines * remove the migrated tests from fsharpqa * fix vstest error message * fix env.lst, removed wrong one... * update baselines of remaining tests * adding one simple test with many overloads * appropriate /// comments on `CalledMeth` constructor arguments * minimize diff / formatting * trim unused code * add simple test, one message is interesting, mentioning parameter count for possible overloads * comment flaky test for now * code review on the `coerceExpr` function from @TIHan, we can discard first `isOutArg` argument as the only hardcoded usage was guarded by `error` when the value is true, and passing an explicit false which is now guaranteed equivalent to `callerArg.IsOptional` * code formatting remarks on ConstraintSolver.fs/fsi * (minor) formatting * format known argument type / updating .bsl * update missing baseline * update missing baselines * update missing baseline * minor: make TTrait better in debugger display * [wip] pass TraitConstraintInfo around failed overload resolution error, and try to display some of it's info * minimize diff * signature file mismatch * removing duplicate in fscomp.txt * surfacing initial bits of TraitConstraintInfo, roughly for now * formatting types of known argument in one go, the formatting is still wrong: * unamed type arguments aren't relabelled (still show their numerical ids) * SRTP constraints are dismissed, not sure how they should be lined up to pass to SimplifyTypes.CollectInfo * rework of overload failure message to prettify *ALL* types in a single go, not only argument types, but return types and known generic argument types (this info was never displayed originally but is useful for scenario similar to FSharpPlus implementation) added `PrettifyDiscriminantAndTypePairs` in TastOps, this allow to weave extra information with the complete list of types, to help reconstituting the several types from their origin (in the usage spot: argument types, return type, generic parameter types) * fixup the tests and add two tests * one checking on the new information of known return type and generic parameter types * one checking we don't leak internal unammed Typar and that they don't all get named 'a despite being different * updating baselines that got tighter. * simplify handling of TraitConstraintInfo * naming couple of fields and turning a property to a methods as it triggers an assert in debugger when inspecting variables * comments in the assembling of overload resolution error message * Add information about which argument doesn't match Add couple of tests Updating bunch of baselines * minor updates to testguide and devguide * fix PrimitiveConstraints.``Invalid object constructor`` test * fix(?) salsa tests * minimize diff * put back tests under !FSHARP_SUITE_DRIVES_CORECLR_TESTS * missing updated message * minor adjustments to TESTGUIDE.md * return type was missing prettifying in prettyLayoutsOfUnresolvedOverloading * address code review nits / minimize diff / add comment on PrettifyDiscriminantAndTypePairs * minimize diff * proposed work around the flaky error message until dotnet/fsharp#6725 has a fix we keep the fsharpqa test around (but removing the overload error messages from what is asserted out of it) in the meantime * fixing baselines of new tests from master * sisyphus round of baseline update * removing type which isn't in use and popped back up after rebase * minimize diff * tidy inconsistent tuple literal * * removing TTrait properties that end up not being used * renaming tys and returnTy fields to better match convention (`tys` is used, so no underscore prefix) * minimizing diff * minimize diff * minimize diff * minimize diff * link to usage example in same file * revert converting CallerArg single cased DU into Record * minimize diff * minimize diff * minimize diff * fix rebase glitches * fix rebase glitch * update baseline * fix base lines / new tests base lines * edge case: needs a new line after "A unique overload for method '%s' could not be determined based on type information prior to this program point. A type annotation may be needed." if there are no optional parts. * updating base line for edge case of missing new line * missing baseline * removing comment
1 parent e95cdd1 commit acd7cfd

File tree

80 files changed

+2828
-812
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+2828
-812
lines changed

DEVGUIDE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Building is simple:
4545

4646
Desktop tests can be run with:
4747

48-
build.cmd -test
48+
build.cmd -test -c Release
4949

5050
After you build the first time you can open and use this solution in Visual Studio:
5151

TESTGUIDE.md

+13-7
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44

55
To run tests, use variations such as the following, depending on which test suite and build configuration you want:
66

7-
build.cmd test
8-
build.cmd net40 test
9-
build.cmd coreclr test
10-
build.cmd vs test
11-
build.cmd all test
7+
.\build -testAll -c Release
8+
.\build -test -c Release
9+
.\build -testCambridge -c Release
10+
.\build -testCompiler -c Release
11+
.\build -testDependencyManager -c Release
12+
.\build -testDesktop -c Release
13+
.\build -testCoreClr -c Release
14+
.\build -testFSharpCore -c Release
15+
.\build -testFSharpQA -c Release
16+
.\build -testScripting -c Release
17+
.\build -testVs -c Release
1218

1319
You can also submit pull requests to https://github.com/dotnet/fsharp and run the tests via continuous integration. Most people do wholesale testing that way.
1420

@@ -48,7 +54,7 @@ There are also negative tests checking code expected to fail compilation. See no
4854

4955
The FSharpQA suite relies on [Perl](http://www.perl.org/get.html), StrawberryPerl package from nuget is used automatically by the test suite.
5056

51-
These tests use the `RunAll.pl` framework to execute, however the easiest way to run them is via the `build.cmd` script, see [usage examples](https://github.com/Microsoft/visualfsharp/blob/master/build.cmd#L31).
57+
These tests use the `RunAll.pl` framework to execute, however the easiest way to run them is via the `.\build` script, see [usage examples](#quick-start-running-tests).
5258

5359
Tests are grouped in folders per area. Each folder contains a number of source code files and a single `env.lst` file. The `env.lst` file defines a series of test cases, one per line.
5460

@@ -66,7 +72,7 @@ For the FSharpQA suite, the list of test areas and their associated "tags" is st
6672

6773
Tags are in the left column, paths to to corresponding test folders are in the right column. If no tags are specified, all tests will be run.
6874

69-
If you want to re-run a particular test area, the easiest way to do so is to set a temporary tag for that area in test.lst (e.g. "RERUN") and then pass that as an argument to `build.cmd`: `build.cmd test-net40-fsharpqa include RERUN`.
75+
If you want to re-run a particular test area, the easiest way to do so is to set a temporary tag for that area in test.lst (e.g. "RERUN") and adjust `ttags` [run.fsharpqa.test.fsx script](tests/fsharpqa/run.fsharpqa.test.fsx) and run it.
7076

7177
### FSharp.Compiler.UnitTests, FSharp.Core.UnitTests, VisualFSharp.UnitTests
7278

src/fsharp/CompileOps.fs

+90-15
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ let GetRangeOfDiagnostic(err: PhasedDiagnostic) =
188188
| NameClash(_, _, _, m, _, _, _)
189189
| UnresolvedOverloading(_, _, _, m)
190190
| UnresolvedConversionOperator (_, _, _, m)
191-
| PossibleOverload(_, _, _, m)
192191
| VirtualAugmentationOnNullValuedType m
193192
| NonVirtualAugmentationOnNullValuedType m
194193
| NonRigidTypar(_, _, _, _, _, m)
@@ -403,12 +402,9 @@ let warningOn err level specificWarnOn =
403402
| 3180 -> false // abImplicitHeapAllocation - off by default
404403
| _ -> level >= GetWarningLevel err
405404

406-
let SplitRelatedDiagnostics(err: PhasedDiagnostic) =
405+
let SplitRelatedDiagnostics(err: PhasedDiagnostic) : PhasedDiagnostic * PhasedDiagnostic list =
407406
let ToPhased e = {Exception=e; Phase = err.Phase}
408407
let rec SplitRelatedException = function
409-
| UnresolvedOverloading(a, overloads, b, c) ->
410-
let related = overloads |> List.map ToPhased
411-
UnresolvedOverloading(a, [], b, c)|>ToPhased, related
412408
| ConstraintSolverRelatedInformation(fopt, m2, e) ->
413409
let e, related = SplitRelatedException e
414410
ConstraintSolverRelatedInformation(fopt, m2, e.Exception)|>ToPhased, related
@@ -452,7 +448,6 @@ let ErrorFromApplyingDefault2E() = DeclareResourceString("ErrorFromApplyingDefau
452448
let ErrorsFromAddingSubsumptionConstraintE() = DeclareResourceString("ErrorsFromAddingSubsumptionConstraint", "%s%s%s")
453449
let UpperCaseIdentifierInPatternE() = DeclareResourceString("UpperCaseIdentifierInPattern", "")
454450
let NotUpperCaseConstructorE() = DeclareResourceString("NotUpperCaseConstructor", "")
455-
let PossibleOverloadE() = DeclareResourceString("PossibleOverload", "%s%s")
456451
let FunctionExpectedE() = DeclareResourceString("FunctionExpected", "")
457452
let BakedInMemberConstraintNameE() = DeclareResourceString("BakedInMemberConstraintName", "%s")
458453
let BadEventTransformationE() = DeclareResourceString("BadEventTransformation", "")
@@ -770,20 +765,100 @@ let OutputPhasedErrorR (os: StringBuilder) (err: PhasedDiagnostic) (canSuggestNa
770765
os.Append(e.ContextualErrorMessage) |> ignore
771766
#endif
772767

773-
| UnresolvedOverloading(_, _, mtext, _) ->
774-
os.Append mtext |> ignore
768+
| UnresolvedOverloading(denv, callerArgs, failure, m) ->
769+
770+
// extract eventual information (return type and type parameters)
771+
// from ConstraintTraitInfo
772+
let knownReturnType, genericParameterTypes =
773+
match failure with
774+
| NoOverloadsFound (cx=Some cx)
775+
| PossibleCandidates (cx=Some cx) -> cx.ReturnType, cx.ArgumentTypes
776+
| _ -> None, []
777+
778+
// prepare message parts (known arguments, known return type, known generic parameters)
779+
let argsMessage, returnType, genericParametersMessage =
780+
781+
let retTy =
782+
knownReturnType
783+
|> Option.defaultValue (TType.TType_var (Typar.NewUnlinked()))
784+
785+
let argRepr =
786+
callerArgs.ArgumentNamesAndTypes
787+
|> List.map (fun (name,tTy) -> tTy, {ArgReprInfo.Name = name |> Option.map (fun name -> Ident(name, range.Zero)); ArgReprInfo.Attribs = []})
788+
789+
let argsL,retTyL,genParamTysL = NicePrint.prettyLayoutsOfUnresolvedOverloading denv argRepr retTy genericParameterTypes
790+
791+
match callerArgs.ArgumentNamesAndTypes with
792+
| [] -> None, Layout.showL retTyL, Layout.showL genParamTysL
793+
| items ->
794+
let args = Layout.showL argsL
795+
let prefixMessage =
796+
match items with
797+
| [_] -> FSComp.SR.csNoOverloadsFoundArgumentsPrefixSingular
798+
| _ -> FSComp.SR.csNoOverloadsFoundArgumentsPrefixPlural
799+
Some (prefixMessage args)
800+
, Layout.showL retTyL
801+
, Layout.showL genParamTysL
802+
803+
let knownReturnType =
804+
match knownReturnType with
805+
| None -> None
806+
| Some _ -> Some (FSComp.SR.csNoOverloadsFoundReturnType returnType)
807+
808+
let genericParametersMessage =
809+
match genericParameterTypes with
810+
| [] -> None
811+
| [_] -> Some (FSComp.SR.csNoOverloadsFoundTypeParametersPrefixSingular genericParametersMessage)
812+
| _ -> Some (FSComp.SR.csNoOverloadsFoundTypeParametersPrefixPlural genericParametersMessage)
813+
814+
let overloadMethodInfo displayEnv m (x: OverloadInformation) =
815+
let paramInfo =
816+
match x.error with
817+
| :? ArgDoesNotMatchError as x ->
818+
let nameOrOneBasedIndexMessage =
819+
x.calledArg.NameOpt
820+
|> Option.map (fun n -> FSComp.SR.csOverloadCandidateNamedArgumentTypeMismatch n.idText)
821+
|> Option.defaultValue (FSComp.SR.csOverloadCandidateIndexedArgumentTypeMismatch ((snd x.calledArg.Position) + 1))
822+
sprintf " // %s" nameOrOneBasedIndexMessage
823+
| _ -> ""
824+
825+
(NicePrint.stringOfMethInfo x.amap m displayEnv x.methodSlot.Method) + paramInfo
826+
827+
let nl = System.Environment.NewLine
828+
let formatOverloads (overloads: OverloadInformation list) =
829+
overloads
830+
|> List.map (overloadMethodInfo denv m)
831+
|> List.sort
832+
|> List.map FSComp.SR.formatDashItem
833+
|> String.concat nl
834+
835+
// assemble final message composing the parts
836+
let msg =
837+
let optionalParts =
838+
[knownReturnType; genericParametersMessage; argsMessage]
839+
|> List.choose id
840+
|> String.concat (nl + nl)
841+
|> function | "" -> nl
842+
| result -> nl + nl + result + nl + nl
843+
844+
match failure with
845+
| NoOverloadsFound (methodName, overloads, _) ->
846+
FSComp.SR.csNoOverloadsFound methodName
847+
+ optionalParts
848+
+ (FSComp.SR.csAvailableOverloads (formatOverloads overloads))
849+
| PossibleCandidates (methodName, [], _) ->
850+
FSComp.SR.csMethodIsOverloaded methodName
851+
| PossibleCandidates (methodName, overloads, _) ->
852+
FSComp.SR.csMethodIsOverloaded methodName
853+
+ optionalParts
854+
+ FSComp.SR.csCandidates (formatOverloads overloads)
855+
856+
os.Append msg |> ignore
775857

776858
| UnresolvedConversionOperator(denv, fromTy, toTy, _) ->
777859
let t1, t2, _tpcs = NicePrint.minimalStringsOfTwoTypes denv fromTy toTy
778860
os.Append(FSComp.SR.csTypeDoesNotSupportConversion(t1, t2)) |> ignore
779861

780-
| PossibleOverload(_, minfo, originalError, _) ->
781-
// print original error that describes reason why this overload was rejected
782-
let buf = new StringBuilder()
783-
OutputExceptionR buf originalError
784-
785-
os.Append(PossibleOverloadE().Format minfo (buf.ToString())) |> ignore
786-
787862
| FunctionExpected _ ->
788863
os.Append(FunctionExpectedE().Format) |> ignore
789864

0 commit comments

Comments
 (0)