Skip to content

Commit d27c3a3

Browse files
committed
Merge pull request #387 from Jand42/master
types and arrays in F# attribute contructor arguments
2 parents daef337 + 2611c8b commit d27c3a3

File tree

3 files changed

+94
-7
lines changed

3 files changed

+94
-7
lines changed

src/fsharp/infos.fs

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

2544-
let evalFSharpAttribArg e =
2544+
let rec evalFSharpAttribArg g e =
25452545
match e with
25462546
| Expr.Const(c,_,_) ->
25472547
match c with
@@ -2560,8 +2560,9 @@ let evalFSharpAttribArg e =
25602560
| Const.Zero -> null
25612561
| Const.String s -> box s
25622562
| _ -> fail()
2563-
// TODO: typeof<..> in attribute values
2564-
// TODO: arrays in attribute values
2563+
| Expr.Op (TOp.Array,_,a,_) -> box [| for i in a -> evalFSharpAttribArg g i |]
2564+
| TypeOfExpr g ty -> box ty
2565+
// TODO: | TypeDefOfExpr g ty
25652566
| _ -> fail()
25662567

25672568
type AttribInfo =
@@ -2590,7 +2591,7 @@ type AttribInfo =
25902591
unnamedArgs
25912592
|> List.map (fun (AttribExpr(origExpr,evaluatedExpr)) ->
25922593
let ty = tyOfExpr g origExpr
2593-
let obj = evalFSharpAttribArg evaluatedExpr
2594+
let obj = evalFSharpAttribArg g evaluatedExpr
25942595
ty,obj)
25952596
| ILAttribInfo (g, amap, scoref, cattr, m) ->
25962597
let parms, _args = decodeILAttribData g.ilg cattr (Some scoref)
@@ -2605,7 +2606,7 @@ type AttribInfo =
26052606
namedArgs
26062607
|> List.map (fun (AttribNamedArg(nm,_,isField,AttribExpr(origExpr,evaluatedExpr))) ->
26072608
let ty = tyOfExpr g origExpr
2608-
let obj = evalFSharpAttribArg evaluatedExpr
2609+
let obj = evalFSharpAttribArg g evaluatedExpr
26092610
ty, nm, isField, obj)
26102611
| ILAttribInfo (g, amap, scoref, cattr, m) ->
26112612
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)