-
Notifications
You must be signed in to change notification settings - Fork 123
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
Fable support #688
Fable support #688
Conversation
@ncave Extraordinary. I'll take a close look Is the demo page hosted somewhere? How big is the overall JS for the bootstrapped compiler? Random future thought: Do you think there's any chance we could eventually produce .NET binaries with the JS compiler (and send them to .NET clients?) I've no idea when/where that would be useful, it's just a thought. Also, I wonder if this might eventually make it into the Microsoft Visual F# repo and the standard F# command line compiler. That would be quite interesting :) Or is it always best to package it via Fable? |
Export.FCS.sln
Outdated
@@ -0,0 +1,27 @@ | |||
Microsoft Visual Studio Solution File, Format Version 12.00 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably best if all files that have something to do with Fable have Fable in the name where possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. It's not really related to the PR, it's just a quick hack to export metadata using FCS, so it should be moved out.
build.fsx
Outdated
@@ -272,14 +272,27 @@ Target "CodeGen.NetCore" (fun _ -> | |||
let fsLex fsl out = runInDir (toolDir + "fslex.exe") "%s --unicode %s -o %s" fsl lexArgs out | |||
let fsYacc fsy out m o = runInDir (toolDir + "fsyacc.exe") "%s %s %s %s %s -o %s" fsy lexArgs yaccArgs m o out | |||
|
|||
#if FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to mention that in the visualfsahrp (and soon fsharp, and soon this) repo FsSrGen has been replaced by a script fssrgen.fsx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, it's there just until the new tooling gets released and FCS is migrated to use it.
build.fsx
Outdated
// comments the #line directive as it is not supported by Fable | ||
["lex.fs"; "pplex.fs"; "illex.fs"; "ilpars.fs"; "pars.fs"; "pppars.fs"] | ||
|> Seq.map (fun fileName -> IO.Path.Combine (workDir, fileName)) | ||
|> RegexReplaceInFilesWithEncoding @"# (?=\d)" "//# " Text.Encoding.UTF8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason this doesn't work in fable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fable uses the line directive already to do source mapping, so we can't. The simplest way is to just comment it out.
build.fsx
Outdated
// comments the #line directive as it is not supported by Fable | ||
["lex.fs"; "pplex.fs"; "illex.fs"; "ilpars.fs"; "pars.fs"; "pppars.fs"] | ||
|> Seq.map (fun fileName -> IO.Path.Combine (workDir, fileName)) | ||
|> RegexReplaceInFilesWithEncoding @"# (?=\d)" "//# " Text.Encoding.UTF8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason this doesn't work in fable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, see this.
src/absil/il.fs
Outdated
@@ -8,14 +8,18 @@ module (*internal*) Microsoft.FSharp.Compiler.AbstractIL.IL | |||
|
|||
|
|||
open Internal.Utilities | |||
#if FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may as well make this unconditional e.g.
open Microsoft.FSharp.Collections // needed for Fable
open Microsoft.FSharp.Core // needed for Fable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be a good idea to retain the conditional as there is some type overwriting that is only needed when compiled with Fable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use FSLANG_NO_IMPLICITOPEN
to indicate a dialect of F# that doesn't have implicit opening of these namespaces, thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not that there is no implicit opening, it's the order of opening after the adapters are loaded which overwrites some core types with custom implementations.
src/absil/il.fs
Outdated
open Microsoft.FSharp.Compiler.AbstractIL | ||
open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics | ||
open Microsoft.FSharp.Compiler.AbstractIL.Internal | ||
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library | ||
open System.Collections | ||
open System.Collections.Generic | ||
open System.Collections.Concurrent | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove whitespace cahnges
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
src/absil/il.fs
Outdated
@@ -77,21 +81,21 @@ let rec splitNamespaceAux (nm:string) = | |||
|
|||
/// Global State. All namespace splits ever seen | |||
// ++GLOBAL MUTABLE STATE | |||
#if FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not conditionally define
type ConcurrentDictionary<'K,'V> = Dictionary<'K'V>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason, just looked cleaner this way. This too can go away after Dictionary constructors can be handled properly by Fable.
src/absil/il.fs
Outdated
(x.Scope = y.Scope) && | ||
(x.Name = y.Name) && | ||
(x.Enclosing = y.Enclosing) | ||
override x.Equals(yobj:obj) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change needed? When would the cast fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't recall the actual reason, probably unsupported casting by Fable.
src/absil/il.fs
Outdated
member x.IsNewSlot = match x.mdKind with | MethodKind.Virtual v -> v.IsNewSlot | _ -> invalidOp "not virtual" | ||
member x.IsCheckAccessOnOverride= match x.mdKind with | MethodKind.Virtual v -> v.IsCheckAccessOnOverride | _ -> invalidOp "not virtual" | ||
member x.IsAbstract = match x.mdKind with | MethodKind.Virtual v -> v.IsAbstract | _ -> invalidOp "not virtual" | ||
member x.IsFinal = match x.mdKind with | MethodKind.Virtual v -> v.IsFinal | _ -> false //invalidOp "not virtual" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these changes needed? I see they are pretty harmless changes though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll revisit that.
src/absil/il.fs
Outdated
@@ -3661,7 +3666,11 @@ type ILTypeSigParser(tstring : string) = | |||
// fetch the arity | |||
let arity = | |||
while (int(here()) >= (int('0'))) && (int(here()) <= ((int('9')))) && (int(peek()) >= (int('0'))) && (int(peek()) <= ((int('9')))) do step() | |||
#if FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just always use the Fable version here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I just tried to be conservative with changes to lower the impact.
src/absil/il.fs
Outdated
@@ -1552,7 +1557,7 @@ and [<Sealed>] ILTypeDefs(f : unit -> (string list * string * ILAttributes * Laz | |||
let mutable array = InlineDelayInit<_>(f) | |||
let mutable dict = InlineDelayInit<_>(fun () -> | |||
let arr = array.Value | |||
let t = Dictionary<_,_>(HashIdentity.Structural) | |||
let t = Dictionary<_,_>(3, HashIdentity.Structural) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's up here - doesn't Fable have a default size constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Main reason is Fable (and Javascript maps/sets) have no support for collections with equality comparers. Technically map/set trees with IComparer can be used as a substitute, but probably the performance will not be too good, more like a list instead of a map (not sure how important collection performance is here though). Very few places in FCS actually use a custom equality comparer, so for now we're getting away with just ignoring them, that's one of the corners that have been cut and has to be fixed. Technically this should eventually go away as it's just a deficiency in Fable.
Made a few initial comments. I suppose the big challenge is going to be keeping this compiling and working as changes flow in from the Visual F# TOols |
src/absil/il.fs
Outdated
@@ -1552,7 +1557,7 @@ and [<Sealed>] ILTypeDefs(f : unit -> (string list * string * ILAttributes * Laz | |||
let mutable array = InlineDelayInit<_>(f) | |||
let mutable dict = InlineDelayInit<_>(fun () -> | |||
let arr = array.Value | |||
let t = Dictionary<_,_>(HashIdentity.Structural) | |||
let t = Dictionary<_,_>(3, HashIdentity.Structural) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should 3 be arr.Length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, but that's not the default value for this contructor. In any case, this will probably go away, as it's just a work around a deficiency in Fable (can't do comparers), when it's resolved I'll take it out.
src/absil/il.fs
Outdated
|
||
member aref.QualifiedName = | ||
let b = new System.Text.StringBuilder(100) | ||
let add (s:string) = (b.Append(s) |> ignore) | ||
let addC (s:char) = (b.Append(s) |> ignore) | ||
let addC (s:char) = (b.Append(string s) |> ignore) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure it impacts much the perf but maybe make a conditional for this as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don argued against making it conditional here.
@dsyme @smoothdeveloper Thank you for your comments!
|
@ncave Looks like this is green :) Do you have more work you'd like to do on this, or should we work towards a final review? |
@dsyme The PR can probably use some work to clean it up a bit, but if I recall correctly, you mentioned that there are some large upstream changes incoming, so it may be a good idea to wait until those are merged in and adapt the PR to them before moving forward. |
63c12b9
to
e646aa8
Compare
.vscode/launch.json
Outdated
@@ -0,0 +1,21 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be included in the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take it out. It was just handy to have a debugging environment out of the box, but it does not belong in the PR.
src/absil/illib.fs
Outdated
let (===) x y = LanguagePrimitives.PhysicalEquality x y | ||
|
||
#if !FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be better to use a conditional based on feature like #if FX_NO_GETCURRENTPROCESS
or the like
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like FX_NO_GETCURRENTPROCESS
is not used anywhere else. I've tried to keep the conditionals to a minimum and not introduce new ones unnecessarily. IMO, there are quite a few BCL APIs not supported by Fable, it would become crowded very fast if we introduce a different conditional for each one that is not supported. But if you feel strongly about it, I'll change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally I'd like the F# compiler codebase to not mention Fable at all , but rather be ``#if`'d on a set of characteristics that Fable happens to have. I'm expecting that there will other F#-to-XYZ attempts in the future, e.g. to the JVM, or another F#-to-Javascript compiler (e.g. WebSharper), or F#-to-native.
The more we can use FX_NO_XYZ...
or FSLANG_NO_BYREFS
the more the compiler code will be "neutral" with respect to these different efforts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To give context: we've had this before, e.g. for Silverlight we scattered hundreds of #if SILVERLIGHT
across the codebase. They hung around for years and years even after we stopped cross-compiling - and we had cause to keep some of them because some carried across to .NET Core, some were feature-specific etc. The lesson I learned from that is to always ask people to be specific about why #if
creep in: if there are just 5-10 uses of an `#ifit's ok, but there are about 180 uses of
if FABLE_COMPILER`` - so we should take the time to divide them into the true underlying reasons now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine, if that's your preference I'll try to replace all #if with feature conditionals.
/// An efficient lazy for inline storage in a class type. Results in fewer thunks. | ||
#if FABLE_COMPILER | ||
type InlineDelayInit<'T when 'T : not struct>(f: unit -> 'T) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you use #if FABLE_COMPILER
please add a comment indicating what Fable doesn't support, or use a feature define like #if FSLANG_NO_MUTABLE_STRUCTS
. The latter helps document that the F# language as supported by Fable has some specific semantic differences to F# as supported by .NET.
src/absil/illib.fs
Outdated
|
||
let order = LanguagePrimitives.FastGenericComparer<string> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove whitespace changes where possible
src/absil/illib.fs
Outdated
@@ -808,10 +831,17 @@ type LayeredMap<'Key,'Value when 'Key : comparison> = Map<'Key,'Value> | |||
type Map<'Key,'Value when 'Key : comparison> with | |||
static member Empty : Map<'Key,'Value> = Map.empty | |||
|
|||
#if FABLE_COMPILER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add explanatory comment for the #if
please
Thanks all, see https://github.com/fable-compiler/repl2/issues/48 :) |
e214fbd
to
dcecef2
Compare
@ncave It seems the fsharp/FSharp.Compiler.Service repo is lagging behind Microsoft/visualfsharp. Would it be possible to change your fork to that repo? Does it make any sense at all? |
@alfonsogarciacaro This has been discussed before. Of course we can, and would be nice to not have to wait until latest (and greatest) gets merged downstream, but there is very little chance (if any) for this PR to ever be merged over there. Not that it has much better chances here either (for understandable reasons), so yeah, perhaps we can just open a new one in a |
ddbeea5
to
bef8db3
Compare
Rebased to latest (26.0.1). |
Rebased to latest. |
Rebased to latest (27.0.1). |
c3cd85d
to
fd3a482
Compare
Rebased to latest (28.0.0). |
Closing this PR in favor of this one upstream. |
fcs\build CodeGen.Fable
See also: Fable JS