diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt
index 643cd8eefc..94b86d1ab3 100644
--- a/src/fsharp/FSComp.txt
+++ b/src/fsharp/FSComp.txt
@@ -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."
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."
diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj b/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
index 95492a7e2f..2424b200d0 100644
--- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
+++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj
@@ -107,6 +107,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 0000000000..e545320b14
--- /dev/null
+++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/NameOfTests.fs
@@ -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
+
+[]
+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.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 = ()
+
+ []
+ member this.``single argument method group name lookup`` () =
+ let b = nameof(this.MethodGroup)
+ Assert.AreEqual("MethodGroup",b)
+
+ []
+ member this.``multiple argument method group name lookup`` () =
+ let b = nameof(this.MethodGroup1)
+ Assert.AreEqual("MethodGroup1",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 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)
+
+ []
+ member this.``lookup name of a generic class`` () =
+ let b = nameof System.Collections.Generic.List
+ Assert.AreEqual("List",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.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
index 0fdcc27abe..1a9c882b66 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs
@@ -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)
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
index cf8156e3fc..349fd24646 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs
@@ -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)
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
index 9c63e5a493..cb3d7dc5e7 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs
@@ -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)
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
index 7c003fea40..a9c5d78e17 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs
@@ -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)
diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
index 4f1d01c64b..1530f4a6cd 100644
--- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
+++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs
@@ -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)
diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs
index 9fdfeef402..cd8f607b31 100644
--- a/src/fsharp/FSharp.Core/prim-types.fs
+++ b/src/fsharp/FSharp.Core/prim-types.fs
@@ -4751,6 +4751,9 @@ namespace Microsoft.FSharp.Core
[]
let inline typeof<'T> = BasicInlinedOperations.typeof<'T>
+ []
+ 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 c943999a09..d33c4f0aca 100644
--- a/src/fsharp/FSharp.Core/prim-types.fsi
+++ b/src/fsharp/FSharp.Core/prim-types.fsi
@@ -2320,6 +2320,10 @@ namespace Microsoft.FSharp.Core
[]
val inline typeof<'T> : System.Type
+ /// 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/NameResolution.fs b/src/fsharp/NameResolution.fs
index 3a19aacbeb..1341b81d8f 100644
--- a/src/fsharp/NameResolution.fs
+++ b/src/fsharp/NameResolution.fs
@@ -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
diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs
index d2576906e0..225159f2f7 100644
--- a/src/fsharp/PostInferenceChecks.fs
+++ b/src/fsharp/PostInferenceChecks.fs
@@ -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))
diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs
index e1b6b40693..59fa150906 100644
--- a/src/fsharp/TastOps.fs
+++ b/src/fsharp/TastOps.fs
@@ -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
@@ -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
@@ -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
diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi
index 5fd13620f7..7e06609e1a 100755
--- a/src/fsharp/TastOps.fsi
+++ b/src/fsharp/TastOps.fsi
@@ -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
diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs
index 9c5a5ec530..3a2ecd61dc 100755
--- a/src/fsharp/TcGlobals.fs
+++ b/src/fsharp/TcGlobals.fs
@@ -572,6 +572,8 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d
let v_typeof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typeof" , None , Some "TypeOf" , [vara], ([], v_system_Type_typ))
let v_methodhandleof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "methodhandleof" , None , Some "MethodHandleOf", [vara;varb], ([[varaTy --> varbTy]], v_system_RuntimeMethodHandle_typ))
let v_sizeof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "sizeof" , None , Some "SizeOf" , [vara], ([], v_int_ty))
+ let v_nameof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "nameof" , None , Some "NameOf" , [vara], ([[varaTy]], v_string_ty))
+
let v_unchecked_defaultof_info = makeIntrinsicValRef(fslib_MFOperatorsUnchecked_nleref, "defaultof" , None , Some "DefaultOf", [vara], ([], varaTy))
let v_typedefof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typedefof" , None , Some "TypeDefOf", [vara], ([], v_system_Type_typ))
let v_enum_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "enum" , None , Some "ToEnum" , [vara], ([[v_int_ty]], varaTy))
@@ -1130,6 +1132,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d
member val methodhandleof_vref = ValRefForIntrinsic v_methodhandleof_info
member val typeof_vref = ValRefForIntrinsic v_typeof_info
member val sizeof_vref = ValRefForIntrinsic v_sizeof_info
+ member val nameof_vref = ValRefForIntrinsic v_nameof_info
member val typedefof_vref = ValRefForIntrinsic v_typedefof_info
member val enum_vref = ValRefForIntrinsic v_enum_info
member val enumOfValue_vref = ValRefForIntrinsic v_enumOfValue_info
@@ -1156,15 +1159,15 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d
member val unbox_fast_vref = ValRefForIntrinsic v_unbox_fast_info
member val istype_vref = ValRefForIntrinsic v_istype_info
member val istype_fast_vref = ValRefForIntrinsic v_istype_fast_info
- member val query_source_vref = ValRefForIntrinsic v_query_source_info
- member val query_value_vref = ValRefForIntrinsic v_query_value_info
- member val query_run_value_vref = ValRefForIntrinsic v_query_run_value_info
- member val query_run_enumerable_vref = ValRefForIntrinsic v_query_run_enumerable_info
- member val query_for_vref = ValRefForIntrinsic v_query_for_value_info
- member val query_yield_vref = ValRefForIntrinsic v_query_yield_value_info
- member val query_yield_from_vref = ValRefForIntrinsic v_query_yield_from_value_info
- member val query_select_vref = ValRefForIntrinsic v_query_select_value_info
- member val query_where_vref = ValRefForIntrinsic v_query_where_value_info
+ member val query_source_vref = ValRefForIntrinsic v_query_source_info
+ member val query_value_vref = ValRefForIntrinsic v_query_value_info
+ member val query_run_value_vref = ValRefForIntrinsic v_query_run_value_info
+ member val query_run_enumerable_vref = ValRefForIntrinsic v_query_run_enumerable_info
+ member val query_for_vref = ValRefForIntrinsic v_query_for_value_info
+ member val query_yield_vref = ValRefForIntrinsic v_query_yield_value_info
+ member val query_yield_from_vref = ValRefForIntrinsic v_query_yield_from_value_info
+ member val query_select_vref = ValRefForIntrinsic v_query_select_value_info
+ member val query_where_vref = ValRefForIntrinsic v_query_where_value_info
member val query_zero_vref = ValRefForIntrinsic v_query_zero_value_info
member __.seq_collect_info = v_seq_collect_info
diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs
index 7d5c40cc28..87c222345a 100755
--- a/src/fsharp/TypeChecker.fs
+++ b/src/fsharp/TypeChecker.fs
@@ -8303,36 +8303,93 @@ and delayRest rest mPrior delayed =
let mPriorAndLongId = unionRanges mPrior (rangeOfLid longId)
DelayedDotLookup (rest,mPriorAndLongId) :: delayed
+//-------------------------------------------------------------------------
+// TcNameOfExpr: Typecheck "nameof" expressions
+//-------------------------------------------------------------------------
+and TcNameOfExpr cenv env tpenv expr =
+ match expr with
+ | SynExpr.Ident _
+ | SynExpr.LongIdent(_, LongIdentWithDots _, _, _) as expr ->
+ ignore (TcExprOfUnknownType cenv env tpenv expr)
+ | SynExpr.TypeApp (expr, _, types, _, _, _, m) as fullExpr ->
+ let idents =
+ match expr with
+ | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> idents
+ | SynExpr.Ident ident -> [ident]
+ | _ -> []
+ match idents with
+ | [] -> ()
+ | idents ->
+ // try to type check it as type application, like A.B.C>
+ match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInType OpenQualified env.eNameResEnv env.eAccessRights idents (TypeNameResolutionStaticArgsInfo.FromTyArgs types.Length) PermitDirectReferenceToGeneratedType.No with
+ | ResultOrException.Result tcref ->
+ ignore (TcTypeApp cenv NewTyparsOK NoCheckCxs ItemOccurence.UseInType env tpenv m tcref [] types)
+ | _ ->
+ // now try to check it as generic function, like func>
+ ignore (TcExprOfUnknownType cenv env tpenv fullExpr)
+ | _ -> ()
//-------------------------------------------------------------------------
// TcFunctionApplicationThen: Typecheck "expr x" + projections
//-------------------------------------------------------------------------
and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty (synArg: SynExpr) atomicFlag delayed =
-
let denv = env.DisplayEnv
let mArg = synArg.Range
let mFunExpr = expr.Range
+
+ /// Finds last ident of LongIdent in SynExpr.Ident, LongIdent or TypeApp.
+ /// Type checkes the whole thing as it goes in order to:
+ ///
+ /// * ensure we pass well typed things to `nameof`
+ ///
+ /// * not to loose `FSharpSymbolUse` for `nameof` argument, because we erase it with `Expr.Const(Const.String ...)` further in this function.
+ let (|LastPartOfLongIdentStripParens|_|) expr =
+ let rec findIdents expr =
+ match expr with
+ | SynExpr.Ident ident -> Some ident
+ | SynExpr.TypeApp (expr = expr) -> findIdents expr
+ | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents
+ | _ -> None
+ findIdents expr
+
+ let rec stripParens expr =
+ match expr with
+ | SynExpr.Paren(expr, _, _, _) -> stripParens expr
+ | _ -> expr
+
// If the type of 'synArg' unifies as a function type, then this is a function application, otherwise
// it is an error or a computation expression
match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr exprty with
| Some (domainTy,resultTy) ->
-
- // Notice the special case 'seq { ... }'. In this case 'seq' is actually a function in the F# library.
- // Set a flag in the syntax tree to say we noticed a leading 'seq'
- match synArg with
- | SynExpr.CompExpr (false,isNotNakedRefCell,_comp,_m) ->
- isNotNakedRefCell :=
- !isNotNakedRefCell
- ||
- (match expr with
- | ApplicableExpr(_,Expr.Op(TOp.Coerce,_,[Expr.App(Expr.Val(vf,_,_),_,_,_,_)],_),_) when valRefEq cenv.g vf cenv.g.seq_vref -> true
- | _ -> false)
- | _ -> ()
-
- let arg,tpenv = TcExpr cenv domainTy env tpenv synArg
- let exprAndArg = buildApp cenv expr exprty arg mExprAndArg
- TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed
+ match expr with
+ | ApplicableExpr(_, NameOfExpr cenv.g _, _) ->
+ let cleanSynArg = stripParens synArg
+ match cleanSynArg with
+ | LastPartOfLongIdentStripParens lastIdent ->
+ TcNameOfExpr cenv env tpenv cleanSynArg
+ let r = expr.Range
+ // generate fake `range` for the constant the `nameof(..)` we are substituting
+ let constRange = mkRange r.FileName r.Start (mkPos r.StartLine (r.StartColumn + lastIdent.idText.Length + 2)) // `2` are for quotes
+ TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(lastIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed
+ | _ -> error (Error(FSComp.SR.expressionHasNoName(), cleanSynArg.Range))
+ | _ ->
+ // Notice the special case 'seq { ... }'. In this case 'seq' is actually a function in the F# library.
+ // Set a flag in the syntax tree to say we noticed a leading 'seq'
+ match synArg with
+ | SynExpr.CompExpr (false,isNotNakedRefCell,_comp,_m) ->
+ isNotNakedRefCell :=
+ !isNotNakedRefCell
+ ||
+ (match expr with
+ | ApplicableExpr(_,Expr.Op(TOp.Coerce,_,[SeqExpr cenv.g],_),_) -> true
+ | _ -> false)
+ | _ -> ()
+
+ let arg,tpenv = TcExpr cenv domainTy env tpenv synArg
+ let exprAndArg = buildApp cenv expr exprty arg mExprAndArg
+ TcDelayed cenv overallTy env tpenv mExprAndArg exprAndArg resultTy atomicFlag delayed
+
| None ->
// OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }'
match synArg with
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 0000000000..2e082efb21
--- /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
+//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 0000000000..49095e69ed
--- /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
+//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 0000000000..76acc5a4bb
--- /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.
+//First-class uses of the 'nameof' operator is not permitted
+
+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 0000000000..0a58a4bba7
--- /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
+//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 0000000000..6b67627d67
--- /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
+//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 0000000000..4fe8db0547
--- /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
+//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 0000000000..c24f7343a1
--- /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
+//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 0000000000..71b66493b5
--- /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
+//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 0000000000..1190f1e8b3
--- /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
+//Expression does not have a name.
+
+let x = nameof "string"
+
+exit 0
diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs
new file mode 100644
index 0000000000..2f998cbb17
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs
@@ -0,0 +1,6 @@
+// #Regression #Conformance #DataExpressions
+// Verify that passing unresolvable symbol name results with compilation error.
+//The value, constructor, namespace or type 'Unknown' is not defined.
+
+let b = nameof System.Collections.Generic.Unknown
+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 0000000000..cae86f5ea0
--- /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.
+//First-class uses of the 'nameof' operator is not permitted.
+
+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 0000000000..7e08cf92ea
--- /dev/null
+++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst
@@ -0,0 +1,11 @@
+ 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
+ SOURCE=E_NameOfUnresolvableName.fs # E_NameOfUnresolvableName.fs
diff --git a/tests/fsharpqa/Source/test.lst b/tests/fsharpqa/Source/test.lst
index e7fe7ebd14..aa6480ba9a 100644
--- a/tests/fsharpqa/Source/test.lst
+++ b/tests/fsharpqa/Source/test.lst
@@ -238,6 +238,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