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
14 changes: 7 additions & 7 deletions src/absil/illib.fs
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,16 @@ module List =

[<Struct>]
type ValueOption<'T> =
| VSome of 'T
| VNone
member x.IsSome = match x with VSome _ -> true | VNone -> false
member x.IsNone = match x with VSome _ -> false | VNone -> true
member x.Value = match x with VSome r -> r | VNone -> failwith "ValueOption.Value: value is None"
| ValueSome of 'T
| ValueNone
member x.IsSome = match x with ValueSome _ -> true | ValueNone -> false
member x.IsNone = match x with ValueSome _ -> false | ValueNone -> true
member x.Value = match x with ValueSome r -> r | ValueNone -> failwith "ValueOption.Value: value is None"

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ValueOption =
let inline ofOption x = match x with Some x -> VSome x | None -> VNone
let inline bind f x = match x with VSome x -> f x | VNone -> VNone
let inline ofOption x = match x with Some x -> ValueSome x | None -> ValueNone
let inline bind f x = match x with ValueSome x -> f x | ValueNone -> ValueNone

module String =
let indexNotFound() = raise (new KeyNotFoundException("An index for the character was not found in the string"))
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/AttributeChecking.fs
Original file line number Diff line number Diff line change
Expand Up @@ -511,15 +511,15 @@ let IsSecurityAttribute (g: TcGlobals) amap (casmap : Dictionary<Stamp, bool>) (
| None -> false
| Some attr ->
match attr.TyconRef.TryDeref with
| VSome _ ->
| ValueSome _ ->
let tcs = tcref.Stamp
match casmap.TryGetValue(tcs) with
| true, c -> c
| _ ->
let exists = ExistsInEntireHierarchyOfType (fun t -> typeEquiv g t (mkAppTy attr.TyconRef [])) g amap m AllowMultiIntfInstantiations.Yes (mkAppTy tcref [])
casmap.[tcs] <- exists
exists
| VNone -> false
| ValueNone -> false

let IsSecurityCriticalAttribute g (Attrib(tcref, _, _, _, _, _, _)) =
(tyconRefEq g tcref g.attrib_SecurityCriticalAttribute.TyconRef || tyconRefEq g tcref g.attrib_SecuritySafeCriticalAttribute.TyconRef)
Expand Down
16 changes: 13 additions & 3 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2972,14 +2972,24 @@ namespace Microsoft.FSharp.Core

and 'T option = Option<'T>


[<StructuralEquality; StructuralComparison>]
[<CompiledName("FSharpResult`2")>]
[<Struct>]
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError

[<StructuralEquality; StructuralComparison>]
[<Struct>]
[<CompiledName("FSharpValueOption`1")>]
type ValueOption<'T> =
| ValueNone : 'T voption
| ValueSome : 'T -> 'T voption

member x.Value = match x with ValueSome x -> x | ValueNone -> raise (new System.InvalidOperationException("ValueOption.Value"))


and 'T voption = ValueOption<'T>

namespace Microsoft.FSharp.Collections

Expand Down Expand Up @@ -3345,11 +3355,11 @@ namespace Microsoft.FSharp.Core

let (^) (s1: string) (s2: string) = System.String.Concat(s1, s2)


[<CompiledName("DefaultArg")>]
[<CodeAnalysis.SuppressMessage("Microsoft.Naming","CA1704:IdentifiersShouldBeSpelledCorrectly")>]
let defaultArg arg defaultValue = match arg with None -> defaultValue | Some v -> v

[<CompiledName("DefaultValueArg")>]
let defaultValueArg arg defaultValue = match arg with ValueNone -> defaultValue | ValueSome v -> v

[<NoDynamicInvocation>]
let inline (~-) (n: ^T) : ^T =
Expand Down
34 changes: 34 additions & 0 deletions src/fsharp/FSharp.Core/prim-types.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,33 @@ namespace Microsoft.FSharp.Core
/// due to the use of <c>null</c> as a value representation.</remarks>
and 'T option = Option<'T>

/// <summary>The type of optional values, represented as structs.</summary>
///
/// <remarks>Use the constructors <c>ValueSome</c> and <c>ValueNone</c> to create values of this type.
/// Use the values in the <c>ValueOption</c> module to manipulate values of this type,
/// or pattern match against the values directly.
[<StructuralEquality; StructuralComparison>]
[<CompiledName("FSharpValueOption`1")>]
[<Struct>]
type ValueOption<'T> =
/// <summary>The representation of "No value"</summary>
| ValueNone: 'T voption

/// <summary>The representation of "Value of type 'T"</summary>
/// <param name="Value">The input value.</param>
/// <returns>An option representing the value.</returns>
| ValueSome: 'T -> 'T voption

/// <summary>Get the value of a 'ValueSome' option. An InvalidOperationException is raised if the option is 'ValueNone'.</summary>
member Value : 'T

/// <summary>The type of optional values, represented as structs.</summary>
///
/// <remarks>Use the constructors <c>ValueSome</c> and <c>ValueNone</c> to create values of this type.
/// Use the values in the <c>ValueOption</c> module to manipulate values of this type,
/// or pattern match against the values directly.
and 'T voption = ValueOption<'T>

/// <summary>Helper type for error handling without exceptions.</summary>
[<StructuralEquality; StructuralComparison>]
[<CompiledName("FSharpResult`2")>]
Expand Down Expand Up @@ -1998,6 +2025,13 @@ namespace Microsoft.FSharp.Core
[<CompiledName("DefaultArg")>]
val defaultArg : arg:'T option -> defaultValue:'T -> 'T

/// <summary>Used to specify a default value for an optional argument in the implementation of a function</summary>
/// <param name="arg">A value option representing the argument.</param>
/// <param name="defaultValue">The default value of the argument.</param>
/// <returns>The argument value. If it is None, the defaultValue is returned.</returns>
[<CompiledName("DefaultValueArg")>]
val defaultValueArg : arg:'T voption -> defaultValue:'T -> 'T

/// <summary>Concatenate two strings. The operator '+' may also be used.</summary>
[<CompilerMessage("This construct is for ML compatibility. Consider using the '+' operator instead. This may require a type annotation to indicate it acts on strings. This message can be disabled using '--nowarn:62' or '#nowarn \"62\"'.", 62, IsHidden=true)>]
val (^): s1:string -> s2:string -> string
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -714,11 +714,11 @@ let AddStorageForVal (g: TcGlobals) (v,s) eenv =
| None -> eenv
| Some vref ->
match vref.TryDeref with
| VNone ->
| ValueNone ->
//let msg = sprintf "could not dereference external value reference to something in FSharp.Core.dll during code generation, v.MangledName = '%s', v.Range = %s" v.MangledName (stringOfRange v.Range)
//System.Diagnostics.Debug.Assert(false, msg)
eenv
| VSome gv ->
| ValueSome gv ->
{ eenv with valsInScope = eenv.valsInScope.Add gv s }
else
eenv
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ type Item =

let valRefHash (vref: ValRef) =
match vref.TryDeref with
| VNone -> 0
| VSome v -> LanguagePrimitives.PhysicalHash v
| ValueNone -> 0
| ValueSome v -> LanguagePrimitives.PhysicalHash v

[<RequireQualifiedAccess>]
/// Pairs an Item with a TyparInst showing how generic type variables of the item are instantiated at
Expand Down
8 changes: 4 additions & 4 deletions src/fsharp/TastOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6324,9 +6324,9 @@ let mkCallLiftValueWithName (g:TcGlobals) m ty nm e1 =
let vref = ValRefForIntrinsic g.lift_value_with_name_info
// Use "Expr.ValueWithName" if it exists in FSharp.Core
match vref.TryDeref with
| VSome _ ->
| ValueSome _ ->
mkApps g (typedExprForIntrinsic g m g.lift_value_with_name_info , [[ty]], [mkRefTupledNoTypes g m [e1; mkString g m nm]], m)
| VNone ->
| ValueNone ->
mkApps g (typedExprForIntrinsic g m g.lift_value_info , [[ty]], [e1], m)

let mkCallLiftValueWithDefn g m qty e1 =
Expand All @@ -6335,11 +6335,11 @@ let mkCallLiftValueWithDefn g m qty e1 =
let vref = ValRefForIntrinsic g.lift_value_with_defn_info
// Use "Expr.WithValue" if it exists in FSharp.Core
match vref.TryDeref with
| VSome _ ->
| ValueSome _ ->
let copyOfExpr = copyExpr g ValCopyFlag.CloneAll e1
let quoteOfCopyOfExpr = Expr.Quote(copyOfExpr, ref None, false, m, qty)
mkApps g (typedExprForIntrinsic g m g.lift_value_with_defn_info , [[ty]], [mkRefTupledNoTypes g m [e1; quoteOfCopyOfExpr]], m)
| VNone ->
| ValueNone ->
Expr.Quote(e1, ref None, false, m, qty)

let mkCallCheckThis g m ty e1 =
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/TypeChecker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16879,8 +16879,8 @@ let ApplyAssemblyLevelAutoOpenAttributeToTcEnv g amap (ccu: CcuThunk) scopem env
let h, t = List.frontAndBack p
let modref = mkNonLocalTyconRef (mkNonLocalEntityRef ccu (Array.ofList h)) t
match modref.TryDeref with
| VNone -> warn()
| VSome _ ->
| ValueNone -> warn()
| ValueSome _ ->
let openDecl = OpenDeclaration.Create ([], [modref], scopem, false)
OpenModulesOrNamespaces TcResultsSink.NoSink g amap scopem root env [modref] openDecl

Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,7 @@ type MethInfo =
| ILMeth(_,ilmeth,_) -> ilmeth.IsClassConstructor
| FSMeth(_,_,vref,_) ->
match vref.TryDeref with
| VSome x -> x.IsClassConstructor
| ValueSome x -> x.IsClassConstructor
| _ -> false
| DefaultStructCtor _ -> false
#if !NO_EXTENSIONTYPING
Expand Down
54 changes: 27 additions & 27 deletions src/fsharp/tast.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2882,15 +2882,15 @@ and NonLocalEntityRef =

/// Try to find the entity corresponding to the given path in the given CCU
static member TryDerefEntityPath(ccu: CcuThunk, path:string[], i:int, entity:Entity) =
if i >= path.Length then VSome entity
if i >= path.Length then ValueSome entity
else
let next = entity.ModuleOrNamespaceType.AllEntitiesByCompiledAndLogicalMangledNames.TryFind(path.[i])
match next with
| Some res -> NonLocalEntityRef.TryDerefEntityPath(ccu, path, (i+1), res)
#if !NO_EXTENSIONTYPING
| None -> NonLocalEntityRef.TryDerefEntityPathViaProvidedType(ccu, path, i, entity)
#else
| None -> VNone
| None -> ValueNone
#endif

#if !NO_EXTENSIONTYPING
Expand All @@ -2908,11 +2908,11 @@ and NonLocalEntityRef =
// types until i = path.Length-1. Create the Tycon's as needed
let rec tryResolveNestedTypeOf(parentEntity:Entity,resolutionEnvironment,st:Tainted<ProvidedType>,i) =
match st.PApply((fun st -> st.GetNestedType path.[i]),m) with
| Tainted.Null -> VNone
| Tainted.Null -> ValueNone
| st ->
let newEntity = Construct.NewProvidedTycon(resolutionEnvironment, st, ccu.ImportProvidedType, false, m)
parentEntity.ModuleOrNamespaceType.AddProvidedTypeEntity(newEntity)
if i = path.Length-1 then VSome(newEntity)
if i = path.Length-1 then ValueSome(newEntity)
else tryResolveNestedTypeOf(newEntity,resolutionEnvironment,st,i+1)

tryResolveNestedTypeOf(entity,resolutionEnvironment,st,i)
Expand Down Expand Up @@ -2970,18 +2970,18 @@ and NonLocalEntityRef =
// newEntity is at 'j'
NonLocalEntityRef.TryDerefEntityPath(ccu, path, (j+1), newEntity)

| [] -> VNone
| [] -> ValueNone
| _ -> failwith "Unexpected"

let rec tryResolvePrefixes j =
if j >= path.Length then VNone
if j >= path.Length then ValueNone
else match tryResolvePrefix j with
| VNone -> tryResolvePrefixes (j+1)
| VSome res -> VSome res
| ValueNone -> tryResolvePrefixes (j+1)
| ValueSome res -> ValueSome res

tryResolvePrefixes i

| _ -> VNone
| _ -> ValueNone
#endif

/// Try to link a non-local entity reference to an actual entity
Expand All @@ -2990,11 +2990,11 @@ and NonLocalEntityRef =
if canError then
ccu.EnsureDerefable(path)

if ccu.IsUnresolvedReference then VNone else
if ccu.IsUnresolvedReference then ValueNone else

match NonLocalEntityRef.TryDerefEntityPath(ccu, path, 0, ccu.Contents) with
| VSome _ as r -> r
| VNone ->
| ValueSome _ as r -> r
| ValueNone ->
// OK, the lookup failed. Check if we can redirect through a type forwarder on this assembly.
// Look for a forwarder for each prefix-path
let rec tryForwardPrefixPath i =
Expand All @@ -3004,7 +3004,7 @@ and NonLocalEntityRef =
| Some tcref -> NonLocalEntityRef.TryDerefEntityPath(ccu, path, (i+1), tcref.Deref)
| None -> tryForwardPrefixPath (i+1)
else
VNone
ValueNone
tryForwardPrefixPath 0

/// Get the CCU referenced by the nonlocal reference.
Expand Down Expand Up @@ -3036,8 +3036,8 @@ and NonLocalEntityRef =
/// Dereference the nonlocal reference, and raise an error if this fails.
member nleref.Deref =
match nleref.TryDeref(canError=true) with
| VSome res -> res
| VNone ->
| ValueSome res -> res
| ValueNone ->
errorR (InternalUndefinedItemRef (FSComp.SR.tastUndefinedItemRefModuleNamespace, nleref.DisplayName, nleref.AssemblyName, "<some module on this path>"))
raise (KeyNotFoundException())

Expand Down Expand Up @@ -3067,9 +3067,9 @@ and
member private tcr.Resolve(canError) =
let res = tcr.nlr.TryDeref(canError)
match res with
| VSome r ->
| ValueSome r ->
tcr.binding <- nullableSlotFull r
| VNone ->
| ValueNone ->
()

/// Dereference the TyconRef to a Tycon. Amortize the cost of doing this.
Expand All @@ -3090,11 +3090,11 @@ and
| null ->
tcr.Resolve(canError=false)
match box tcr.binding with
| null -> VNone
| _ -> VSome tcr.binding
| null -> ValueNone
| _ -> ValueSome tcr.binding

| _ ->
VSome tcr.binding
ValueSome tcr.binding

/// Is the destination assembly available?
member tcr.CanDeref = tcr.TryDeref.IsSome
Expand Down Expand Up @@ -3417,8 +3417,8 @@ and
let e = nlr.EnclosingEntity.Deref
let possible = e.ModuleOrNamespaceType.TryLinkVal(nlr.EnclosingEntity.nlr.Ccu, nlr.ItemKey)
match possible with
| VNone -> error (InternalUndefinedItemRef (FSComp.SR.tastUndefinedItemRefVal, e.DisplayNameWithStaticParameters, nlr.AssemblyName, sprintf "%+A" nlr.ItemKey.PartialKey))
| VSome h -> h
| ValueNone -> error (InternalUndefinedItemRef (FSComp.SR.tastUndefinedItemRefVal, e.DisplayNameWithStaticParameters, nlr.AssemblyName, sprintf "%+A" nlr.ItemKey.PartialKey))
| ValueSome h -> h
vr.binding <- nullableSlotFull res
res
else vr.binding
Expand All @@ -3428,14 +3428,14 @@ and
if obj.ReferenceEquals(vr.binding, null) then
let resOpt =
match vr.nlr.EnclosingEntity.TryDeref with
| VNone -> VNone
| VSome e -> e.ModuleOrNamespaceType.TryLinkVal(vr.nlr.EnclosingEntity.nlr.Ccu, vr.nlr.ItemKey)
| ValueNone -> ValueNone
| ValueSome e -> e.ModuleOrNamespaceType.TryLinkVal(vr.nlr.EnclosingEntity.nlr.Ccu, vr.nlr.ItemKey)
match resOpt with
| VNone -> ()
| VSome res ->
| ValueNone -> ()
| ValueSome res ->
vr.binding <- nullableSlotFull res
resOpt
else VSome vr.binding
else ValueSome vr.binding

/// The type of the value. May be a TType_forall for a generic value.
/// May be a type variable or type containing type variables during type inference.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,37 @@ type OptionModule() =
member this.MapBindEquivalenceProperties () =
let fn x = x + 3
Assert.AreEqual(Option.map fn None, Option.bind (fn >> Some) None)
Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5))
Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5))

[<TestFixture>]
type ValueOptionTests() =

let assertWasNotCalledThunk () = raise (exn "Thunk should not have been called.")

[<Test>]
member this.ValueOptionBasics () =
Assert.AreEqual( (ValueNone: int voption), (ValueNone: int voption))
Assert.True( (ValueNone: int voption) <= (ValueNone: int voption))
Assert.True( (ValueNone: int voption) >= (ValueNone: int voption))
Assert.True( (ValueNone: int voption) < (ValueSome 1: int voption))
Assert.True( (ValueSome 0: int voption) < (ValueSome 1: int voption))
Assert.True( (ValueSome 1: int voption) > (ValueSome 0: int voption))
Assert.False( (ValueSome 1: int voption) < (ValueNone : int voption))
Assert.True( (ValueSome 1: int voption) <= (ValueSome 1: int voption))
Assert.AreEqual( compare (ValueSome 1) (ValueSome 1), 0)
Assert.True( compare (ValueSome 0) (ValueSome 1) < 0)
Assert.True( compare (ValueNone: int voption) (ValueSome 1) < 0)
Assert.True( compare (ValueSome 1) (ValueNone : int voption) > 0)
Assert.AreEqual( ValueSome 1, ValueSome 1)
Assert.AreNotEqual( ValueSome 2, ValueSome 1)
Assert.AreEqual( ValueSome 2, ValueSome 2)
Assert.AreEqual( ValueSome (ValueSome 2), ValueSome (ValueSome 2))
Assert.AreNotEqual( ValueSome (ValueSome 2), ValueSome (ValueSome 1))
Assert.AreNotEqual( ValueSome (ValueSome 0), ValueSome ValueNone)
Assert.AreEqual( ValueSome (ValueNone: int voption), ValueSome (ValueNone: int voption))
Assert.AreEqual( (ValueSome (ValueNone: int voption)).Value, (ValueNone: int voption))
Assert.AreEqual( (ValueSome 1).Value, 1)
Assert.AreEqual( (ValueSome (1,2)).Value, (1,2))
Assert.AreEqual(defaultValueArg ValueNone 1, 1)
Assert.AreEqual(defaultValueArg (ValueSome 3) 1, 3)

Loading