diff --git a/FSharpBuild.Directory.Build.props b/FSharpBuild.Directory.Build.props
index 0c8d9cef75c..21e531409e8 100644
--- a/FSharpBuild.Directory.Build.props
+++ b/FSharpBuild.Directory.Build.props
@@ -27,6 +27,7 @@
$(OtherFlags) --nowarn:3384
$(OtherFlags) --times --nowarn:75
$(OtherFlags) --test:ParallelCheckingWithSignatureFilesOn
+ $(OtherFlags) $(AdditionalFscCmdFlags)
diff --git a/a b/a
new file mode 100644
index 00000000000..6ff3473cd9a
Binary files /dev/null and b/a differ
diff --git a/src/Compiler/AbstractIL/ilsign.fs b/src/Compiler/AbstractIL/ilsign.fs
index 0239f4759c0..c568da7ade6 100644
--- a/src/Compiler/AbstractIL/ilsign.fs
+++ b/src/Compiler/AbstractIL/ilsign.fs
@@ -297,12 +297,6 @@ let signStream stream keyBlob =
let signature = createSignature hash keyBlob KeyType.KeyPair
patchSignature stream peReader signature
-let signFile fileName keyBlob =
- use fs =
- FileSystem.OpenFileForWriteShim(fileName, FileMode.Open, FileAccess.ReadWrite)
-
- signStream fs keyBlob
-
let signatureSize (pk: byte[]) =
if pk.Length < 25 then
raise (CryptographicException(getResourceString (FSComp.SR.ilSignInvalidPKBlob ())))
@@ -339,18 +333,9 @@ let signerOpenKeyPairFile filePath =
let signerGetPublicKeyForKeyPair (kp: keyPair) : pubkey = getPublicKeyForKeyPair kp
-let signerGetPublicKeyForKeyContainer (_kcName: keyContainerName) : pubkey =
- raise (NotImplementedException("signerGetPublicKeyForKeyContainer is not yet implemented"))
-
-let signerCloseKeyContainer (_kc: keyContainerName) : unit =
- raise (NotImplementedException("signerCloseKeyContainer is not yet implemented"))
-
let signerSignatureSize (pk: pubkey) : int = signatureSize pk
-let signerSignFileWithKeyPair (fileName: string) (kp: keyPair) : unit = signFile fileName kp
-
-let signerSignFileWithKeyContainer (_fileName: string) (_kcName: keyContainerName) : unit =
- raise (NotImplementedException("signerSignFileWithKeyContainer is not yet implemented"))
+let signerSignStreamWithKeyPair stream keyBlob = signStream stream keyBlob
let failWithContainerSigningUnsupportedOnThisPlatform () =
failwith (FSComp.SR.containerSigningUnsupportedOnThisPlatform () |> snd)
@@ -364,20 +349,12 @@ type ILStrongNameSigner =
| KeyPair of keyPair
| KeyContainer of keyContainerName
- static member OpenPublicKeyOptions s p =
- PublicKeyOptionsSigner((signerOpenPublicKeyFile s), p)
+ static member OpenPublicKeyOptions kp p = PublicKeyOptionsSigner(kp, p)
- static member OpenPublicKey pubkey = PublicKeySigner pubkey
- static member OpenKeyPairFile s = KeyPair(signerOpenKeyPairFile s)
+ static member OpenPublicKey bytes = PublicKeySigner bytes
+ static member OpenKeyPairFile bytes = KeyPair(bytes)
static member OpenKeyContainer s = KeyContainer s
- member s.Close() =
- match s with
- | PublicKeySigner _
- | PublicKeyOptionsSigner _
- | KeyPair _ -> ()
- | KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
-
member s.IsFullySigned =
match s with
| PublicKeySigner _ -> false
@@ -412,9 +389,9 @@ type ILStrongNameSigner =
| KeyPair kp -> pkSignatureSize (signerGetPublicKeyForKeyPair kp)
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
- member s.SignFile file =
+ member s.SignStream stream =
match s with
| PublicKeySigner _ -> ()
| PublicKeyOptionsSigner _ -> ()
- | KeyPair kp -> signerSignFileWithKeyPair file kp
+ | KeyPair kp -> signerSignStreamWithKeyPair stream kp
| KeyContainer _ -> failWithContainerSigningUnsupportedOnThisPlatform ()
diff --git a/src/Compiler/AbstractIL/ilsign.fsi b/src/Compiler/AbstractIL/ilsign.fsi
index 23a82daffca..9dcdbf8ecda 100644
--- a/src/Compiler/AbstractIL/ilsign.fsi
+++ b/src/Compiler/AbstractIL/ilsign.fsi
@@ -7,18 +7,20 @@
module internal FSharp.Compiler.AbstractIL.StrongNameSign
+open System
+open System.IO
+
//---------------------------------------------------------------------
// Strong name signing
//---------------------------------------------------------------------
[]
type ILStrongNameSigner =
member PublicKey: byte[]
- static member OpenPublicKeyOptions: string -> bool -> ILStrongNameSigner
+ static member OpenPublicKeyOptions: byte array -> bool -> ILStrongNameSigner
static member OpenPublicKey: byte[] -> ILStrongNameSigner
- static member OpenKeyPairFile: string -> ILStrongNameSigner
+ static member OpenKeyPairFile: byte[] -> ILStrongNameSigner
static member OpenKeyContainer: string -> ILStrongNameSigner
- member Close: unit -> unit
member IsFullySigned: bool
member PublicKey: byte[]
member SignatureSize: int
- member SignFile: string -> unit
+ member SignStream: Stream -> unit
diff --git a/src/Compiler/AbstractIL/ilwrite.fs b/src/Compiler/AbstractIL/ilwrite.fs
index fb024b63f06..33894493f4b 100644
--- a/src/Compiler/AbstractIL/ilwrite.fs
+++ b/src/Compiler/AbstractIL/ilwrite.fs
@@ -502,9 +502,7 @@ type cenv =
emitTailcalls: bool
- deterministic: bool
-
- showTimes: bool
+ deterministic: bool
desiredMetadataVersion: ILVersionInfo
@@ -3023,14 +3021,14 @@ let GenModule (cenv : cenv) (modul: ILModuleDef) =
let midx = AddUnsharedRow cenv TableNames.Module (GetModuleAsRow cenv modul)
List.iter (GenResourcePass3 cenv) (modul.Resources.AsList())
let tdefs = destTypeDefsWithGlobalFunctionsFirst cenv.ilg modul.TypeDefs
- reportTime cenv.showTimes "Module Generation Preparation"
+ reportTime "Module Generation Preparation"
GenTypeDefsPass1 [] cenv tdefs
- reportTime cenv.showTimes "Module Generation Pass 1"
+ reportTime "Module Generation Pass 1"
GenTypeDefsPass2 0 [] cenv tdefs
- reportTime cenv.showTimes "Module Generation Pass 2"
+ reportTime "Module Generation Pass 2"
(match modul.Manifest with None -> () | Some m -> GenManifestPass3 cenv m)
GenTypeDefsPass3 [] cenv tdefs
- reportTime cenv.showTimes "Module Generation Pass 3"
+ reportTime "Module Generation Pass 3"
GenCustomAttrsPass3Or4 cenv (hca_Module, midx) modul.CustomAttrs
// GenericParam is the only sorted table indexed by Columns in other tables (GenericParamConstraint\CustomAttributes).
// Hence we need to sort it before we emit any entries in GenericParamConstraint\CustomAttributes that are attached to generic params.
@@ -3038,7 +3036,7 @@ let GenModule (cenv : cenv) (modul: ILModuleDef) =
// the key --> index map since it is no longer valid
cenv.GetTable(TableNames.GenericParam).SetRowsOfSharedTable (SortTableRows TableNames.GenericParam (cenv.GetTable(TableNames.GenericParam).GenericRowsOfTable))
GenTypeDefsPass4 [] cenv tdefs
- reportTime cenv.showTimes "Module Generation Pass 4"
+ reportTime "Module Generation Pass 4"
/// Arbitrary value
[]
@@ -3056,8 +3054,7 @@ let generateIL (
generatePdb,
ilg: ILGlobals,
emitTailcalls,
- deterministic,
- showTimes,
+ deterministic,
referenceAssemblyOnly,
referenceAssemblyAttribOpt: ILAttribute option,
allGivenSources,
@@ -3098,8 +3095,7 @@ let generateIL (
MetadataTable.Unshared (MetadataTable.New ("row table "+string i, EqualityComparer.Default)))
use cenv =
{ emitTailcalls=emitTailcalls
- deterministic = deterministic
- showTimes=showTimes
+ deterministic = deterministic
ilg = ilg
desiredMetadataVersion=desiredMetadataVersion
requiredDataFixups= requiredDataFixups
@@ -3183,7 +3179,7 @@ let generateIL (
EventTokenMap = (fun t edef ->
let tidx = idxForNextedTypeDef t
getUncodedToken TableNames.Event (cenv.eventDefs.GetTableEntry (EventKey (tidx, edef.Name)))) }
- reportTime cenv.showTimes "Finalize Module Generation Results"
+ reportTime "Finalize Module Generation Results"
// New return the results
let data = cenv.data.AsMemory().ToArray()
let resources = cenv.resources.AsMemory().ToArray()
@@ -3217,8 +3213,7 @@ let writeILMetadataAndCode (
desiredMetadataVersion,
ilg,
emitTailcalls,
- deterministic,
- showTimes,
+ deterministic,
referenceAssemblyOnly,
referenceAssemblyAttribOpt,
allGivenSources,
@@ -3240,8 +3235,7 @@ let writeILMetadataAndCode (
generatePdb,
ilg,
emitTailcalls,
- deterministic,
- showTimes,
+ deterministic,
referenceAssemblyOnly,
referenceAssemblyAttribOpt,
allGivenSources,
@@ -3249,7 +3243,7 @@ let writeILMetadataAndCode (
cilStartAddress,
normalizeAssemblyRefs)
- reportTime showTimes "Generated Tables and Code"
+ reportTime "Generated Tables and Code"
let tableSize (tab: TableName) = tables[tab.Index].Count
// Now place the code
@@ -3321,7 +3315,7 @@ let writeILMetadataAndCode (
(if tableSize TableNames.GenericParamConstraint > 0 then 0x00001000 else 0x00000000) |||
0x00000200
- reportTime showTimes "Layout Header of Tables"
+ reportTime "Layout Header of Tables"
let guidAddress n = (if n = 0 then 0 else (n - 1) * 0x10 + 0x01)
@@ -3365,7 +3359,7 @@ let writeILMetadataAndCode (
if n >= blobAddressTable.Length then failwith "blob index out of range"
blobAddressTable[n]
- reportTime showTimes "Build String/Blob Address Tables"
+ reportTime "Build String/Blob Address Tables"
let sortedTables =
Array.init 64 (fun i ->
@@ -3374,7 +3368,7 @@ let writeILMetadataAndCode (
let rows = tab.GenericRowsOfTable
if TableRequiresSorting tabName then SortTableRows tabName rows else rows)
- reportTime showTimes "Sort Tables"
+ reportTime "Sort Tables"
let codedTables =
@@ -3489,7 +3483,7 @@ let writeILMetadataAndCode (
tablesBuf.EmitInt32 rows.Length
- reportTime showTimes "Write Header of tablebuf"
+ reportTime "Write Header of tablebuf"
// The tables themselves
for rows in sortedTables do
@@ -3524,7 +3518,7 @@ let writeILMetadataAndCode (
tablesBuf.AsMemory().ToArray()
- reportTime showTimes "Write Tables to tablebuf"
+ reportTime "Write Tables to tablebuf"
let tablesStreamUnpaddedSize = codedTables.Length
// QUERY: extra 4 empty bytes in array.exe - why? Include some extra padding after
@@ -3541,7 +3535,7 @@ let writeILMetadataAndCode (
let blobsChunk, _next = chunk blobsStreamPaddedSize next
let blobsStreamPadding = blobsChunk.size - blobsStreamUnpaddedSize
- reportTime showTimes "Layout Metadata"
+ reportTime "Layout Metadata"
let metadata, guidStart =
use mdbuf = ByteBuffer.Create(MetadataCapacity, useArrayPool = true)
@@ -3576,12 +3570,12 @@ let writeILMetadataAndCode (
mdbuf.EmitInt32 blobsChunk.size
mdbuf.EmitIntsAsBytes [| 0x23; 0x42; 0x6c; 0x6f; 0x62; 0x00; 0x00; 0x00; (* #Blob000 *)|]
- reportTime showTimes "Write Metadata Header"
+ reportTime "Write Metadata Header"
// Now the coded tables themselves
mdbuf.EmitBytes codedTables
for i = 1 to tablesStreamPadding do
mdbuf.EmitIntAsByte 0x00
- reportTime showTimes "Write Metadata Tables"
+ reportTime "Write Metadata Tables"
// The string stream
mdbuf.EmitByte 0x00uy
@@ -3589,7 +3583,7 @@ let writeILMetadataAndCode (
mdbuf.EmitBytes s
for i = 1 to stringsStreamPadding do
mdbuf.EmitIntAsByte 0x00
- reportTime showTimes "Write Metadata Strings"
+ reportTime "Write Metadata Strings"
// The user string stream
mdbuf.EmitByte 0x00uy
for s in userStrings do
@@ -3599,7 +3593,7 @@ let writeILMetadataAndCode (
for i = 1 to userStringsStreamPadding do
mdbuf.EmitIntAsByte 0x00
- reportTime showTimes "Write Metadata User Strings"
+ reportTime "Write Metadata User Strings"
// The GUID stream
let guidStart = mdbuf.Position
Array.iter mdbuf.EmitBytes guids
@@ -3611,7 +3605,7 @@ let writeILMetadataAndCode (
mdbuf.EmitBytes s
for i = 1 to blobsStreamPadding do
mdbuf.EmitIntAsByte 0x00
- reportTime showTimes "Write Blob Stream"
+ reportTime "Write Blob Stream"
// Done - close the buffer and return the result.
mdbuf.AsMemory().ToArray(), guidStart
@@ -3627,7 +3621,7 @@ let writeILMetadataAndCode (
let token = getUncodedToken TableNames.UserStrings (userStringAddress userStringIndex)
if (Bytes.get code (locInCode-1) <> i_ldstr) then failwith "strings-in-code fixup: not at ldstr instruction!"
applyFixup32 code locInCode token
- reportTime showTimes "Fixup Metadata"
+ reportTime "Fixup Metadata"
entryPointToken, code, codePadding, metadata, data, resources, requiredDataFixups.Value, pdbData, mappings, guidStart
@@ -3690,8 +3684,7 @@ let writeDirectory os dict =
let writeBytes (os: BinaryWriter) (chunk: byte[]) = os.Write(chunk, 0, chunk.Length)
let writePdb (
- dumpDebugInfo,
- showTimes,
+ dumpDebugInfo,
embeddedPDB,
pdbfile,
outfile,
@@ -3714,9 +3707,22 @@ let writePdb (
// Used to capture the pdb file bytes in the case we're generating in-memory
let mutable pdbBytes = None
+ let signImage () =
+ // Sign the binary. No further changes to binary allowed past this point!
+ match signer with
+ | None -> ()
+ | Some s ->
+ use fs = reopenOutput()
+ try
+ s.SignStream fs
+ with exn ->
+ failwith ($"Warning: A call to SignFile failed ({exn.Message})")
+ reportTime "Signing Image"
+
// Now we've done the bulk of the binary, do the PDB file and fixup the binary.
match pdbfile with
- | None -> ()
+ | None -> signImage ()
+
| Some pdbfile ->
let idd =
match pdbInfoOpt with
@@ -3741,7 +3747,7 @@ let writePdb (
stream.WriteTo fs
getInfoForPortablePdb contentId pdbfile pathMap debugDataChunk debugDeterministicPdbChunk debugChecksumPdbChunk algorithmName checkSum embeddedPDB deterministic
| None -> [| |]
- reportTime showTimes "Generate PDB Info"
+ reportTime "Generate PDB Info"
// Now we have the debug data we can go back and fill in the debug directory in the image
use fs2 = reopenOutput()
@@ -3766,28 +3772,15 @@ let writePdb (
os2.BaseStream.Seek (int64 (textV2P i.iddChunk.addr), SeekOrigin.Begin) |> ignore
if i.iddChunk.size < i.iddData.Length then failwith "Debug data area is not big enough. Debug info may not be usable"
writeBytes os2 i.iddData
+ reportTime "Finalize PDB"
+ signImage ()
os2.Dispose()
with exn ->
failwith ("Error while writing debug directory entry: " + exn.Message)
(try os2.Dispose(); FileSystem.FileDeleteShim outfile with _ -> ())
reraise()
-
- reportTime showTimes "Finalize PDB"
-
- // Sign the binary. No further changes to binary allowed past this point!
- match signer with
- | None -> ()
- | Some s ->
- try
- s.SignFile outfile
- s.Close()
- with exn ->
- failwith ("Warning: A call to SignFile failed ("+exn.Message+")")
- (try s.Close() with _ -> ())
- (try FileSystem.FileDeleteShim outfile with _ -> ())
- ()
-
- reportTime showTimes "Signing Image"
+
+ reportTime "Finish"
pdbBytes
type options =
@@ -3803,8 +3796,7 @@ type options =
checksumAlgorithm: HashAlgorithm
signer: ILStrongNameSigner option
emitTailcalls: bool
- deterministic: bool
- showTimes: bool
+ deterministic: bool
dumpDebugInfo: bool
referenceAssemblyOnly: bool
referenceAssemblyAttribOpt: ILAttribute option
@@ -3815,7 +3807,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
// Store the public key from the signer into the manifest. This means it will be written
// to the binary and also acts as an indicator to leave space for delay sign
- reportTime options.showTimes "Write Started"
+ reportTime "Write Started"
let isDll = modul.IsDLL
let ilg = options.ilg
@@ -3929,8 +3921,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
desiredMetadataVersion,
ilg,
options.emitTailcalls,
- options.deterministic,
- options.showTimes,
+ options.deterministic,
options.referenceAssemblyOnly,
options.referenceAssemblyAttribOpt,
options.allGivenSources,
@@ -3939,7 +3930,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
normalizeAssemblyRefs
)
- reportTime options.showTimes "Generated IL and metadata"
+ reportTime "Generated IL and metadata"
let _codeChunk, next = chunk code.Length next
let _codePaddingChunk, next = chunk codePadding.Length next
@@ -3972,7 +3963,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
match options.pdbfile, options.portablePDB with
| Some _, true ->
let pdbInfo =
- generatePortablePdb options.embedAllSource options.embedSourceList options.sourceLink options.checksumAlgorithm options.showTimes pdbData options.pathMap
+ generatePortablePdb options.embedAllSource options.embedSourceList options.sourceLink options.checksumAlgorithm pdbData options.pathMap
if options.embeddedPDB then
let (uncompressedLength, contentId, stream, algorithmName, checkSum) = pdbInfo
@@ -4098,7 +4089,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
let imageEndSectionPhysLoc = nextPhys
let imageEndAddr = next
- reportTime options.showTimes "Layout image"
+ reportTime "Layout image"
let write p (os: BinaryWriter) chunkName chunk =
match p with
@@ -4505,7 +4496,7 @@ let writeBinaryAux (stream: Stream, options: options, modul, normalizeAssemblyRe
pdbData, pdbInfoOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, mappings
- reportTime options.showTimes "Writing Image"
+ reportTime "Writing Image"
pdbData, pdbInfoOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, mappings
let writeBinaryFiles (options: options, modul, normalizeAssemblyRefs) =
@@ -4531,10 +4522,9 @@ let writeBinaryFiles (options: options, modul, normalizeAssemblyRefs) =
reraise()
let reopenOutput () =
- FileSystem.OpenFileForWriteShim(options.outfile, FileMode.Open, FileAccess.Write, FileShare.Read)
+ FileSystem.OpenFileForWriteShim(options.outfile, FileMode.Open, FileAccess.ReadWrite, FileShare.Read)
- writePdb (options.dumpDebugInfo,
- options.showTimes,
+ writePdb (options.dumpDebugInfo,
options.embeddedPDB,
options.pdbfile,
options.outfile,
@@ -4561,11 +4551,12 @@ let writeBinaryInMemory (options: options, modul, normalizeAssemblyRefs) =
let pdbData, pdbInfoOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, _mappings =
writeBinaryAux(stream, options, modul, normalizeAssemblyRefs)
- let reopenOutput () = stream
+ let reopenOutput () =
+ stream.Seek(0, SeekOrigin.Begin) |> ignore
+ stream
let pdbBytes =
- writePdb (options.dumpDebugInfo,
- options.showTimes,
+ writePdb (options.dumpDebugInfo,
options.embeddedPDB,
options.pdbfile,
options.outfile,
diff --git a/src/Compiler/AbstractIL/ilwrite.fsi b/src/Compiler/AbstractIL/ilwrite.fsi
index 780a6a95f09..a5240473fb1 100644
--- a/src/Compiler/AbstractIL/ilwrite.fsi
+++ b/src/Compiler/AbstractIL/ilwrite.fsi
@@ -22,7 +22,6 @@ type options =
signer: ILStrongNameSigner option
emitTailcalls: bool
deterministic: bool
- showTimes: bool
dumpDebugInfo: bool
referenceAssemblyOnly: bool
referenceAssemblyAttribOpt: ILAttribute option
diff --git a/src/Compiler/AbstractIL/ilwritepdb.fs b/src/Compiler/AbstractIL/ilwritepdb.fs
index 715987a2ad1..9b969bae098 100644
--- a/src/Compiler/AbstractIL/ilwritepdb.fs
+++ b/src/Compiler/AbstractIL/ilwritepdb.fs
@@ -316,10 +316,10 @@ let pdbGetDebugInfo
let getDebugFileName outfile =
(FileSystemUtils.chopExtension outfile) + ".pdb"
-let sortMethods showTimes info =
- reportTime showTimes (sprintf "PDB: Defined %d documents" info.Documents.Length)
+let sortMethods info =
+ reportTime (sprintf "PDB: Defined %d documents" info.Documents.Length)
Array.sortInPlaceBy (fun x -> x.MethToken) info.Methods
- reportTime showTimes (sprintf "PDB: Sorted %d methods" info.Methods.Length)
+ reportTime (sprintf "PDB: Sorted %d methods" info.Methods.Length)
()
let getRowCounts tableRowCounts =
@@ -345,7 +345,6 @@ type PortablePdbGenerator
embedSourceList: string list,
sourceLink: string,
checksumAlgorithm,
- showTimes,
info: PdbData,
pathMap: PathMap
) =
@@ -784,7 +783,7 @@ type PortablePdbGenerator
| Some scope -> writeMethodScopes minfo.MethToken scope
member _.Emit() =
- sortMethods showTimes info
+ sortMethods info
metadata.SetCapacity(TableIndex.MethodDebugInformation, info.Methods.Length)
defineModuleImportScope ()
@@ -823,7 +822,7 @@ type PortablePdbGenerator
let contentId = serializer.Serialize blobBuilder
let portablePdbStream = new MemoryStream()
blobBuilder.WriteContentTo portablePdbStream
- reportTime showTimes "PDB: Created"
+ reportTime "PDB: Created"
(portablePdbStream.Length, contentId, portablePdbStream, algorithmName, contentHash)
let generatePortablePdb
@@ -831,12 +830,11 @@ let generatePortablePdb
(embedSourceList: string list)
(sourceLink: string)
checksumAlgorithm
- showTimes
(info: PdbData)
(pathMap: PathMap)
=
let generator =
- PortablePdbGenerator(embedAllSource, embedSourceList, sourceLink, checksumAlgorithm, showTimes, info, pathMap)
+ PortablePdbGenerator(embedAllSource, embedSourceList, sourceLink, checksumAlgorithm, info, pathMap)
generator.Emit()
diff --git a/src/Compiler/AbstractIL/ilwritepdb.fsi b/src/Compiler/AbstractIL/ilwritepdb.fsi
index 79c1db52ac0..5987cc165e3 100644
--- a/src/Compiler/AbstractIL/ilwritepdb.fsi
+++ b/src/Compiler/AbstractIL/ilwritepdb.fsi
@@ -107,7 +107,6 @@ val generatePortablePdb:
embedSourceList: string list ->
sourceLink: string ->
checksumAlgorithm: HashAlgorithm ->
- showTimes: bool ->
info: PdbData ->
pathMap: PathMap ->
int64 * BlobContentId * MemoryStream * string * byte[]
diff --git a/src/Compiler/Checking/AugmentWithHashCompare.fs b/src/Compiler/Checking/AugmentWithHashCompare.fs
index dd81dc0a575..ad2645e1940 100644
--- a/src/Compiler/Checking/AugmentWithHashCompare.fs
+++ b/src/Compiler/Checking/AugmentWithHashCompare.fs
@@ -996,7 +996,16 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon
// build the hash rhs
let withcGetHashCodeExpr =
let compv, compe = mkCompGenLocal m "comp" g.IEqualityComparer_ty
- let thisv, hashe = hashf g tcref tycon compe
+
+ // Special case List type to avoid StackOverflow exception , call custom hash code instead
+ let thisv,hashe =
+ if tyconRefEq g tcref g.list_tcr_canon && tycon.HasMember g "CustomHashCode" [g.IEqualityComparer_ty] then
+ let customCodeVal = (tycon.TryGetMember g "CustomHashCode" [g.IEqualityComparer_ty]).Value
+ let tinst, ty = mkMinimalTy g tcref
+ let thisv, thise = mkThisVar g m ty
+ thisv,mkApps g ((exprForValRef m customCodeVal, customCodeVal.Type), (if isNil tinst then [] else [tinst]), [thise; compe], m)
+ else
+ hashf g tcref tycon compe
mkLambdas g m tps [thisv; compv] (hashe, g.int_ty)
// build the equals rhs
diff --git a/src/Compiler/Checking/CheckComputationExpressions.fs b/src/Compiler/Checking/CheckComputationExpressions.fs
index db8d307381f..a1c89f61dc7 100644
--- a/src/Compiler/Checking/CheckComputationExpressions.fs
+++ b/src/Compiler/Checking/CheckComputationExpressions.fs
@@ -1672,6 +1672,9 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
let bindCall = mkSynCall bindName bindRange (bindArgs @ [consumeExpr])
translatedCtxt (bindCall |> addBindDebugPoint))
+ /// This function is for desugaring into .Bind{N}Return calls if possible
+ /// The outer option indicates if .BindReturn is possible. When it returns None, .BindReturn cannot be used
+ /// The inner option indicates if a custom operation is involved inside
and convertSimpleReturnToExpr varSpace innerComp =
match innerComp with
| SynExpr.YieldOrReturn ((false, _), returnExpr, m) ->
@@ -1697,7 +1700,8 @@ let TcComputationExpression (cenv: cenv) env (overallTy: OverallTy) tpenv (mWhol
| Some (thenExpr, None) ->
let elseExprOptOpt =
match elseCompOpt with
- | None -> Some None
+ // When we are missing an 'else' part alltogether in case of 'if cond then return exp', we fallback from BindReturn into regular Bind+Return
+ | None -> None
| Some elseComp ->
match convertSimpleReturnToExpr varSpace elseComp with
| None -> None // failure
diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs
index 7ea1c4b3429..a501f74edc0 100644
--- a/src/Compiler/Checking/CheckDeclarations.fs
+++ b/src/Compiler/Checking/CheckDeclarations.fs
@@ -1655,6 +1655,19 @@ module MutRecBindingChecking =
defnsEs, envMutRec
+let private ReportErrorOnStaticClass (synMembers: SynMemberDefn list) =
+ for mem in synMembers do
+ match mem with
+ | SynMemberDefn.ImplicitCtor(ctorArgs = SynSimplePats.SimplePats(pats = pats)) when (not pats.IsEmpty) ->
+ for pat in pats do
+ errorR(Error(FSComp.SR.chkConstructorWithArgumentsOnStaticClasses(), pat.Range))
+
+ | SynMemberDefn.Member(SynBinding(valData = SynValData(memberFlags = Some memberFlags)), m) when memberFlags.MemberKind = SynMemberKind.Constructor ->
+ errorR(Error(FSComp.SR.chkAdditionalConstructorOnStaticClasses(), m))
+ | SynMemberDefn.Member(SynBinding(valData = SynValData(memberFlags = Some memberFlags)), m) when memberFlags.MemberKind = SynMemberKind.Member && memberFlags.IsInstance ->
+ errorR(Error(FSComp.SR.chkInstanceMemberOnStaticClasses(), m));
+ | _ -> ()
+
/// Check and generalize the interface implementations, members, 'let' definitions in a mutually recursive group of definitions.
let TcMutRecDefns_Phase2 (cenv: cenv) envInitial mBinds scopem mutRecNSInfo (envMutRec: TcEnv) (mutRecDefns: MutRecDefnsPhase2Data) isMutRec =
let g = cenv.g
@@ -1755,7 +1768,13 @@ let TcMutRecDefns_Phase2 (cenv: cenv) envInitial mBinds scopem mutRecNSInfo (env
let binds: MutRecDefnsPhase2Info =
(envMutRec, mutRecDefns) ||> MutRecShapes.mapTyconsWithEnv (fun envForDecls tyconData ->
- let (MutRecDefnsPhase2DataForTycon(tyconOpt, _, declKind, tcref, _, _, declaredTyconTypars, _, _, _, fixupFinalAttrs)) = tyconData
+ let (MutRecDefnsPhase2DataForTycon(tyconOpt, _x, declKind, tcref, _, _, declaredTyconTypars, synMembers, _, _, fixupFinalAttrs)) = tyconData
+
+ // If a tye uses both [] and [] attributes it means it is a static class.
+ let isStaticClass = HasFSharpAttribute cenv.g cenv.g.attrib_SealedAttribute tcref.Attribs && HasFSharpAttribute cenv.g cenv.g.attrib_AbstractClassAttribute tcref.Attribs
+ if isStaticClass && cenv.g.langVersion.SupportsFeature(LanguageFeature.ErrorReportingOnStaticClasses) then
+ ReportErrorOnStaticClass synMembers
+
let envForDecls =
// This allows to implement protected interface methods if it's a DIM.
// Does not need to be hidden behind a lang version as it needs to be possible to
@@ -4030,6 +4049,7 @@ module TcDeclarations =
let rec private SplitTyconDefn (SynTypeDefn(typeInfo=synTyconInfo;typeRepr=trepr; members=extraMembers)) =
let extraMembers = desugarGetSetMembers extraMembers
let implements1 = List.choose (function SynMemberDefn.Interface (interfaceType=ty) -> Some(ty, ty.Range) | _ -> None) extraMembers
+
match trepr with
| SynTypeDefnRepr.ObjectModel(kind, cspec, m) ->
let cspec = desugarGetSetMembers cspec
@@ -4047,7 +4067,7 @@ module TcDeclarations =
let members =
let membersIncludingAutoProps =
cspec |> List.filter (fun memb ->
- match memb with
+ match memb with
| SynMemberDefn.Interface _
| SynMemberDefn.Member _
| SynMemberDefn.GetSetMember _
@@ -4837,7 +4857,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
let moduleEntity = Construct.NewModuleOrNamespace (Some env.eCompPath) vis id xmlDoc modAttrs (MaybeLazy.Strict moduleTy)
// Now typecheck.
- let! moduleContents, topAttrsNew, envAtEnd = TcModuleOrNamespaceElements cenv (Parent (mkLocalModuleRef moduleEntity)) endm envForModule xml None [] moduleDefs
+ let! moduleContents, topAttrsNew, envAtEnd = TcModuleOrNamespaceElements cenv (Parent (mkLocalModuleRef moduleEntity)) endm envForModule xml None [] moduleDefs
// Get the inferred type of the decls and record it in the modul.
moduleEntity.entity_modul_type <- MaybeLazy.Strict moduleTyAcc.Value
@@ -4924,8 +4944,7 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
let! moduleContents, topAttrs, envAtEnd = TcModuleOrNamespaceElements cenv parent endm envNS xml mutRecNSInfo [] defs
- MutRecBindingChecking.TcMutRecDefns_UpdateNSContents nsInfo
-
+ MutRecBindingChecking.TcMutRecDefns_UpdateNSContents nsInfo
let env, openDecls =
if isNil enclosingNamespacePath then
envAtEnd, []
@@ -5316,8 +5335,8 @@ let CheckOneImplFile
use _ =
Activity.start "CheckDeclarations.CheckOneImplFile"
[|
- "fileName", fileName
- "qualifiedNameOfFile", qualNameOfFile.Text
+ Activity.Tags.fileName, fileName
+ Activity.Tags.qualifiedNameOfFile, qualNameOfFile.Text
|]
let cenv =
cenv.Create (g, isScript, amap, thisCcu, false, Option.isSome rootSigOpt,
@@ -5450,8 +5469,8 @@ let CheckOneSigFile (g, amap, thisCcu, checkForErrors, conditionalDefines, tcSin
use _ =
Activity.start "CheckDeclarations.CheckOneSigFile"
[|
- "fileName", sigFile.FileName
- "qualifiedNameOfFile", sigFile.QualifiedName.Text
+ Activity.Tags.fileName, sigFile.FileName
+ Activity.Tags.qualifiedNameOfFile, sigFile.QualifiedName.Text
|]
let cenv =
cenv.Create
diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs
index d4ff82dd1da..ef4930408a0 100644
--- a/src/Compiler/Checking/CheckExpressions.fs
+++ b/src/Compiler/Checking/CheckExpressions.fs
@@ -1015,15 +1015,16 @@ let MakeMemberDataAndMangledNameForMemberVal(g, tcref, isExtrinsic, attrs, implS
if not isCompGen && IsLogicalInfixOpName id.idText then
let m = id.idRange
- let name = ConvertValLogicalNameToDisplayNameCore id.idText
+ let logicalName = id.idText
+ let displayName = ConvertValLogicalNameToDisplayNameCore logicalName
// Check symbolic members. Expect valSynData implied arity to be [[2]].
match SynInfo.AritiesOfArgs valSynData with
- | [] | [0] -> warning(Error(FSComp.SR.memberOperatorDefinitionWithNoArguments name, m))
+ | [] | [0] -> warning(Error(FSComp.SR.memberOperatorDefinitionWithNoArguments displayName, m))
| n :: otherArgs ->
- let opTakesThreeArgs = IsLogicalTernaryOperator name
- if n<>2 && not opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonPairArgument(name, n), m))
- if n<>3 && opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonTripleArgument(name, n), m))
- if not (isNil otherArgs) then warning(Error(FSComp.SR.memberOperatorDefinitionWithCurriedArguments name, m))
+ let opTakesThreeArgs = IsLogicalTernaryOperator logicalName
+ if n<>2 && not opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonPairArgument(displayName, n), m))
+ if n<>3 && opTakesThreeArgs then warning(Error(FSComp.SR.memberOperatorDefinitionWithNonTripleArgument(displayName, n), m))
+ if not (isNil otherArgs) then warning(Error(FSComp.SR.memberOperatorDefinitionWithCurriedArguments displayName, m))
if isExtrinsic && IsLogicalOpName id.idText then
warning(Error(FSComp.SR.tcMemberOperatorDefinitionInExtrinsic(), id.idRange))
@@ -1209,6 +1210,12 @@ let CheckRequiredProperties (g:TcGlobals) (env: TcEnv) (cenv: TcFileState) (minf
let details = NicePrint.multiLineStringOfPropInfos g cenv.amap mMethExpr env.DisplayEnv missingProps
errorR(Error(FSComp.SR.tcMissingRequiredMembers details, mMethExpr))
+let private HasMethodImplNoInliningAttribute g attrs =
+ match TryFindFSharpAttribute g g.attrib_MethodImplAttribute attrs with
+ // NO_INLINING = 8
+ | Some (Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> (flags &&& 0x8) <> 0x0
+ | _ -> false
+
let MakeAndPublishVal (cenv: cenv) env (altActualParent, inSig, declKind, valRecInfo, vscheme, attrs, xmlDoc, konst, isGeneratedEventVal) =
let g = cenv.g
@@ -1257,16 +1264,10 @@ let MakeAndPublishVal (cenv: cenv) env (altActualParent, inSig, declKind, valRec
errorR(Error(FSComp.SR.tcDllImportStubsCannotBeInlined(), m))
ValInline.Never
else
- let implflags =
- match TryFindFSharpAttribute g g.attrib_MethodImplAttribute attrs with
- | Some (Attrib(_, _, [ AttribInt32Arg flags ], _, _, _, _)) -> flags
- | _ -> 0x0
- // MethodImplOptions.NoInlining = 0x8
- let NO_INLINING = 0x8
- if (implflags &&& NO_INLINING) <> 0x0 then
- ValInline.Never
- else
- inlineFlag
+ if HasMethodImplNoInliningAttribute g attrs
+ then ValInline.Never
+ else inlineFlag
+
// CompiledName not allowed on virtual/abstract/override members
let compiledNameAttrib = TryFindFSharpStringAttribute g g.attrib_CompiledNameAttribute attrs
@@ -2204,26 +2205,32 @@ module GeneralizationHelpers =
// ComputeInlineFlag
//-------------------------------------------------------------------------
-let ComputeInlineFlag (memFlagsOption: SynMemberFlags option) isInline isMutable hasNoCompilerInliningAttribute m =
- let inlineFlag =
- let isCtorOrAbstractSlot =
- match memFlagsOption with
- | None -> false
- | Some x -> (x.MemberKind = SynMemberKind.Constructor) || x.IsDispatchSlot || x.IsOverrideOrExplicitImpl
+let ComputeInlineFlag (memFlagsOption: SynMemberFlags option) isInline isMutable g attrs m =
+ let hasNoCompilerInliningAttribute() = HasFSharpAttribute g g.attrib_NoCompilerInliningAttribute attrs
+ let isCtorOrAbstractSlot() =
+ match memFlagsOption with
+ | None -> false
+ | Some x -> (x.MemberKind = SynMemberKind.Constructor) || x.IsDispatchSlot || x.IsOverrideOrExplicitImpl
+ let inlineFlag, reportIncorrectInlineKeywordUsage =
// Mutable values may never be inlined
// Constructors may never be inlined
// Calls to virtual/abstract slots may never be inlined
- // Values marked with NoCompilerInliningAttribute may never be inlined
- if isMutable || isCtorOrAbstractSlot || hasNoCompilerInliningAttribute then
- ValInline.Never
+ // Values marked with NoCompilerInliningAttribute or [] may never be inlined
+ if isMutable || isCtorOrAbstractSlot() || hasNoCompilerInliningAttribute() then
+ ValInline.Never, errorR
+ elif HasMethodImplNoInliningAttribute g attrs then
+ ValInline.Never,
+ if g.langVersion.SupportsFeature LanguageFeature.WarningWhenInliningMethodImplNoInlineMarkedFunction
+ then warning
+ else ignore
elif isInline then
- ValInline.Always
+ ValInline.Always, ignore
else
- ValInline.Optional
+ ValInline.Optional, ignore
if isInline && (inlineFlag <> ValInline.Always) then
- errorR(Error(FSComp.SR.tcThisValueMayNotBeInlined(), m))
+ reportIncorrectInlineKeywordUsage (Error(FSComp.SR.tcThisValueMayNotBeInlined(), m))
inlineFlag
@@ -4378,7 +4385,7 @@ and CheckIWSAM (cenv: cenv) (env: TcEnv) checkConstraints iwsam m tcref =
if iwsam = WarnOnIWSAM.Yes && isInterfaceTy g ty && checkConstraints = CheckCxs then
let tcref = tcrefOfAppTy g ty
let meths = AllMethInfosOfTypeInScope ResultCollectionSettings.AllResults cenv.infoReader env.NameEnv None ad IgnoreOverrides m ty
- if meths |> List.exists (fun meth -> not meth.IsInstance && meth.IsDispatchSlot) then
+ if meths |> List.exists (fun meth -> not meth.IsInstance && meth.IsDispatchSlot && not meth.IsExtensionMember) then
warning(Error(FSComp.SR.tcUsingInterfaceWithStaticAbstractMethodAsType(tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))
and TcLongIdentType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env tpenv synLongId =
@@ -4550,16 +4557,6 @@ and TcTypeMeasurePower kindOpt (cenv: cenv) newOk checkConstraints occ env tpenv
let ms, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv ty m
TType_measure (Measure.RationalPower (ms, TcSynRationalConst exponent)), tpenv
-and TcTypeMeasureDivide kindOpt (cenv: cenv) newOk checkConstraints occ env tpenv typ1 typ2 m =
- match kindOpt with
- | Some TyparKind.Type ->
- errorR(Error(FSComp.SR.tcUnexpectedSymbolInTypeExpression("/"), m))
- NewErrorType (), tpenv
- | _ ->
- let ms1, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv typ1 m
- let ms2, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv typ2 m
- TType_measure (Measure.Prod(ms1, Measure.Inv ms2)), tpenv
-
and TcTypeMeasureApp kindOpt (cenv: cenv) newOk checkConstraints occ env tpenv arg1 args postfix m =
match arg1 with
| StripParenTypes (SynType.Var(_, m1) | SynType.MeasurePower(_, _, m1)) ->
@@ -10287,10 +10284,8 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt
SynValData(valMf, SynValInfo(args, SynArgInfo({Attributes=rotRetSynAttrs; Range=mHead} :: attrs, opt, retId)), valId)
retAttribs, valAttribs, valSynData
- let isVolatile = HasFSharpAttribute g g.attrib_VolatileFieldAttribute valAttribs
- let hasNoCompilerInliningAttribute = HasFSharpAttribute g g.attrib_NoCompilerInliningAttribute valAttribs
-
- let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable hasNoCompilerInliningAttribute mBinding
+ let isVolatile = HasFSharpAttribute g g.attrib_VolatileFieldAttribute valAttribs
+ let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable g valAttribs mBinding
let argAttribs =
spatsL |> List.map (SynInfo.InferSynArgInfoFromSimplePats >> List.map (SynInfo.AttribsOfArgData >> TcAttrs AttributeTargets.Parameter false))
@@ -11423,10 +11418,9 @@ and AnalyzeAndMakeAndPublishRecursiveValue
let bindingAttribs = TcAttributes cenv env attrTgt bindingSynAttribs
// Allocate the type inference variable for the inferred type
- let ty = NewInferenceType g
- let hasNoCompilerInliningAttribute = HasFSharpAttribute g g.attrib_NoCompilerInliningAttribute bindingAttribs
+ let ty = NewInferenceType g
- let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable hasNoCompilerInliningAttribute mBinding
+ let inlineFlag = ComputeInlineFlag memberFlagsOpt isInline isMutable g bindingAttribs mBinding
if isMutable then errorR(Error(FSComp.SR.tcOnlyRecordFieldsAndSimpleLetCanBeMutable(), mBinding))
@@ -12042,7 +12036,6 @@ let TcAndPublishValSpec (cenv: cenv, env, containerInfo: ContainerInfo, declKind
let attrs = TcAttributes cenv env attrTgt synAttrs
let newOk = if canInferTypars then NewTyparsOK else NoNewTypars
- let hasNoCompilerInliningAttribute = HasFSharpAttribute g g.attrib_NoCompilerInliningAttribute attrs
let valinfos, tpenv = TcValSpec cenv env declKind newOk containerInfo memFlagsOpt None tpenv synValSig attrs
let denv = env.DisplayEnv
@@ -12051,7 +12044,7 @@ let TcAndPublishValSpec (cenv: cenv, env, containerInfo: ContainerInfo, declKind
let (ValSpecResult (altActualParent, memberInfoOpt, id, enclosingDeclaredTypars, declaredTypars, ty, prelimValReprInfo, declKind)) = valSpecResult
- let inlineFlag = ComputeInlineFlag (memberInfoOpt |> Option.map (fun (PrelimMemberInfo(memberInfo, _, _)) -> memberInfo.MemberFlags)) isInline mutableFlag hasNoCompilerInliningAttribute m
+ let inlineFlag = ComputeInlineFlag (memberInfoOpt |> Option.map (fun (PrelimMemberInfo(memberInfo, _, _)) -> memberInfo.MemberFlags)) isInline mutableFlag g attrs m
let freeInType = freeInTypeLeftToRight g false ty
diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs
index 8652e305761..8d287145dcb 100644
--- a/src/Compiler/Checking/CheckFormatStrings.fs
+++ b/src/Compiler/Checking/CheckFormatStrings.fs
@@ -48,6 +48,13 @@ let newInfo () =
addZeros = false
precision = false}
+let escapeDotnetFormatString str =
+ str
+ // We need to double '{' and '}', because even if they were escaped in the
+ // original string, extra curly braces were stripped away by the F# lexer.
+ |> Seq.collect (fun x -> if x = '{' || x = '}' then [x;x] else [x])
+ |> System.String.Concat
+
let parseFormatStringInternal
(m: range)
(fragRanges: range list)
@@ -55,7 +62,7 @@ let parseFormatStringInternal
isInterpolated
isFormattableString
(context: FormatStringCheckContext option)
- fmt
+ (fmt: string)
printerArgTy
printerResidueTy =
@@ -86,6 +93,8 @@ let parseFormatStringInternal
// there are no accurate intra-string ranges available for exact error message locations within the string.
// The 'm' range passed as an input is however accurate and covers the whole string.
//
+ let escapeFormatStringEnabled = g.langVersion.SupportsFeature Features.LanguageFeature.EscapeDotnetFormattableStrings
+
let fmt, fragments =
//printfn "--------------------"
@@ -175,7 +184,7 @@ let parseFormatStringInternal
| _ ->
// Don't muck with the fmt when there is no source code context to go get the original
// source code (i.e. when compiling or background checking)
- fmt, [ (0, 1, m) ]
+ (if escapeFormatStringEnabled then escapeDotnetFormatString fmt else fmt), [ (0, 1, m) ]
let len = fmt.Length
diff --git a/src/Compiler/Driver/CompilerConfig.fs b/src/Compiler/Driver/CompilerConfig.fs
index 91a2e9fde3d..e945c9564a4 100644
--- a/src/Compiler/Driver/CompilerConfig.fs
+++ b/src/Compiler/Driver/CompilerConfig.fs
@@ -300,7 +300,7 @@ type ImportedAssembly =
IsProviderGenerated: bool
mutable TypeProviders: Tainted list
#endif
- FSharpOptimizationData: Microsoft.FSharp.Control.Lazy