Skip to content

WIP RFC FS-1092: Anonymous Type-tagged Union types - #10896

Closed
dsyme wants to merge 48 commits into
feature/auto-widenfrom
feature/erased-unions
Closed

WIP RFC FS-1092: Anonymous Type-tagged Union types#10896
dsyme wants to merge 48 commits into
feature/auto-widenfrom
feature/erased-unions

Conversation

@dsyme

@dsymedsyme commented Jan 19, 2021

Copy link
Copy Markdown
Contributor

@dsymedsyme changed the title WIP RFC FS-1092: Prototyping Erased Union typesWIP RFC FS-1092: Erased Union typesJan 19, 2021
@dsyme
dsyme changed the base branch from main to feature/auto-widenJanuary 19, 2021 14:29
@dsyme

Copy link
Copy Markdown
ContributorAuthor

I set up auto-flow from feature/auto-widen to this branch here: https://github.com/dotnet/roslyn-tools/blob/master/src/GitHubCreateMergePRs/config.xml

@Happypig375

Copy link
Copy Markdown
Member

Can we get the "Candidate for F# vNext" here?

@cartermp

Copy link
Copy Markdown
Contributor

The base of this is still an experiment (for example: it's a draft) and nowhere near the quality of other vNext-style PRs. Once design quirks are worked out I think we can proceed with labeling it as such. I expect quite a bit of churn in both places until we get at something that's considered reviewable.

@dsymedsyme changed the title WIP RFC FS-1092: Erased Union typesWIP RFC FS-1092: Anonymous Type-tagged Union typesJan 27, 2021
@dsyme

Copy link
Copy Markdown
ContributorAuthor

@Swoorup I updated this by merging in the base branch

@dsyme
dsyme marked this pull request as draft January 27, 2021 15:18
Don Symeand others added 3 commits January 28, 2021 18:08
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
KevinRansomand others added 8 commits July 13, 2021 11:54
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
…ature/erased-unions
Merge feature/auto-widen to feature/erased-unions
@chkn

chkn commented Aug 4, 2021

Copy link
Copy Markdown
Contributor

Looks like there is an issue when a function type is used as one of the union types:

>typeIntOrFn=(int | unit -> int);;typeIntOrFn=(int |(unit -> int))>letfoo:IntOrFn =5;;valfoo:IntOrFn =5>letfoo:IntOrFn =fun()->5;;letfoo:IntOrFn =fun()->5;;-------------------^^^^^^^^^^^
stdin(6,20): error FS0002: This function takes too many arguments,or is used in a context where a function is not expected

@chkn

chkn commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

Also, flexible types seem to work for let bound functions (which is great), but not for static methods:

>typeIntOrStr=(int | string);;typeIntOrStr=(int | string)>letmer(fn :unit -> #IntOrStr)= fn();;valmer:fn:(unit -> 'a) ->'a when 'a :>IntOrStr>typeFoof=static memberBoom(fn :unit -> #IntOrStr)= fn();;
Process terminated. Assertion failed.
Unexpected exception raised in compiler: buildGenParam: multiple base types
System.Exception: buildGenParam: multiple base types
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildGenParamsPass1b@1405.Invoke(Int32 i, ILGenericParameterDef gp)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1414
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildGenParamsPass1b(cenv cenv, emEnv emEnv, Type[] genArgs, FSharpList`1 gps)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1405
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildMethodPass2(cenv cenv, ILTypeRef tref, TypeBuilder typB, emEnv emEnv, ILMethodDef mdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1544
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.emEnv@1819-2.Invoke(emEnv emEnv, ILMethodDef mdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1819
at Microsoft.FSharp.Collections.ArrayModule.Fold[T,TState](FSharpFunc`2 folder, TState state, T[] array)in/fsharp/src/fsharp/FSharp.Core/array.fs:line 901
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildTypeDefPass2(cenv cenv, FSharpList`1 nesting, emEnv emEnv, ILTypeDef tdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1819
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.emEnv@1825-5.Invoke(emEnv emEnv, ILTypeDef tdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1825
at Microsoft.FSharp.Collections.ListModule.Fold[T,TState](FSharpFunc`2 folder, TState state, FSharpList`1 list)in/fsharp/src/fsharp/FSharp.Core/list.fs:line 221
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildTypeDefPass2(cenv cenv, FSharpList`1 nesting, emEnv emEnv, ILTypeDef tdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 1825
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildModuleTypePass2(cenv cenv, emEnv emEnv, ILTypeDef tdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 2019
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.emEnv@2032-9.Invoke(emEnv emEnv, ILTypeDef tdef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 2032
at Microsoft.FSharp.Collections.ListModule.Fold[T,TState](FSharpFunc`2 folder, TState state, FSharpList`1 list)in/fsharp/src/fsharp/FSharp.Core/list.fs:line 221
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.buildModuleFragment(cenv cenv, emEnv emEnv, AssemblyBuilder asmB, ModuleBuilder modB, ILModuleDef m)in/fsharp/src/fsharp/absil/ilreflect.fs:line 2032
at FSharp.Compiler.AbstractIL.ILRuntimeWriter.emitModuleFragment(ILGlobals ilg, Boolean emitTailcalls, emEnv emEnv, AssemblyBuilder asmB, ModuleBuilder modB, ILModuleDef modul, Boolean debugInfo, FSharpFunc`2 resolveAssemblyRef, FSharpFunc`2 tryFindSysILTypeRef)in/fsharp/src/fsharp/absil/ilreflect.fs:line 2103
at FSharp.Compiler.Interactive.Shell.FsiDynamicCompiler.ProcessCodegenResults(CompilationThreadToken ctok, ErrorLogger errorLogger, FsiDynamicCompilerState istate, IncrementalOptimizationEnv optEnv, TcState tcState, TcConfig tcConfig, FSharpList`1 prefixPath, Boolean showTypes, Boolean isIncrementalFragment, String fragName, FSharpList`1 declaredImpls, IlxAssemblyGenerator ilxGenerator, IlxGenResults codegenResults)in/fsharp/src/fsharp/fsi/fsi.fs:line 1159
at FSharp.Compiler.Interactive.Shell.FsiDynamicCompiler.ProcessInputs(CompilationThreadToken ctok, ErrorLogger errorLogger, FsiDynamicCompilerState istate, FSharpList`1 inputs, Boolean showTypes, Boolean isIncrementalFragment, Boolean isInteractiveItExpr, FSharpList`1 prefixPath)in/fsharp/src/fsharp/fsi/fsi.fs:line 1257
at FSharp.Compiler.Interactive.Shell.FsiDynamicCompiler.EvalParsedDefinitions(CompilationThreadToken ctok, ErrorLogger errorLogger, FsiDynamicCompilerState istate, Boolean showTypes, Boolean isInteractiveItExpr, FSharpList`1 defs)in/fsharp/src/fsharp/fsi/fsi.fs:line 1390
at FSharp.Compiler.Interactive.Shell.clo@2212-597.Invoke(FsiDynamicCompilerState istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2224
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.InteractiveCatch[a](ErrorLogger errorLogger, FSharpFunc`2 f, a istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2122
at FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ErrorLogger.EmitDiagnostic(ErrorLogger x, Exception exn, FSharpDiagnosticSeverity severity)in/fsharp/src/fsharp/ErrorLogger.fs:line 372
at FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ErrorLogger.ErrorRecovery(ErrorLogger x, Exception exn, Range m)in/fsharp/src/fsharp/ErrorLogger.fs:line 408
at FSharp.Compiler.ErrorLogger.ErrorLoggerExtensions.ErrorLogger.StopProcessingRecovery(ErrorLogger x, Exception exn, Range m)in/fsharp/src/fsharp/ErrorLogger.fs:line 422
at FSharp.Compiler.ErrorLogger.stopProcessingRecovery(Exception exn, Range m)in/fsharp/src/fsharp/ErrorLogger.fs:line 482
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.InteractiveCatch[a](ErrorLogger errorLogger, FSharpFunc`2 f, a istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2122
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.ExecInteraction(CompilationThreadToken ctok, TcConfig tcConfig, FsiDynamicCompilerState istate, ParsedScriptInteraction action, ErrorLogger errorLogger)in/fsharp/src/fsharp/fsi/fsi.fs:line 2212
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.execParsedInteractions(CompilationThreadToken ctok, TcConfig tcConfig, FsiDynamicCompilerState istate, FSharpOption`1 action, ErrorLogger errorLogger, FSharpOption`1 lastResult, CancellationToken cancellationToken)in/fsharp/src/fsharp/fsi/fsi.fs:line 2357
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.executeParsedInteractions(CompilationThreadToken ctok, TcConfig tcConfig, FsiDynamicCompilerState istate, FSharpOption`1 action, ErrorLogger errorLogger, FSharpOption`1 lastResult, CancellationToken cancellationToken)in/fsharp/src/fsharp/fsi/fsi.fs:line 2368
at FSharp.Compiler.Interactive.Shell.clo@2398-599.Invoke(CompilationThreadToken ctok, TcConfig tcConfig, FsiDynamicCompilerState istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2399
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.mainThreadProcessAction[a,b](a ctok, FSharpFunc`2 action, b istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2381
at FSharp.Compiler.Interactive.Shell.FsiInteractionProcessor.mainThreadProcessParsedInteractions(CompilationThreadToken ctok, ErrorLogger errorLogger, FSharpOption`1 action, FsiDynamicCompilerState istate, CancellationToken cancellationToken)in/fsharp/src/fsharp/fsi/fsi.fs:line 2398
at FSharp.Compiler.Interactive.Shell.res@2458-60.Invoke(CompilationThreadToken ctok, FsiDynamicCompilerState istate)in/fsharp/src/fsharp/fsi/fsi.fs:line 2458
at FSharp.Compiler.Interactive.Shell.clo@2102-596.Invoke(Unit unitVar0)in/fsharp/src/fsharp/fsi/fsi.fs:line 2111
at <StartupCode$FSharp-Compiler-Interactive-Settings>.$Fsiaux.FSharp-Compiler-Interactive-IEventLoop-Invoke@50-1.Invoke(Unit x)in/fsharp/src/fsharp/fsiaux.fs:line 50
at <StartupCode$FSharp-Compiler-Interactive-Settings>.$Fsiaux.run@41-4.Invoke(FSharpFunc`2 f)in/fsharp/src/fsharp/fsiaux.fs:line 41
at <StartupCode$FSharp-Compiler-Interactive-Settings>.$Fsiaux.run@39.Invoke(Unit unitVar0)in/fsharp/src/fsharp/fsiaux.fs:line 41
at FSharp.Compiler.Interactive.SimpleEventLoop.FSharp.Compiler.Interactive.IEventLoop.Run()in/fsharp/src/fsharp/fsiaux.fs:line 48
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at FSharp.Compiler.Interactive.Shell.Utilities.callInstanceMethod0[a](Object obj, Type[] typeArgs, String nm)in/fsharp/src/fsharp/fsi/fsi.fs:line 131
at Sample.FSharp.Compiler.Interactive.Main.evaluateSession@228-4.EventLoopRun()in/fsharp/src/fsharp/fsi/fsimain.fs:line 246
at FSharp.Compiler.Interactive.Shell.runLoop@2707.Invoke(Unit unitVar0)in/fsharp/src/fsharp/fsi/fsi.fs:line 2712
at FSharp.Compiler.Interactive.Shell.DriveFsiEventLoop(FsiEvaluationSessionHostConfig fsi, FsiConsoleOutput fsiConsoleOutput)in/fsharp/src/fsharp/fsi/fsi.fs:line 2728
at FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.Run()in/fsharp/src/fsharp/fsi/fsi.fs:line 3182
at Sample.FSharp.Compiler.Interactive.Main.evaluateSession(String[] argv)in/fsharp/src/fsharp/fsi/fsimain.fs:line 298
at Sample.FSharp.Compiler.Interactive.Main.MainMain(String[] argv)in/fsharp/src/fsharp/fsi/fsimain.fs:line 342
Abort trap:6

@Swoorup

Copy link
Copy Markdown
Contributor

I doubt flexible type should be used that way. I can't see it making sense, at least not right now, as generics wouldn't be supported in this feature.

@chkn

chkn commented Aug 5, 2021

Copy link
Copy Markdown
Contributor

@Swoorup this is the problem I'm trying to solve:

>typeIntOrStr=(int | string);;typeIntOrStr=(int | string)>letfn=fun()->5;;valfn:unit ->int>// with flexible types -letfoo(fn :unit -> #IntOrStr)= fn();;valfoo:fn:(unit -> 'a) ->'a when 'a :>IntOrStr> foo fn;;valit:int =5>// without flexible types -letbar(fn :unit ->IntOrStr)= fn();;valbar:fn:(unit -> IntOrStr) ->IntOrStr> bar fn;;
bar fn;;----^^
stdin(6,5): error FS0001: Type mismatch. Expecting a
'unit -> IntOrStr' but given a
'unit -> int' The type'IntOrStr'doesnotmatchthetype'int'

@Swoorup

Swoorup commented Aug 9, 2021

Copy link
Copy Markdown
Contributor

@chkn It looks more like a problem for auto-widening (as future improvements). Ideally you shouldn't need flexible type for this case.

if not (ResizeArray.exists (isObjTy g) list) then
if isObjTy g pt then
list.Clear()
list.Add(pt)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This creates a compatibility consideration for libraries that publish erased union types. It might not be a concern, but I think it's important to be aware of:

Library1

typeFoo= obj

Library2 (references Library1)

typeBar=(* ... *)typeProblematic=(Foo | Bar)// where `Foo` is from Library1

Due to this conditional, the Bar part of Problematic will be discarded, keeping only obj aliased through Foo. But if Library1 is later updated to change the type of Foo, any code compiled against the updated Library1 and old Library2 will find that the Problematic type no longer accepts Bars.

@SwoorupSwoorupAug 12, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Wouldn't that be same issue as the following:

Library1

typeFoo= int

Library2 (references Library1)

lethandle(foo:Foo)= foo +1

Later Library1 is updated to so that Foo is aliased to String? handle doesn't handle string. I don't know enough about how .net handles transitive dependencies in depth.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah you'd definitely expect that sort of breakage with the Foo type. But I wouldn't expect that using Problematic with Bar would also be broken in that case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

But you would just recompile the code no in that case?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sure, if you could. But it might be a dependency you don't have the source for

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't see, how this is different to other issues that arise out of dependency version mismatch. You'd only have the issue if you publish a package using a version and then republish it using the same version, causing the breakage.

@En3Tho

Copy link
Copy Markdown
Contributor

@Swoorup@chkn Do you guys need help with this?

@Swoorup

Swoorup commented Aug 24, 2021

Copy link
Copy Markdown
Contributor

@Swoorup@chkn Do you guys need help with this?

Pattern matching, (giving out warnings when matches are incomplete or overmatching) is an area that needs to be looked after. At the moment, it is just based on :? pattern match which doesn't do much. There are other tickets which are addressing areas of pattern matching, so probably best holding for now.

@dsyme
dsyme deleted the branch feature/auto-widenOctober 8, 2021 14:14
@dsymedsyme closed this Oct 8, 2021
@brettfo
brettfo deleted the feature/erased-unions branch October 15, 2021 21:01
@Swoorup

Copy link
Copy Markdown
Contributor

Any reasons for this being closed? @dsyme

@dsyme

Copy link
Copy Markdown
ContributorAuthor

Hmm looks like it got auto-closed when the branch it was targeting got deleted. I'll retarget to main

@dsyme

Copy link
Copy Markdown
ContributorAuthor

Actually looks like feature/erased-unions got deleted by mistake

@dsyme
dsyme restored the feature/erased-unions branch October 18, 2021 12:40
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants

@dsyme@Happypig375@cartermp@chkn@Swoorup@En3Tho@KevinRansom@brettfo@vzarytovskii