From 9512ed16b717b16fb8701f547767a3c4bf55a407 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Fri, 2 Jun 2017 00:24:29 +0200 Subject: [PATCH] Better error message for list/array init (#3161) * Better error message for list/array init * add comma --- src/fsharp/CompileOps.fs | 18 ++++++--- src/fsharp/ConstraintSolver.fs | 2 + src/fsharp/ConstraintSolver.fsi | 2 + src/fsharp/FSComp.txt | 4 +- src/fsharp/TypeChecker.fs | 10 ++++- tests/fsharp/typecheck/sigs/neg20.bsl | 37 ++++--------------- tests/fsharp/typecheck/sigs/neg21.bsl | 18 ++------- .../Source/Warnings/ElseBranchHasWrongType.fs | 2 +- .../Warnings/ElseBranchHasWrongType2.fs | 2 +- 9 files changed, 41 insertions(+), 54 deletions(-) diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs index cb653ac93..106c23b17 100644 --- a/src/fsharp/CompileOps.fs +++ b/src/fsharp/CompileOps.fs @@ -623,15 +623,11 @@ let OutputPhasedErrorR (os:StringBuilder) (err:PhasedDiagnostic) = os.Append(ConstraintSolverMissingConstraintE().Format (NicePrint.stringOfTyparConstraint denv (tpr,tpc))) |> ignore if m.StartLine <> m2.StartLine then os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore - | ConstraintSolverTypesNotInEqualityRelation(denv,(TType_measure _ as t1),(TType_measure _ as t2),m,m2,contextInfo) -> + | ConstraintSolverTypesNotInEqualityRelation(denv,(TType_measure _ as t1),(TType_measure _ as t2),m,m2,_) -> // REVIEW: consider if we need to show _cxs (the type parameter constraints) let t1, t2, _cxs = NicePrint.minimalStringsOfTwoTypes denv t1 t2 - match contextInfo with - | ContextInfo.IfExpression range when range = m -> os.Append(FSComp.SR.ifExpression(t1,t2)) |> ignore - | ContextInfo.OmittedElseBranch range when range = m -> os.Append(FSComp.SR.missingElseBranch(t2)) |> ignore - | ContextInfo.ElseBranchResult range when range = m -> os.Append(FSComp.SR.elseBranchHasWrongType(t1,t2)) |> ignore - | _ -> os.Append(ConstraintSolverTypesNotInEqualityRelation1E().Format t1 t2 ) |> ignore + os.Append(ConstraintSolverTypesNotInEqualityRelation1E().Format t1 t2 ) |> ignore if m.StartLine <> m2.StartLine then os.Append(SeeAlsoE().Format (stringOfRange m)) |> ignore @@ -641,6 +637,11 @@ let OutputPhasedErrorR (os:StringBuilder) (err:PhasedDiagnostic) = match contextInfo with | ContextInfo.IfExpression range when range = m -> os.Append(FSComp.SR.ifExpression(t1,t2)) |> ignore + | ContextInfo.CollectionElement (isArray,range) when range = m -> + if isArray then + os.Append(FSComp.SR.arrayElementHasWrongType(t1,t2)) |> ignore + else + os.Append(FSComp.SR.listElementHasWrongType(t1,t2)) |> ignore | ContextInfo.OmittedElseBranch range when range = m -> os.Append(FSComp.SR.missingElseBranch(t2)) |> ignore | ContextInfo.ElseBranchResult range when range = m -> os.Append(FSComp.SR.elseBranchHasWrongType(t1,t2)) |> ignore | _ -> os.Append(ConstraintSolverTypesNotInEqualityRelation2E().Format t1 t2) |> ignore @@ -667,6 +668,11 @@ let OutputPhasedErrorR (os:StringBuilder) (err:PhasedDiagnostic) = let t1,t2,tpcs = NicePrint.minimalStringsOfTwoTypes denv t1 t2 match contextInfo with | ContextInfo.IfExpression range when range = m -> os.Append(FSComp.SR.ifExpression(t1,t2)) |> ignore + | ContextInfo.CollectionElement (isArray,range) when range = m -> + if isArray then + os.Append(FSComp.SR.arrayElementHasWrongType(t1,t2)) |> ignore + else + os.Append(FSComp.SR.listElementHasWrongType(t1,t2)) |> ignore | ContextInfo.OmittedElseBranch range when range = m -> os.Append(FSComp.SR.missingElseBranch(t2)) |> ignore | ContextInfo.ElseBranchResult range when range = m -> os.Append(FSComp.SR.elseBranchHasWrongType(t1,t2)) |> ignore | ContextInfo.TupleInRecordFields -> diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index 859bf7668..f65b981c9 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -127,6 +127,8 @@ type ContextInfo = | RecordFields /// The type equation comes from the verification of a tuple in record fields. | TupleInRecordFields +/// The type equation comes from a list or array constructor +| CollectionElement of bool * range /// The type equation comes from a return in a computation expression. | ReturnInComputationExpression /// The type equation comes from a yield in a computation expression. diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index 780978787..880bf98c7 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -62,6 +62,8 @@ type ContextInfo = | RecordFields /// The type equation comes from the verification of a tuple in record fields. | TupleInRecordFields +/// The type equation comes from a list or array constructor +| CollectionElement of bool * range /// The type equation comes from a return in a computation expression. | ReturnInComputationExpression /// The type equation comes from a yield in a computation expression. diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 702c8b212..ede5a0f4e 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -16,9 +16,11 @@ undefinedNameSuggestionsIntro,"Maybe you want one of the following:" undefinedNameTypeParameter,"The type parameter %s is not defined." undefinedNamePatternDiscriminator,"The pattern discriminator '%s' is not defined." replaceWithSuggestion,"Replace with '%s'" +listElementHasWrongType,"All elements of a list constructor expression must have the same type. This expression was expected to have type '%s', but here has type '%s'." +arrayElementHasWrongType,"All elements of an array constructor expression must have the same type. This expression was expected to have type '%s', but here has type '%s'." missingElseBranch,"The 'if' expression is missing an 'else' branch. The 'then' branch has type '%s'. Because 'if' is an expression, and not a statement, add an 'else' branch which returns a value of the same type." ifExpression,"The 'if' expression needs to have type '%s' to satisfy context type requirements. It currently has type '%s'." -elseBranchHasWrongType,"All branches of an 'if' expression must return the same type. This expression was expected to have type '%s' but here has type '%s'." +elseBranchHasWrongType,"All branches of an 'if' expression must return the same type. This expression was expected to have type '%s', but here has type '%s'." commaInsteadOfSemicolonInRecord,"A ';' is used to separate field values in records. Consider replacing ',' with ';'." derefInsteadOfNot,"The '!' operator is used to dereference a ref cell. Consider using 'not expr' here." buildUnexpectedTypeArgs,"The non-generic type '%s' does not expect any type arguments, but here is given %d type argument(s)" diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 64ef2e593..86500baea 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -5715,7 +5715,15 @@ and TcExprUndelayed cenv overallTy env tpenv (expr: SynExpr) = // Always allow subsumption if a nominal type is known prior to type checking any arguments let flex = not (isTyparTy cenv.g argty) - let args',tpenv = List.mapFold (TcExprFlex cenv flex argty env) tpenv args + let first = ref true + let getInitEnv m = + if !first then + first := false + env + else + { env with eContextInfo = ContextInfo.CollectionElement (isArray,m) } + + let args',tpenv = List.mapFold (fun tpenv (x:SynExpr) -> TcExprFlex cenv flex argty (getInitEnv x.Range) tpenv x) tpenv args let expr = if isArray then Expr.Op(TOp.Array, [argty],args',m) diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 192550d74..aad345410 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -69,35 +69,17 @@ neg20.fs(53,38,53,39): typecheck error FS0001: This expression was expected to h but here has type 'int' -neg20.fs(60,26,60,33): typecheck error FS0001: This expression was expected to have type - 'B' -but here has type - 'A' +neg20.fs(60,26,60,33): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'B', but here has type 'A'. -neg20.fs(61,27,61,35): typecheck error FS0001: This expression was expected to have type - 'B1' -but here has type - 'B2' +neg20.fs(61,27,61,35): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'B1', but here has type 'B2'. -neg20.fs(62,26,62,33): typecheck error FS0001: This expression was expected to have type - 'C' -but here has type - 'B' +neg20.fs(62,26,62,33): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'C', but here has type 'B'. -neg20.fs(66,25,66,32): typecheck error FS0001: This expression was expected to have type - 'A' -but here has type - 'B' +neg20.fs(66,25,66,32): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'A', but here has type 'B'. -neg20.fs(67,27,67,34): typecheck error FS0001: This expression was expected to have type - 'B' -but here has type - 'C' +neg20.fs(67,27,67,34): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'B', but here has type 'C'. -neg20.fs(70,31,70,38): typecheck error FS0001: This expression was expected to have type - 'B' -but here has type - 'C' +neg20.fs(70,31,70,38): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'B', but here has type 'C'. neg20.fs(71,34,71,42): typecheck error FS0001: Type mismatch. Expecting a 'A list' @@ -128,7 +110,7 @@ but given a 'B list' The type 'A' does not match the type 'B' -neg20.fs(83,47,83,54): typecheck error FS0001: All branches of an 'if' expression must return the same type. This expression was expected to have type 'B' but here has type 'C'. +neg20.fs(83,47,83,54): typecheck error FS0001: All branches of an 'if' expression must return the same type. This expression was expected to have type 'B', but here has type 'C'. neg20.fs(87,54,87,61): typecheck error FS0001: This expression was expected to have type 'B' @@ -150,10 +132,7 @@ neg20.fs(97,26,97,33): typecheck error FS0001: This expression was expected to h but here has type 'B' -neg20.fs(99,26,99,33): typecheck error FS0001: This expression was expected to have type - 'B' -but here has type - 'A' +neg20.fs(99,26,99,33): typecheck error FS0001: All elements of a list constructor expression must have the same type. This expression was expected to have type 'B', but here has type 'A'. neg20.fs(108,12,108,16): typecheck error FS0001: Type mismatch. Expecting a 'B * B -> 'a' diff --git a/tests/fsharp/typecheck/sigs/neg21.bsl b/tests/fsharp/typecheck/sigs/neg21.bsl index b942403c3..d395b72b0 100644 --- a/tests/fsharp/typecheck/sigs/neg21.bsl +++ b/tests/fsharp/typecheck/sigs/neg21.bsl @@ -17,23 +17,11 @@ but given a 'float' The unit of measure 's ^ 3' does not match the unit of measure 's ^ 4' -neg21.fs(19,59,19,67): typecheck error FS0001: Type mismatch. Expecting a - 'area' -but given a - 'float' -The unit of measure 'sqrm' does not match the unit of measure 'm ^ 3' +neg21.fs(19,59,19,67): typecheck error FS0001: The unit of measure 'sqrm' does not match the unit of measure 'm ^ 3' -neg21.fs(20,36,20,44): typecheck error FS0001: Type mismatch. Expecting a - 'area' -but given a - 'float' -The unit of measure 'sqrm' does not match the unit of measure 'm ^ 3' +neg21.fs(20,36,20,44): typecheck error FS0001: The unit of measure 'sqrm' does not match the unit of measure 'm ^ 3' -neg21.fs(21,53,21,59): typecheck error FS0001: Type mismatch. Expecting a - 'float' -but given a - 'float' -The unit of measure 's ^ 2' does not match the unit of measure 'm' +neg21.fs(21,53,21,59): typecheck error FS0001: The unit of measure 's ^ 2' does not match the unit of measure 'm' neg21.fs(22,17,22,21): typecheck error FS0001: The unit of measure 's ^ 4' does not match the unit of measure 'sqrm' diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs index 21755964a..854d96177 100644 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs +++ b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType.fs @@ -1,5 +1,5 @@ // #Warnings -//All branches of an 'if' expression must return the same type. This expression was expected to have type 'string' but here has type 'int'. +//All branches of an 'if' expression must return the same type. This expression was expected to have type 'string', but here has type 'int'. let test = 100 let y = diff --git a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs index 5b975f056..805b53898 100644 --- a/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs +++ b/tests/fsharpqa/Source/Warnings/ElseBranchHasWrongType2.fs @@ -1,5 +1,5 @@ // #Warnings -//All branches of an 'if' expression must return the same type. This expression was expected to have type 'string' but here has type 'int'. +//All branches of an 'if' expression must return the same type. This expression was expected to have type 'string', but here has type 'int'. let test = 100 let f x = test -- GitLab