Skip to content

Commit b6f0be9

Browse files
author
dotnet-automerge-bot
authored
Merge pull request #7192 from dotnet/merges/release/dev16.3-to-release/fsharp47
Merge release/dev16.3 to release/fsharp47
2 parents 1bc2896 + 928d050 commit b6f0be9

11 files changed

Lines changed: 3936 additions & 279 deletions

File tree

eng/Version.Details.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<ProductDependencies>
44
</ProductDependencies>
55
<ToolsetDependencies>
6-
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19359.1">
6+
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="1.0.0-beta.19359.6">
77
<Uri>https://github.com/dotnet/arcade</Uri>
8-
<Sha>ef3834feb8615429a58808cdcf9ad9284d767654</Sha>
8+
<Sha>0f5dd7680174620f31c9a00cdb2ac0b0e70e631f</Sha>
99
</Dependency>
1010
</ToolsetDependencies>
1111
</Dependencies>

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
}
1111
},
1212
"msbuild-sdks": {
13-
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19359.1",
13+
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19359.6",
1414
"Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19069.2"
1515
}
1616
}

src/fsharp/IlxGen.fs

Lines changed: 119 additions & 69 deletions
Large diffs are not rendered by default.

src/fsharp/lib.fs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,14 @@ module UnmanagedProcessExecutionOptions =
534534
"HeapSetInformation() returned FALSE; LastError = 0x" +
535535
GetLastError().ToString("X").PadLeft(8, '0') + "."))
536536

537+
[<RequireQualifiedAccess>]
538+
module StackGuard =
539+
540+
open System.Runtime.CompilerServices
541+
542+
[<Literal>]
543+
let private MaxUncheckedRecursionDepth = 20
544+
545+
let EnsureSufficientExecutionStack recursionDepth =
546+
if recursionDepth > MaxUncheckedRecursionDepth then
547+
RuntimeHelpers.EnsureSufficientExecutionStack ()

tests/fsharp/Compiler/CompilerAssert.fs

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ open FSharp.Compiler.SourceCodeServices
1212
open FSharp.Compiler.Interactive.Shell
1313

1414
open NUnit.Framework
15+
open System.Reflection.Emit
16+
17+
[<Sealed>]
18+
type ILVerifier (dllFilePath: string) =
19+
20+
member this.VerifyIL (qualifiedItemName: string, expectedIL: string) =
21+
ILChecker.checkILItem qualifiedItemName dllFilePath [ expectedIL ]
22+
23+
member this.VerifyIL (expectedIL: string list) =
24+
ILChecker.checkIL dllFilePath expectedIL
25+
26+
member this.VerifyILWithLineNumbers (qualifiedItemName: string, expectedIL: string) =
27+
ILChecker.checkILItemWithLineNumbers qualifiedItemName dllFilePath [ expectedIL ]
1528

1629
[<RequireQualifiedAccess>]
1730
module CompilerAssert =
@@ -47,11 +60,45 @@ module CompilerAssert =
4760
ExtraProjectInfo = None
4861
Stamp = None
4962
}
50-
51-
let lockObj = obj ()
63+
let private gate = obj ()
64+
65+
let private compile isExe source f =
66+
lock gate <| fun () ->
67+
let inputFilePath = Path.ChangeExtension(Path.GetTempFileName(), ".fs")
68+
let outputFilePath = Path.ChangeExtension (Path.GetTempFileName(), if isExe then ".exe" else ".dll")
69+
let runtimeConfigFilePath = Path.ChangeExtension (outputFilePath, ".runtimeconfig.json")
70+
let fsCoreDllPath = config.FSCOREDLLPATH
71+
let tmpFsCoreFilePath = Path.Combine (Path.GetDirectoryName(outputFilePath), Path.GetFileName(fsCoreDllPath))
72+
try
73+
File.Copy (fsCoreDllPath , tmpFsCoreFilePath, true)
74+
File.WriteAllText (inputFilePath, source)
75+
File.WriteAllText (runtimeConfigFilePath, """
76+
{
77+
"runtimeOptions": {
78+
"tfm": "netcoreapp2.1",
79+
"framework": {
80+
"name": "Microsoft.NETCore.App",
81+
"version": "2.1.0"
82+
}
83+
}
84+
}
85+
""")
86+
87+
let args =
88+
defaultProjectOptions.OtherOptions
89+
|> Array.append [| "fsc.exe"; inputFilePath; "-o:" + outputFilePath; (if isExe then "--target:exe" else "--target:library"); "--nowin32manifest" |]
90+
let errors, _ = checker.Compile args |> Async.RunSynchronously
91+
92+
f (errors, outputFilePath)
93+
94+
finally
95+
try File.Delete inputFilePath with | _ -> ()
96+
try File.Delete outputFilePath with | _ -> ()
97+
try File.Delete runtimeConfigFilePath with | _ -> ()
98+
try File.Delete tmpFsCoreFilePath with | _ -> ()
5299

53100
let Pass (source: string) =
54-
lock lockObj <| fun () ->
101+
lock gate <| fun () ->
55102
let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously
56103

57104
Assert.IsEmpty(parseResults.Errors, sprintf "Parse errors: %A" parseResults.Errors)
@@ -64,7 +111,7 @@ module CompilerAssert =
64111

65112

66113
let TypeCheckSingleError (source: string) (expectedErrorNumber: int) (expectedErrorRange: int * int * int * int) (expectedErrorMsg: string) =
67-
lock lockObj <| fun () ->
114+
lock gate <| fun () ->
68115
let parseResults, fileAnswer = checker.ParseAndCheckFileInProject("test.fs", 0, SourceText.ofString source, defaultProjectOptions) |> Async.RunSynchronously
69116

70117
Assert.IsEmpty(parseResults.Errors, sprintf "Parse errors: %A" parseResults.Errors)
@@ -82,8 +129,46 @@ module CompilerAssert =
82129
Assert.AreEqual(expectedErrorMsg, info.Message, "expectedErrorMsg")
83130
)
84131

132+
let CompileExe (source: string) =
133+
compile true source (fun (errors, _) ->
134+
if errors.Length > 0 then
135+
Assert.Fail (sprintf "Compile had warnings and/or errors: %A" errors))
136+
137+
let CompileExeAndRun (source: string) =
138+
compile true source (fun (errors, outputExe) ->
139+
140+
if errors.Length > 0 then
141+
Assert.Fail (sprintf "Compile had warnings and/or errors: %A" errors)
142+
143+
let pInfo = ProcessStartInfo ()
144+
#if NETCOREAPP
145+
pInfo.FileName <- config.DotNetExe
146+
pInfo.Arguments <- outputExe
147+
#else
148+
pInfo.FileName <- outputExe
149+
#endif
150+
151+
pInfo.RedirectStandardError <- true
152+
pInfo.UseShellExecute <- false
153+
154+
let p = Process.Start(pInfo)
155+
156+
p.WaitForExit()
157+
let errors = p.StandardError.ReadToEnd ()
158+
if not (String.IsNullOrWhiteSpace errors) then
159+
Assert.Fail errors
160+
)
161+
162+
let CompileLibraryAndVerifyIL (source: string) (f: ILVerifier -> unit) =
163+
compile false source (fun (errors, outputFilePath) ->
164+
if errors.Length > 0 then
165+
Assert.Fail (sprintf "Compile had warnings and/or errors: %A" errors)
166+
167+
f (ILVerifier outputFilePath)
168+
)
169+
85170
let RunScript (source: string) (expectedErrorMessages: string list) =
86-
lock lockObj <| fun () ->
171+
lock gate <| fun () ->
87172
// Intialize output and input streams
88173
use inStream = new StringReader("")
89174
use outStream = new StringWriter()

tests/fsharp/Compiler/ILChecker.fs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+
namespace FSharp.Compiler.UnitTests
4+
5+
open System
6+
open System.IO
7+
open System.Diagnostics
8+
9+
open NUnit.Framework
10+
open TestFramework
11+
12+
[<RequireQualifiedAccess>]
13+
module ILChecker =
14+
15+
let config = initializeSuite ()
16+
17+
let private exec exe args =
18+
let startInfo = ProcessStartInfo(exe, String.concat " " args)
19+
startInfo.RedirectStandardError <- true
20+
startInfo.UseShellExecute <- false
21+
use p = Process.Start(startInfo)
22+
p.WaitForExit()
23+
p.StandardError.ReadToEnd(), p.ExitCode
24+
25+
/// Filters i.e ['The system type \'System.ReadOnlySpan`1\' was required but no referenced system DLL contained this type']
26+
let private filterSpecialComment (text: string) =
27+
let pattern = @"(\[\'(.*?)\'\])"
28+
System.Text.RegularExpressions.Regex.Replace(text, pattern,
29+
(fun me -> String.Empty)
30+
)
31+
32+
let private checkILAux ildasmArgs dllFilePath expectedIL =
33+
let ilFilePath = Path.ChangeExtension(dllFilePath, ".il")
34+
35+
let mutable errorMsgOpt = None
36+
try
37+
let ildasmPath = config.ILDASM
38+
39+
exec ildasmPath (ildasmArgs @ [ sprintf "%s /out=%s" dllFilePath ilFilePath ]) |> ignore
40+
41+
let text = File.ReadAllText(ilFilePath)
42+
let blockComments = @"/\*(.*?)\*/"
43+
let lineComments = @"//(.*?)\r?\n"
44+
let strings = @"""((\\[^\n]|[^""\n])*)"""
45+
let verbatimStrings = @"@(""[^""]*"")+"
46+
let textNoComments =
47+
System.Text.RegularExpressions.Regex.Replace(text,
48+
blockComments + "|" + lineComments + "|" + strings + "|" + verbatimStrings,
49+
(fun me ->
50+
if (me.Value.StartsWith("/*") || me.Value.StartsWith("//")) then
51+
if me.Value.StartsWith("//") then Environment.NewLine else String.Empty
52+
else
53+
me.Value), System.Text.RegularExpressions.RegexOptions.Singleline)
54+
|> filterSpecialComment
55+
56+
expectedIL
57+
|> List.iter (fun (ilCode: string) ->
58+
let expectedLines = ilCode.Split('\n')
59+
let startIndex = textNoComments.IndexOf(expectedLines.[0])
60+
if startIndex = -1 || textNoComments.Length < startIndex + ilCode.Length then
61+
errorMsgOpt <- Some("==EXPECTED CONTAINS==\n" + ilCode + "\n")
62+
else
63+
let errors = ResizeArray()
64+
let actualLines = textNoComments.Substring(startIndex, textNoComments.Length - startIndex).Split('\n')
65+
for i = 0 to expectedLines.Length - 1 do
66+
let expected = expectedLines.[i].Trim()
67+
let actual = actualLines.[i].Trim()
68+
if expected <> actual then
69+
errors.Add(sprintf "\n==\nName: %s\n\nExpected:\t %s\nActual:\t\t %s\n==" actualLines.[0] expected actual)
70+
71+
if errors.Count > 0 then
72+
let msg = String.concat "\n" errors + "\n\n\n==EXPECTED==\n" + ilCode + "\n"
73+
errorMsgOpt <- Some(msg + "\n\n\n==ACTUAL==\n" + String.Join("\n", actualLines, 0, expectedLines.Length))
74+
)
75+
76+
if expectedIL.Length = 0 then
77+
errorMsgOpt <- Some ("No Expected IL")
78+
79+
match errorMsgOpt with
80+
| Some(msg) -> errorMsgOpt <- Some(msg + "\n\n\n==ENTIRE ACTUAL==\n" + textNoComments)
81+
| _ -> ()
82+
finally
83+
try File.Delete(ilFilePath) with | _ -> ()
84+
85+
match errorMsgOpt with
86+
| Some(errorMsg) ->
87+
Assert.Fail(errorMsg)
88+
| _ -> ()
89+
90+
let checkILItem item dllFilePath expectedIL =
91+
checkILAux [ sprintf "/item:%s" item ] dllFilePath expectedIL
92+
93+
let checkILItemWithLineNumbers item dllFilePath expectedIL =
94+
checkILAux [ sprintf "/item:\"%s\"" item; "/linenum" ] dllFilePath expectedIL
95+
96+
let checkIL dllFilePath expectedIL =
97+
checkILAux [] dllFilePath expectedIL

0 commit comments

Comments
 (0)