Uh oh!
There was an error while loading. Please reload this page.
[WIP, RFC FS-1043] Extension members visible to trait constraints - #6286
[WIP, RFC FS-1043] Extension members visible to trait constraints#6286dsyme wants to merge 69 commits into
Conversation
…sualfsharp into extensionconstraints
…o extensionconstraints
…o extensionconstraints
…o extensionconstraints
@alfonsogarciacaro It is critical that we update the TAST (and the FCS API) to include solutions (witnesses) for trait constraints. This has long been a flaw in the TAST and our code generation, leading to horrors where we rediscover the solution during code generation and likewise where we rediscover solutions using reflection in FSHarp.Core. I need to finally address this problem and record solutions to trait constraints in the TAST itself, and possibly pass them as witnesses in the underlying generic code used for reflection calls and quotation evaluation. This is very tricky and awkward as we can't break compat, I need to prototype carefully. Much of the compiler cleanup and documentation I've been doing has been preparing to storm this particular castle, or die doing it. |
realvictorprm
commented
Mar 14, 2019
kevmal
commented
Mar 14, 2019
testfiles\test.fs does not compile: |
dsyme
commented
Mar 14, 2019
kevmal
commented
Mar 15, 2019
@dsyme Not sure what the best way is to help with this one. So I'll just outline what I found here: In ConstraintSolver.fs /// Only consider overload resolution if canonicalizing or all the types are now nominal. /// That is, don't perform resolution if more nominal information may influence the set of available overloads andGetRelevantMethodsForTrait(csenv:ConstraintSolverEnv)permitWeakResolution nm (TTrait(tys,_,memFlags,argtys,rty,soln,extSlns,ad)as traitInfo):MethInfo list =letresults=if permitWeakResolution || MemberConstraintSupportIsReadyForDeterminingOverloads csenv traitInfo thenletm= csenv.m
letminfos=match memFlags.MemberKind with| MemberKind.Constructor ->
tys |> List.map (GetIntrinsicConstructorInfosOfType csenv.SolverState.InfoReader m)|_->
tys |> List.map (GetIntrinsicMethInfosOfType csenv.SolverState.InfoReader (Some nm, AccessibleFromSomeFSharpCode, AllowMultiIntfInstantiations.Yes) IgnoreOverrides m)// Merge the sets so we don't get the same minfo from each side // We merge based on whether minfos use identical metadata or not. letminfos= List.reduce (ListSet.unionFavourLeft MethInfo.MethInfosUseIdenticalDefinitions) minfos
// Get the extension method that may be relevant to solving the constraint as MethInfo objects.// Extension members are not used when canonicalizing prior to generalization (permitWeakResolution=true)letextMInfos=if MemberConstraintSupportIsReadyForDeterminingOverloads csenv traitInfo then GetRelevantExtensionMethodsForTrait csenv.m csenv.amap traitInfo
else[]letextMInfos= extMInfos |> ListSet.setify MethInfo.MethInfosUseIdenticalDefinitions letminfos= minfos @ extMInfos
/// Check that the available members aren't hiding a member from the parent (depth 1 only)letrelevantMinfos= minfos |> List.filter(fun minfo ->not minfo.IsDispatchSlot &¬ minfo.IsVirtual && minfo.IsInstance)
minfos
|> List.filter(fun minfo1 ->not(minfo1.IsDispatchSlot && relevantMinfos
|> List.exists (fun minfo2 -> MethInfosEquivByNameAndSig EraseAll true csenv.g csenv.amap m minfo2 minfo1)))else[]// The trait name "op_Explicit" also covers "op_Implicit", so look for that one too.if nm ="op_Explicit"then results @ GetRelevantMethodsForTrait csenv permitWeakResolution "op_Implicit"(TTrait(tys,"op_Implicit", memFlags, argtys, rty, soln, extSlns, ad))else
results With this change the testfile now has three errors: |
kevmal
commented
Mar 15, 2019
The three remaining errors can be reproduced by typeMyType=| MyType ofint/// Locally extending an F# type with a wide range of standard operatorsmoduleFSharpTypeWithExtrinsicOperators =[<AutoOpen>]moduleExtensions =typeMyTypewithstatic member(|||)(MyType (x :int),MyType (y :int))= MyType (x ||| y)static member(&&&)(MyType x,MyType y)= MyType (x &&& y)static member(^^^)(MyType x,MyType y)= MyType (x ^^^ y)Here, Going back to the test file this leaves one last error on Where With a type annotation ( |
kevmal
commented
Mar 15, 2019
Using openSystem.Runtime.CompilerServices[<Extension>]typeExt2()=[<Extension>]static member inline(!@)(a :string)= a.Length
!@"324234"
|
dsyme
commented
Mar 15, 2019
@kevmal Super work, thanks. Could you submit the first change as a PR to my branch? Thanks |
append extension methods in GetRelevantMethodsForTrait
kevmal
commented
Mar 20, 2019
openSystem.Runtime.CompilerServices[<Extension>]typeExt2()=[<Extension>]static memberBleh(a :string)= a.Length
let inlinebleh s =(^a:(memberBleh: unit -> int) s)works. The last operator example, as the error states, is an instance member and shouldn't work. Currently I think that's okay because typeSystem.Int32withstatic member(!@)(a:string)= a.Length
!@"32423"also works. My only concern is it would make sense to restrict the above (you must extend string with string operators). But it's important to me to be able to do something like (not exactly this, just staying on the same theme) typeSystem.Int32withstatic member inline(!@)(a)=(^a:(memberLength: int) a)where, in similar cases, I'd usually have to use the With that said there seems to be an issue: typeSystem.Int32withstatic member inline(+)(a,b)= Array.map2 (+) a b
[|1;2;3|]+[|2;3;4|]//Okay[|TimeSpan.Zero|]+[|TimeSpan.Zero|]//Okay[|1m|]+[|2m|]//Okay[|1uy|]+[|2uy|]//Okay[|1L|]+[|2L|]//Okay[|1I|]+[|2I|]//Okay[|[|1;1|];[|2|]|]+[|[|2;2|];[|3|]|]//Okay[|"1"|]+[|"2"|]//error FS0001[|1.f|]+[|2.f|]//error FS0001[|1.0|]+[|2.0|]//error FS0001Where the errors (for float/single/string) are: |
dsyme
commented
Mar 22, 2019
Yes, I remember reverting this during integration, thanks, I will fix it now |
dsyme
commented
Mar 22, 2019
Re this: I think this should be an error. |
dsyme
commented
Mar 22, 2019
@kevmal Thanks for your help! I've pushed the required fixes to the branch and If you'd like to contribute a bit of code, then moving |
kevmal
commented
Mar 22, 2019
@dsyme With that change (wildcard match on minfos) all solution tests passed. I think the overall issue relates to the last TODO you listed. So in the context of the previous issue I brought up... With integertypes we hit this branch Since the check minfos passes for integer types it's fine but for double/float/string the invalid method (array extension op) causes this branch to skip and error on the available method. In the case of Though with that said I'm not sure why the above would not be |
kevmal
commented
Mar 27, 2019
With
It compiles to |
dsyme
commented
May 22, 2019
Closed in favour of #6805 |
RFC https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1043-extension-members-for-operators-and-srtp-constraints.md
This is work by @TobyShaw and myself to implement RFC FS-1043. This PR brings #3582 up-to-date with master
TODO items from the code
extSlns // TODO: do we need to remap here???extSlns starts empty. TODO: check the ramifications of this when inlining solved trait calls from other assemblies// TODO: consider what happens when the expression refers to extSlns that have become hiddenNonefor TraitFreshener, e.g. https://github.com/Microsoft/visualfsharp/pull/3582/files#diff-5b9ab9dd9d7133aaf23add1048742031R576// TODO: check the use of 'allPairs' - not all these extensions apply to each type variable.Things to test
Things from previous PR