Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d380a0e
substitute 'nameof(<long ident>)` with `Conts(<long ident as string l…
Jan 18, 2017
223d313
Implementing basic nameof and typenameof operators
Jan 18, 2017
529cc6f
Apply feedback
Jan 18, 2017
f3c4ba5
Revert "Apply feedback"
Jan 18, 2017
8fd0392
Revert "Implementing basic nameof and typenameof operators"
Jan 18, 2017
77c8f77
revert nameof and typenameof functions to FSharp.Core
vasily-kirichenko Jan 18, 2017
3070c1d
wip
vasily-kirichenko Jan 18, 2017
b3e712d
it works
vasily-kirichenko Jan 18, 2017
6c6e3b5
Merge remote-tracking branch 'origin/master' into nameof-operator
Jan 19, 2017
7832be5
refactoring
Jan 19, 2017
6581790
make it work on simple `Ident`s
Jan 19, 2017
0f5165f
use proper error message
Jan 19, 2017
22898ad
restrict using `nameof` operator as first class
Jan 19, 2017
e5033af
remove `typenameof` bits
Jan 19, 2017
1ad0a0e
nameof(typeof<_>) works
Jan 19, 2017
c9a64b2
Merge branch 'master' into nameof-operator
vasily-kirichenko Jan 28, 2017
5657759
fix QA tests
vasily-kirichenko Jan 28, 2017
b26994c
Merge branch 'master' into nameof-operator
vasily-kirichenko Feb 3, 2017
a732de0
remove nameof function form FSharp.Core
vasily-kirichenko Feb 3, 2017
b29fe57
Merge remote-tracking branch 'origin/master' into nameof-operator
vasily-kirichenko Feb 4, 2017
b7763a6
Revert "remove nameof function form FSharp.Core"
vasily-kirichenko Feb 4, 2017
906a934
Try to resolve the `nameof` operator argument to prevent passing anyt…
vasily-kirichenko Feb 4, 2017
a770e3c
nameof works on generic types
vasily-kirichenko Feb 4, 2017
067955a
fix error range in case of wrong `nameof`operator argument
vasily-kirichenko Feb 4, 2017
bfcc390
notify name resolution sink about nameof operator argument Item in or…
vasily-kirichenko Feb 5, 2017
6a92a80
fully type check `nameof` argument
vasily-kirichenko Feb 5, 2017
bcec600
try to type check arg again
vasily-kirichenko Feb 5, 2017
f64b3c5
Merge remote-tracking branch 'origin/master' into nameof-operator
Feb 6, 2017
0c1cad2
type check `nameof` argument more carefully
vasily-kirichenko Feb 6, 2017
15bf862
Merge remote-tracking branch 'vasily-kirichenko/nameof-operator' into…
vasily-kirichenko Feb 6, 2017
5b72f32
Merge remote-tracking branch 'origin/master' into nameof-operator
vasily-kirichenko Feb 15, 2017
ceb7731
Merge branch 'master' into nameof-operator
vasily-kirichenko Mar 1, 2017
588de2e
factor tcExpr to top level function
vasily-kirichenko Mar 1, 2017
f2ae00f
Merge remote-tracking branch 'origin/master' into nameof-operator
vasily-kirichenko Mar 8, 2017
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
2 changes: 2 additions & 0 deletions src/fsharp/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,8 @@ tcGlobalsSystemTypeNotFound,"The system type '%s' was required but no referenced
3213,typrelMemberHasMultiplePossibleDispatchSlots,"The member '%s' matches multiple overloads of the same method.\nPlease restrict it to one of the following:%s."
3214,methodIsNotStatic,"Method or object constructor '%s' is not static"
3215,parsUnexpectedSymbolEqualsInsteadOfIn,"Unexpected symbol '=' in expression. Did you intend to use 'for x in y .. z do' instead?"
3216,expressionHasNoName,"Expression does not have a name."
3217,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted."
Copy link
Contributor

@ErikSchierboom ErikSchierboom Mar 22, 2017

Choose a reason for hiding this comment

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

Shouldn't "First-class uses" not be "First-class use"?

keywordDescriptionAbstract,"Indicates a method that either has no implementation in the type in which it is declared or that is virtual and has a default implementation."
keyworkDescriptionAnd,"Used in mutually recursive bindings, in property declarations, and with multiple constraints on generic parameters."
keywordDescriptionAs,"Used to give the current class object an object name. Also used to give a name to a whole pattern within a pattern match."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
<Compile Include="FSharp.Core\Microsoft.FSharp.Core\OptionModule.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Core\PrintfTests.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Core\ResultTests.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Core\NameOfTests.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\Cancellation.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\AsyncType.fs" />
<Compile Include="FSharp.Core\Microsoft.FSharp.Control\LazyType.fs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace FSharp.Core.Unittests
open System
open NUnit.Framework

[<TestFixture>]
type BasicNameOfTests() =
let localConstant = 23
member this.MemberMethod() = 0
member this.MemberProperty = this.MemberMethod()
static member StaticMethod() = 0
static member StaticProperty = BasicNameOfTests.StaticMethod()

[<Test>]
member this.``local variable name lookup`` () =
let a = 0
let result = nameof a
Assert.AreEqual("a",result)
Assert.AreEqual("result",nameof result)

[<Test>]
member this.``local int function name`` () =
let myFunction x = 0 * x
let b = nameof myFunction
Assert.AreEqual("myFunction",b)

[<Test>]
member this.``local curried function name`` () =
let curriedFunction x y = x * y
let b = nameof curriedFunction
Assert.AreEqual("curriedFunction",b)

[<Test>]
member this.``local tupled function name`` () =
let tupledFunction(x,y) = x * y
let b = nameof tupledFunction
Assert.AreEqual("tupledFunction",b)

[<Test>]
member this.``local unit function name`` () =
let myFunction() = 1
let b = nameof(myFunction)
Assert.AreEqual("myFunction",b)

[<Test>]
member this.``local function parameter name`` () =
let myFunction parameter1 = nameof parameter1

Assert.AreEqual("parameter1",myFunction "x")

[<Test>]
member this.``can get name from inside a local function (needs to be let rec)`` () =
let rec myLocalFunction x =
let z = 2 * x
nameof myLocalFunction + " " + z.ToString()

Assert.AreEqual("myLocalFunction 46",myLocalFunction 23)
Assert.AreEqual("myLocalFunction 50",myLocalFunction 25)

[<Test>]
member this.CanGetNameFromInsideAMember () =
let b = nameof(this.CanGetNameFromInsideAMember)
Assert.AreEqual("CanGetNameFromInsideAMember",b)

[<Test>]
member this.``member function name`` () =
let b = nameof(this.MemberMethod)
Assert.AreEqual("MemberMethod",b)

[<Test>]
member this.``member function which is defined below`` () =
let b = nameof(this.MemberMethodDefinedBelow)
Assert.AreEqual("MemberMethodDefinedBelow",b)

member this.MemberMethodDefinedBelow(x,y) = x * y

[<Test>]
member this.``static member function name`` () =
let b = nameof(BasicNameOfTests.StaticMethod)
Assert.AreEqual("StaticMethod",b)

[<Test>]
member this.``class member lookup`` () =
let b = nameof(localConstant)
Assert.AreEqual("localConstant",b)

[<Test>]
member this.``member property name`` () =
let b = nameof(this.MemberProperty)
Assert.AreEqual("MemberProperty",b)

[<Test>]
member this.``static property name`` () =
let b = nameof(BasicNameOfTests.StaticProperty)
Assert.AreEqual("StaticProperty",b)

member this.get_XYZ() = 1

[<Test>]
member this.``member method starting with get_`` () =
let b = nameof(this.get_XYZ)
Assert.AreEqual("get_XYZ",b)

static member get_SXYZ() = 1

[<Test>]
member this.``static method starting with get_`` () =
let b = nameof(BasicNameOfTests.get_SXYZ)
Assert.AreEqual("get_SXYZ",b)

[<Test>]
member this.``nameof local property with encapsulated name`` () =
let ``local property with encapsulated name and %.f`` = 0
let b = nameof(``local property with encapsulated name and %.f``)
Assert.AreEqual("local property with encapsulated name and %.f",b)

[<TestFixture>]
type MethodGroupTests() =
member this.MethodGroup() = ()
member this.MethodGroup(i:int) = ()

member this.MethodGroup1(i:int, f:float, s:string) = 0
member this.MethodGroup1(f:float, l:int64) = "foo"
member this.MethodGroup1(u:unit -> unit -> int, h: unit) : unit = ()

[<Test>]
member this.``single argument method group name lookup`` () =
let b = nameof(this.MethodGroup)
Assert.AreEqual("MethodGroup",b)

[<Test>]
member this.``multiple argument method group name lookup`` () =
let b = nameof(this.MethodGroup1)
Assert.AreEqual("MethodGroup1",b)

[<TestFixture>]
type FrameworkMethodTests() =
[<Test>]
member this.``library function name`` () =
let b = nameof(List.map)
Assert.AreEqual("map",b)

[<Test>]
member this.``static class function name`` () =
let b = nameof(Tuple.Create)
Assert.AreEqual("Create",b)

type CustomUnionType =
| OptionA of string
| OptionB of int * string

[<TestFixture>]
type OperatorNameTests() =

[<Test>]
member this.``lookup name of typeof operator`` () =
let b = nameof(typeof<int>)
Assert.AreEqual("typeof",b)

[<Test>]
member this.``lookup name of + operator`` () =
let b = nameof(+)
Assert.AreEqual("op_Addition",b)

[<Test>]
member this.``lookup name of |> operator`` () =
let a = nameof(|>)
Assert.AreEqual("op_PipeRight",a)
let b = nameof(op_PipeRight)
Assert.AreEqual("op_PipeRight",b)

[<Test>]
member this.``lookup name of nameof operator`` () =
let b = nameof(nameof)
Assert.AreEqual("nameof",b)

[<TestFixture>]
type PatternMatchingOfOperatorNameTests() =
member this.Method1(i:int) = ()

[<Test>]
member this.``use it as a match case guard`` () =
match "Method1" with
| x when x = nameof(this.Method1) -> ()
| _ -> Assert.Fail("not expected")

[<TestFixture>]
type NameOfOperatorInQuotations() =
[<Test>]
member this.``use it in a quotation`` () =
let q =
<@
let f(x:int) = nameof x
f 20
@>
()

[<TestFixture>]
type NameOfOperatorForGenerics() =
[<Test>]
member this.``use it in a generic function`` () =
let fullyGeneric x = x
let b = nameof(fullyGeneric)
Assert.AreEqual("fullyGeneric",b)

[<Test>]
member this.``lookup name of a generic class`` () =
let b = nameof System.Collections.Generic.List<int>
Assert.AreEqual("List",b)

[<TestFixture>]
type UserDefinedNameOfTests() =
[<Test>]
member this.``userdefined nameof should shadow the operator`` () =
let nameof x = "test" + x.ToString()

let y = nameof 1
Assert.AreEqual("test1",y)

type Person =
{ Name : string
Age : int }
member __.Update(fld : string, value : obj) =
match fld with
| x when x = nameof __.Name -> { __ with Name = string value }
| x when x = nameof __.Age -> { __ with Age = value :?> int }
| _ -> __
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2632,6 +2632,7 @@ Microsoft.FSharp.Core.Operators: System.Object Box[T](T)" +
Microsoft.FSharp.Core.Operators: System.RuntimeMethodHandle MethodHandleOf[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult])" +
#endif
@"
Microsoft.FSharp.Core.Operators: System.String NameOf[T](T)
Microsoft.FSharp.Core.Operators: System.String ToString()
Microsoft.FSharp.Core.Operators: System.String ToString[T](T)
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,7 @@ Microsoft.FSharp.Core.Operators: System.Object Box[T](T)" +
Microsoft.FSharp.Core.Operators: System.RuntimeMethodHandle MethodHandleOf[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult])" +
#endif
@"
Microsoft.FSharp.Core.Operators: System.String NameOf[T](T)
Microsoft.FSharp.Core.Operators: System.String ToString()
Microsoft.FSharp.Core.Operators: System.String ToString[T](T)
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2606,6 +2606,7 @@ Microsoft.FSharp.Core.Operators: System.Object Box[T](T)" +
Microsoft.FSharp.Core.Operators: System.RuntimeMethodHandle MethodHandleOf[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult])" +
#endif
@"
Microsoft.FSharp.Core.Operators: System.String NameOf[T](T)
Microsoft.FSharp.Core.Operators: System.String ToString()
Microsoft.FSharp.Core.Operators: System.String ToString[T](T)
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2617,6 +2617,7 @@ Microsoft.FSharp.Core.Operators: System.Object Box[T](T)" +
Microsoft.FSharp.Core.Operators: System.RuntimeMethodHandle MethodHandleOf[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult])" +
#endif
@"
Microsoft.FSharp.Core.Operators: System.String NameOf[T](T)
Microsoft.FSharp.Core.Operators: System.String ToString()
Microsoft.FSharp.Core.Operators: System.String ToString[T](T)
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,7 @@ Microsoft.FSharp.Core.Operators: System.Object Box[T](T)" +
Microsoft.FSharp.Core.Operators: System.RuntimeMethodHandle MethodHandleOf[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult])" +
#endif
@"
Microsoft.FSharp.Core.Operators: System.String NameOf[T](T)
Microsoft.FSharp.Core.Operators: System.String ToString()
Microsoft.FSharp.Core.Operators: System.String ToString[T](T)
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Expand Down
3 changes: 3 additions & 0 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4751,6 +4751,9 @@ namespace Microsoft.FSharp.Core
[<CompiledName("TypeOf")>]
let inline typeof<'T> = BasicInlinedOperations.typeof<'T>

[<CompiledName("NameOf")>]
let inline nameof (_: 'T) : string = raise (Exception "may not call directly, should always be optimized away")

[<CompiledName("MethodHandleOf")>]
let methodhandleof (_call: ('T -> 'TResult)) : System.RuntimeMethodHandle = raise (Exception "may not call directly, should always be optimized away")

Expand Down
4 changes: 4 additions & 0 deletions src/fsharp/FSharp.Core/prim-types.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,10 @@ namespace Microsoft.FSharp.Core
[<CompiledName("TypeOf")>]
val inline typeof<'T> : System.Type

/// <summary>Returns the name of the given symbol.</summary>
[<CompiledName("NameOf")>]
val inline nameof : 'T -> string

/// <summary>An internal, library-only compiler intrinsic for compile-time
/// generation of a RuntimeMethodHandle.</summary>
[<CompiledName("MethodHandleOf")>]
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,7 @@ type ItemOccurence =
type ITypecheckResultsSink =
abstract NotifyEnvWithScope : range * NameResolutionEnv * AccessorDomain -> unit
abstract NotifyExprHasType : pos * TType * Tastops.DisplayEnv * NameResolutionEnv * AccessorDomain * range -> unit
abstract NotifyNameResolution : pos * Item * Item * ItemOccurence * Tastops.DisplayEnv * NameResolutionEnv * AccessorDomain * range * bool -> unit
abstract NotifyNameResolution : pos * item: Item * itemMethodGroup: Item * ItemOccurence * Tastops.DisplayEnv * NameResolutionEnv * AccessorDomain * range * replace: bool -> unit
abstract NotifyFormatSpecifierLocation : range -> unit
abstract CurrentSource : string option

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/PostInferenceChecks.fs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ and CheckVal (cenv:cenv) (env:env) v m context =
if isSpliceOperator cenv.g v then errorR(Error(FSComp.SR.chkNoFirstClassSplicing(), m))
if valRefEq cenv.g v cenv.g.addrof_vref then errorR(Error(FSComp.SR.chkNoFirstClassAddressOf(), m))
if valRefEq cenv.g v cenv.g.reraise_vref then errorR(Error(FSComp.SR.chkNoFirstClassRethrow(), m))
if valRefEq cenv.g v cenv.g.nameof_vref then errorR(Error(FSComp.SR.chkNoFirstClassNameOf(), m))
if noByrefs context && isByrefLikeTy cenv.g v.Type then
// byref typed val can only occur in permitting contexts
errorR(Error(FSComp.SR.chkNoByrefAtThisPoint(v.DisplayName), m))
Expand Down
16 changes: 15 additions & 1 deletion src/fsharp/TastOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2882,6 +2882,11 @@ let isSizeOfValRef g vref =
// There is an internal version of typeof defined in prim-types.fs that needs to be detected
|| (g.compilingFslib && vref.LogicalName = "sizeof")

let isNameOfValRef g vref =
valRefEq g vref g.nameof_vref
// There is an internal version of typeof defined in prim-types.fs that needs to be detected
|| (g.compilingFslib && vref.LogicalName = "nameof")

let isTypeDefOfValRef g vref =
valRefEq g vref g.typedefof_vref
// There is an internal version of typedefof defined in prim-types.fs that needs to be detected
Expand All @@ -2907,7 +2912,15 @@ let (|TypeDefOfExpr|_|) g expr =
| Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isTypeDefOfValRef g vref -> Some ty
| _ -> None

let (|NameOfExpr|_|) g expr =
match expr with
| Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isNameOfValRef g vref -> Some ty
| _ -> None

let (|SeqExpr|_|) g expr =
match expr with
| Expr.App(Expr.Val(vref,_,_),_,_,_,_) when valRefEq g vref g.seq_vref -> Some()
| _ -> None

//--------------------------------------------------------------------------
// DEBUG layout
Expand Down Expand Up @@ -7748,7 +7761,8 @@ let IsSimpleSyntacticConstantExpr g inputExpr =
| Expr.Op (TOp.UnionCase _,_,[],_) // Nullary union cases
| UncheckedDefaultOfExpr g _
| SizeOfExpr g _
| TypeOfExpr g _ -> true
| TypeOfExpr g _
| NameOfExpr g _ -> true
// All others are not simple constant expressions
| _ -> false

Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/TastOps.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1415,6 +1415,8 @@ val (|AttribBitwiseOrExpr|_|) : TcGlobals -> Expr -> (Expr * Expr) option
val (|EnumExpr|_|) : TcGlobals -> Expr -> Expr option
val (|TypeOfExpr|_|) : TcGlobals -> Expr -> TType option
val (|TypeDefOfExpr|_|) : TcGlobals -> Expr -> TType option
val (|NameOfExpr|_|) : TcGlobals -> Expr -> TType option
val (|SeqExpr|_|) : TcGlobals -> Expr -> unit option

val EvalLiteralExprOrAttribArg: TcGlobals -> Expr -> Expr
val EvaledAttribExprEquality : TcGlobals -> Expr -> Expr -> bool
Expand Down
Loading