Skip to content

Commit

Permalink
Wrong type is reported in type mismatch error (#13347)
Browse files Browse the repository at this point in the history
Co-authored-by: Petr Pokorny <petrpokorny@microsoft.com>
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
Co-authored-by: Don Syme <dsyme@users.noreply.github.com>
  • Loading branch information
4 people authored Oct 17, 2022
1 parent 0040029 commit 8ba53ff
Show file tree
Hide file tree
Showing 25 changed files with 236 additions and 57 deletions.
52 changes: 34 additions & 18 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,8 @@ let UnifyTupleTypeAndInferCharacteristics contextInfo (cenv: cenv) denv m knownT
if isAnyTupleTy g knownTy then
let tupInfo, ptys = destAnyTupleTy g knownTy
let tupInfo = (if isExplicitStruct then tupInfoStruct else tupInfo)
let ptys =
if List.length ps = List.length ptys then ptys
let ptys =
if List.length ps = List.length ptys then ptys
else NewInferenceTypes g ps
tupInfo, ptys
else
Expand Down Expand Up @@ -5288,11 +5288,16 @@ and TcExprThenDynamic (cenv: cenv) overallTy env tpenv isArg e1 mQmark e2 delaye

TcExprThen cenv overallTy env tpenv isArg appExpr delayed

and TcExprsWithFlexes (cenv: cenv) env m tpenv flexes argTys args =
if List.length args <> List.length argTys then error(Error(FSComp.SR.tcExpressionCountMisMatch((List.length argTys), (List.length args)), m))
and TcExprsWithFlexes (cenv: cenv) env m tpenv flexes (argTys: TType list) (args: SynExpr list) =
if args.Length <> argTys.Length then error(Error(FSComp.SR.tcExpressionCountMisMatch((argTys.Length), (args.Length)), m))
(tpenv, List.zip3 flexes argTys args) ||> List.mapFold (fun tpenv (flex, ty, e) ->
TcExprFlex cenv flex false ty env tpenv e)

and TcExprsNoFlexes (cenv: cenv) env m tpenv (argTys: TType list) (args: SynExpr list) =
if args.Length <> argTys.Length then error(Error(FSComp.SR.tcExpressionCountMisMatch((argTys.Length), (args.Length)), m))
(tpenv, List.zip argTys args) ||> List.mapFold (fun tpenv (ty, e) ->
TcExprFlex2 cenv ty env false tpenv e)

and CheckSuperInit (cenv: cenv) objTy m =
let g = cenv.g

Expand Down Expand Up @@ -5348,7 +5353,7 @@ and TcPropagatingExprLeafThenConvert (cenv: cenv) overallTy actualTy (env: TcEnv
UnifyTypes cenv env m overallTy.Commit actualTy
f ()

/// Process a leaf construct, for cases where we propogate the overall type eagerly in
/// Process a leaf construct, for cases where we propagate the overall type eagerly in
/// some cases. Then apply additional type-directed conversions.
///
/// However in some cases favour propagating characteristics of the overall type.
Expand All @@ -5360,7 +5365,7 @@ and TcPropagatingExprLeafThenConvert (cenv: cenv) overallTy actualTy (env: TcEnv
/// - tuple (except if overallTy is a tuple type or a variable type that can become one)
/// - anon record (except if overallTy is an anon record type or a variable type that can become one)
/// - record (except if overallTy is requiresCtor || haveCtor or a record type or a variable type that can become one))
and TcPossiblyPropogatingExprLeafThenConvert isPropagating (cenv: cenv) (overallTy: OverallTy) (env: TcEnv) m processExpr =
and TcPossiblyPropagatingExprLeafThenConvert isPropagating (cenv: cenv) (overallTy: OverallTy) (env: TcEnv) m processExpr =

let g = cenv.g

Expand Down Expand Up @@ -5538,7 +5543,7 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE

| SynExpr.AnonRecd (isStruct, withExprOpt, unsortedFieldExprs, mWholeExpr) ->
TcNonControlFlowExpr env <| fun env ->
TcPossiblyPropogatingExprLeafThenConvert (fun ty -> isAnonRecdTy g ty || isTyparTy g ty) cenv overallTy env mWholeExpr (fun overallTy ->
TcPossiblyPropagatingExprLeafThenConvert (fun ty -> isAnonRecdTy g ty || isTyparTy g ty) cenv overallTy env mWholeExpr (fun overallTy ->
TcAnonRecdExpr cenv overallTy env tpenv (isStruct, withExprOpt, unsortedFieldExprs, mWholeExpr)
)

Expand Down Expand Up @@ -5799,13 +5804,27 @@ and TcExprLazy (cenv: cenv) overallTy env tpenv (synInnerExpr, m) =
let expr = mkLazyDelayed g m innerTy (mkUnitDelayLambda g m innerExpr)
expr, tpenv

and CheckTupleIsCorrectLength g (env: TcEnv) m tupleTy (args: 'a list) tcArgs =
if isAnyTupleTy g tupleTy then
let tupInfo, ptys = destAnyTupleTy g tupleTy

if args.Length <> ptys.Length then
let argTys = NewInferenceTypes g args
suppressErrorReporting (fun () -> tcArgs argTys)
let expectedTy = TType_tuple (tupInfo, argTys)

// We let error recovery handle this exception
error (ErrorFromAddingTypeEquation(g, env.DisplayEnv, tupleTy, expectedTy,
(ConstraintSolverTupleDiffLengths(env.DisplayEnv, ptys, argTys, m, m)), m))

and TcExprTuple (cenv: cenv) overallTy env tpenv (isExplicitStruct, args, m) =
let g = cenv.g
TcPossiblyPropogatingExprLeafThenConvert (fun ty -> isAnyTupleTy g ty || isTyparTy g ty) cenv overallTy env m (fun overallTy ->
let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args
TcPossiblyPropagatingExprLeafThenConvert (fun ty -> isAnyTupleTy g ty || isTyparTy g ty) cenv overallTy env m (fun overallTy ->

let flexes = argTys |> List.map (fun _ -> false)
let argsR, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys args
CheckTupleIsCorrectLength g env m overallTy args (fun argTys -> TcExprsNoFlexes cenv env m tpenv argTys args |> ignore)

let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m overallTy isExplicitStruct args
let argsR, tpenv = TcExprsNoFlexes cenv env m tpenv argTys args
let expr = mkAnyTupled g m tupInfo argsR argTys
expr, tpenv
)
Expand Down Expand Up @@ -5882,7 +5901,7 @@ and TcExprRecord (cenv: cenv) overallTy env tpenv (inherits, withExprOpt, synRec
CallExprHasTypeSink cenv.tcSink (mWholeExpr, env.NameEnv, overallTy.Commit, env.AccessRights)
let requiresCtor = (GetCtorShapeCounter env = 1) // Get special expression forms for constructors
let haveCtor = Option.isSome inherits
TcPossiblyPropogatingExprLeafThenConvert (fun ty -> requiresCtor || haveCtor || isRecdTy g ty || isTyparTy g ty) cenv overallTy env mWholeExpr (fun overallTy ->
TcPossiblyPropagatingExprLeafThenConvert (fun ty -> requiresCtor || haveCtor || isRecdTy g ty || isTyparTy g ty) cenv overallTy env mWholeExpr (fun overallTy ->
TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, mWholeExpr)
)

Expand Down Expand Up @@ -6085,8 +6104,7 @@ and TcExprILAssembly (cenv: cenv) overallTy env tpenv (ilInstrs, synTyArgs, synA
let argTys = NewInferenceTypes g synArgs
let tyargs, tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType WarnOnIWSAM.Yes env tpenv synTyArgs
// No subsumption at uses of IL assembly code
let flexes = argTys |> List.map (fun _ -> false)
let args, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys synArgs
let args, tpenv = TcExprsNoFlexes cenv env m tpenv argTys synArgs
let retTys, tpenv = TcTypes cenv NewTyparsOK CheckCxs ItemOccurence.UseInType WarnOnIWSAM.Yes env tpenv synRetTys
let returnTy =
match retTys with
Expand Down Expand Up @@ -7151,8 +7169,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn
mkCallNewFormat g m printerTy printerArgTy printerResidueTy printerResultTy printerTupleTy str, tpenv
else
// Type check the expressions filling the holes
let flexes = argTys |> List.map (fun _ -> false)
let fillExprs, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys synFillExprs
let fillExprs, tpenv = TcExprsNoFlexes cenv env m tpenv argTys synFillExprs

let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m)

Expand All @@ -7178,8 +7195,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn
| Choice2Of2 createFormattableStringMethod ->

// Type check the expressions filling the holes
let flexes = argTys |> List.map (fun _ -> false)
let fillExprs, tpenv = TcExprsWithFlexes cenv env m tpenv flexes argTys synFillExprs
let fillExprs, tpenv = TcExprsNoFlexes cenv env m tpenv argTys synFillExprs

let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m)

Expand Down
6 changes: 6 additions & 0 deletions src/Compiler/Checking/CheckExpressions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,12 @@ val TcExpr:
synExpr: SynExpr ->
Expr * UnscopedTyparEnv

/// Check that 'args' have the correct number of elements for a tuple expression.
/// If not, use 'tcArgs' to type check the given elements to show
/// their correct types (if known) in the error message and raise the error
val CheckTupleIsCorrectLength:
g: TcGlobals -> env: TcEnv -> m: range -> tupleTy: TType -> args: 'a list -> tcArgs: (TType list -> unit) -> unit

/// Converts 'a..b' to a call to the '(..)' operator in FSharp.Core
/// Converts 'a..b..c' to a call to the '(.. ..)' operator in FSharp.Core
val RewriteRangeExpr: synExpr: SynExpr -> SynExpr option
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Checking/CheckPatterns.fs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@ and TcPatAnds warnOnUpper cenv env vFlags patEnv ty pats m =
and TcPatTuple warnOnUpper cenv env vFlags patEnv ty isExplicitStruct args m =
let g = cenv.g
try
CheckTupleIsCorrectLength g env m ty args (fun argTys -> TcPatterns warnOnUpper cenv env vFlags patEnv argTys args |> ignore)

let tupInfo, argTys = UnifyTupleTypeAndInferCharacteristics env.eContextInfo cenv env.DisplayEnv m ty isExplicitStruct args
let argsR, acc = TcPatterns warnOnUpper cenv env vFlags patEnv argTys args
let phase2 values = TPat_tuple(tupInfo, List.map (fun f -> f values) argsR, argTys, m)
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,9 +1225,9 @@ and SolveTypeEqualsTypeEqns csenv ndeep m2 trace cxsln origl1 origl2 =
let rec loop l1 l2 =
match l1, l2 with
| [], [] -> CompleteD
| h1 :: t1, h2 :: t2 ->
| h1 :: t1, h2 :: t2 when t1.Length = t2.Length ->
SolveTypeEqualsTypeKeepAbbrevsWithCxsln csenv ndeep m2 trace cxsln h1 h2 ++ (fun () -> loop t1 t2)
| _ ->
| _ ->
ErrorD(ConstraintSolverTupleDiffLengths(csenv.DisplayEnv, origl1, origl2, csenv.m, m2))
loop origl1 origl2

Expand Down
7 changes: 7 additions & 0 deletions src/Compiler/Driver/CompilerDiagnostics.fs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ module OldStyleMessages =
let ConstraintSolverTypesNotInSubsumptionRelationE () = Message("ConstraintSolverTypesNotInSubsumptionRelation", "%s%s%s")
let ErrorFromAddingTypeEquation1E () = Message("ErrorFromAddingTypeEquation1", "%s%s%s")
let ErrorFromAddingTypeEquation2E () = Message("ErrorFromAddingTypeEquation2", "%s%s%s")
let ErrorFromAddingTypeEquationTuplesE () = Message("ErrorFromAddingTypeEquationTuples", "%d%s%d%s%s")
let ErrorFromApplyingDefault1E () = Message("ErrorFromApplyingDefault1", "%s")
let ErrorFromApplyingDefault2E () = Message("ErrorFromApplyingDefault2", "")
let ErrorsFromAddingSubsumptionConstraintE () = Message("ErrorsFromAddingSubsumptionConstraint", "%s%s%s")
Expand Down Expand Up @@ -737,6 +738,12 @@ type Exception with

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

| ErrorFromAddingTypeEquation (_g, denv, ty1, ty2, ConstraintSolverTupleDiffLengths (_, tl1, tl2, _, _), _) ->
let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2

if ty1 <> ty2 + tpcs then
os.AppendString(ErrorFromAddingTypeEquationTuplesE().Format tl1.Length ty1 tl2.Length ty2 tpcs)

| ErrorFromAddingTypeEquation (g, denv, ty1, ty2, e, _) ->
if not (typeEquiv g ty1 ty2) then
let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2
Expand Down
7 changes: 5 additions & 2 deletions src/Compiler/FSStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@
<data name="Parser.TOKEN.AND" xml:space="preserve">
<value>keyword 'and'</value>
</data>
!<data name="Parser.TOKEN.AND.BANG" xml:space="preserve">
<data name="Parser.TOKEN.AND.BANG" xml:space="preserve">
<value>keyword 'and!'</value>
</data>
<data name="Parser.TOKEN.AS" xml:space="preserve">
Expand Down Expand Up @@ -907,7 +907,7 @@
<value>This expression is a function value, i.e. is missing arguments. Its type is {0}.</value>
</data>
<data name="UnitTypeExpected" xml:space="preserve">
<value>The result of this expression has type '{0}' 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'.</value>
<value>The result of this expression has type '{0}' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |&gt; ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.</value>
</data>
<data name="UnitTypeExpectedWithEquality" xml:space="preserve">
<value>The result of this equality expression has type '{0}' and is implicitly discarded. Consider using 'let' to bind the result to a name, e.g. 'let result = expression'.</value>
Expand Down Expand Up @@ -1110,4 +1110,7 @@
<data name="NotUpperCaseConstructorWithoutRQA" xml:space="preserve">
<value>Lowercase discriminated union cases are only allowed when using RequireQualifiedAccess attribute</value>
</data>
<data name="ErrorFromAddingTypeEquationTuples" xml:space="preserve">
<value>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</value>
</data>
</root>
2 changes: 1 addition & 1 deletion src/Compiler/Facilities/DiagnosticsLogger.fs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ let conditionallySuppressErrorReporting cond f =
//------------------------------------------------------------------------
// Errors as data: Sometimes we have to reify errors as data, e.g. if backtracking

/// The result type of a computational modality to colelct warnings and possibly fail
/// The result type of a computational modality to collect warnings and possibly fail
[<NoEquality; NoComparison>]
type OperationResult<'T> =
| OkResult of warnings: exn list * result: 'T
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="cs" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">Nejméně jedna informační zpráva v načteném souboru\n</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="de" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">Mindestens eine Informationsmeldung in der geladenen Datei.\n</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="es" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">Uno o más mensajes informativos en el archivo cargado.\n</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="fr" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">Un ou plusieurs messages d’information dans le fichier chargé.\n</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="it" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">Uno o più messaggi informativi nel file caricato.\n</target>
Expand Down
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSStrings.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<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">
<file datatype="xml" source-language="en" target-language="ja" original="../FSStrings.resx">
<body>
<trans-unit id="ErrorFromAddingTypeEquationTuples">
<source>Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</source>
<target state="new">Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n</target>
<note />
</trans-unit>
<trans-unit id="HashLoadedSourceHasIssues0">
<source>One or more informational messages in loaded file.\n</source>
<target state="translated">読み込まれたファイル内の 1 つ以上の情報メッセージ。\n</target>
Expand Down
Loading

0 comments on commit 8ba53ff

Please sign in to comment.