Skip to content

Commit 4842127

Browse files
smoothdeveloperbaronfel
authored andcommitted
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 37575d6 commit 4842127

File tree

13 files changed

+363
-149
lines changed

13 files changed

+363
-149
lines changed

src/fsharp/CompileOps.fs

Lines changed: 90 additions & 15 deletions
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)