diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt
index 5bbff5d3ffa..5bebaef7422 100644
--- a/src/fsharp/FSComp.txt
+++ b/src/fsharp/FSComp.txt
@@ -1307,3 +1307,5 @@ estApplyStaticArgumentsForMethodNotImplemented,"A type provider implemented GetS
3201,tcModuleAbbrevFirstInMutRec,"In a recursive declaration group, module abbreviations must come after all 'open' declarations and before other declarations"
3202,tcUnsupportedMutRecDecl,"This declaration is not supported in recursive declaration groups"
3203,parsInvalidUseOfRec,"Invalid use of 'rec' keyword"
+3204,expressionHasNoName,"This expression does not have a name."
+3205,nameofNotPermitted,"The nameof operator is not allowed in this position."
diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj b/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
index 83ed633defa..e0e3765a40b 100644
--- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
+++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
@@ -120,6 +120,7 @@
+
diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/NameOfTests.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/NameOfTests.fs
new file mode 100644
index 00000000000..1c82fc8ef04
--- /dev/null
+++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/NameOfTests.fs
@@ -0,0 +1,248 @@
+// 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
+
+[]
+type BasicNameOfTests() =
+ let localConstant = 23
+ member this.MemberMethod() = 0
+ member this.MemberProperty = this.MemberMethod()
+ static member StaticMethod() = 0
+ static member StaticProperty = BasicNameOfTests.StaticMethod()
+
+ []
+ member this.``local variable name lookup`` () =
+ let a = 0
+ let result = nameof a
+ Assert.AreEqual("a",result)
+ Assert.AreEqual("result",nameof result)
+
+ []
+ member this.``local int function name`` () =
+ let myFunction x = 0 * x
+ let b = nameof myFunction
+ Assert.AreEqual("myFunction",b)
+
+ []
+ member this.``local curried function name`` () =
+ let curriedFunction x y = x * y
+ let b = nameof curriedFunction
+ Assert.AreEqual("curriedFunction",b)
+
+ []
+ member this.``local tupled function name`` () =
+ let tupledFunction(x,y) = x * y
+ let b = nameof tupledFunction
+ Assert.AreEqual("tupledFunction",b)
+
+ []
+ member this.``local unit function name`` () =
+ let myFunction() = 1
+ let b = nameof(myFunction)
+ Assert.AreEqual("myFunction",b)
+
+ []
+ member this.``local function parameter name`` () =
+ let myFunction parameter1 = nameof parameter1
+
+ Assert.AreEqual("parameter1",myFunction "x")
+
+ []
+ 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)
+
+ []
+ member this.CanGetNameFromInsideAMember () =
+ let b = nameof(this.CanGetNameFromInsideAMember)
+ Assert.AreEqual("CanGetNameFromInsideAMember",b)
+
+ []
+ member this.``member function name`` () =
+ let b = nameof(this.MemberMethod)
+ Assert.AreEqual("MemberMethod",b)
+
+ []
+ member this.``member function which is defined below`` () =
+ let b = nameof(this.MemberMethodDefinedBelow)
+ Assert.AreEqual("MemberMethodDefinedBelow",b)
+
+ member this.MemberMethodDefinedBelow(x,y) = x * y
+
+ []
+ member this.``static member function name`` () =
+ let b = nameof(BasicNameOfTests.StaticMethod)
+ Assert.AreEqual("StaticMethod",b)
+
+ []
+ member this.``class member lookup`` () =
+ let b = nameof(localConstant)
+ Assert.AreEqual("localConstant",b)
+
+ []
+ member this.``member property name`` () =
+ let b = nameof(this.MemberProperty)
+ Assert.AreEqual("MemberProperty",b)
+
+ []
+ member this.``static property name`` () =
+ let b = nameof(BasicNameOfTests.StaticProperty)
+ Assert.AreEqual("StaticProperty",b)
+
+ member this.get_XYZ() = 1
+
+ []
+ member this.``member method starting with get_`` () =
+ let b = nameof(this.get_XYZ)
+ Assert.AreEqual("get_XYZ",b)
+
+ static member get_SXYZ() = 1
+
+ []
+ member this.``static method starting with get_`` () =
+ let b = nameof(BasicNameOfTests.get_SXYZ)
+ Assert.AreEqual("get_SXYZ",b)
+
+ []
+ 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)
+
+[]
+type MethodGroupTests() =
+ member this.MethodGroup() = ()
+ member this.MethodGroup(i:int) = ()
+
+ []
+ member this.``method group name lookup`` () =
+ let b = nameof(this.MethodGroup)
+ Assert.AreEqual("MethodGroup",b)
+
+[]
+type FrameworkMethodTests() =
+ []
+ member this.``library function name`` () =
+ let b = nameof(List.map)
+ Assert.AreEqual("Map",b)
+
+ []
+ member this.``static class function name`` () =
+ let b = nameof(Tuple.Create)
+ Assert.AreEqual("Create",b)
+
+type CustomUnionType =
+| OptionA of string
+| OptionB of int * string
+
+[]
+type NameOfOperatorForTypes() =
+ []
+ member this.``use typenameof on Int32`` () =
+ let b = typenameof
+ Assert.AreEqual("System.Int32",b)
+
+ []
+ member this.``use typenameof on a custom type`` () =
+ let b = typenameof
+ Assert.AreEqual("FSharp.Core.Unittests.NameOfOperatorForTypes",b)
+
+ []
+ member this.``use typenameof on a custom union type`` () =
+ let b = typenameof
+ Assert.AreEqual("FSharp.Core.Unittests.CustomUnionType",b)
+//
+// []
+// member this.``use typenameof on a custom union case`` () =
+// let b = typenameof
+// Assert.AreEqual("FSharp.Core.Unittests.CustomUnionType.OptionB",b)
+
+ []
+ member this.``use typenameof on List`` () =
+ let b = typenameof>
+ Assert.AreEqual("System.Collections.Generic.List`1",b)
+
+ []
+ member this.``use typenameof on generic List`` () =
+ let b = typenameof>
+ Assert.AreEqual("System.Collections.Generic.List`1",b)
+
+
+
+[]
+type OperatorNameTests() =
+
+ []
+ member this.``lookup name of typeof operator`` () =
+ let b = nameof(typeof)
+ Assert.AreEqual("TypeOf",b)
+
+ []
+ member this.``lookup name of + operator`` () =
+ let b = nameof(+)
+ Assert.AreEqual("op_Addition",b)
+
+ []
+ member this.``lookup name of |> operator`` () =
+ let a = nameof(|>)
+ Assert.AreEqual("op_PipeRight",a)
+ let b = nameof(op_PipeRight)
+ Assert.AreEqual("op_PipeRight",b)
+
+ []
+ member this.``lookup name of nameof operator`` () =
+ let b = nameof(nameof)
+ Assert.AreEqual("NameOf",b)
+
+[]
+type PatternMatchingOfOperatorNameTests() =
+ member this.Method1(i:int) = ()
+
+ []
+ member this.``use it as a match case guard`` () =
+ match "Method1" with
+ | x when x = nameof(this.Method1) -> ()
+ | _ -> Assert.Fail("not expected")
+
+[]
+type NameOfOperatorInQuotations() =
+ []
+ member this.``use it in a quotation`` () =
+ let q =
+ <@
+ let f(x:int) = nameof x
+ f 20
+ @>
+ ()
+
+[]
+type NameOfOperatorForGenerics() =
+ []
+ member this.``use it in a generic function`` () =
+ let fullyGeneric x = x
+ let b = nameof(fullyGeneric)
+ Assert.AreEqual("fullyGeneric",b)
+
+[]
+type UserDefinedNameOfTests() =
+ []
+ 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 }
+ | _ -> __
\ No newline at end of file
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Silverlight.2.0.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Silverlight.2.0.fs
index 3d933f40517..eb3eed957e9 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Silverlight.2.0.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.Silverlight.2.0.fs
@@ -2197,8 +2197,10 @@ Microsoft.FSharp.Core.Operators: System.IO.TextReader ConsoleIn[T]()
Microsoft.FSharp.Core.Operators: System.IO.TextWriter ConsoleError[T]()
Microsoft.FSharp.Core.Operators: System.IO.TextWriter ConsoleOut[T]()
Microsoft.FSharp.Core.Operators: System.Object Box[T](T)
+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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net20.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net20.fs
index c8caf782564..e6c4c706130 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net20.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net20.fs
@@ -2438,8 +2438,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
index 6879946205f..f22e36ce3ee 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
@@ -2602,8 +2602,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
index 2102f9d951d..0f554627561 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
@@ -2574,8 +2574,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
index 856107f69f2..b3d6e1d4db6 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
@@ -2576,8 +2576,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
index 745df1359bf..60fe06e203a 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
@@ -2587,8 +2587,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
index 72df723cf36..1c9fc1d346b 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
@@ -2574,8 +2574,10 @@ 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 TypeNameOf[T]()
Microsoft.FSharp.Core.Operators: System.String op_Concatenate(System.String, System.String)
Microsoft.FSharp.Core.Operators: System.Tuple`2[TKey,TValue] KeyValuePattern[TKey,TValue](System.Collections.Generic.KeyValuePair`2[TKey,TValue])
Microsoft.FSharp.Core.Operators: System.Type GetType()
diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs
index 8ff1a91732b..72fb0444119 100644
--- a/src/fsharp/FSharp.Core/prim-types.fs
+++ b/src/fsharp/FSharp.Core/prim-types.fs
@@ -4753,6 +4753,12 @@ namespace Microsoft.FSharp.Core
[]
let inline typeof<'T> = BasicInlinedOperations.typeof<'T>
+ []
+ let inline typenameof<'T> : string = raise (Exception "may not call directly, should always be optimized away")
+
+ []
+ let inline nameof (_: 'T) : string = raise (Exception "may not call directly, should always be optimized away")
+
[]
let methodhandleof (_call: ('T -> 'TResult)) : System.RuntimeMethodHandle = raise (Exception "may not call directly, should always be optimized away")
diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi
index d3202b3aeee..0653e9be9ac 100644
--- a/src/fsharp/FSharp.Core/prim-types.fsi
+++ b/src/fsharp/FSharp.Core/prim-types.fsi
@@ -2306,6 +2306,15 @@ namespace Microsoft.FSharp.Core
[]
val inline typeof<'T> : System.Type
+ /// Returns the name of the given static type.
+ []
+ []
+ val inline typenameof<'T> : string
+
+ /// Returns the name of the given symbol.
+ []
+ val inline nameof : 'T -> string
+
/// An internal, library-only compiler intrinsic for compile-time
/// generation of a RuntimeMethodHandle.
[]
diff --git a/src/fsharp/Optimizer.fs b/src/fsharp/Optimizer.fs
index 186113ed2a2..989d26c7d8b 100644
--- a/src/fsharp/Optimizer.fs
+++ b/src/fsharp/Optimizer.fs
@@ -1219,7 +1219,7 @@ let AbstractAndRemapModulInfo msg g m (repackage,hidden) info =
info
//-------------------------------------------------------------------------
-// Misc helerps
+// Misc helpers
//-------------------------------------------------------------------------
// Mark some variables (the ones we introduce via abstractBigTargets) as don't-eliminate
@@ -2345,8 +2345,17 @@ and DevirtualizeApplication cenv env (vref:ValRef) ty tyargs args m =
let transformedExpr = wrap (MakeApplicationAndBetaReduce cenv.g (exprForValRef m vref,vref.Type,(if isNil tyargs then [] else [tyargs]),args,m))
OptimizeExpr cenv env transformedExpr
-
-
+
+and GetNameFromTypeName tcGlobals m typeName =
+ match stripTyEqns tcGlobals typeName with
+ | TType_app (tcref, _) -> tcref.CompiledRepresentationForNamedType.FullName
+ | TType_forall _ -> errorR(Error(FSComp.SR.expressionHasNoName(), m)); ""
+ | TType_tuple _ -> errorR(Error(FSComp.SR.expressionHasNoName(), m)); ""
+ | TType_fun _ -> errorR(Error(FSComp.SR.expressionHasNoName(), m)); ""
+ | TType_ucase _ -> errorR(Error(FSComp.SR.expressionHasNoName(), m)); ""
+ | TType_var tp -> tp.DisplayName
+ | TType_measure ms -> sprintf "%A" ms
+
and TryDevirtualizeApplication cenv env (f,tyargs,args,m) =
match f,tyargs,args with
@@ -2542,6 +2551,28 @@ and TryDevirtualizeApplication cenv env (f,tyargs,args,m) =
MightMakeCriticalTailcall = false;
Info=UnknownValue})
+ // Analyze the name of the given symbol and rewrite AST to constant string expression with the name
+ | Expr.Val(vref,_,_),_,_ when valRefEq cenv.g vref cenv.g.nameof_vref ->
+ PostTypeCheckSemanticChecks.tryExtractNameOf args
+ |> Option.map (fun name ->
+ Expr.Const(Const.String name, m, cenv.g.string_ty),
+ { TotalSize = 1
+ FunctionSize = 1
+ HasEffect = false
+ MightMakeCriticalTailcall = false
+ Info = UnknownValue })
+ // Analyze the name of the given type and rewrite AST to constant string expression with the name
+ | Expr.Val(vref,_,_),_,_ when valRefEq cenv.g vref cenv.g.typenameof_vref ->
+ match tyargs with
+ | typeName:: _ ->
+ let name = GetNameFromTypeName cenv.g m typeName
+ Some(Expr.Const(Const.String name, m, cenv.g.string_ty),
+ { TotalSize = 1
+ FunctionSize = 1
+ HasEffect = false
+ MightMakeCriticalTailcall = false
+ Info = UnknownValue })
+ | _ -> None
| _ -> None
/// Attempt to inline an application of a known value at callsites
diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs
index d9ea90e1715..261023316ec 100644
--- a/src/fsharp/PostInferenceChecks.fs
+++ b/src/fsharp/PostInferenceChecks.fs
@@ -459,6 +459,30 @@ let CheckMultipleInterfaceInstantiations cenv interfaces m =
| Some (typ1,typ2) ->
errorR(Error(FSComp.SR.chkMultipleGenericInterfaceInstantiations((NicePrint.minimalStringOfType cenv.denv typ1), (NicePrint.minimalStringOfType cenv.denv typ2)),m))
+// tries to extract the name of an expression
+let tryExtractNameOf args =
+ match args with
+ | [Expr.Val(r,_,_)] -> Some(r.CompiledName)
+ | [Expr.App(Expr.Val(r,_,_),_,_,Expr.Const(constant,_,_)::_,_)] ->
+ match constant with
+ | Const.Unit ->
+ if r.CompiledName.StartsWith("get_") then // TODO: We need a better way to find static property getters
+ Some(r.CompiledName.Substring(4))
+ else
+ None // the function was applied
+ | _ -> None
+ | [Expr.App(Expr.Val(r,_,_),_,_,[],_)] -> Some(r.CompiledName)
+ | [Expr.App(Expr.Val(r,_,_),_,_,_,_)] ->
+ if r.CompiledName.StartsWith("get_") then // TODO: We need a better way to find member property getters
+ Some(r.CompiledName.Substring(4))
+ else
+ None // the function was applied
+ | [Expr.Let(_,Expr.Val(r,_,_),_,_)] -> Some(r.CompiledName)
+ | [Expr.Let(_,Expr.Lambda(_,_,_,_,Expr.App(Expr.Val(r,_,_),_,_,_,_),_,_),_,_)] -> Some(r.CompiledName)
+ | [Expr.Lambda(_,_,_,_,Expr.App(Expr.Val(r,_,_),_,_,_,_),_,_)] -> Some(r.CompiledName)
+ | [Expr.Op(TOp.ValFieldGet(r),_,_,_)] -> Some(r.FieldName)
+ | [Expr.Lambda(_,_,_,_,Expr.Op(TOp.ILCall(_,_,_,_,_,_,_,r,_,_,_),_,_,_),_,_)] -> Some(r.Name)
+ | _ -> None
let rec CheckExpr (cenv:cenv) (env:env) expr =
CheckExprInContext cenv env expr GeneralContext
@@ -489,8 +513,18 @@ and CheckExprInContext (cenv:cenv) (env:env) expr (context:ByrefCallContext) =
BindVal cenv bind.Var
CheckExpr cenv env body
| Expr.Const (_,m,ty) ->
- CheckTypePermitByrefs cenv env m ty
-
+ CheckTypePermitByrefs cenv env m ty
+
+ | Expr.App(Expr.Val (v,_,_),_,_,args,m) ->
+ if cenv.reportErrors then
+ if valRefEq cenv.g v cenv.g.nameof_vref && tryExtractNameOf args = None then
+ errorR(Error(FSComp.SR.expressionHasNoName(), m))
+ match args with
+ | [_;Expr.App(Expr.Val (v,_,_),_,_,args,m)] ->
+ if valRefEq cenv.g v cenv.g.nameof_vref && tryExtractNameOf args = None then
+ errorR(Error(FSComp.SR.nameofNotPermitted(), m))
+ | _ -> ()
+
| Expr.Val (v,vFlags,m) ->
if cenv.reportErrors then
if v.BaseOrThisInfo = BaseVal then
diff --git a/src/fsharp/PostInferenceChecks.fsi b/src/fsharp/PostInferenceChecks.fsi
index b647dd2cc0a..e25cfed7f96 100644
--- a/src/fsharp/PostInferenceChecks.fsi
+++ b/src/fsharp/PostInferenceChecks.fsi
@@ -10,3 +10,4 @@ open Microsoft.FSharp.Compiler.InfoReader
val testFlagMemberBody : bool ref
val CheckTopImpl : TcGlobals * Import.ImportMap * bool * InfoReader * Tast.CompilationPath list * Tast.CcuThunk * Tastops.DisplayEnv * Tast.ModuleOrNamespaceExprWithSig * Tast.Attribs * (bool * bool) -> bool
+val tryExtractNameOf : Microsoft.FSharp.Compiler.Tast.Expr list -> string option
diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs
index 57320d2205e..a4ee75800d2 100755
--- a/src/fsharp/TastOps.fs
+++ b/src/fsharp/TastOps.fs
@@ -2761,6 +2761,11 @@ let isTypeOfValRef g vref =
// There is an internal version of typeof defined in prim-types.fs that needs to be detected
|| (g.compilingFslib && vref.LogicalName = "typeof")
+let isTypeNameOfValRef g vref =
+ valRefEq g vref g.typenameof_vref
+ // There is an internal version of typenameof defined in prim-types.fs that needs to be detected
+ || (g.compilingFslib && vref.LogicalName = "typenameof")
+
let isSizeOfValRef g vref =
valRefEq g vref g.sizeof_vref
// There is an internal version of typeof defined in prim-types.fs that needs to be detected
@@ -2781,6 +2786,11 @@ let (|TypeOfExpr|_|) g expr =
| Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isTypeOfValRef g vref -> Some ty
| _ -> None
+let (|TypeNameOfExpr|_|) g expr =
+ match expr with
+ | Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isTypeNameOfValRef g vref -> Some ty
+ | _ -> None
+
let (|SizeOfExpr|_|) g expr =
match expr with
| Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isSizeOfValRef g vref -> Some ty
@@ -5911,6 +5921,7 @@ let mkCallUnbox g m ty e1 = mkApps g (typedExprForIntrinsic g
let mkCallUnboxFast g m ty e1 = mkApps g (typedExprForIntrinsic g m g.unbox_fast_info, [[ty]], [ e1 ], m)
let mkCallTypeTest g m ty e1 = mkApps g (typedExprForIntrinsic g m g.istype_info, [[ty]], [ e1 ], m)
let mkCallTypeOf g m ty = mkApps g (typedExprForIntrinsic g m g.typeof_info, [[ty]], [ ], m)
+let mkCallTypeNameOf g m ty = mkApps g (typedExprForIntrinsic g m g.typenameof_info, [[ty]], [ ], m)
let mkCallTypeDefOf g m ty = mkApps g (typedExprForIntrinsic g m g.typedefof_info, [[ty]], [ ], m)
@@ -7568,6 +7579,7 @@ let IsSimpleSyntacticConstantExpr g inputExpr =
| Expr.Op (TOp.UnionCase _,_,[],_) // Nullary union cases
| UncheckedDefaultOfExpr g _
| SizeOfExpr g _
+ | TypeNameOfExpr g _
| TypeOfExpr g _ -> true
// All others are not simple constant expressions
| _ -> false
diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi
index e4719f1b86f..43aaaffa650 100755
--- a/src/fsharp/TastOps.fsi
+++ b/src/fsharp/TastOps.fsi
@@ -1137,6 +1137,7 @@ val mkCallTypeTest : TcGlobals -> range -> TType -> Expr -> Expr
val canUseTypeTestFast : TcGlobals -> TType -> bool
val mkCallTypeOf : TcGlobals -> range -> TType -> Expr
+val mkCallTypeNameOf : TcGlobals -> range -> TType -> Expr
val mkCallTypeDefOf : TcGlobals -> range -> TType -> Expr
val mkCallCreateInstance : TcGlobals -> range -> TType -> Expr
diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs
index a02124d5e42..821f7ddf5da 100755
--- a/src/fsharp/TcGlobals.fs
+++ b/src/fsharp/TcGlobals.fs
@@ -403,6 +403,10 @@ type public TcGlobals =
reraise_vref : ValRef
typeof_info : IntrinsicValRef
typeof_vref : ValRef
+ nameof_info : IntrinsicValRef
+ nameof_vref : ValRef
+ typenameof_info : IntrinsicValRef
+ typenameof_vref : ValRef
methodhandleof_info : IntrinsicValRef
methodhandleof_vref : ValRef
sizeof_vref : ValRef
@@ -929,6 +933,8 @@ let mkTcGlobals (compilingFslib,sysCcu,ilg,fslibCcu,directoryToResolveRelativePa
let reraise_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "reraise" ,None ,Some "Reraise",[vara], ([[unit_ty]],varaTy))
let typeof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typeof" ,None ,Some "TypeOf" ,[vara], ([],system_Type_typ))
+ let typenameof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typenameof" ,None ,Some "TypeNameOf" ,[vara], ([],string_ty))
+ let nameof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "nameof" ,None ,Some "NameOf" ,[vara], ([[varaTy]],string_ty))
let methodhandleof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "methodhandleof" ,None ,Some "MethodHandleOf",[vara;varb],([[varaTy --> varbTy]],system_RuntimeMethodHandle_typ))
let sizeof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "sizeof" ,None ,Some "SizeOf" ,[vara], ([],int_ty))
let unchecked_defaultof_info = makeIntrinsicValRef(fslib_MFOperatorsUnchecked_nleref, "defaultof" ,None ,Some "DefaultOf",[vara], ([],varaTy))
@@ -1383,6 +1389,10 @@ let mkTcGlobals (compilingFslib,sysCcu,ilg,fslibCcu,directoryToResolveRelativePa
reraise_vref = ValRefForIntrinsic reraise_info
methodhandleof_info = methodhandleof_info
methodhandleof_vref = ValRefForIntrinsic methodhandleof_info
+ nameof_info = nameof_info
+ nameof_vref = ValRefForIntrinsic nameof_info
+ typenameof_info = typenameof_info
+ typenameof_vref = ValRefForIntrinsic typenameof_info
typeof_info = typeof_info
typeof_vref = ValRefForIntrinsic typeof_info
sizeof_vref = ValRefForIntrinsic sizeof_info
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs
new file mode 100644
index 00000000000..f71add7dd74
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs
@@ -0,0 +1,7 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on const string
+//This expression does not have a name.
+
+let x = nameof(1+2)
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs
new file mode 100644
index 00000000000..6663899751e
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs
@@ -0,0 +1,8 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on applied functions
+//This expression does not have a name.
+
+let f() = 1
+let x = nameof(f())
+
+exit 0
\ No newline at end of file
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs
new file mode 100644
index 00000000000..f7e104cfe64
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs
@@ -0,0 +1,7 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof can't be used as a function.
+//This expression does not have a name.
+
+let f = nameof
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs
new file mode 100644
index 00000000000..761b23cb3ea
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs
@@ -0,0 +1,8 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on dictionary lookup
+//This expression does not have a name.
+
+let dict = new System.Collections.Generic.Dictionary()
+let b = nameof(dict.[2])
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs
new file mode 100644
index 00000000000..a5144348e05
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs
@@ -0,0 +1,7 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on const int
+//This expression does not have a name.
+
+let x = nameof 1
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs
new file mode 100644
index 00000000000..7fe241fe86f
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs
@@ -0,0 +1,8 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on applied functions
+//This expression does not have a name.
+
+let f x = 1 * x
+let x = nameof(f 2)
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs
new file mode 100644
index 00000000000..5f24456195c
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs
@@ -0,0 +1,9 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on applied functions
+//This expression does not have a name.
+
+let f x y = x y
+let z x = 1 * x
+let b = nameof(f z 1)
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs
new file mode 100644
index 00000000000..4a572a983f3
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs
@@ -0,0 +1,8 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on partially applied functions
+//This expression does not have a name.
+
+let f x y = y * x
+let x = nameof(f 2)
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs
new file mode 100644
index 00000000000..b30f702b1ae
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs
@@ -0,0 +1,7 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof doesn't work on const string
+//This expression does not have a name.
+
+let x = nameof "string"
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs
new file mode 100644
index 00000000000..f959420f99f
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs
@@ -0,0 +1,7 @@
+// #Regression #Conformance #DataExpressions
+// Verify that nameof can't be used as a function.
+//The nameof operator is not allowed in this position.
+
+let curriedFunction x y = x * y
+let b = curriedFunction |> nameof
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst
new file mode 100644
index 00000000000..4b62ea892e7
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst
@@ -0,0 +1,10 @@
+ SOURCE=E_NameOfIntConst.fs # E_NameOfIntConst.fs
+ SOURCE=E_NameOfStringConst.fs # E_NameOfStringConst.fs
+ SOURCE=E_NameOfAppliedFunction.fs # E_NameOfAppliedFunction.fs
+ SOURCE=E_NameOfIntegerAppliedFunction.fs # E_NameOfIntegerAppliedFunction.fs
+ SOURCE=E_NameOfPartiallyAppliedFunction.fs # E_NameOfPartiallyAppliedFunction.fs
+ SOURCE=E_NameOfDictLookup.fs # E_NameOfDictLookup.fs
+ SOURCE=E_NameOfAdditionExpr.fs # E_NameOfAdditionExpr.fs
+ SOURCE=E_NameOfParameterAppliedFunction.fs # E_NameOfParameterAppliedFunction.fs
+ SOURCE=E_NameOfAsAFunction.fs # E_NameOfAsAFunction.fs
+ SOURCE=E_NameOfWithPipe.fs # E_NameOfWithPipe.fs
diff --git a/tests/fsharpqa/Source/test.lst b/tests/fsharpqa/Source/test.lst
index b9391dc0801..7b3b1a46e8a 100644
--- a/tests/fsharpqa/Source/test.lst
+++ b/tests/fsharpqa/Source/test.lst
@@ -236,6 +236,7 @@ Conformance08 Conformance\UnitsOfMeasure\Parenthesis
Conformance08 Conformance\UnitsOfMeasure\Parsing
Conformance08 Conformance\UnitsOfMeasure\TypeChecker
Conformance08 Conformance\UnitsOfMeasure\WithOOP
+Conformance08 Conformance\Expressions\DataExpressions\NameOf
Misc01 ClrFx\PseudoCustomAttributes\AssemblyAlgorithmId
Misc01 ClrFx\PseudoCustomAttributes\AssemblyConfiguration