diff --git a/src/fsharp/CompileOps.fs b/src/fsharp/CompileOps.fs
index 5585ae6a6f9..63dba3fed83 100644
--- a/src/fsharp/CompileOps.fs
+++ b/src/fsharp/CompileOps.fs
@@ -404,6 +404,7 @@ let warningOn err level specificWarnOn =
| 1182 -> false // chkUnusedValue - off by default
| 3218 -> false // ArgumentsInSigAndImplMismatch - off by default
| 3180 -> false // abImplicitHeapAllocation - off by default
+ | 3390 -> false // xmlDocBadlyFormed - off by default
| _ -> level >= GetWarningLevel err
let SplitRelatedDiagnostics(err: PhasedDiagnostic) : PhasedDiagnostic * PhasedDiagnostic list =
diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt
index b5d1d9806ec..2ad9d2c35ba 100644
--- a/src/fsharp/FSComp.txt
+++ b/src/fsharp/FSComp.txt
@@ -1540,3 +1540,6 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable
3382,parsEmptyFillInInterpolatedString,"Invalid interpolated string. This interpolated string expression fill is empty, an expression was expected."
3383,lexRBraceInInterpolatedString,"A '}}' character must be escaped (by doubling) in an interpolated string."
#3501 "This construct is not supported by your version of the F# compiler" CompilerMessage(ExperimentalAttributeMessages.NotSupportedYet, 3501, IsError=true)
+3390,xmlDocBadlyFormed,"This XML comment is invalid: '%s'"
+3390,xmlDocMissingParameterName,"This XML comment is invalid: missing parameter name"
+3390,xmlDocInvalidParameterName,"This XML comment is invalid: invalid parameter reference '%s'"
diff --git a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
index c83d93afc3f..b00fd69c9ce 100644
--- a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
+++ b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
@@ -21,7 +21,7 @@
FSharp.Compiler.Service.nuspectrueThe F# Compiler Services package For F# $(FSLanguageVersion) exposes additional functionality for implementing F# language bindings, additional tools based on the compiler or refactoring tools. The package also includes F# interactive service that can be used for embedding F# scripting into your applications. Contains code from the F# Software Foundation.
- /blob/main/release-notes.md#FSharp-Compilere-Service-$(FSharpCompilerServiceReleaseNotesVersion)
+ /blob/main/release-notes.md#FSharp-Compiler-Service-$(FSharpCompilerServiceReleaseNotesVersion)F#, fsharp, interactive, compiler, editor
diff --git a/src/fsharp/FSharp.Core/FSharp.Core.fsproj b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
index 8eb2bb01a74..28f398848e0 100644
--- a/src/fsharp/FSharp.Core/FSharp.Core.fsproj
+++ b/src/fsharp/FSharp.Core/FSharp.Core.fsproj
@@ -9,7 +9,7 @@
true$(DefineConstants);FSHARP_COREBUILDING_WITH_LKG;$(DefineConstants)
- $(OtherFlags) --warnon:1182 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1 --nowarn:57
+ $(OtherFlags) --warnon:1182 --warnon:3390 --compiling-fslib --compiling-fslib-40 --maxerrors:20 --extraoptimizationloops:1 --nowarn:57truetrue
diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs
index 29750a8cc50..307fd22c20a 100644
--- a/src/fsharp/FSharp.Core/prim-types.fs
+++ b/src/fsharp/FSharp.Core/prim-types.fs
@@ -370,7 +370,7 @@ namespace Microsoft.FSharp.Core
[] type int16<[] 'Measure> = int16
[] type int64<[] 'Measure> = int64
- /// Represents a managed pointer in F# code.
+ /// Represents a managed pointer in F# code.
type byref<'T> = (# "!0&" #)
/// Represents a managed pointer in F# code.
diff --git a/src/fsharp/ParseHelpers.fs b/src/fsharp/ParseHelpers.fs
index 33e7872b186..6a94962108a 100644
--- a/src/fsharp/ParseHelpers.fs
+++ b/src/fsharp/ParseHelpers.fs
@@ -85,7 +85,7 @@ module LexbufLocalXmlDocStore =
lexbuf.BufferLocalStore.[xmlDocKey] <- box (XmlDocCollector())
/// Called from the lexer to save a single line of XML doc comment.
- let internal SaveXmlDocLine (lexbuf: Lexbuf, lineText, pos) =
+ let internal SaveXmlDocLine (lexbuf: Lexbuf, lineText, range: range) =
let collector =
match lexbuf.BufferLocalStore.TryGetValue xmlDocKey with
| true, collector -> collector
@@ -94,7 +94,7 @@ module LexbufLocalXmlDocStore =
lexbuf.BufferLocalStore.[xmlDocKey] <- collector
collector
let collector = unbox(collector)
- collector.AddXmlDocLine(lineText, pos)
+ collector.AddXmlDocLine(lineText, range)
/// Called from the parser each time we parse a construct that marks the end of an XML doc comment range,
/// e.g. a 'type' declaration. The markerRange is the range of the keyword that delimits the construct.
diff --git a/src/fsharp/TypedTree.fs b/src/fsharp/TypedTree.fs
index 46019fae45b..c0c82ded20e 100644
--- a/src/fsharp/TypedTree.fs
+++ b/src/fsharp/TypedTree.fs
@@ -745,7 +745,9 @@ type Entity =
member x.XmlDoc =
#if !NO_EXTENSIONTYPING
match x.TypeReprInfo with
- | TProvidedTypeExtensionPoint info -> XmlDoc (info.ProvidedType.PUntaintNoFailure(fun st -> (st :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(info.ProvidedType.TypeProvider.PUntaintNoFailure id)))
+ | TProvidedTypeExtensionPoint info ->
+ let lines = info.ProvidedType.PUntaintNoFailure(fun st -> (st :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(info.ProvidedType.TypeProvider.PUntaintNoFailure id))
+ XmlDoc (lines |> Array.map (fun line -> line, x.DefinitionRange))
| _ ->
#endif
match x.entity_opt_data with
diff --git a/src/fsharp/TypedTreePickle.fs b/src/fsharp/TypedTreePickle.fs
index 837021b92e2..6a0deb51f4a 100644
--- a/src/fsharp/TypedTreePickle.fs
+++ b/src/fsharp/TypedTreePickle.fs
@@ -1345,7 +1345,7 @@ let p_range (x: range) st =
let p_dummy_range : range pickler = fun _x _st -> ()
let p_ident (x: Ident) st = p_tup2 p_string p_range (x.idText, x.idRange) st
-let p_xmldoc (XmlDoc x) st = p_array p_string x st
+let p_xmldoc (XmlDoc lines) st = p_array p_string (Array.map fst lines) st
let u_pos st = let a = u_int st in let b = u_int st in mkPos a b
let u_range st = let a = u_string st in let b = u_pos st in let c = u_pos st in mkRange a b c
@@ -1353,7 +1353,7 @@ let u_range st = let a = u_string st in let b = u_pos st in let c = u_pos st in
// Most ranges (e.g. on optimization expressions) can be elided from stored data
let u_dummy_range : range unpickler = fun _st -> range0
let u_ident st = let a = u_string st in let b = u_range st in ident(a, b)
-let u_xmldoc st = XmlDoc (u_array u_string st)
+let u_xmldoc st = XmlDoc (u_array u_string st |> Array.map (fun line -> line, range0))
let p_local_item_ref ctxt tab st = p_osgn_ref ctxt tab st
diff --git a/src/fsharp/XmlDoc.fs b/src/fsharp/XmlDoc.fs
index dc183affeb6..7560ac1804e 100644
--- a/src/fsharp/XmlDoc.fs
+++ b/src/fsharp/XmlDoc.fs
@@ -2,37 +2,61 @@
module public FSharp.Compiler.XmlDoc
+open System
+open System.Xml.Linq
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.Lib
open FSharp.Compiler.AbstractIL.Internal.Library
open FSharp.Compiler.Range
-/// Represents the final form of collected XmlDoc lines
+/// Represents collected XmlDoc lines
type XmlDoc =
- | XmlDoc of string[]
+ | XmlDoc of (string * range)[]
static member Empty = XmlDocStatics.Empty
- member x.NonEmpty = (let (XmlDoc lines) = x in lines.Length <> 0)
+ member x.IsEmpty =
+ let (XmlDoc lines) = x
+ lines |> Array.forall (fst >> String.IsNullOrWhiteSpace)
+
+ member x.NonEmpty = not x.IsEmpty
- static member Merge (XmlDoc lines) (XmlDoc lines') = XmlDoc (Array.append lines lines')
+ static member Merge (XmlDoc lines) (XmlDoc lines') =
+ XmlDoc (Array.append lines lines')
+ member x.Range =
+ let (XmlDoc lines) = x
+ match lines with
+ | [| |] -> Range.range0
+ | _ -> Array.reduce Range.unionRanges (Array.map snd lines)
+
/// This code runs for .XML generation and thus influences cross-project xmldoc tooltips; for within-project tooltips,
/// see XmlDocumentation.fs in the language service
static member Process (XmlDoc lines) =
- let rec processLines (lines: string list) =
+ let rec processLines (lines: (string * range) list) =
match lines with
| [] -> []
- | (lineA :: rest) as lines ->
+ | ((lineA, m) :: rest) as lines ->
let lineAT = lineA.TrimStart([|' '|])
if lineAT = "" then processLines rest
else if lineAT.StartsWithOrdinal("<") then lines
- else [""] @
- (lines |> List.map (fun line -> Microsoft.FSharp.Core.XmlAdapters.escape line)) @
- [""]
+ else [("", m)] @
+ (lines |> List.map (map1Of2 Microsoft.FSharp.Core.XmlAdapters.escape)) @
+ [("", m)]
let lines = processLines (Array.toList lines)
if isNil lines then XmlDoc.Empty
else XmlDoc (Array.ofList lines)
+ member x.GetXmlText() =
+ match XmlDoc.Process x with
+ | XmlDoc [| |] -> ""
+ | XmlDoc strs ->
+ strs
+ |> Array.toList
+ |> List.map fst
+ |> String.concat Environment.NewLine
+
// Discriminated unions can't contain statics, so we use a separate type
and XmlDocStatics() =
@@ -42,14 +66,14 @@ and XmlDocStatics() =
/// Used to collect XML documentation during lexing and parsing.
type XmlDocCollector() =
- let mutable savedLines = new ResizeArray<(string * pos)>()
+ let mutable savedLines = new ResizeArray<(string * range)>()
let mutable savedGrabPoints = new ResizeArray()
let posCompare p1 p2 = if posGeq p1 p2 then 1 else if posEq p1 p2 then 0 else -1
let savedGrabPointsAsArray =
lazy (savedGrabPoints.ToArray() |> Array.sortWith posCompare)
let savedLinesAsArray =
- lazy (savedLines.ToArray() |> Array.sortWith (fun (_, p1) (_, p2) -> posCompare p1 p2))
+ lazy (savedLines.ToArray() |> Array.sortWith (fun (_, p1) (_, p2) -> posCompare p1.End p2.End))
let check() =
// can't add more XmlDoc elements to XmlDocCollector after extracting first XmlDoc from the overall results
@@ -59,15 +83,15 @@ type XmlDocCollector() =
check()
savedGrabPoints.Add pos
- member x.AddXmlDocLine(line, pos) =
+ member x.AddXmlDocLine(line, range) =
check()
- savedLines.Add(line, pos)
+ savedLines.Add(line, range)
member x.LinesBefore grabPointPos =
try
let lines = savedLinesAsArray.Force()
let grabPoints = savedGrabPointsAsArray.Force()
- let firstLineIndexAfterGrabPoint = Array.findFirstIndexWhereTrue lines (fun (_, pos) -> posGeq pos grabPointPos)
+ let firstLineIndexAfterGrabPoint = Array.findFirstIndexWhereTrue lines (fun (_, m) -> posGeq m.End grabPointPos)
let grabPointIndex = Array.findFirstIndexWhereTrue grabPoints (fun pos -> posGeq pos grabPointPos)
assert (posEq grabPoints.[grabPointIndex] grabPointPos)
let firstLineIndexAfterPrevGrabPoint =
@@ -75,10 +99,10 @@ type XmlDocCollector() =
0
else
let prevGrabPointPos = grabPoints.[grabPointIndex-1]
- Array.findFirstIndexWhereTrue lines (fun (_, pos) -> posGeq pos prevGrabPointPos)
+ Array.findFirstIndexWhereTrue lines (fun (_, m) -> posGeq m.End prevGrabPointPos)
let lines = lines.[firstLineIndexAfterPrevGrabPoint..firstLineIndexAfterGrabPoint-1]
- lines |> Array.map fst
+ lines
with e ->
[| |]
@@ -89,13 +113,42 @@ type PreXmlDoc =
| PreXmlDocEmpty
member x.ToXmlDoc() =
- match x with
- | PreXmlMerge(a, b) -> XmlDoc.Merge (a.ToXmlDoc()) (b.ToXmlDoc())
- | PreXmlDocEmpty -> XmlDoc.Empty
- | PreXmlDoc (pos, collector) ->
- let lines = collector.LinesBefore pos
- if lines.Length = 0 then XmlDoc.Empty
- else XmlDoc lines
+ let doc =
+ match x with
+ | PreXmlMerge(a, b) -> XmlDoc.Merge (a.ToXmlDoc()) (b.ToXmlDoc())
+ | PreXmlDocEmpty -> XmlDoc.Empty
+ | PreXmlDoc (pos, collector) ->
+ let lines = collector.LinesBefore pos
+ if lines.Length = 0 then XmlDoc.Empty
+ else XmlDoc lines
+ if doc.NonEmpty then
+ try
+ // We must wrap with in order to have only one root element
+ let xml = XDocument.Parse("\n"+doc.GetXmlText()+"\n", LoadOptions.SetLineInfo)
+
+ // Note, the parameter names are curently only checked for internal
+ // consistency, so parameter references must match an XML doc parameter name.
+ let paramNames =
+ [ for p in xml.Descendants(XName.op_Implicit "param") do
+ match p.Attribute(XName.op_Implicit "name") with
+ | null ->
+ warning (Error (FSComp.SR.xmlDocMissingParameterName(), doc.Range))
+ | nm ->
+ nm.Value ]
+
+ for pref in xml.Descendants(XName.op_Implicit "paramref") do
+ match pref.Attribute(XName.op_Implicit "name") with
+ | null -> warning (Error (FSComp.SR.xmlDocMissingParameterName(), doc.Range))
+ | attr ->
+ let nm = attr.Value
+ if not (paramNames |> List.contains nm) then
+ warning (Error (FSComp.SR.xmlDocInvalidParameterName(nm), doc.Range))
+ xml |> ignore
+
+ with e ->
+ warning (Error (FSComp.SR.xmlDocBadlyFormed(e.Message), doc.Range))
+ doc
+
static member CreateFromGrabPoint(collector: XmlDocCollector, grabPointPos) =
collector.AddGrabPoint grabPointPos
diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs
index 68e768acbf6..46f82dbff6d 100644
--- a/src/fsharp/fsc.fs
+++ b/src/fsharp/fsc.fs
@@ -328,11 +328,6 @@ module InterfaceFileWriter =
module XmlDocWriter =
- let getDoc xmlDoc =
- match XmlDoc.Process xmlDoc with
- | XmlDoc [| |] -> ""
- | XmlDoc strs -> strs |> Array.toList |> String.concat Environment.NewLine
-
let hasDoc xmlDoc =
// No need to process the xml doc - just need to know if there's anything there
match xmlDoc with
@@ -389,7 +384,7 @@ module XmlDocWriter =
let mutable members = []
let addMember id xmlDoc =
if hasDoc xmlDoc then
- let doc = getDoc xmlDoc
+ let doc = xmlDoc.GetXmlText()
members <- (id, doc) :: members
let doVal (v: Val) = addMember v.XmlDocSig v.XmlDoc
let doUnionCase (uc: UnionCase) = addMember uc.XmlDocSig uc.XmlDoc
diff --git a/src/fsharp/infos.fs b/src/fsharp/infos.fs
index 8b909c41829..bf70d34431a 100755
--- a/src/fsharp/infos.fs
+++ b/src/fsharp/infos.fs
@@ -1064,7 +1064,9 @@ type MethInfo =
| DefaultStructCtor _ -> XmlDoc.Empty
#if !NO_EXTENSIONTYPING
| ProvidedMeth(_, mi, _, m)->
- XmlDoc (mi.PUntaint((fun mix -> (mix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(mi.TypeProvider.PUntaintNoFailure id)), m))
+ let lines = mi.PUntaint((fun mix -> (mix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(mi.TypeProvider.PUntaintNoFailure id)), m)
+ let lines = lines |> Array.map (fun line -> line, m)
+ XmlDoc lines
#endif
/// Try to get an arbitrary F# ValRef associated with the member. This is to determine if the member is virtual, amongst other things.
@@ -2162,7 +2164,9 @@ type PropInfo =
| FSProp(_, _, None, None) -> failwith "unreachable"
#if !NO_EXTENSIONTYPING
| ProvidedProp(_, pi, m) ->
- XmlDoc (pi.PUntaint((fun pix -> (pix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(pi.TypeProvider.PUntaintNoFailure id)), m))
+ let lines = pi.PUntaint((fun pix -> (pix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(pi.TypeProvider.PUntaintNoFailure id)), m)
+ let lines = lines |> Array.map (fun line -> line, m)
+ XmlDoc lines
#endif
/// Get the TcGlobals associated with the object
@@ -2416,7 +2420,9 @@ type EventInfo =
| FSEvent (_, p, _, _) -> p.XmlDoc
#if !NO_EXTENSIONTYPING
| ProvidedEvent (_, ei, m) ->
- XmlDoc (ei.PUntaint((fun eix -> (eix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(ei.TypeProvider.PUntaintNoFailure id)), m))
+ let lines = ei.PUntaint((fun eix -> (eix :> IProvidedCustomAttributeProvider).GetXmlDocAttributes(ei.TypeProvider.PUntaintNoFailure id)), m)
+ let lines = lines |> Array.map (fun line -> line, m)
+ XmlDoc lines
#endif
/// Get the logical name of the event.
diff --git a/src/fsharp/lex.fsl b/src/fsharp/lex.fsl
index 5322a3ddf48..e46718a3d1f 100644
--- a/src/fsharp/lex.fsl
+++ b/src/fsharp/lex.fsl
@@ -166,15 +166,17 @@ let startString args (lexbuf: UnicodeLexing.Lexbuf) =
// Utility functions for processing XML documentation
-let trySaveXmlDoc lexbuf (buff:option) =
+let trySaveXmlDoc (lexbuf: LexBuffer) (buff: (range * StringBuilder) option) =
match buff with
| None -> ()
- | Some sb -> LexbufLocalXmlDocStore.SaveXmlDocLine (lexbuf, sb.ToString(), posOfLexPosition lexbuf.StartPos)
+ | Some (start, sb) ->
+ let xmlCommentLineRange = mkFileIndexRange start.FileIndex start.Start (posOfLexPosition lexbuf.StartPos)
+ LexbufLocalXmlDocStore.SaveXmlDocLine (lexbuf, sb.ToString(), xmlCommentLineRange)
-let tryAppendXmlDoc (buff:option) (s:string) =
+let tryAppendXmlDoc (buff: (range * StringBuilder) option) (s:string) =
match buff with
| None -> ()
- | Some sb -> ignore(sb.Append s)
+ | Some (_, sb) -> ignore(sb.Append s)
// Utilities for parsing #if/#else/#endif
@@ -660,7 +662,7 @@ rule token args skip = parse
let doc = lexemeTrimLeft lexbuf 3
let sb = (new StringBuilder(100)).Append(doc)
if not skip then LINE_COMMENT (LexCont.SingleLineComment(args.ifdefStack, args.stringNest, 1, m))
- else singleLineComment (Some sb,1,m,args) skip lexbuf }
+ else singleLineComment (Some (m, sb),1,m,args) skip lexbuf }
| "//" op_char*
{ // Need to read all operator symbols too, otherwise it might be parsed by a rule below
diff --git a/src/fsharp/service/ServiceXmlDocParser.fs b/src/fsharp/service/ServiceXmlDocParser.fs
index 01073ec599a..a13edf537cf 100644
--- a/src/fsharp/service/ServiceXmlDocParser.fs
+++ b/src/fsharp/service/ServiceXmlDocParser.fs
@@ -49,12 +49,10 @@ module XmlDocParsing =
i
let isEmptyXmlDoc (preXmlDoc: PreXmlDoc) =
- match preXmlDoc.ToXmlDoc() with
- | XmlDoc [||] -> true
- | XmlDoc [|x|] when x.Trim() = "" -> true
- | _ -> false
+ preXmlDoc.ToXmlDoc().IsEmpty
- let rec getXmlDocablesSynModuleDecl = function
+ let rec getXmlDocablesSynModuleDecl decl =
+ match decl with
| SynModuleDecl.NestedModule(_, _, synModuleDecls, _, _) ->
(synModuleDecls |> List.collect getXmlDocablesSynModuleDecl)
| SynModuleDecl.Let(_, synBindingList, range) ->
diff --git a/src/fsharp/symbols/SymbolHelpers.fs b/src/fsharp/symbols/SymbolHelpers.fs
index bbe3e5b2de8..a9d147873d1 100644
--- a/src/fsharp/symbols/SymbolHelpers.fs
+++ b/src/fsharp/symbols/SymbolHelpers.fs
@@ -662,13 +662,14 @@ module internal SymbolHelpers =
let GetXmlCommentForItemAux (xmlDoc: XmlDoc option) (infoReader: InfoReader) m d =
let result =
match xmlDoc with
- | None | Some (XmlDoc [| |]) -> ""
- | Some (XmlDoc l) ->
+ | None -> ""
+ | Some xmlDoc when xmlDoc.IsEmpty -> ""
+ | Some (XmlDoc lines) ->
bufs (fun os ->
bprintf os "\n"
- l |> Array.iter (fun (s: string) ->
+ lines |> Array.iter (fun (line, _) ->
// Note: this code runs for local/within-project xmldoc tooltips, but not for cross-project or .XML
- bprintf os "\n%s" s))
+ bprintf os "\n%s" line))
if String.IsNullOrEmpty result then
GetXmlDocHelpSigOfItemForLookup infoReader m d
diff --git a/src/fsharp/symbols/Symbols.fs b/src/fsharp/symbols/Symbols.fs
index 4fe8986ec97..d0bb6c2aa13 100644
--- a/src/fsharp/symbols/Symbols.fs
+++ b/src/fsharp/symbols/Symbols.fs
@@ -78,7 +78,8 @@ module Impl =
let makeReadOnlyCollection (arr: seq<'T>) =
System.Collections.ObjectModel.ReadOnlyCollection<_>(Seq.toArray arr) :> IList<_>
- let makeXmlDoc (XmlDoc x) = makeReadOnlyCollection x
+ let makeXmlDoc (XmlDoc lines) =
+ makeReadOnlyCollection (Array.map fst lines)
let rescopeEntity optViewedCcu (entity: Entity) =
match optViewedCcu with
diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf
index ee4520e2f46..3dc155020cc 100644
--- a/src/fsharp/xlf/FSComp.txt.cs.xlf
+++ b/src/fsharp/xlf/FSComp.txt.cs.xlf
@@ -522,6 +522,21 @@
Pro odkazy na rozhraní .NET používejte referenční sestavení, pokud jsou k dispozici (ve výchozím nastavení povolené).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Zvažte použití parametru yield! namísto yield.
diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf
index 084d3c4031e..292f6c66669 100644
--- a/src/fsharp/xlf/FSComp.txt.de.xlf
+++ b/src/fsharp/xlf/FSComp.txt.de.xlf
@@ -522,6 +522,21 @@
Verweisassemblys für .NET Framework-Verweise verwenden, wenn verfügbar (standardmäßig aktiviert).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Verwenden Sie ggf. "yield!" anstelle von "yield".
diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf
index 83ba01bb5a5..c7e00ed68b6 100644
--- a/src/fsharp/xlf/FSComp.txt.es.xlf
+++ b/src/fsharp/xlf/FSComp.txt.es.xlf
@@ -522,6 +522,21 @@
Use ensamblados de referencia para las referencias de .NET Framework cuando estén disponibles (habilitado de forma predeterminada).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Considere la posibilidad de usar "yield!" en lugar de "yield".
diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf
index 5e2edeccf43..c64e4e544a8 100644
--- a/src/fsharp/xlf/FSComp.txt.fr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.fr.xlf
@@ -522,6 +522,21 @@
Utilisez des assemblys de référence pour les références .NET Framework quand ils sont disponibles (activé par défaut).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Utilisez 'yield!' à la place de 'yield'.
diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf
index d870e6feaac..dbd6a9eada2 100644
--- a/src/fsharp/xlf/FSComp.txt.it.xlf
+++ b/src/fsharp/xlf/FSComp.txt.it.xlf
@@ -522,6 +522,21 @@
Usa gli assembly di riferimento per i riferimenti a .NET Framework quando disponibili (abilitato per impostazione predefinita).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Provare a usare 'yield!' invece di 'yield'.
diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf
index 634025e3144..767dd75391e 100644
--- a/src/fsharp/xlf/FSComp.txt.ja.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ja.xlf
@@ -522,6 +522,21 @@
使用可能な場合は、.NET Framework リファレンスの参照アセンブリを使用します (既定で有効)。
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.'yield' の代わりに 'yield!' を使うことを検討してください。
diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf
index 9684a8b6077..a7ba88f7d29 100644
--- a/src/fsharp/xlf/FSComp.txt.ko.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ko.xlf
@@ -522,6 +522,21 @@
기본적으로 활성화되는 참조 어셈블리를 .NET Framework 참조에 사용합니다(사용 가능한 경우).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.'yield'가 아닌 'yield!'를 사용하세요.
diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf
index 77b9a86179f..8b1a2b6cd59 100644
--- a/src/fsharp/xlf/FSComp.txt.pl.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pl.xlf
@@ -522,6 +522,21 @@
Użyj zestawów odwołań dla odwołań do programu .NET Framework, gdy są dostępne (domyślnie włączone).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Rozważ użycie polecenia „yield!” zamiast „yield”.
diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
index 2bb3ed9fff6..5648c5a32b7 100644
--- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
+++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf
@@ -522,6 +522,21 @@
Use assemblies de referência para referências do .NET Framework quando disponível (habilitado por padrão).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Considere usar 'yield!' em vez de 'yield'.
diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf
index 80477df0542..13b5b7cee10 100644
--- a/src/fsharp/xlf/FSComp.txt.ru.xlf
+++ b/src/fsharp/xlf/FSComp.txt.ru.xlf
@@ -522,6 +522,21 @@
Использовать базовые сборки для ссылок на платформу .NET, если базовые сборки доступны (включено по умолчанию).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.Рекомендуется использовать "yield!" вместо "yield".
diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf
index 86a7308ffbd..370df29dc88 100644
--- a/src/fsharp/xlf/FSComp.txt.tr.xlf
+++ b/src/fsharp/xlf/FSComp.txt.tr.xlf
@@ -522,6 +522,21 @@
Kullanılabilir olduğunda, .NET Framework başvuruları için başvuru bütünleştirilmiş kodlarını kullanın (Varsayılan olarak etkindir).
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.'yield' yerine 'yield!' kullanmayı deneyin.
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
index 7b7b5e75ac9..a1a8e6f59f4 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf
@@ -522,6 +522,21 @@
如果可用,请对 .NET Framework 引用使用引用程序集(默认启用)。
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.考虑使用 "yield!",而非 "yield"。
diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
index 6db7230450c..8fd91081031 100644
--- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
+++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf
@@ -522,6 +522,21 @@
請在可行的情況下使用適用於 .NET 架構參考的參考組件 (預設會啟用)。
+
+ This XML comment is invalid: '{0}'
+ This XML comment is invalid: '{0}'
+
+
+
+ This XML comment is invalid: invalid parameter reference '{0}'
+ This XML comment is invalid: invalid parameter reference '{0}'
+
+
+
+ This XML comment is invalid: missing parameter name
+ This XML comment is invalid: missing parameter name
+
+ Consider using 'yield!' instead of 'yield'.請考慮使用 'yield!' 而不使用 'yield'。
diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
index f97a823591c..27f4cb4c6dd 100644
--- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
+++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj
@@ -40,6 +40,7 @@
+
@@ -54,4 +55,8 @@
+
+
+
+
diff --git a/tests/FSharp.Compiler.ComponentTests/Language/XmlComments.fs b/tests/FSharp.Compiler.ComponentTests/Language/XmlComments.fs
new file mode 100644
index 00000000000..8881d1a4712
--- /dev/null
+++ b/tests/FSharp.Compiler.ComponentTests/Language/XmlComments.fs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler.ComponentTests.XmlComments
+
+open Xunit
+open FSharp.Test.Utilities.Compiler
+
+module XmlCommentChecking =
+
+ []
+ let ``invalid XML is reported`` () =
+ Fsx"""
+///
+let x = 1
+
+///
+/// Yo
+/// Yo
+module M =
+ /// <
+ let y = 1
+
+ """
+ |> withXmlCommentChecking
+ |> ignoreWarnings // means "don't treat warnings as errors"
+ |> compile
+ |> shouldSucceed
+ |> withDiagnostics
+ [ (Warning 3390, Line 2, Col 1, Line 2, Col 14,
+ "This XML comment is invalid: 'The 'summary' start tag on line 2 position 3 does not match the end tag of 'doc'. Line 3, position 3.'");
+ (Warning 3390, Line 5, Col 1, Line 7, Col 21,
+ """This XML comment is invalid: 'The 'remark' start tag on line 3 position 3 does not match the end tag of 'rem'. Line 3, position 14.'""");
+ (Warning 3390, Line 9, Col 5, Line 9, Col 20,
+ "This XML comment is invalid: 'Name cannot begin with the '\n' character, hexadecimal value 0x0A. Line 2, position 13.'")
+ ]
+ []
+ let ``invalid parameter reference is reported`` () =
+ Fsx"""
+ /// Return
+ /// the parameter
+ let f a = a
+ """
+ |> withXmlCommentChecking
+ |> ignoreWarnings // means "don't treat warnings as errors"
+ |> compile
+ |> shouldSucceed
+ |> withDiagnostics
+ [ (Warning 3390, Line 2, Col 5, Line 3, Col 48,
+ "This XML comment is invalid: invalid parameter reference 'b'");
+ ]
diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.net472.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.net472.fs
index 0cacf6073ee..55dd7b6127e 100644
--- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.net472.fs
+++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.net472.fs
@@ -41930,25 +41930,27 @@ FSharp.Compiler.XmlDoc+XmlDoc: Boolean Equals(System.Object, System.Collections.
FSharp.Compiler.XmlDoc+XmlDoc: Boolean Equals(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: Boolean NonEmpty
FSharp.Compiler.XmlDoc+XmlDoc: Boolean get_NonEmpty()
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(System.Object)
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: Int32 GetHashCode()
FSharp.Compiler.XmlDoc+XmlDoc: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.XmlDoc+XmlDoc: Int32 Tag
FSharp.Compiler.XmlDoc+XmlDoc: Int32 get_Tag()
FSharp.Compiler.XmlDoc+XmlDoc: System.String ToString()
-FSharp.Compiler.XmlDoc+XmlDoc: System.String[] Item
-FSharp.Compiler.XmlDoc+XmlDoc: System.String[] get_Item()
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Empty
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Merge(XmlDoc, XmlDoc)
-FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc NewXmlDoc(System.String[])
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Process(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc get_Empty()
-FSharp.Compiler.XmlDoc+XmlDocCollector: System.String[] LinesBefore(pos)
+FSharp.Compiler.XmlDoc+XmlDoc: Boolean IsEmpty
+FSharp.Compiler.XmlDoc+XmlDoc: Boolean get_IsEmpty()
+FSharp.Compiler.XmlDoc+XmlDoc: System.String GetXmlText()
+FSharp.Compiler.XmlDoc+XmlDoc: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] Item
+FSharp.Compiler.XmlDoc+XmlDoc: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] get_Item()
+FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc NewXmlDoc(System.Tuple`2[System.String,FSharp.Compiler.Range+range][])
+FSharp.Compiler.XmlDoc+XmlDoc: range Range
+FSharp.Compiler.XmlDoc+XmlDoc: range get_Range()
+FSharp.Compiler.XmlDoc+XmlDocCollector: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] LinesBefore(pos)
+FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddXmlDocLine(System.String, range)
FSharp.Compiler.XmlDoc+XmlDocCollector: Void .ctor()
FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddGrabPoint(pos)
-FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddXmlDocLine(System.String, pos)
FSharp.Compiler.XmlDoc+XmlDocStatics: Void .ctor()
FSharp.Compiler.XmlDoc+XmlDocStatics: XmlDoc Empty
FSharp.Compiler.XmlDoc+XmlDocStatics: XmlDoc get_Empty()
diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
index 9cd1423c6e3..25e45e1d9ee 100644
--- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
+++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
@@ -41875,25 +41875,27 @@ FSharp.Compiler.XmlDoc+XmlDoc: Boolean Equals(System.Object, System.Collections.
FSharp.Compiler.XmlDoc+XmlDoc: Boolean Equals(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: Boolean NonEmpty
FSharp.Compiler.XmlDoc+XmlDoc: Boolean get_NonEmpty()
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(System.Object)
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(System.Object, System.Collections.IComparer)
-FSharp.Compiler.XmlDoc+XmlDoc: Int32 CompareTo(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: Int32 GetHashCode()
FSharp.Compiler.XmlDoc+XmlDoc: Int32 GetHashCode(System.Collections.IEqualityComparer)
FSharp.Compiler.XmlDoc+XmlDoc: Int32 Tag
FSharp.Compiler.XmlDoc+XmlDoc: Int32 get_Tag()
FSharp.Compiler.XmlDoc+XmlDoc: System.String ToString()
-FSharp.Compiler.XmlDoc+XmlDoc: System.String[] Item
-FSharp.Compiler.XmlDoc+XmlDoc: System.String[] get_Item()
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Empty
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Merge(XmlDoc, XmlDoc)
-FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc NewXmlDoc(System.String[])
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc Process(XmlDoc)
FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc get_Empty()
-FSharp.Compiler.XmlDoc+XmlDocCollector: System.String[] LinesBefore(pos)
+FSharp.Compiler.XmlDoc+XmlDoc: Boolean IsEmpty
+FSharp.Compiler.XmlDoc+XmlDoc: Boolean get_IsEmpty()
+FSharp.Compiler.XmlDoc+XmlDoc: System.String GetXmlText()
+FSharp.Compiler.XmlDoc+XmlDoc: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] Item
+FSharp.Compiler.XmlDoc+XmlDoc: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] get_Item()
+FSharp.Compiler.XmlDoc+XmlDoc: XmlDoc NewXmlDoc(System.Tuple`2[System.String,FSharp.Compiler.Range+range][])
+FSharp.Compiler.XmlDoc+XmlDoc: range Range
+FSharp.Compiler.XmlDoc+XmlDoc: range get_Range()
FSharp.Compiler.XmlDoc+XmlDocCollector: Void .ctor()
FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddGrabPoint(pos)
-FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddXmlDocLine(System.String, pos)
+FSharp.Compiler.XmlDoc+XmlDocCollector: System.Tuple`2[System.String,FSharp.Compiler.Range+range][] LinesBefore(pos)
+FSharp.Compiler.XmlDoc+XmlDocCollector: Void AddXmlDocLine(System.String, range)
FSharp.Compiler.XmlDoc+XmlDocStatics: Void .ctor()
FSharp.Compiler.XmlDoc+XmlDocStatics: XmlDoc Empty
FSharp.Compiler.XmlDoc+XmlDocStatics: XmlDoc get_Empty()
diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs
index f63bf89e32b..8080a23b599 100644
--- a/tests/FSharp.Test.Utilities/Compiler.fs
+++ b/tests/FSharp.Test.Utilities/Compiler.fs
@@ -178,7 +178,7 @@ module rec Compiler =
| _ -> failwith message
let withOptions (options: string list) (cUnit: CompilationUnit) : CompilationUnit =
- withOptionsHelper options "withOptions is only supported n F#" cUnit
+ withOptionsHelper options "withOptions is only supported for F#" cUnit
let withErrorRanges (cUnit: CompilationUnit) : CompilationUnit =
withOptionsHelper [ "--test:ErrorRanges" ] "withErrorRanges is only supported on F#" cUnit
@@ -195,6 +195,9 @@ module rec Compiler =
let withLangVersionPreview (cUnit: CompilationUnit) : CompilationUnit =
withOptionsHelper [ "--langversion:preview" ] "withLangVersionPreview is only supported on F#" cUnit
+ let withXmlCommentChecking (cUnit: CompilationUnit) : CompilationUnit =
+ withOptionsHelper [ "--warnon:3390" ] "withXmlCommentChecking is only supported for F#" cUnit
+
let asLibrary (cUnit: CompilationUnit) : CompilationUnit =
match cUnit with
| FS fs -> FS { fs with OutputType = CompileOutput.Library }
@@ -573,7 +576,7 @@ module rec Compiler =
let inline checkEqual k a b =
if a <> b then
- Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A" what k a b errors)
+ Assert.AreEqual(a, b, sprintf "%s: Mismatch in %s, expected '%A', got '%A'.\nAll errors:\n%A\nExpected errors:\n%A" what k a b errors expected)
// TODO: Check all "categories", collect all results and print alltogether.
checkEqual "Errors count" expected.Length errors.Length