Skip to content

Commit 4ad5615

Browse files
authored
Keeping error context for tuple length mismatch (dotnet#14003)
1 parent a5dfa94 commit 4ad5615

19 files changed

Lines changed: 452 additions & 49 deletions

src/Compiler/Checking/CheckExpressions.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5815,7 +5815,7 @@ and CheckTupleIsCorrectLength g (env: TcEnv) m tupleTy (args: 'a list) tcArgs =
58155815

58165816
// We let error recovery handle this exception
58175817
error (ErrorFromAddingTypeEquation(g, env.DisplayEnv, tupleTy, expectedTy,
5818-
(ConstraintSolverTupleDiffLengths(env.DisplayEnv, ptys, argTys, m, m)), m))
5818+
(ConstraintSolverTupleDiffLengths(env.DisplayEnv, env.eContextInfo, ptys, argTys, m, m)), m))
58195819

58205820
and TcExprTuple (cenv: cenv) overallTy env tpenv (isExplicitStruct, args, m) =
58215821
let g = cenv.g

src/Compiler/Checking/ConstraintSolver.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ type OverallTy =
232232
| MustEqual ty -> ty
233233
| MustConvertTo (_, ty) -> ty
234234

235-
exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * TType list * TType list * range * range
235+
exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * contextInfo: ContextInfo * TType list * TType list * range * range
236236

237237
exception ConstraintSolverInfiniteTypes of displayEnv: DisplayEnv * contextInfo: ContextInfo * TType * TType * range * range
238238

@@ -1228,7 +1228,7 @@ and SolveTypeEqualsTypeEqns csenv ndeep m2 trace cxsln origl1 origl2 =
12281228
| h1 :: t1, h2 :: t2 when t1.Length = t2.Length ->
12291229
SolveTypeEqualsTypeKeepAbbrevsWithCxsln csenv ndeep m2 trace cxsln h1 h2 ++ (fun () -> loop t1 t2)
12301230
| _ ->
1231-
ErrorD(ConstraintSolverTupleDiffLengths(csenv.DisplayEnv, origl1, origl2, csenv.m, m2))
1231+
ErrorD(ConstraintSolverTupleDiffLengths(csenv.DisplayEnv, csenv.eContextInfo, origl1, origl2, csenv.m, m2))
12321232
loop origl1 origl2
12331233

12341234
and SolveFunTypeEqn csenv ndeep m2 trace cxsln domainTy1 domainTy2 rangeTy1 rangeTy2 = trackErrors {

src/Compiler/Checking/ConstraintSolver.fsi

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,13 @@ type OverallTy =
141141
/// Represents a point where no subsumption/widening is possible
142142
member Commit: TType
143143

144-
exception ConstraintSolverTupleDiffLengths of displayEnv: DisplayEnv * TType list * TType list * range * range
144+
exception ConstraintSolverTupleDiffLengths of
145+
displayEnv: DisplayEnv *
146+
contextInfo: ContextInfo *
147+
TType list *
148+
TType list *
149+
range *
150+
range
145151

146152
exception ConstraintSolverInfiniteTypes of
147153
displayEnv: DisplayEnv *

src/Compiler/Driver/CompilerDiagnostics.fs

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ type Exception with
170170
| VirtualAugmentationOnNullValuedType m
171171
| NonVirtualAugmentationOnNullValuedType m
172172
| NonRigidTypar (_, _, _, _, _, m)
173-
| ConstraintSolverTupleDiffLengths (_, _, _, m, _)
173+
| ConstraintSolverTupleDiffLengths (_, _, _, _, m, _)
174174
| ConstraintSolverInfiniteTypes (_, _, _, _, m, _)
175175
| ConstraintSolverMissingConstraint (_, _, _, m, _)
176176
| ConstraintSolverTypesNotInEqualityRelation (_, _, _, m, _, _)
@@ -617,12 +617,28 @@ let OutputNameSuggestions (os: StringBuilder) suggestNames suggestionsF idText =
617617
os.AppendString " "
618618
os.AppendString(ConvertValLogicalNameToDisplayNameCore value)
619619

620+
let OutputTypesNotInEqualityRelationContextInfo contextInfo ty1 ty2 m (os: StringBuilder) fallback =
621+
match contextInfo with
622+
| ContextInfo.IfExpression range when equals range m -> os.AppendString(FSComp.SR.ifExpression (ty1, ty2))
623+
| ContextInfo.CollectionElement (isArray, range) when equals range m ->
624+
if isArray then
625+
os.AppendString(FSComp.SR.arrayElementHasWrongType (ty1, ty2))
626+
else
627+
os.AppendString(FSComp.SR.listElementHasWrongType (ty1, ty2))
628+
| ContextInfo.OmittedElseBranch range when equals range m -> os.AppendString(FSComp.SR.missingElseBranch (ty2))
629+
| ContextInfo.ElseBranchResult range when equals range m -> os.AppendString(FSComp.SR.elseBranchHasWrongType (ty1, ty2))
630+
| ContextInfo.FollowingPatternMatchClause range when equals range m ->
631+
os.AppendString(FSComp.SR.followingPatternMatchClauseHasWrongType (ty1, ty2))
632+
| ContextInfo.PatternMatchGuard range when equals range m -> os.AppendString(FSComp.SR.patternMatchGuardIsNotBool (ty2))
633+
| contextInfo -> fallback contextInfo
634+
620635
type Exception with
621636

622637
member exn.Output(os: StringBuilder, suggestNames) =
623638

624639
match exn with
625-
| ConstraintSolverTupleDiffLengths (_, tl1, tl2, m, m2) ->
640+
// TODO: this is now unused...?
641+
| ConstraintSolverTupleDiffLengths (_, _, tl1, tl2, m, m2) ->
626642
os.AppendString(ConstraintSolverTupleDiffLengthsE().Format tl1.Length tl2.Length)
627643

628644
if m.StartLine <> m2.StartLine then
@@ -663,19 +679,8 @@ type Exception with
663679
// REVIEW: consider if we need to show _cxs (the type parameter constraints)
664680
let ty1, ty2, _cxs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
665681

666-
match contextInfo with
667-
| ContextInfo.IfExpression range when equals range m -> os.AppendString(FSComp.SR.ifExpression (ty1, ty2))
668-
| ContextInfo.CollectionElement (isArray, range) when equals range m ->
669-
if isArray then
670-
os.AppendString(FSComp.SR.arrayElementHasWrongType (ty1, ty2))
671-
else
672-
os.AppendString(FSComp.SR.listElementHasWrongType (ty1, ty2))
673-
| ContextInfo.OmittedElseBranch range when equals range m -> os.AppendString(FSComp.SR.missingElseBranch (ty2))
674-
| ContextInfo.ElseBranchResult range when equals range m -> os.AppendString(FSComp.SR.elseBranchHasWrongType (ty1, ty2))
675-
| ContextInfo.FollowingPatternMatchClause range when equals range m ->
676-
os.AppendString(FSComp.SR.followingPatternMatchClauseHasWrongType (ty1, ty2))
677-
| ContextInfo.PatternMatchGuard range when equals range m -> os.AppendString(FSComp.SR.patternMatchGuardIsNotBool (ty2))
678-
| _ -> os.AppendString(ConstraintSolverTypesNotInEqualityRelation2E().Format ty1 ty2)
682+
OutputTypesNotInEqualityRelationContextInfo contextInfo ty1 ty2 m os (fun _ ->
683+
os.AppendString(ConstraintSolverTypesNotInEqualityRelation2E().Format ty1 ty2))
679684

680685
if m.StartLine <> m2.StartLine then
681686
os.AppendString(SeeAlsoE().Format(stringOfRange m))
@@ -699,33 +704,15 @@ type Exception with
699704
->
700705
let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
701706

702-
match contextInfo with
703-
| ContextInfo.IfExpression range when equals range m -> os.AppendString(FSComp.SR.ifExpression (ty1, ty2))
704-
705-
| ContextInfo.CollectionElement (isArray, range) when equals range m ->
706-
if isArray then
707-
os.AppendString(FSComp.SR.arrayElementHasWrongType (ty1, ty2))
708-
else
709-
os.AppendString(FSComp.SR.listElementHasWrongType (ty1, ty2))
710-
711-
| ContextInfo.OmittedElseBranch range when equals range m -> os.AppendString(FSComp.SR.missingElseBranch (ty2))
712-
713-
| ContextInfo.ElseBranchResult range when equals range m -> os.AppendString(FSComp.SR.elseBranchHasWrongType (ty1, ty2))
714-
715-
| ContextInfo.FollowingPatternMatchClause range when equals range m ->
716-
os.AppendString(FSComp.SR.followingPatternMatchClauseHasWrongType (ty1, ty2))
717-
718-
| ContextInfo.PatternMatchGuard range when equals range m -> os.AppendString(FSComp.SR.patternMatchGuardIsNotBool (ty2))
719-
720-
| ContextInfo.TupleInRecordFields ->
721-
os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)
722-
os.AppendString(Environment.NewLine + FSComp.SR.commaInsteadOfSemicolonInRecord ())
723-
724-
| _ when ty2 = "bool" && ty1.EndsWithOrdinal(" ref") ->
725-
os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)
726-
os.AppendString(Environment.NewLine + FSComp.SR.derefInsteadOfNot ())
727-
728-
| _ -> os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)
707+
OutputTypesNotInEqualityRelationContextInfo contextInfo ty1 ty2 m os (fun contextInfo ->
708+
match contextInfo with
709+
| ContextInfo.TupleInRecordFields ->
710+
os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)
711+
os.AppendString(Environment.NewLine + FSComp.SR.commaInsteadOfSemicolonInRecord ())
712+
| _ when ty2 = "bool" && ty1.EndsWithOrdinal(" ref") ->
713+
os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)
714+
os.AppendString(Environment.NewLine + FSComp.SR.derefInsteadOfNot ())
715+
| _ -> os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs))
729716

730717
| ErrorFromAddingTypeEquation (_, _, _, _, (ConstraintSolverTypesNotInEqualityRelation (_, _, _, _, _, contextInfo) as e), _) when
731718
(match contextInfo with
@@ -738,11 +725,23 @@ type Exception with
738725

739726
| ErrorFromAddingTypeEquation(error = ConstraintSolverError _ as e) -> e.Output(os, suggestNames)
740727

741-
| ErrorFromAddingTypeEquation (_g, denv, ty1, ty2, ConstraintSolverTupleDiffLengths (_, tl1, tl2, _, _), _) ->
728+
| ErrorFromAddingTypeEquation (_g, denv, ty1, ty2, ConstraintSolverTupleDiffLengths (_, contextInfo, tl1, tl2, _, _), m) ->
742729
let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
730+
let messageArgs = tl1.Length, ty1, tl2.Length, ty2
743731

744732
if ty1 <> ty2 + tpcs then
745-
os.AppendString(ErrorFromAddingTypeEquationTuplesE().Format tl1.Length ty1 tl2.Length ty2 tpcs)
733+
match contextInfo with
734+
| ContextInfo.IfExpression range when equals range m -> os.AppendString(FSComp.SR.ifExpressionTuple messageArgs)
735+
| ContextInfo.ElseBranchResult range when equals range m ->
736+
os.AppendString(FSComp.SR.elseBranchHasWrongTypeTuple messageArgs)
737+
| ContextInfo.FollowingPatternMatchClause range when equals range m ->
738+
os.AppendString(FSComp.SR.followingPatternMatchClauseHasWrongTypeTuple messageArgs)
739+
| ContextInfo.CollectionElement (isArray, range) when equals range m ->
740+
if isArray then
741+
os.AppendString(FSComp.SR.arrayElementHasWrongTypeTuple messageArgs)
742+
else
743+
os.AppendString(FSComp.SR.listElementHasWrongTypeTuple messageArgs)
744+
| _ -> os.AppendString(ErrorFromAddingTypeEquationTuplesE().Format tl1.Length ty1 tl2.Length ty2 tpcs)
746745

747746
| ErrorFromAddingTypeEquation (g, denv, ty1, ty2, e, _) ->
748747
if not (typeEquiv g ty1 ty2) then
@@ -2107,7 +2106,7 @@ type PhasedDiagnostic with
21072106
Printf.bprintf buf "\n"
21082107

21092108
match e with
2110-
| FormattedDiagnostic.Short (_, txt) -> buf.AppendString txt |> ignore
2109+
| FormattedDiagnostic.Short (_, txt) -> buf.AppendString txt
21112110
| FormattedDiagnostic.Long (_, details) ->
21122111
match details.Location with
21132112
| Some l when not l.IsEmpty -> buf.AppendString l.TextRepresentation

src/Compiler/FSComp.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@ undefinedNamePatternDiscriminator,"The pattern discriminator '%s' is not defined
1919
replaceWithSuggestion,"Replace with '%s'"
2020
addIndexerDot,"Add . for indexer access."
2121
listElementHasWrongType,"All elements of a list must be implicitly convertible to the type of the first element, which here is '%s'. This element has type '%s'."
22+
listElementHasWrongTypeTuple,"All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length %d of type\n %s \nThis element is a tuple of length %d of type\n %s \n"
2223
arrayElementHasWrongType,"All elements of an array must be implicitly convertible to the type of the first element, which here is '%s'. This element has type '%s'."
24+
arrayElementHasWrongTypeTuple,"All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length %d of type\n %s \nThis element is a tuple of length %d of type\n %s \n"
2325
missingElseBranch,"This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type '%s'."
2426
ifExpression,"The 'if' expression needs to have type '%s' to satisfy context type requirements. It currently has type '%s'."
27+
ifExpressionTuple,"The 'if' expression needs to return a tuple of length %d of type\n %s \nto satisfy context type requirements. It currently returns a tuple of length %d of type\n %s \n"
2528
elseBranchHasWrongType,"All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is '%s'. This branch returns a value of type '%s'."
29+
elseBranchHasWrongTypeTuple,"All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length %d of type\n %s \nThis branch returns a tuple of length %d of type\n %s \n"
2630
followingPatternMatchClauseHasWrongType,"All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is '%s'. This branch returns a value of type '%s'."
31+
followingPatternMatchClauseHasWrongTypeTuple,"All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length %d of type\n %s \nThis branch returns a tuple of length %d of type\n %s \n"
2732
patternMatchGuardIsNotBool,"A pattern match guard must be of type 'bool', but this 'when' expression is of type '%s'."
2833
commaInsteadOfSemicolonInRecord,"A ';' is used to separate field values in records. Consider replacing ',' with ';'."
2934
derefInsteadOfNot,"The '!' operator is used to dereference a ref cell. Consider using 'not expr' here."

src/Compiler/xlf/FSComp.txt.cs.xlf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
33
<file datatype="xml" source-language="en" target-language="cs" original="../FSComp.resx">
44
<body>
5+
<trans-unit id="arrayElementHasWrongTypeTuple">
6+
<source>All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n</source>
7+
<target state="new">All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n</target>
8+
<note />
9+
</trans-unit>
510
<trans-unit id="buildInvalidSourceFileExtensionML">
611
<source>The file extension of '{0}' is not recognized. Source files must have extension .fs, .fsi, .fsx or .fsscript. To enable the deprecated use of .ml or .mli extensions, use '--langversion:5.0' and '--mlcompatibility'.</source>
712
<target state="translated">Soubor {0} má nerozpoznanou příponu. Zdrojové soubory musí mít příponu .fs, .fsi, .fsx nebo .fsscript. Pokud chcete povolit použití zastaralých přípon .ml nebo .mli, použijte parametry --langversion:5.0 a --mlcompatibility.</target>
@@ -107,6 +112,11 @@
107112
<target state="translated">Argument {0} neodpovídá</target>
108113
<note />
109114
</trans-unit>
115+
<trans-unit id="elseBranchHasWrongTypeTuple">
116+
<source>All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length {0} of type\n {1} \nThis branch returns a tuple of length {2} of type\n {3} \n</source>
117+
<target state="new">All branches of an 'if' expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length {0} of type\n {1} \nThis branch returns a tuple of length {2} of type\n {3} \n</target>
118+
<note />
119+
</trans-unit>
110120
<trans-unit id="etProviderHasDesignerAssemblyDependency">
111121
<source>The type provider designer assembly '{0}' could not be loaded from folder '{1}' because a dependency was missing or could not loaded. All dependencies of the type provider designer assembly must be located in the same folder as that assembly. The exception reported was: {2} - {3}</source>
112122
<target state="translated">Navržené sestavení poskytovatele typu {0} nešlo načíst ze složky {1}, protože chyběla závislost nebo ji nešlo načíst. Všechny závislosti tohoto sestavení se musí nacházet ve stejné složce jako toto sestavení. Ohlášená výjimka: {2} – {3}</target>
@@ -317,6 +327,11 @@
317327
<target state="translated">Předávání kopie clusteru pro omezení vlastností v uvozovkách v jazyce F#</target>
318328
<note />
319329
</trans-unit>
330+
<trans-unit id="followingPatternMatchClauseHasWrongTypeTuple">
331+
<source>All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length {0} of type\n {1} \nThis branch returns a tuple of length {2} of type\n {3} \n</source>
332+
<target state="new">All branches of a pattern match expression must return values implicitly convertible to the type of the first branch, which here is a tuple of length {0} of type\n {1} \nThis branch returns a tuple of length {2} of type\n {3} \n</target>
333+
<note />
334+
</trans-unit>
320335
<trans-unit id="forFormatInvalidForInterpolated">
321336
<source>Interpolated strings may not use '%' format specifiers unless each is given an expression, e.g. '%d{{1+1}}'.</source>
322337
<target state="translated">Interpolované řetězce nemůžou používat specifikátory formátu %, pokud se každému z nich nezadá nějaký výraz, např. %d{{1+1}}.</target>
@@ -357,6 +372,11 @@
357372
<target state="translated">Neplatná direktiva #{0} {1}</target>
358373
<note />
359374
</trans-unit>
375+
<trans-unit id="ifExpressionTuple">
376+
<source>The 'if' expression needs to return a tuple of length {0} of type\n {1} \nto satisfy context type requirements. It currently returns a tuple of length {2} of type\n {3} \n</source>
377+
<target state="new">The 'if' expression needs to return a tuple of length {0} of type\n {1} \nto satisfy context type requirements. It currently returns a tuple of length {2} of type\n {3} \n</target>
378+
<note />
379+
</trans-unit>
360380
<trans-unit id="ilxGenUnknownDebugPoint">
361381
<source>Unknown debug point '{0}'. The available debug points are '{1}'.</source>
362382
<target state="translated">Neznámý bod ladění {0}. Dostupné body ladění jsou {1}.</target>
@@ -417,6 +437,11 @@
417437
<target state="translated">Neplatný interpolovaný řetězec. V interpolovaných výrazech se nedají použít řetězcové literály s trojitými uvozovkami. Zvažte možnost použít pro interpolovaný výraz explicitní vazbu let.</target>
418438
<note />
419439
</trans-unit>
440+
<trans-unit id="listElementHasWrongTypeTuple">
441+
<source>All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n</source>
442+
<target state="new">All elements of a list must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n</target>
443+
<note />
444+
</trans-unit>
420445
<trans-unit id="matchNotAllowedForUnionCaseWithNoData">
421446
<source>Pattern discard is not allowed for union case that takes no data.</source>
422447
<target state="new">Pattern discard is not allowed for union case that takes no data.</target>

0 commit comments

Comments
 (0)