diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs
index 94fbd7ff60f..0cd10e2fc4e 100644
--- a/src/fsharp/MethodCalls.fs
+++ b/src/fsharp/MethodCalls.fs
@@ -767,7 +767,7 @@ let BuildILMethInfoCall g amap m isProp (minfo: ILMethInfo) valUseFlags minst di
let ilMethRef = minfo.ILMethodRef
let newobj = ctor && (match valUseFlags with NormalValUse -> true | _ -> false)
let exprTy = if ctor then minfo.ApparentEnclosingType else minfo.GetFSharpReturnTy(amap, m, minst)
- let retTy = if not ctor && ilMethRef.ReturnType = ILType.Void then [] else [exprTy]
+ let retTy = if not ctor && (stripILModifiedFromTy ilMethRef.ReturnType) = ILType.Void then [] else [exprTy]
let isDllImport = minfo.IsDllImport g
Expr.Op (TOp.ILCall (useCallvirt, isProtected, valu, newobj, valUseFlags, isProp, isDllImport, ilMethRef, minfo.DeclaringTypeInst, minst, retTy), [], args, m),
exprTy
diff --git a/src/fsharp/absil/il.fs b/src/fsharp/absil/il.fs
index a93aac6893b..a2e1f0ee3ec 100644
--- a/src/fsharp/absil/il.fs
+++ b/src/fsharp/absil/il.fs
@@ -2722,6 +2722,11 @@ let isILBoxedTy = function ILType.Boxed _ -> true | _ -> false
let isILValueTy = function ILType.Value _ -> true | _ -> false
+let rec stripILModifiedFromTy (ty: ILType) =
+ match ty with
+ | ILType.Modified(_, _, ty) -> stripILModifiedFromTy ty
+ | _ -> ty
+
let isBuiltInTySpec (ilg: ILGlobals) (tspec: ILTypeSpec) n =
let tref = tspec.TypeRef
let scoref = tref.Scope
diff --git a/src/fsharp/absil/il.fsi b/src/fsharp/absil/il.fsi
index 2f8b44a627b..14ce112b1d6 100644
--- a/src/fsharp/absil/il.fsi
+++ b/src/fsharp/absil/il.fsi
@@ -2002,6 +2002,9 @@ val internal instILType: ILGenericArgs -> ILType -> ILType
/// This is a 'vendor neutral' way of referencing mscorlib.
val internal ecmaPublicKey: PublicKey
+/// Strips ILType.Modified from the ILType.
+val internal stripILModifiedFromTy: ILType -> ILType
+
/// Discriminating different important built-in types.
val internal isILObjectTy: ILGlobals -> ILType -> bool
val internal isILStringTy: ILGlobals -> ILType -> bool
diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs
index c80b05bbdb9..0233c3f3954 100644
--- a/tests/FSharp.Test.Utilities/Compiler.fs
+++ b/tests/FSharp.Test.Utilities/Compiler.fs
@@ -122,8 +122,8 @@ module rec Compiler =
| null -> failwith "Source cannot be null"
| _ ->
{ Source = Text source
- LangVersion = CSharpLanguageVersion.CSharp8
- TargetFramework = TargetFramework.NetCoreApp31
+ LangVersion = CSharpLanguageVersion.CSharp9
+ TargetFramework = TargetFramework.Current
Name = None
References = [] }
diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs
index 240275139d4..c2f4e33607e 100644
--- a/tests/FSharp.Test.Utilities/CompilerAssert.fs
+++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs
@@ -76,109 +76,6 @@ type CompilerAssert private () =
static let checker = FSharpChecker.Create(suggestNamesForErrors=true)
- static let config = TestFramework.initializeSuite ()
-
- static let _ = config |> ignore
-
-// Do a one time dotnet sdk build to compute the proper set of reference assemblies to pass to the compiler
- static let projectFile = """
-
-
-
- Exe
- $TARGETFRAMEWORK
- true
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-"""
-
- static let directoryBuildProps = """
-
-
-"""
-
- static let directoryBuildTargets = """
-
-
-"""
-
- static let programFs = """
-open System
-
-[]
-let main argv = 0"""
-
- static let getNetCoreAppReferences =
- let mutable output = ""
- let mutable errors = ""
- let mutable cleanUp = true
- let pathToArtifacts = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../../../.."))
- if Path.GetFileName(pathToArtifacts) <> "artifacts" then failwith "CompilerAssert did not find artifacts directory --- has the location changed????"
- let pathToTemp = Path.Combine(pathToArtifacts, "Temp")
- let projectDirectory = Path.Combine(pathToTemp, "CompilerAssert", Path.GetRandomFileName())
- let pathToFSharpCore = typeof.Assembly.Location
- try
- try
- Directory.CreateDirectory(projectDirectory) |> ignore
- let projectFileName = Path.Combine(projectDirectory, "ProjectFile.fsproj")
- let programFsFileName = Path.Combine(projectDirectory, "Program.fs")
- let directoryBuildPropsFileName = Path.Combine(projectDirectory, "Directory.Build.props")
- let directoryBuildTargetsFileName = Path.Combine(projectDirectory, "Directory.Build.targets")
- let frameworkReferencesFileName = Path.Combine(projectDirectory, "FrameworkReferences.txt")
-#if NETCOREAPP
- File.WriteAllText(projectFileName, projectFile.Replace("$TARGETFRAMEWORK", "net5.0").Replace("$FSHARPCORELOCATION", pathToFSharpCore))
-#else
- File.WriteAllText(projectFileName, projectFile.Replace("$TARGETFRAMEWORK", "net472").Replace("$FSHARPCORELOCATION", pathToFSharpCore))
-#endif
- File.WriteAllText(programFsFileName, programFs)
- File.WriteAllText(directoryBuildPropsFileName, directoryBuildProps)
- File.WriteAllText(directoryBuildTargetsFileName, directoryBuildTargets)
-
- let timeout = 30000
- let exitCode, output, errors = Commands.executeProcess (Some config.DotNetExe) "build" projectDirectory timeout
-
- if exitCode <> 0 || errors.Length > 0 then
- printfn "Output:\n=======\n"
- output |> Seq.iter(fun line -> printfn "STDOUT:%s\n" line)
- printfn "Errors:\n=======\n"
- errors |> Seq.iter(fun line -> printfn "STDERR:%s\n" line)
- Assert.True(false, "Errors produced generating References")
-
- File.ReadLines(frameworkReferencesFileName) |> Seq.toArray
- with | e ->
- cleanUp <- false
- printfn "Project directory: %s" projectDirectory
- printfn "STDOUT: %s" output
- File.WriteAllText(Path.Combine(projectDirectory, "project.stdout"), output)
- printfn "STDERR: %s" errors
- File.WriteAllText(Path.Combine(projectDirectory, "project.stderror"), errors)
- raise (new Exception (sprintf "An error occurred getting netcoreapp references: %A" e))
- finally
- if cleanUp then
- try Directory.Delete(projectDirectory, recursive=true) with | _ -> ()
-
#if FX_NO_APP_DOMAINS
static let executeBuiltApp assembly deps =
let ctxt = AssemblyLoadContext("ContextName", true)
@@ -214,7 +111,7 @@ let main argv = 0"""
ProjectId = None
SourceFiles = [|"test.fs"|]
OtherOptions =
- let assemblies = getNetCoreAppReferences |> Array.map (fun x -> sprintf "-r:%s" x)
+ let assemblies = TargetFrameworkUtil.currentReferences |> Array.map (fun x -> sprintf "-r:%s" x)
#if NETCOREAPP
Array.append [|"--preferreduilang:en-US"; "--targetprofile:netcore"; "--noframework"; "--simpleresolution"; "--warn:5"|] assemblies
#else
@@ -510,7 +407,7 @@ let main argv = 0"""
let dependencies =
#if NETCOREAPP
- Array.toList getNetCoreAppReferences
+ Array.toList TargetFrameworkUtil.currentReferences
#else
[]
#endif
@@ -534,7 +431,7 @@ let main argv = 0"""
let dependencies =
#if NETCOREAPP
- Array.toList getNetCoreAppReferences
+ Array.toList TargetFrameworkUtil.currentReferences
#else
[]
#endif
diff --git a/tests/FSharp.Test.Utilities/Utilities.fs b/tests/FSharp.Test.Utilities/Utilities.fs
index 762849037cf..fa02e829b7b 100644
--- a/tests/FSharp.Test.Utilities/Utilities.fs
+++ b/tests/FSharp.Test.Utilities/Utilities.fs
@@ -10,6 +10,8 @@ open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.CSharp
open System.Diagnostics
open FSharp.Test.Utilities
+open TestFramework
+open NUnit.Framework
// This file mimics how Roslyn handles their compilation references for compilation testing
@@ -19,6 +21,7 @@ module Utilities =
type TargetFramework =
| NetStandard20
| NetCoreApp31
+ | Current
let private getResourceStream name =
let assembly = typeof.GetTypeInfo().Assembly
@@ -77,6 +80,107 @@ module Utilities =
[]
module TargetFrameworkUtil =
+ let private config = TestFramework.initializeSuite ()
+
+ // Do a one time dotnet sdk build to compute the proper set of reference assemblies to pass to the compiler
+ let private projectFile = """
+
+
+
+ Exe
+ $TARGETFRAMEWORK
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
+
+ let private directoryBuildProps = """
+
+
+"""
+
+ let private directoryBuildTargets = """
+
+
+"""
+
+ let private programFs = """
+open System
+
+[]
+let main argv = 0"""
+
+ let private getNetCoreAppReferences =
+ let mutable output = ""
+ let mutable errors = ""
+ let mutable cleanUp = true
+ let pathToArtifacts = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../../../.."))
+ if Path.GetFileName(pathToArtifacts) <> "artifacts" then failwith "CompilerAssert did not find artifacts directory --- has the location changed????"
+ let pathToTemp = Path.Combine(pathToArtifacts, "Temp")
+ let projectDirectory = Path.Combine(pathToTemp, "CompilerAssert", Path.GetRandomFileName())
+ let pathToFSharpCore = typeof.Assembly.Location
+ try
+ try
+ Directory.CreateDirectory(projectDirectory) |> ignore
+ let projectFileName = Path.Combine(projectDirectory, "ProjectFile.fsproj")
+ let programFsFileName = Path.Combine(projectDirectory, "Program.fs")
+ let directoryBuildPropsFileName = Path.Combine(projectDirectory, "Directory.Build.props")
+ let directoryBuildTargetsFileName = Path.Combine(projectDirectory, "Directory.Build.targets")
+ let frameworkReferencesFileName = Path.Combine(projectDirectory, "FrameworkReferences.txt")
+#if NETCOREAPP
+ File.WriteAllText(projectFileName, projectFile.Replace("$TARGETFRAMEWORK", "net5.0").Replace("$FSHARPCORELOCATION", pathToFSharpCore))
+#else
+ File.WriteAllText(projectFileName, projectFile.Replace("$TARGETFRAMEWORK", "net472").Replace("$FSHARPCORELOCATION", pathToFSharpCore))
+#endif
+ File.WriteAllText(programFsFileName, programFs)
+ File.WriteAllText(directoryBuildPropsFileName, directoryBuildProps)
+ File.WriteAllText(directoryBuildTargetsFileName, directoryBuildTargets)
+
+ let timeout = 30000
+ let exitCode, output, errors = Commands.executeProcess (Some config.DotNetExe) "build" projectDirectory timeout
+
+ if exitCode <> 0 || errors.Length > 0 then
+ printfn "Output:\n=======\n"
+ output |> Seq.iter(fun line -> printfn "STDOUT:%s\n" line)
+ printfn "Errors:\n=======\n"
+ errors |> Seq.iter(fun line -> printfn "STDERR:%s\n" line)
+ Assert.True(false, "Errors produced generating References")
+
+ File.ReadLines(frameworkReferencesFileName) |> Seq.toArray
+ with | e ->
+ cleanUp <- false
+ printfn "Project directory: %s" projectDirectory
+ printfn "STDOUT: %s" output
+ File.WriteAllText(Path.Combine(projectDirectory, "project.stdout"), output)
+ printfn "STDERR: %s" errors
+ File.WriteAllText(Path.Combine(projectDirectory, "project.stderror"), errors)
+ raise (new Exception (sprintf "An error occurred getting netcoreapp references: %A" e))
+ finally
+ if cleanUp then
+ try Directory.Delete(projectDirectory, recursive=true) with | _ -> ()
+
open TestReferences
let private netStandard20References =
@@ -84,10 +188,21 @@ module Utilities =
let private netCoreApp31References =
lazy ImmutableArray.Create(NetCoreApp31.netStandard.Value, NetCoreApp31.mscorlibRef.Value, NetCoreApp31.systemRuntimeRef.Value, NetCoreApp31.systemCoreRef.Value, NetCoreApp31.systemDynamicRuntimeRef.Value, NetCoreApp31.systemConsoleRef.Value)
+ let currentReferences =
+ getNetCoreAppReferences
+
+ let currentReferencesAsPEs =
+ getNetCoreAppReferences
+ |> Seq.map (fun x ->
+ PortableExecutableReference.CreateFromFile(x)
+ )
+ |> ImmutableArray.CreateRange
+
let getReferences tf =
match tf with
| TargetFramework.NetStandard20 -> netStandard20References.Value
| TargetFramework.NetCoreApp31 -> netCoreApp31References.Value
+ | TargetFramework.Current -> currentReferencesAsPEs
type RoslynLanguageVersion = LanguageVersion
@@ -128,6 +243,7 @@ module Utilities =
type CSharpLanguageVersion =
| CSharp8 = 0
+ | CSharp9 = 1
[]
type CompilationUtil private () =
@@ -136,6 +252,7 @@ module Utilities =
let lv =
match lv with
| CSharpLanguageVersion.CSharp8 -> LanguageVersion.CSharp8
+ | CSharpLanguageVersion.CSharp9 -> LanguageVersion.CSharp9
| _ -> LanguageVersion.Default
let tf = defaultArg tf TargetFramework.NetStandard20
diff --git a/tests/fsharp/Compiler/Language/InitOnlyPropertyConsumptionTests.fs b/tests/fsharp/Compiler/Language/InitOnlyPropertyConsumptionTests.fs
new file mode 100644
index 00000000000..eca26290cec
--- /dev/null
+++ b/tests/fsharp/Compiler/Language/InitOnlyPropertyConsumptionTests.fs
@@ -0,0 +1,57 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler.UnitTests
+
+open NUnit.Framework
+open FSharp.Test.Utilities.Compiler
+open FSharp.Test.Utilities
+open FSharp.Test.Utilities.Utilities
+open FSharp.Tests
+
+#if NETCOREAPP
+
+[]
+module InitOnlyPropertyConsumptionTests =
+
+ []
+ let ``Should be able to set an init-only property from a C# record`` () =
+ let csharpSource =
+ """
+using System;
+
+namespace CSharpTest
+{
+ public record Test
+ {
+ public int X { get; init; }
+ }
+}
+ """
+
+ let fsharpSource =
+ """
+open System
+open System.Runtime.CompilerServices
+open CSharpTest
+
+let test() =
+ Test(X = 123)
+
+[]
+let main _ =
+ let x = test()
+ Console.Write(x.X)
+ 0
+ """
+
+ let csCmpl =
+ CompilationUtil.CreateCSharpCompilation(csharpSource, CSharpLanguageVersion.CSharp9, TargetFramework.Current)
+ |> CompilationReference.Create
+
+ let fsCmpl =
+ Compilation.Create(fsharpSource, Fs, Exe, options = [|"--langversion:5.0"|], cmplRefs = [csCmpl])
+
+ CompilerAssert.ExecutionHasOutput(fsCmpl, "123")
+
+#endif
+
diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj
index 6ba0c4a6a5d..ce4becaea00 100644
--- a/tests/fsharp/FSharpSuite.Tests.fsproj
+++ b/tests/fsharp/FSharpSuite.Tests.fsproj
@@ -40,6 +40,7 @@
+