Skip to content

Commit fa71e46

Browse files
committed
update release notes
2 parents 7a0c29e + d27c3a3 commit fa71e46

File tree

4 files changed

+97
-7
lines changed

4 files changed

+97
-7
lines changed

RELEASE_NOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#### 1.4.0.2 -
2+
* #387 - types and arrays in F# attribute contructor arguments
3+
14
#### 1.4.0.1 - F# 4.0 support
25
* Use FSharp.Core 4.4.0.0 by default for scripting scenarios if not FSharp.Core referenced by host process
36

src/fsharp/infos.fs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,7 +2598,7 @@ let rec evalILAttribElem e =
25982598
| ILAttribElem.TypeRef (Some _t) -> fail()
25992599
| ILAttribElem.TypeRef None -> null
26002600

2601-
let evalFSharpAttribArg e =
2601+
let rec evalFSharpAttribArg g e =
26022602
match e with
26032603
| Expr.Const(c,_,_) ->
26042604
match c with
@@ -2617,8 +2617,9 @@ let evalFSharpAttribArg e =
26172617
| Const.Zero -> null
26182618
| Const.String s -> box s
26192619
| _ -> fail()
2620-
// TODO: typeof<..> in attribute values
2621-
// TODO: arrays in attribute values
2620+
| Expr.Op (TOp.Array,_,a,_) -> box [| for i in a -> evalFSharpAttribArg g i |]
2621+
| TypeOfExpr g ty -> box ty
2622+
// TODO: | TypeDefOfExpr g ty
26222623
| _ -> fail()
26232624

26242625
type AttribInfo =
@@ -2647,7 +2648,7 @@ type AttribInfo =
26472648
unnamedArgs
26482649
|> List.map (fun (AttribExpr(origExpr,evaluatedExpr)) ->
26492650
let ty = tyOfExpr g origExpr
2650-
let obj = evalFSharpAttribArg evaluatedExpr
2651+
let obj = evalFSharpAttribArg g evaluatedExpr
26512652
ty,obj)
26522653
| ILAttribInfo (g, amap, scoref, cattr, m) ->
26532654
let parms, _args = decodeILAttribData g.ilg cattr (Some scoref)
@@ -2662,7 +2663,7 @@ type AttribInfo =
26622663
namedArgs
26632664
|> List.map (fun (AttribNamedArg(nm,_,isField,AttribExpr(origExpr,evaluatedExpr))) ->
26642665
let ty = tyOfExpr g origExpr
2665-
let obj = evalFSharpAttribArg evaluatedExpr
2666+
let obj = evalFSharpAttribArg g evaluatedExpr
26662667
ty, nm, isField, obj)
26672668
| ILAttribInfo (g, amap, scoref, cattr, m) ->
26682669
let _parms, namedArgs = decodeILAttribData g.ilg cattr (Some scoref)

src/fsharp/vs/Symbols.fs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,19 +1711,25 @@ and FSharpType(cenv, typ:TType) =
17111711

17121712
and FSharpAttribute(cenv: cenv, attrib: AttribInfo) =
17131713

1714+
let rec resolveArgObj (arg: obj) =
1715+
match arg with
1716+
| :? TType as t -> box (FSharpType(cenv, t))
1717+
| :? (obj[]) as a -> a |> Array.map resolveArgObj |> box
1718+
| _ -> arg
1719+
17141720
member __.AttributeType =
17151721
FSharpEntity(cenv, attrib.TyconRef)
17161722

17171723
member __.IsUnresolved = entityIsUnresolved(attrib.TyconRef)
17181724

17191725
member __.ConstructorArguments =
17201726
attrib.ConstructorArguments
1721-
|> List.map (fun (ty, obj) -> FSharpType(cenv, ty), obj)
1727+
|> List.map (fun (ty, obj) -> FSharpType(cenv, ty), resolveArgObj obj)
17221728
|> makeReadOnlyCollection
17231729

17241730
member __.NamedArguments =
17251731
attrib.NamedArguments
1726-
|> List.map (fun (ty, nm, isField, obj) -> FSharpType(cenv, ty), nm, isField, obj)
1732+
|> List.map (fun (ty, nm, isField, obj) -> FSharpType(cenv, ty), nm, isField, resolveArgObj obj)
17271733
|> makeReadOnlyCollection
17281734

17291735
member __.Format(denv: FSharpDisplayContext) =

tests/service/ProjectAnalysisTests.fs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4496,3 +4496,83 @@ let ``Test project36 FSharpMemberOrFunctionOrValue.LiteralValue`` () =
44964496

44974497
let notLit = project36Module.MembersFunctionsAndValues.[1]
44984498
shouldEqual true notLit.LiteralValue.IsNone
4499+
4500+
module Project37 =
4501+
open System.IO
4502+
4503+
let fileName1 = Path.ChangeExtension(Path.GetTempFileName(), ".fs")
4504+
let base2 = Path.GetTempFileName()
4505+
let dllName = Path.ChangeExtension(base2, ".dll")
4506+
let projFileName = Path.ChangeExtension(base2, ".fsproj")
4507+
let fileSource1 = """
4508+
[<System.AttributeUsage(System.AttributeTargets.Method)>]
4509+
type AttrTestAttribute() =
4510+
inherit System.Attribute()
4511+
4512+
new (t: System.Type) = AttrTestAttribute()
4513+
new (t: System.Type[]) = AttrTestAttribute()
4514+
new (t: int[]) = AttrTestAttribute()
4515+
4516+
type TestUnion = | A of string
4517+
type TestRecord = { B : int }
4518+
4519+
module Test =
4520+
[<AttrTest(typeof<int>)>]
4521+
let withType = 0
4522+
[<AttrTest(typeof<list<int>>)>]
4523+
let withGenericType = 0
4524+
[<AttrTest(typeof<int * int>)>]
4525+
let withTupleType = 0
4526+
[<AttrTest(typeof<int -> int>)>]
4527+
let withFuncType = 0
4528+
[<AttrTest([| typeof<TestUnion>; typeof<TestRecord> |])>]
4529+
let withTypeArray = 0
4530+
[<AttrTest([| 0; 1; 2 |])>]
4531+
let withIntArray = 0
4532+
"""
4533+
File.WriteAllText(fileName1, fileSource1)
4534+
let fileNames = [fileName1]
4535+
let args = mkProjectCommandLineArgs (dllName, fileNames)
4536+
let options = checker.GetProjectOptionsFromCommandLineArgs (projFileName, args)
4537+
let wholeProjectResults =
4538+
checker.ParseAndCheckProject(options)
4539+
|> Async.RunSynchronously
4540+
4541+
[<Test>]
4542+
let ``Test project37 typeof and arrays in attribute constructor arguments`` () =
4543+
let allSymbolsUses = Project37.wholeProjectResults.GetAllUsesOfAllSymbols() |> Async.RunSynchronously
4544+
for su in allSymbolsUses do
4545+
match su.Symbol with
4546+
| :? FSharpMemberOrFunctionOrValue as funcSymbol ->
4547+
let getAttrArg() =
4548+
let arg = funcSymbol.Attributes.[0].ConstructorArguments.[0] |> snd
4549+
arg :?> FSharpType
4550+
match funcSymbol.DisplayName with
4551+
| "withType" ->
4552+
let t = getAttrArg()
4553+
t.TypeDefinition.DisplayName |> shouldEqual "int"
4554+
| "withGenericType" ->
4555+
let t = getAttrArg()
4556+
t.TypeDefinition.DisplayName |> shouldEqual "list"
4557+
t.GenericArguments.[0].TypeDefinition.DisplayName |> shouldEqual "int"
4558+
| "withTupleType" ->
4559+
let t = getAttrArg()
4560+
t.IsTupleType |> shouldEqual true
4561+
t.GenericArguments.[0].TypeDefinition.DisplayName |> shouldEqual "int"
4562+
t.GenericArguments.[1].TypeDefinition.DisplayName |> shouldEqual "int"
4563+
| "withFuncType" ->
4564+
let t = getAttrArg()
4565+
t.IsFunctionType |> shouldEqual true
4566+
t.GenericArguments.[0].TypeDefinition.DisplayName |> shouldEqual "int"
4567+
t.GenericArguments.[1].TypeDefinition.DisplayName |> shouldEqual "int"
4568+
| "withTypeArray" ->
4569+
let attr = funcSymbol.Attributes.[0].ConstructorArguments.[0] |> snd
4570+
let ta = attr :?> obj[] |> Array.map (fun t -> t :?> FSharpType)
4571+
ta.[0].TypeDefinition.DisplayName |> shouldEqual "TestUnion"
4572+
ta.[1].TypeDefinition.DisplayName |> shouldEqual "TestRecord"
4573+
| "withIntArray" ->
4574+
let attr = funcSymbol.Attributes.[0].ConstructorArguments.[0] |> snd
4575+
let a = attr :?> obj[] |> Array.map (fun t -> t :?> int)
4576+
a |> shouldEqual [| 0; 1; 2 |]
4577+
| _ -> ()
4578+
| _ -> ()

0 commit comments

Comments
 (0)