Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
Prev Previous commit
Next Next commit
Feedback
  • Loading branch information
TIHan committed Apr 11, 2019
commit 76e30d5563eba9068144cf92bf295ad1ef54f089
10 changes: 4 additions & 6 deletions src/fsharp/TastOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3017,22 +3017,20 @@ let isByrefLikeTyconRef (g: TcGlobals) m (tcref: TyconRef) =
| None ->
let res =
isByrefTyconRef g tcref ||
TyconRefHasAttribute g m g.attrib_IsByRefLikeAttribute tcref
(isStructTyconRef tcref && TyconRefHasAttribute g m g.attrib_IsByRefLikeAttribute tcref)
tcref.SetIsByRefLike res
res

let isSpanLikeTyconRef g m tcref =
isByrefLikeTyconRef g m tcref &&
not (isByrefTyconRef g tcref) &&
isStructTyconRef tcref
not (isByrefTyconRef g tcref)

let isByrefLikeTy g m ty =
ty |> stripTyEqns g |> (function TType_app(tcref, _) -> isByrefLikeTyconRef g m tcref | _ -> false)

let isSpanLikeTy g m ty =
isByrefLikeTy g m ty &&
not (isByrefTy g ty) &&
isStructTy g ty
not (isByrefTy g ty)

let isSpanTyconRef g m tcref =
isByrefLikeTyconRef g m tcref &&
Expand All @@ -3041,7 +3039,7 @@ let isSpanTyconRef g m tcref =
let isSpanTy g m ty =
ty |> stripTyEqns g |> (function TType_app(tcref, _) -> isSpanTyconRef g m tcref | _ -> false)

let tryDestSpanTy g m ty =
let rec tryDestSpanTy g m ty =
match tryAppTy g ty with
| ValueSome(tcref, [ty]) when isSpanTyconRef g m tcref -> ValueSome(struct(tcref, ty))
| _ -> ValueNone
Expand Down
33 changes: 15 additions & 18 deletions src/fsharp/TypeChecker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3044,25 +3044,22 @@ let TryFindIntrinsicOrExtensionMethInfo (cenv: cenv) (env: TcEnv) m ad nm ty =
AllMethInfosOfTypeInScope cenv.infoReader env.NameEnv (Some(nm), ad) IgnoreOverrides m ty

let TryFindFSharpSignatureInstanceGetterProperty (cenv: cenv) (env: TcEnv) m nm ty (sigTys: TType list) =
match TryFindPropInfo cenv.infoReader m env.AccessRights nm ty with
| [] -> None
| propInfos ->
propInfos
|> List.tryFind (fun propInfo ->
not propInfo.IsStatic && propInfo.HasGetter &&
(
match propInfo.GetterMethod.GetParamTypes(cenv.amap, m, []) with
| [] -> false
| argTysList ->
TryFindPropInfo cenv.infoReader m env.AccessRights nm ty
|> List.tryFind (fun propInfo ->
not propInfo.IsStatic && propInfo.HasGetter &&
(
match propInfo.GetterMethod.GetParamTypes(cenv.amap, m, []) with
| [] -> false
| argTysList ->

let argTys = (argTysList |> List.reduce (@)) @ [ propInfo.GetterMethod.GetFSharpReturnTy(cenv.amap, m, []) ] in
if argTys.Length <> sigTys.Length then
false
else
(argTys, sigTys)
||> List.forall2 (typeEquiv cenv.g)
)
let argTys = (argTysList |> List.reduce (@)) @ [ propInfo.GetterMethod.GetFSharpReturnTy(cenv.amap, m, []) ] in
if argTys.Length <> sigTys.Length then
false
else
(argTys, sigTys)
||> List.forall2 (typeEquiv cenv.g)
)
)

/// Build the 'test and dispose' part of a 'use' statement
let BuildDisposableCleanup cenv env m (v: Val) =
Expand Down Expand Up @@ -7138,7 +7135,7 @@ and TcForEachExpr cenv overallTy env tpenv (pat, enumSynExpr, bodySynExpr, mWhol
| ValueSome(struct(_, destTy)) ->
match TryFindFSharpSignatureInstanceGetterProperty cenv env m "Item" ty [ g.int32_ty; (if isReadOnlySpan then mkInByrefTy g destTy else mkByrefTy g destTy) ],
TryFindFSharpSignatureInstanceGetterProperty cenv env m "Length" ty [ g.int32_ty ] with
| Some(itemPropInfo), Some(lengthPropInfo) when itemPropInfo.HasGetter && lengthPropInfo.HasGetter ->
| Some(itemPropInfo), Some(lengthPropInfo) ->
ValueSome(struct(itemPropInfo.GetterMethod, lengthPropInfo.GetterMethod, isReadOnlySpan))
| _ ->
ValueNone
Expand Down
102 changes: 102 additions & 0 deletions tests/fsharp/Compiler/Language/SpanOptimizationTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,106 @@ let test () =
IL_0034: ret
}"""
]

[<Test>]
let ExplicitSpanTypeForInDo() =

let source =
"""
namespace System.Runtime.CompilerServices

open System

[<Sealed>]
type IsByRefLikeAttribute() =
inherit Attribute()

namespace System

open System.Collections
open System.Runtime.CompilerServices

[<Struct;IsByRefLike>]
type Span<'T>(arr: 'T []) =

member __.Item
with get (i: int) = &arr.[0]

member __.Length
with get () = &arr.[0]

static member Empty = Span<'T>([||])

interface IEnumerable with

member __.GetEnumerator() = null

module Test =

let test () =
let span = Span<obj>.Empty
for item in span do
Console.WriteLine(item)
"""

// The current behavior doesn't optimize, but it could in the future. Making a test to catch if it ever does.
ILChecker.checkWithDlls
(ILChecker.getPackageDlls "System.Memory" "4.5.0" "netstandard2.0" [ "System.Memory.dll" ])
source
[
""".method public static void test() cil managed
{

.maxstack 3
.locals init (valuetype System.Span`1<object> V_0,
class [mscorlib]System.Collections.IEnumerator V_1,
class [FSharp.Core]Microsoft.FSharp.Core.Unit V_2,
class [mscorlib]System.IDisposable V_3)
IL_0000: ldc.i4.0
IL_0001: newarr [mscorlib]System.Object
IL_0006: newobj instance void valuetype System.Span`1<object>::.ctor(!0[])
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: box valuetype System.Span`1<object>
IL_0012: unbox.any [mscorlib]System.Collections.IEnumerable
IL_0017: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_001c: stloc.1
.try
{
IL_001d: ldloc.1
IL_001e: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0023: brfalse.s IL_0032

IL_0025: ldloc.1
IL_0026: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_002b: call void [mscorlib]System.Console::WriteLine(object)
IL_0030: br.s IL_001d

IL_0032: ldnull
IL_0033: stloc.2
IL_0034: leave.s IL_004c

}
finally
{
IL_0036: ldloc.1
IL_0037: isinst [mscorlib]System.IDisposable
IL_003c: stloc.3
IL_003d: ldloc.3
IL_003e: brfalse.s IL_0049

IL_0040: ldloc.3
IL_0041: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0046: ldnull
IL_0047: pop
IL_0048: endfinally
IL_0049: ldnull
IL_004a: pop
IL_004b: endfinally
}
IL_004c: ldloc.2
IL_004d: pop
IL_004e: ret
}"""
]
#endif