Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support .NET Standard 2.0 in F# Interactive and type providers #3307

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 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
3 changes: 3 additions & 0 deletions packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<package id="System.ValueTuple" version="4.3.1" />
<package id="Microsoft.VisualFSharp.Msbuild.15.0" version="1.0.1" />

<!-- To support use of .NET Standard 2.0 components when fsc.exe and fsi.exe are running -->
<package id="NETStandard.Library.NETFramework" version="2.0.0-preview2-25405-01" />

<!-- Testing -->
<package id="FsCheck" version="2.6.2" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
Expand Down
197 changes: 197 additions & 0 deletions setup/FSharp.SDK/component-groups/Compiler_Redist.wxs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/FSharpSource.targets
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
<Import Project="FSharpSource.Profiles.targets" />

<PropertyGroup Condition="'$(TargetDotnetProfile)'=='net40'">
<TargetFrameworkVersion Condition="'$(TargetFrameworkVersion)' == ''">v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion Condition="'$(TargetFrameworkVersion)' == ''">v4.6.1</TargetFrameworkVersion>
<TargetFrameworkProfile></TargetFrameworkProfile>
<!-- MSbuild works out the assembly references -->
</PropertyGroup>
Expand Down
222 changes: 125 additions & 97 deletions src/fsharp/CompileOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1639,15 +1639,111 @@ let GetDefaultFSharpCoreReference() = typeof<list<int>>.Assembly.Location

// If necessary assume a reference to the latest System.ValueTuple with which those tools are built.
let GetDefaultSystemValueTupleReference() =
try
let asm = typeof<System.ValueTuple<int,int>>.Assembly
if asm.FullName.StartsWith "System.ValueTuple" then
Some asm.Location
else None
with _ -> None
let path = Path.GetDirectoryName(GetDefaultFSharpCoreReference())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not really right and the existing code is wrong too ...

This forces us to co-locate System.ValueTuple.dll with FSharp.Core.dll which is not right. Especially since dotnet cli hosting can locate assemblies in a central shared cache rather than app local.

The existing code assumes that ValueTuple was loaded from an assembly named System.ValueTuple.dll which is also not right. Since from dotnet 4.7 it exists in mscorlib, probably System.Private.Corlib.dll on coreclr.

I guess I will have to revisit this code at some point, but we need to do better long term.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, yes, this is wrong when running the compiler or F# Interactive in .NET Core without --noframework etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it won't work on the dotnet cli. Since we don't co-locate system.valuetuple.dll

let file = Path.Combine(path, "System.ValueTuple.dll")
if FileSystem.SafeExists file then Some file
else None

let GetFsiLibraryName () = "FSharp.Compiler.Interactive.Settings"

let NetFrameworkFacadesForNetStandard20 () =
[ "Microsoft.Win32.Primitives"
"netstandard"
"System.AppContext"
"System.Collections.Concurrent"
"System.Collections"
"System.Collections.NonGeneric"
"System.Collections.Specialized"
"System.ComponentModel"
"System.ComponentModel.EventBasedAsync"
"System.ComponentModel.Primitives"
"System.ComponentModel.TypeConverter"
"System.Console"
"System.Data.Common"
"System.Diagnostics.Contracts"
"System.Diagnostics.Debug"
"System.Diagnostics.FileVersionInfo"
"System.Diagnostics.Process"
"System.Diagnostics.StackTrace"
"System.Diagnostics.TextWriterTraceListener"
"System.Diagnostics.Tools"
"System.Diagnostics.TraceSource"
"System.Diagnostics.Tracing"
"System.Drawing.Primitives"
"System.Dynamic.Runtime"
"System.Globalization.Calendars"
"System.Globalization"
"System.Globalization.Extensions"
"System.IO.Compression"
"System.IO.Compression.ZipFile"
"System.IO"
"System.IO.FileSystem"
"System.IO.FileSystem.DriveInfo"
"System.IO.FileSystem.Primitives"
"System.IO.FileSystem.Watcher"
"System.IO.IsolatedStorage"
"System.IO.MemoryMappedFiles"
"System.IO.Pipes"
"System.IO.UnmanagedMemoryStream"
"System.Linq"
"System.Linq.Expressions"
"System.Linq.Parallel"
"System.Linq.Queryable"
"System.Net.Http"
"System.Net.NameResolution"
"System.Net.NetworkInformation"
"System.Net.Ping"
"System.Net.Primitives"
"System.Net.Requests"
"System.Net.Security"
"System.Net.Sockets"
"System.Net.WebHeaderCollection"
"System.Net.WebSockets.Client"
"System.Net.WebSockets"
"System.ObjectModel"
"System.Reflection"
"System.Reflection.Extensions"
"System.Reflection.Primitives"
"System.Resources.Reader"
"System.Resources.ResourceManager"
"System.Resources.Writer"
"System.Runtime.CompilerServices.VisualC"
"System.Runtime"
"System.Runtime.Extensions"
"System.Runtime.Handles"
"System.Runtime.InteropServices"
"System.Runtime.InteropServices.RuntimeInformation"
"System.Runtime.Numerics"
"System.Runtime.Serialization.Formatters"
"System.Runtime.Serialization.Json"
"System.Runtime.Serialization.Primitives"
"System.Runtime.Serialization.Xml"
"System.Security.Claims"
"System.Security.Cryptography.Algorithms"
"System.Security.Cryptography.Csp"
"System.Security.Cryptography.Encoding"
"System.Security.Cryptography.Primitives"
"System.Security.Cryptography.X509Certificates"
"System.Security.Principal"
"System.Security.SecureString"
"System.Text.Encoding"
"System.Text.Encoding.Extensions"
"System.Text.RegularExpressions"
"System.Threading"
"System.Threading.Overlapped"
"System.Threading.Tasks"
"System.Threading.Tasks.Parallel"
"System.Threading.Thread"
"System.Threading.ThreadPool"
"System.Threading.Timer"
//"System.ValueTuple"
"System.Xml.ReaderWriter"
"System.Xml.XDocument"
"System.Xml.XmlDocument"
"System.Xml.XmlSerializer"
"System.Xml.XPath"
"System.Xml.XPath.XDocument" ]

// This list is the default set of references for "non-project" files.
//
// These DLLs are
Expand All @@ -1659,34 +1755,33 @@ let DefaultReferencesForScriptsAndOutOfProjectSources(assumeDotNetFramework) =
[ if assumeDotNetFramework then
yield "System"
yield "System.Xml"
yield "System.Runtime.Remoting"
yield "System.Runtime.Serialization.Formatters.Soap"
yield "System.Xml.Linq"
yield "System.Data"
yield "System.Drawing"
yield "System.Core"
// These are the Portable-profile and .NET Standard 1.6 dependencies of FSharp.Core.dll. These are needed
// when an F# sript references an F# profile 7, 78, 259 or .NET Standard 1.6 component which in turn refers
// to FSharp.Core for profile 7, 78, 259 or .NET Standard.
yield "System.Runtime" // lots of types
yield "System.Linq" // System.Linq.Expressions.Expression<T>
yield "System.Reflection" // System.Reflection.ParameterInfo
yield "System.Linq.Expressions" // System.Linq.IQueryable<T>
yield "System.Threading.Tasks" // valuetype [System.Threading.Tasks]System.Threading.CancellationToken
yield "System.IO" // System.IO.TextWriter
//yield "System.Console" // System.Console.Out etc.
yield "System.Net.Requests" // System.Net.WebResponse etc.
yield "System.Collections" // System.Collections.Generic.List<T>
yield "System.Runtime.Numerics" // BigInteger
yield "System.Threading" // OperationCanceledException

// always include a default reference to System.ValueTuple.dll in scripts and out-of-project sources
match GetDefaultSystemValueTupleReference() with
| None -> ()
| Some v -> yield v

// These are assuumed in the F# scripting model for Mono/.NET Framework if they are available. We should deprecate these or find some way
// to transition to a world where they are not assumed
yield "System.Runtime.Remoting"
yield "System.Runtime.Serialization.Formatters.Soap"
yield "System.Drawing"
yield "System.Web"
yield "System.Web.Services"
yield "System.Windows.Forms"
yield "System.Numerics"

// Assume sufficient facade references to allow .NET Standard 2.0 components to be referenced
let facadePath = System.IO.Path.GetDirectoryName(GetDefaultFSharpCoreReference())
for facadeDllShortName in NetFrameworkFacadesForNetStandard20() do
let facadeDll = System.IO.Path.Combine(facadePath, facadeDllShortName + ".dll")
if File.Exists(facadeDll) then
yield facadeDll


else
yield Path.Combine(Path.GetDirectoryName(typeof<System.Object>.Assembly.Location),"mscorlib.dll"); // mscorlib
yield typeof<System.Console>.Assembly.Location; // System.Console
Expand All @@ -1708,8 +1803,6 @@ let DefaultReferencesForScriptsAndOutOfProjectSources(assumeDotNetFramework) =
let SystemAssemblies () =
HashSet
[ yield "mscorlib"
yield "netstandard"
yield "System.Runtime"
yield GetFSharpCoreLibraryName()
yield "System"
yield "System.Xml"
Expand All @@ -1725,88 +1818,23 @@ let SystemAssemblies () =
yield "System.Web.Services"
yield "System.Windows.Forms"
yield "System.Core"
yield "System.Runtime"
yield "System.Observable"
yield "System.Numerics"
yield "System.ValueTuple"

// Additions for coreclr and portable profiles
yield "System.Collections"
yield "System.Collections.Concurrent"
yield "System.Console"
yield "System.Diagnostics.Debug"
yield "System.Diagnostics.Tools"
yield "System.Globalization"
yield "System.IO"
yield "System.Linq"
yield "System.Linq.Expressions"
yield "System.Linq.Queryable"
yield "System.Net.Requests"
yield "System.Reflection"
yield "System.Reflection.Emit"
yield "System.Reflection.Emit.ILGeneration"
yield "System.Reflection.Extensions"
yield "System.Resources.ResourceManager"
yield "System.Runtime.Extensions"
yield "System.Runtime.InteropServices"
yield "System.Runtime.InteropServices.PInvoke"
yield "System.Runtime.Numerics"
yield "System.Text.Encoding"
yield "System.Text.Encoding.Extensions"
yield "System.Text.RegularExpressions"
yield "System.Threading"
yield "System.Threading.Tasks"
yield "System.Threading.Tasks.Parallel"
yield "System.Threading.Thread"
yield "System.Threading.ThreadPool"
yield "System.Threading.Timer"
for facadeDllShortName in NetFrameworkFacadesForNetStandard20() do
yield facadeDllShortName

yield "FSharp.Compiler.Interactive.Settings"
yield "Microsoft.DiaSymReader"
yield "Microsoft.DiaSymReader.PortablePdb"
yield "Microsoft.Win32.Registry"
yield "System.Diagnostics.Tracing"
yield "System.Globalization.Calendars"
yield "System.Reflection.Primitives"
yield "System.Runtime.Handles"
yield "Microsoft.Win32.Primitives"
yield "System.IO.FileSystem"
yield "System.Net.Primitives"
yield "System.Net.Sockets"
yield "System.Private.Uri"
yield "System.AppContext"
yield "System.Buffers"
yield "System.Collections.Immutable"
yield "System.Diagnostics.DiagnosticSource"
yield "System.Diagnostics.Process"
yield "System.Diagnostics.TraceSource"
yield "System.Globalization.Extensions"
yield "System.IO.Compression"
yield "System.IO.Compression.ZipFile"
yield "System.IO.FileSystem.Primitives"
yield "System.Net.Http"
yield "System.Net.NameResolution"
yield "System.Net.WebHeaderCollection"
yield "System.ObjectModel"
yield "System.Reflection.TypeExtensions"
yield "System.Reflection.Emit.Lightweight"
yield "System.Reflection.Metadata"
yield "System.Reflection.TypeExtensions"
yield "System.Runtime.InteropServices.RuntimeInformation"
yield "System.Runtime.Loader"
yield "System.Security.Claims"
yield "System.Security.Cryptography.Algorithms"
yield "System.Security.Cryptography.Cng"
yield "System.Security.Cryptography.Csp"
yield "System.Security.Cryptography.Encoding"
yield "System.Security.Cryptography.OpenSsl"
yield "System.Security.Cryptography.Primitives"
yield "System.Security.Cryptography.X509Certificates"
yield "System.Security.Principal"
yield "System.Security.Principal.Windows"
yield "System.Threading.Overlapped"
yield "System.Threading.Tasks.Extensions"
yield "System.Xml.ReaderWriter"
yield "System.Xml.XDocument"

yield "FSharp.Compiler.Interactive.Settings"
yield "Microsoft.DiaSymReader"
yield "Microsoft.DiaSymReader.PortablePdb"

]

Expand Down
15 changes: 12 additions & 3 deletions src/fsharp/ErrorLogger.fs
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,30 @@ let inline protectAssemblyExploration dflt f =
try
f()
with
| UnresolvedPathReferenceNoRange _ -> dflt
| UnresolvedReferenceNoRange _
| UnresolvedReferenceError _
| UnresolvedPathReferenceNoRange _
| UnresolvedPathReference _ -> dflt
| _ -> reraise()

let inline protectAssemblyExplorationF dflt f =
try
f()
with
| UnresolvedPathReferenceNoRange (asmName, path) -> dflt(asmName,path)
| UnresolvedReferenceNoRange asmName
| UnresolvedReferenceError (asmName, _) -> dflt(asmName, "")
| UnresolvedPathReferenceNoRange (asmName, path)
| UnresolvedPathReference (asmName, path, _) -> dflt(asmName,path)
| _ -> reraise()

let inline protectAssemblyExplorationNoReraise dflt1 dflt2 f =
try
f()
with
| UnresolvedPathReferenceNoRange _ -> dflt1
| UnresolvedReferenceNoRange _
| UnresolvedReferenceError _
| UnresolvedPathReferenceNoRange _
| UnresolvedPathReference _ -> dflt1
| _ -> dflt2

// Attach a range if this is a range dual exception.
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/FSStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1036,10 +1036,10 @@
<value>Interface implementations should be given on the initial declaration of a type.</value>
</data>
<data name="UnresolvedReferenceNoRange" xml:space="preserve">
<value>A required assembly reference is missing. You must add a reference to assembly '{0}'.</value>
<value>The type '{0}' is required here and is unavailable. You must add a reference to assembly '{1}'.</value>
</data>
<data name="UnresolvedPathReferenceNoRange" xml:space="preserve">
<value>The type referenced through '{0}' is defined in an assembly that is not referenced. You must add a reference to assembly '{1}'.</value>
<value>A reference to the type '{0}' in assembly '{1}' was found, but the type could not be found in that assembly.</value>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this broken the codefixer that looks for this compile error to automatically add references?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, amazing code review catch. I had no idea we were matching on messages like this.

By the look of this code it's ok, since the order of {0} and {1} are still the same in the error message

                let message = diagnostic.GetMessage()
                let parts = message.Split([| '\'' |], StringSplitOptions.None)

                match parts with
                | [| _; _type; _; assemblyName; _ |] ->

In fact the adjustment to UnresolvedReferenceNoRange will make that case now work as well.

</data>
<data name="HashIncludeNotAllowedInNonScript" xml:space="preserve">
<value>#I directives may only occur in F# script files (extensions .fsx or .fsscript). Either move this code to a script file, add a '-I' compiler option for this reference or delimit the directive with delimit it with '#if INTERACTIVE'/'#endif'.</value>
Expand Down
Loading