Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/fsharp/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/fsharp/absil/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/absil/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tests/FSharp.Test.Utilities/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [] }

Expand Down
109 changes: 3 additions & 106 deletions tests/FSharp.Test.Utilities/CompilerAssert.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = """
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$TARGETFRAMEWORK</TargetFramework>
<UseFSharpPreview>true</UseFSharpPreview>
<DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>
</PropertyGroup>

<ItemGroup><Compile Include="Program.fs" /></ItemGroup>
<ItemGroup><Reference Include="$FSHARPCORELOCATION" /></ItemGroup>
<ItemGroup Condition="'$(TARGETFRAMEWORK)'=='net472'">
<Reference Include="System" />
<Reference Include="System.Runtime" />
<Reference Include="System.Core.dll" />
<Reference Include="System.Xml.Linq.dll" />
<Reference Include="System.Data.DataSetExtensions.dll" />
<Reference Include="Microsoft.CSharp.dll" />
<Reference Include="System.Data.dll" />
<Reference Include="System.Deployment.dll" />
<Reference Include="System.Drawing.dll" />
<Reference Include="System.Net.Http.dll" />
<Reference Include="System.Windows.Forms.dll" />
<Reference Include="System.Xml.dll" />
</ItemGroup>

<Target Name="WriteFrameworkReferences" AfterTargets="AfterBuild">
<WriteLinesToFile File="FrameworkReferences.txt" Lines="@(ReferencePath)" Overwrite="true" WriteOnlyWhenDifferent="true" />
</Target>

</Project>"""

static let directoryBuildProps = """
<Project>
</Project>
"""

static let directoryBuildTargets = """
<Project>
</Project>
"""

static let programFs = """
open System

[<EntryPoint>]
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<RequireQualifiedAccessAttribute>.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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -510,7 +407,7 @@ let main argv = 0"""

let dependencies =
#if NETCOREAPP
Array.toList getNetCoreAppReferences
Array.toList TargetFrameworkUtil.currentReferences
#else
[]
#endif
Expand All @@ -534,7 +431,7 @@ let main argv = 0"""

let dependencies =
#if NETCOREAPP
Array.toList getNetCoreAppReferences
Array.toList TargetFrameworkUtil.currentReferences
#else
[]
#endif
Expand Down
117 changes: 117 additions & 0 deletions tests/FSharp.Test.Utilities/Utilities.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -19,6 +21,7 @@ module Utilities =
type TargetFramework =
| NetStandard20
| NetCoreApp31
| Current

let private getResourceStream name =
let assembly = typeof<TargetFramework>.GetTypeInfo().Assembly
Expand Down Expand Up @@ -77,17 +80,129 @@ module Utilities =
[<RequireQualifiedAccess>]
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 = """
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$TARGETFRAMEWORK</TargetFramework>
<UseFSharpPreview>true</UseFSharpPreview>
<DisableImplicitFSharpCoreReference>true</DisableImplicitFSharpCoreReference>
</PropertyGroup>

<ItemGroup><Compile Include="Program.fs" /></ItemGroup>
<ItemGroup><Reference Include="$FSHARPCORELOCATION" /></ItemGroup>
<ItemGroup Condition="'$(TARGETFRAMEWORK)'=='net472'">
<Reference Include="System" />
<Reference Include="System.Runtime" />
<Reference Include="System.Core.dll" />
<Reference Include="System.Xml.Linq.dll" />
<Reference Include="System.Data.DataSetExtensions.dll" />
<Reference Include="Microsoft.CSharp.dll" />
<Reference Include="System.Data.dll" />
<Reference Include="System.Deployment.dll" />
<Reference Include="System.Drawing.dll" />
<Reference Include="System.Net.Http.dll" />
<Reference Include="System.Windows.Forms.dll" />
<Reference Include="System.Xml.dll" />
</ItemGroup>

<Target Name="WriteFrameworkReferences" AfterTargets="AfterBuild">
<WriteLinesToFile File="FrameworkReferences.txt" Lines="@(ReferencePath)" Overwrite="true" WriteOnlyWhenDifferent="true" />
</Target>

</Project>"""

let private directoryBuildProps = """
<Project>
</Project>
"""

let private directoryBuildTargets = """
<Project>
</Project>
"""

let private programFs = """
open System

[<EntryPoint>]
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<RequireQualifiedAccessAttribute>.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 =
lazy ImmutableArray.Create(NetStandard20.netStandard.Value, NetStandard20.mscorlibRef.Value, NetStandard20.systemRuntimeRef.Value, NetStandard20.systemCoreRef.Value, NetStandard20.systemDynamicRuntimeRef.Value)
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

Expand Down Expand Up @@ -128,6 +243,7 @@ module Utilities =

type CSharpLanguageVersion =
| CSharp8 = 0
| CSharp9 = 1

[<AbstractClass; Sealed>]
type CompilationUtil private () =
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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

[<TestFixture>]
module InitOnlyPropertyConsumptionTests =

[<Test>]
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)

[<EntryPoint>]
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

Loading