From d380a0ef9e785467c9b29dd32784ee21e71757f0 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 16:24:39 +0300 Subject: [PATCH 01/25] substitute 'nameof()` with `Conts()` --- src/fsharp/TypeChecker.fs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 614ca668d8..952e4c3b56 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8271,6 +8271,17 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | SynExpr.CompExpr (false,_isNotNakedRefCell,comp,_m) -> let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (isNil idents) -> + match expr with + // `nameof` operator + | ApplicableExpr (_, Expr.App(Expr.Const(Const.String("nameof"), _, _), _, _, _, _), _) -> // no idea really what shape we should match on here, will check in debugger + let argIdent = List.last idents + 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 + argIdent.idText.Length + 2)) // `2` are for quotes + TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed + | _ -> + error (NotAFunction(denv,overallTy,mFunExpr,mArg)) | _ -> error (NotAFunction(denv,overallTy,mFunExpr,mArg)) From 223d3137188d5c184c1be2c7640233183f447181 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 16:42:58 +0300 Subject: [PATCH 02/25] Implementing basic nameof and typenameof operators Conflicts: src/fsharp/FSComp.txt src/fsharp/FSharp.Core.Unittests/SurfaceArea.Silverlight.2.0.fs src/fsharp/FSharp.Core.Unittests/SurfaceArea.net20.fs src/fsharp/PostInferenceChecks.fs src/fsharp/TastOps.fs src/fsharp/TcGlobals.fs --- src/fsharp/FSComp.txt | 4 +- .../FSharp.Core.Unittests.fsproj | 1 + .../Microsoft.FSharp.Core/NameOfTests.fs | 248 ++++++++++++++++++ .../SurfaceArea.net40.fs | 2 + .../SurfaceArea.portable259.fs | 2 + .../SurfaceArea.portable47.fs | 2 + .../SurfaceArea.portable7.fs | 2 + .../SurfaceArea.portable78.fs | 2 + src/fsharp/FSharp.Core/prim-types.fs | 6 + src/fsharp/FSharp.Core/prim-types.fsi | 9 + src/fsharp/Optimizer.fs | 33 ++- src/fsharp/PostInferenceChecks.fs | 35 ++- src/fsharp/PostInferenceChecks.fsi | 1 + src/fsharp/TastOps.fs | 12 + src/fsharp/TastOps.fsi | 1 + src/fsharp/TcGlobals.fs | 10 + .../NameOf/E_NameOfAdditionExpr.fs | 7 + .../NameOf/E_NameOfAppliedFunction.fs | 8 + .../NameOf/E_NameOfAsAFunction.fs | 7 + .../NameOf/E_NameOfDictLookup.fs | 8 + .../NameOf/E_NameOfIntConst.fs | 7 + .../NameOf/E_NameOfIntegerAppliedFunction.fs | 8 + .../E_NameOfParameterAppliedFunction.fs | 9 + .../E_NameOfPartiallyAppliedFunction.fs | 8 + .../NameOf/E_NameOfStringConst.fs | 7 + .../NameOf/E_NameOfWithPipe.fs | 7 + .../DataExpressions/NameOf/env.lst | 10 + tests/fsharpqa/Source/test.lst | 1 + 28 files changed, 453 insertions(+), 4 deletions(-) create mode 100644 src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/NameOfTests.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 32412f95c2..bb4f3ebfbb 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1332,4 +1332,6 @@ tcTupleStructMismatch,"One tuple type is a struct tuple, the other is a referenc 3211,DefaultParameterValueNotAppropriateForArgument,"The default value does not have the same type as the argument. The DefaultParameterValue attribute and any Optional attribute will be ignored. Note: 'null' needs to be annotated with the correct type, e.g. 'DefaultParameterValue(null:obj)'." tcGlobalsSystemTypeNotFound,"The system type '%s' was required but no referenced system DLL contained this type" 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" \ No newline at end of file +3214,methodIsNotStatic,"Method or object constructor '%s' is not static" +3215,expressionHasNoName,"This expression does not have a name." +3216,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 278c681eb3..cbd6958adc 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core.Unittests.fsproj @@ -111,6 +111,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..1c82fc8ef0 --- /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.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index bacb36eb34..d5a9e905f8 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs @@ -2632,8 +2632,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 cf8156e3fc..b618478397 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs @@ -2604,8 +2604,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 01a15aff35..8078e44f42 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs @@ -2606,8 +2606,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 7c003fea40..a3db8830ef 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs @@ -2617,8 +2617,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 4f1d01c64b..799616f508 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs @@ -2604,8 +2604,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 9fcc440268..4feb09cf01 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,6 +4748,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 c943999a09..077dbd49e3 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2320,6 +2320,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 ee2c88c1b0..e237c02df2 100644 --- a/src/fsharp/Optimizer.fs +++ b/src/fsharp/Optimizer.fs @@ -1185,7 +1185,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 @@ -2501,6 +2501,37 @@ 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:TType):: _ -> + let name = + match typeName with + | TType_forall (_tps,ty) -> ty.ToString() + | TType_app (tcref, _) -> tcref.CompiledRepresentationForNamedType.FullName + | TType_tuple tinst -> "(" + String.concat "," (List.map string tinst) + ")" + | TType_fun (d,r) -> "(" + string d + " -> " + string r + ")" + | TType_ucase (uc,_) -> uc.CaseName + | TType_var tp -> tp.DisplayName + | TType_measure ms -> sprintf "%A" ms + + 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 0eb6936f0e..f2dbcd6b8a 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -507,6 +507,27 @@ let CheckMultipleInterfaceInstantiations cenv interfaces m = let rec CheckExprNoByrefs (cenv:cenv) (env:env) expr = CheckExpr cenv env expr NoByrefs +// tries to extract the name of an expression +let tryExtractNameOf args = + match args with + | [Expr.App(Expr.Val(r,_,_),_,_,Expr.Const(constant,_,_)::_,_)] -> + if r.CompiledName.StartsWith("get_") && constant = Const.Unit then // TODO: We need a better way to find static property getters + Some(r.CompiledName.Substring(4)) + else + None // the function was applied + | [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 + /// Check a value and CheckVal (cenv:cenv) (env:env) v m context = if cenv.reportErrors then @@ -536,8 +557,18 @@ and CheckExpr (cenv:cenv) (env:env) expr (context:ByrefContext) = CheckExpr cenv env body context | 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 b647dd2cc0..e25cfed7f9 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 f7d91a6f6d..c6d779165e 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2879,6 +2879,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 @@ -2899,6 +2904,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 @@ -6079,6 +6089,7 @@ let mkCallUnboxFast (g:TcGlobals) m ty e1 = mkApps g (typedExprFor let mkCallTypeTest (g:TcGlobals) m ty e1 = mkApps g (typedExprForIntrinsic g m g.istype_info, [[ty]], [ e1 ], m) let mkCallTypeOf (g:TcGlobals) m ty = mkApps g (typedExprForIntrinsic g m g.typeof_info, [[ty]], [ ], m) let mkCallTypeDefOf (g:TcGlobals) m ty = mkApps g (typedExprForIntrinsic g m g.typedefof_info, [[ty]], [ ], m) +let mkCallTypeNameOf g m ty = mkApps g (typedExprForIntrinsic g m g.typenameof_info, [[ty]], [ ], m) let mkCallDispose (g:TcGlobals) m ty e1 = mkApps g (typedExprForIntrinsic g m g.dispose_info, [[ty]], [ e1 ], m) @@ -7740,6 +7751,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 4ce0aab7a1..eafd901920 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1179,6 +1179,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 44a70385f8..3303093ae1 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -162,6 +162,10 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d // The helper to find system types amongst referenced DLLs tryFindSysTypeCcu, emitDebugInfoInQuotations: bool, usesMscorlib: bool, noDebugData: bool) = + nameof_info : IntrinsicValRef + nameof_vref : ValRef + typenameof_info : IntrinsicValRef + typenameof_vref : ValRef let vara = NewRigidTypar "a" envRange let varb = NewRigidTypar "b" envRange @@ -569,6 +573,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 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 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)) @@ -910,6 +916,10 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member val system_MarshalByRefObject_typ = tryMkSysNonGenericTy sys "MarshalByRefObject" member __.system_Reflection_MethodInfo_typ = v_system_Reflection_MethodInfo_typ + nameof_info = nameof_info + nameof_vref = ValRefForIntrinsic nameof_info + typenameof_info = typenameof_info + typenameof_vref = ValRefForIntrinsic typenameof_info member val system_Array_tcref = findSysTyconRef sys "Array" member val system_Object_tcref = findSysTyconRef sys "Object" 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..64c41f78e3 --- /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 0000000000..3a812478a8 --- /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 0000000000..6411781236 --- /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 0000000000..ff9915209f --- /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 0000000000..89aa6ae3b1 --- /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 0000000000..099ed0ad53 --- /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 0000000000..ad3f9772eb --- /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 0000000000..3aa6244c07 --- /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 0000000000..b225f8ea62 --- /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 0000000000..7973767fbc --- /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 0000000000..4b62ea892e --- /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 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 From 529cc6fd9f54abbbd98f3b5be8093c8eb873b0b4 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 16:44:42 +0300 Subject: [PATCH 03/25] Apply feedback --- src/fsharp/Optimizer.fs | 26 +++++++++---------- src/fsharp/PostInferenceChecks.fs | 11 +++++--- .../NameOf/E_NameOfAdditionExpr.fs | 2 +- .../NameOf/E_NameOfAppliedFunction.fs | 2 +- .../NameOf/E_NameOfAsAFunction.fs | 2 +- .../NameOf/E_NameOfDictLookup.fs | 2 +- .../NameOf/E_NameOfIntConst.fs | 2 +- .../NameOf/E_NameOfIntegerAppliedFunction.fs | 2 +- .../E_NameOfParameterAppliedFunction.fs | 2 +- .../E_NameOfPartiallyAppliedFunction.fs | 2 +- .../NameOf/E_NameOfStringConst.fs | 2 +- .../NameOf/E_NameOfWithPipe.fs | 2 +- 12 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/fsharp/Optimizer.fs b/src/fsharp/Optimizer.fs index e237c02df2..6caf53216a 100644 --- a/src/fsharp/Optimizer.fs +++ b/src/fsharp/Optimizer.fs @@ -2304,8 +2304,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 @@ -2514,17 +2523,8 @@ and TryDevirtualizeApplication cenv env (f,tyargs,args,m) = // 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:TType):: _ -> - let name = - match typeName with - | TType_forall (_tps,ty) -> ty.ToString() - | TType_app (tcref, _) -> tcref.CompiledRepresentationForNamedType.FullName - | TType_tuple tinst -> "(" + String.concat "," (List.map string tinst) + ")" - | TType_fun (d,r) -> "(" + string d + " -> " + string r + ")" - | TType_ucase (uc,_) -> uc.CaseName - | TType_var tp -> tp.DisplayName - | TType_measure ms -> sprintf "%A" ms - + | typeName:: _ -> + let name = GetNameFromTypeName cenv.g m typeName Some(Expr.Const(Const.String name, m, cenv.g.string_ty), { TotalSize = 1 FunctionSize = 1 diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index f2dbcd6b8a..ee16d38962 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -511,10 +511,13 @@ let rec CheckExprNoByrefs (cenv:cenv) (env:env) expr = let tryExtractNameOf args = match args with | [Expr.App(Expr.Val(r,_,_),_,_,Expr.Const(constant,_,_)::_,_)] -> - if r.CompiledName.StartsWith("get_") && constant = Const.Unit then // TODO: We need a better way to find static property getters - Some(r.CompiledName.Substring(4)) - else - None // the function was applied + 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 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs index 64c41f78e3..f71add7dd7 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//This expression does not have a name. let x = nameof(1+2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs index 3a812478a8..6663899751 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f() = 1 let x = nameof(f()) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs index 6411781236..f7e104cfe6 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof can't be used as a function. -//This expression does not have a name. +//This expression does not have a name. let f = nameof diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs index ff9915209f..761b23cb3e 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on dictionary lookup -//This expression does not have a name. +//This expression does not have a name. let dict = new System.Collections.Generic.Dictionary() let b = nameof(dict.[2]) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs index 89aa6ae3b1..a5144348e0 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const int -//This expression does not have a name. +//This expression does not have a name. let x = nameof 1 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs index 099ed0ad53..7fe241fe86 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f x = 1 * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs index ad3f9772eb..5f24456195 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f x y = x y let z x = 1 * x diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs index 3aa6244c07..4a572a983f 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on partially applied functions -//This expression does not have a name. +//This expression does not have a name. let f x y = y * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs index b225f8ea62..b30f702b1a 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//This expression does not have a name. let x = nameof "string" diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs index 7973767fbc..f959420f99 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof can't be used as a function. -//The nameof operator is not allowed in this position. +//The nameof operator is not allowed in this position. let curriedFunction x y = x * y let b = curriedFunction |> nameof From f3c4ba59606b081c9b9ce400c1129b00f7726276 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 16:51:14 +0300 Subject: [PATCH 04/25] Revert "Apply feedback" This reverts commit 529cc6fd9f54abbbd98f3b5be8093c8eb873b0b4. --- src/fsharp/Optimizer.fs | 26 +++++++++++++------------- src/fsharp/PostInferenceChecks.fs | 11 ++++------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/fsharp/Optimizer.fs b/src/fsharp/Optimizer.fs index 6caf53216a..e237c02df2 100644 --- a/src/fsharp/Optimizer.fs +++ b/src/fsharp/Optimizer.fs @@ -2304,17 +2304,8 @@ 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 @@ -2523,8 +2514,17 @@ and TryDevirtualizeApplication cenv env (f,tyargs,args,m) = // 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 + | (typeName:TType):: _ -> + let name = + match typeName with + | TType_forall (_tps,ty) -> ty.ToString() + | TType_app (tcref, _) -> tcref.CompiledRepresentationForNamedType.FullName + | TType_tuple tinst -> "(" + String.concat "," (List.map string tinst) + ")" + | TType_fun (d,r) -> "(" + string d + " -> " + string r + ")" + | TType_ucase (uc,_) -> uc.CaseName + | TType_var tp -> tp.DisplayName + | TType_measure ms -> sprintf "%A" ms + Some(Expr.Const(Const.String name, m, cenv.g.string_ty), { TotalSize = 1 FunctionSize = 1 diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index ee16d38962..f2dbcd6b8a 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -511,13 +511,10 @@ let rec CheckExprNoByrefs (cenv:cenv) (env:env) expr = let tryExtractNameOf args = match args with | [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 + if r.CompiledName.StartsWith("get_") && constant = Const.Unit then // TODO: We need a better way to find static property getters + Some(r.CompiledName.Substring(4)) + else + None // the function was applied | [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 From 8fd039239c427df0c4974f8995388431f711f396 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 16:54:38 +0300 Subject: [PATCH 05/25] Revert "Implementing basic nameof and typenameof operators" This reverts commit 223d3137188d5c184c1be2c7640233183f447181. Conflicts: tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs --- src/fsharp/FSharp.Core/prim-types.fs | 6 ----- src/fsharp/FSharp.Core/prim-types.fsi | 9 ------- src/fsharp/Optimizer.fs | 33 +------------------------ src/fsharp/PostInferenceChecks.fs | 35 ++------------------------- src/fsharp/PostInferenceChecks.fsi | 1 - src/fsharp/TastOps.fs | 12 --------- src/fsharp/TastOps.fsi | 1 - src/fsharp/TcGlobals.fs | 10 -------- 8 files changed, 3 insertions(+), 104 deletions(-) diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 4feb09cf01..9fcc440268 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,12 +4748,6 @@ 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 077dbd49e3..c943999a09 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2320,15 +2320,6 @@ 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 e237c02df2..ee2c88c1b0 100644 --- a/src/fsharp/Optimizer.fs +++ b/src/fsharp/Optimizer.fs @@ -1185,7 +1185,7 @@ let AbstractAndRemapModulInfo msg g m (repackage,hidden) info = info //------------------------------------------------------------------------- -// Misc helpers +// Misc helerps //------------------------------------------------------------------------- // Mark some variables (the ones we introduce via abstractBigTargets) as don't-eliminate @@ -2501,37 +2501,6 @@ 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:TType):: _ -> - let name = - match typeName with - | TType_forall (_tps,ty) -> ty.ToString() - | TType_app (tcref, _) -> tcref.CompiledRepresentationForNamedType.FullName - | TType_tuple tinst -> "(" + String.concat "," (List.map string tinst) + ")" - | TType_fun (d,r) -> "(" + string d + " -> " + string r + ")" - | TType_ucase (uc,_) -> uc.CaseName - | TType_var tp -> tp.DisplayName - | TType_measure ms -> sprintf "%A" ms - - 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 f2dbcd6b8a..0eb6936f0e 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -507,27 +507,6 @@ let CheckMultipleInterfaceInstantiations cenv interfaces m = let rec CheckExprNoByrefs (cenv:cenv) (env:env) expr = CheckExpr cenv env expr NoByrefs -// tries to extract the name of an expression -let tryExtractNameOf args = - match args with - | [Expr.App(Expr.Val(r,_,_),_,_,Expr.Const(constant,_,_)::_,_)] -> - if r.CompiledName.StartsWith("get_") && constant = Const.Unit then // TODO: We need a better way to find static property getters - Some(r.CompiledName.Substring(4)) - else - None // the function was applied - | [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 - /// Check a value and CheckVal (cenv:cenv) (env:env) v m context = if cenv.reportErrors then @@ -557,18 +536,8 @@ and CheckExpr (cenv:cenv) (env:env) expr (context:ByrefContext) = CheckExpr cenv env body context | Expr.Const (_,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)) - | _ -> () - + CheckTypePermitByrefs cenv env m ty + | 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 e25cfed7f9..b647dd2cc0 100644 --- a/src/fsharp/PostInferenceChecks.fsi +++ b/src/fsharp/PostInferenceChecks.fsi @@ -10,4 +10,3 @@ 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 c6d779165e..f7d91a6f6d 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2879,11 +2879,6 @@ 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 @@ -2904,11 +2899,6 @@ 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 @@ -6089,7 +6079,6 @@ let mkCallUnboxFast (g:TcGlobals) m ty e1 = mkApps g (typedExprFor let mkCallTypeTest (g:TcGlobals) m ty e1 = mkApps g (typedExprForIntrinsic g m g.istype_info, [[ty]], [ e1 ], m) let mkCallTypeOf (g:TcGlobals) m ty = mkApps g (typedExprForIntrinsic g m g.typeof_info, [[ty]], [ ], m) let mkCallTypeDefOf (g:TcGlobals) m ty = mkApps g (typedExprForIntrinsic g m g.typedefof_info, [[ty]], [ ], m) -let mkCallTypeNameOf g m ty = mkApps g (typedExprForIntrinsic g m g.typenameof_info, [[ty]], [ ], m) let mkCallDispose (g:TcGlobals) m ty e1 = mkApps g (typedExprForIntrinsic g m g.dispose_info, [[ty]], [ e1 ], m) @@ -7751,7 +7740,6 @@ 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 eafd901920..4ce0aab7a1 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1179,7 +1179,6 @@ 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 3303093ae1..44a70385f8 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -162,10 +162,6 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d // The helper to find system types amongst referenced DLLs tryFindSysTypeCcu, emitDebugInfoInQuotations: bool, usesMscorlib: bool, noDebugData: bool) = - nameof_info : IntrinsicValRef - nameof_vref : ValRef - typenameof_info : IntrinsicValRef - typenameof_vref : ValRef let vara = NewRigidTypar "a" envRange let varb = NewRigidTypar "b" envRange @@ -573,8 +569,6 @@ 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 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 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)) @@ -916,10 +910,6 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member val system_MarshalByRefObject_typ = tryMkSysNonGenericTy sys "MarshalByRefObject" member __.system_Reflection_MethodInfo_typ = v_system_Reflection_MethodInfo_typ - nameof_info = nameof_info - nameof_vref = ValRefForIntrinsic nameof_info - typenameof_info = typenameof_info - typenameof_vref = ValRefForIntrinsic typenameof_info member val system_Array_tcref = findSysTyconRef sys "Array" member val system_Object_tcref = findSysTyconRef sys "Object" From 77c8f779042416c99d17cb6d88cadca847690e43 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 20:07:39 +0300 Subject: [PATCH 06/25] revert nameof and typenameof functions to FSharp.Core --- src/fsharp/FSharp.Core/prim-types.fs | 6 ++++++ src/fsharp/FSharp.Core/prim-types.fsi | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 9fcc440268..4feb09cf01 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,6 +4748,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 c943999a09..a13dbdad11 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2320,6 +2320,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. [] From 3070c1dd4718ded17b213b2d8a20ec6bd854541d Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 22:28:16 +0300 Subject: [PATCH 07/25] wip --- src/fsharp/TastOps.fs | 18 +++++++++++++++++ src/fsharp/TcGlobals.fs | 5 +++++ src/fsharp/TypeChecker.fs | 42 ++++++++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index f7d91a6f6d..3400b9cd1a 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2884,6 +2884,16 @@ 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 isTypeNameOfValRef g vref = + valRefEq g vref g.typenameof_vref + // There is an internal version of typeof defined in prim-types.fs that needs to be detected + || (g.compilingFslib && vref.LogicalName = "typenameof") + 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 @@ -2909,7 +2919,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 (|TypeNameOfExpr|_|) g expr = + match expr with + | Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isTypeNameOfValRef g vref -> Some ty + | _ -> None //-------------------------------------------------------------------------- // DEBUG layout diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index 44a70385f8..6c49417edc 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -569,6 +569,9 @@ 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_typenameof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typenameof" , None , Some "TypeNameOf" ,[vara], ([], v_string_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)) @@ -1121,6 +1124,8 @@ 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 typenameof_vref = ValRefForIntrinsic v_typenameof_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 diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 952e4c3b56..23d9fee620 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8249,22 +8249,32 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // 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, synArg with + | (ApplicableExpr(_, Expr.Val(vref,_,_), _), SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _)) + when valRefEq cenv.g vref cenv.g.nameof_vref && not (isNil idents) -> + + let argIdent = List.last idents + 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 + argIdent.idText.Length + 2)) // `2` are for quotes + TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed + | _ -> + // 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 + | None -> // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' match synArg with From b3e712d165a1093dafa180884ca1d3d8a58bed72 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 18 Jan 2017 23:40:58 +0300 Subject: [PATCH 08/25] it works --- src/fsharp/TypeChecker.fs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 23d9fee620..d0063f987b 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8241,19 +8241,27 @@ and delayRest rest mPrior delayed = //------------------------------------------------------------------------- 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 + + let (|LastIdentOfLongIdentStripPars|_|) expr = + let rec stripParens expr = + match expr with + | SynExpr.Paren(expr, _, _, _) -> stripParens expr + | _ -> expr + + match stripParens expr with + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents + | _ -> None + // 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) -> match expr, synArg with - | (ApplicableExpr(_, Expr.Val(vref,_,_), _), SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _)) - when valRefEq cenv.g vref cenv.g.nameof_vref && not (isNil idents) -> - - let argIdent = List.last idents + | (ApplicableExpr(_, Expr.App(Expr.Val(vref,_,_),_,_,_,_), _), LastIdentOfLongIdentStripPars argIdent) + when valRefEq cenv.g vref cenv.g.nameof_vref -> 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 + argIdent.idText.Length + 2)) // `2` are for quotes From 7832be59b5354899a35fef054256beef3a85b627 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 10:32:59 +0300 Subject: [PATCH 09/25] refactoring --- src/fsharp/TastOps.fs | 9 +++++++-- src/fsharp/TastOps.fsi | 3 +++ src/fsharp/TypeChecker.fs | 18 +++--------------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 3400b9cd1a..ca51d51df5 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2891,12 +2891,12 @@ let isNameOfValRef g vref = let isTypeNameOfValRef g vref = valRefEq g vref g.typenameof_vref - // There is an internal version of typeof defined in prim-types.fs that needs to be detected + // There is an internal version of namef defined in prim-types.fs that needs to be detected || (g.compilingFslib && vref.LogicalName = "typenameof") 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 + // There is an internal version of typenameof defined in prim-types.fs that needs to be detected || (g.compilingFslib && vref.LogicalName = "typedefof") let (|UncheckedDefaultOfExpr|_|) g expr = @@ -2929,6 +2929,11 @@ let (|TypeNameOfExpr|_|) g expr = | Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isTypeNameOfValRef 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 //--------------------------------------------------------------------------- diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index 4ce0aab7a1..eaebc6cb90 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1409,6 +1409,9 @@ 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 (|TypeNameOfExpr|_|) : 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/TypeChecker.fs b/src/fsharp/TypeChecker.fs index d0063f987b..a8a15e8f31 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8245,7 +8245,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( let mArg = synArg.Range let mFunExpr = expr.Range - let (|LastIdentOfLongIdentStripPars|_|) expr = + let (|LastPartOfLongIdentStripParens|_|) expr = let rec stripParens expr = match expr with | SynExpr.Paren(expr, _, _, _) -> stripParens expr @@ -8260,8 +8260,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr exprty with | Some (domainTy,resultTy) -> match expr, synArg with - | (ApplicableExpr(_, Expr.App(Expr.Val(vref,_,_),_,_,_,_), _), LastIdentOfLongIdentStripPars argIdent) - when valRefEq cenv.g vref cenv.g.nameof_vref -> + | (ApplicableExpr(_, NameOfExpr cenv.g _, _), LastPartOfLongIdentStripParens argIdent) -> 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 + argIdent.idText.Length + 2)) // `2` are for quotes @@ -8275,7 +8274,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( !isNotNakedRefCell || (match expr with - | ApplicableExpr(_,Expr.Op(TOp.Coerce,_,[Expr.App(Expr.Val(vf,_,_),_,_,_,_)],_),_) when valRefEq cenv.g vf cenv.g.seq_vref -> true + | ApplicableExpr(_,Expr.Op(TOp.Coerce,_,[SeqExpr cenv.g],_),_) -> true | _ -> false) | _ -> () @@ -8289,17 +8288,6 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | SynExpr.CompExpr (false,_isNotNakedRefCell,comp,_m) -> let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed - | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (isNil idents) -> - match expr with - // `nameof` operator - | ApplicableExpr (_, Expr.App(Expr.Const(Const.String("nameof"), _, _), _, _, _, _), _) -> // no idea really what shape we should match on here, will check in debugger - let argIdent = List.last idents - 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 + argIdent.idText.Length + 2)) // `2` are for quotes - TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed - | _ -> - error (NotAFunction(denv,overallTy,mFunExpr,mArg)) | _ -> error (NotAFunction(denv,overallTy,mFunExpr,mArg)) From 65817902474e852393f5ddcdf09a6bed0f9cd572 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 10:52:05 +0300 Subject: [PATCH 10/25] make it work on simple `Ident`s it raises a proper error if applicated to non (Long)Ident arg --- src/fsharp/FSComp.txt | 1 + src/fsharp/TypeChecker.fs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index bb4f3ebfbb..03f9d02edd 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1335,3 +1335,4 @@ tcGlobalsSystemTypeNotFound,"The system type '%s' was required but no referenced 3214,methodIsNotStatic,"Method or object constructor '%s' is not static" 3215,expressionHasNoName,"This expression does not have a name." 3216,nameofNotPermitted,"The nameof operator is not allowed in this position." +3217,wrongNameofArgument,"Only identifiers are allowed as argument for nameof operator." \ No newline at end of file diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index a8a15e8f31..cd16bfc05a 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8252,6 +8252,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | _ -> expr match stripParens expr with + | SynExpr.Ident ident -> Some ident | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents | _ -> None @@ -8259,12 +8260,15 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // it is an error or a computation expression match UnifyFunctionTypeUndoIfFailed cenv denv mFunExpr exprty with | Some (domainTy,resultTy) -> - match expr, synArg with - | (ApplicableExpr(_, NameOfExpr cenv.g _, _), LastPartOfLongIdentStripParens argIdent) -> - 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 + argIdent.idText.Length + 2)) // `2` are for quotes - TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed + match expr with + | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> + match synArg with + | LastPartOfLongIdentStripParens argIdent -> + 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 + argIdent.idText.Length + 2)) // `2` are for quotes + TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed + | _ -> error (Error(FSComp.SR.wrongNameofArgument(), synArg.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' From 0f5165f6a1c7887754646e169031939ffc6487f4 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 12:49:41 +0300 Subject: [PATCH 11/25] use proper error message --- src/fsharp/FSComp.txt | 3 +-- src/fsharp/TypeChecker.fs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 03f9d02edd..e888d00c17 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1334,5 +1334,4 @@ 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,expressionHasNoName,"This expression does not have a name." -3216,nameofNotPermitted,"The nameof operator is not allowed in this position." -3217,wrongNameofArgument,"Only identifiers are allowed as argument for nameof operator." \ No newline at end of file +3216,nameofNotPermitted,"The nameof operator is not allowed in this position." \ No newline at end of file diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index cd16bfc05a..8cb13bc1d4 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8268,7 +8268,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // generate fake `range` for the constant the `nameof(..)` we are substituting let constRange = mkRange r.FileName r.Start (mkPos r.StartLine (r.StartColumn + argIdent.idText.Length + 2)) // `2` are for quotes TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed - | _ -> error (Error(FSComp.SR.wrongNameofArgument(), synArg.Range)) + | _ -> error (Error(FSComp.SR.expressionHasNoName(), synArg.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' From 22898adc81938c9b128f6b5b61de141d62503190 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 13:17:13 +0300 Subject: [PATCH 12/25] restrict using `nameof` operator as first class --- src/fsharp/FSComp.txt | 3 ++- src/fsharp/PostInferenceChecks.fs | 1 + src/fsharp/TastOps.fs | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index e888d00c17..ce5fa7b0eb 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1334,4 +1334,5 @@ 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,expressionHasNoName,"This expression does not have a name." -3216,nameofNotPermitted,"The nameof operator is not allowed in this position." \ No newline at end of file +3216,nameofNotPermitted,"The nameof operator is not allowed in this position." +3217,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted" \ No newline at end of file diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index 0eb6936f0e..eed9d56f60 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 ca51d51df5..39b06fd979 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -7763,7 +7763,9 @@ let IsSimpleSyntacticConstantExpr g inputExpr = | Expr.Op (TOp.UnionCase _,_,[],_) // Nullary union cases | UncheckedDefaultOfExpr g _ | SizeOfExpr g _ - | TypeOfExpr g _ -> true + | TypeOfExpr g _ + | NameOfExpr g _ + | TypeNameOfExpr g _ -> true // All others are not simple constant expressions | _ -> false From e5033af78a949eb5ad998b9209eb8dcf9be4b78d Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 13:50:30 +0300 Subject: [PATCH 13/25] remove `typenameof` bits --- src/fsharp/FSComp.txt | 3 +-- src/fsharp/TastOps.fs | 13 +------------ src/fsharp/TastOps.fsi | 1 - src/fsharp/TcGlobals.fs | 20 +++++++++----------- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index ce5fa7b0eb..5db6809f95 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1334,5 +1334,4 @@ 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,expressionHasNoName,"This expression does not have a name." -3216,nameofNotPermitted,"The nameof operator is not allowed in this position." -3217,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted" \ No newline at end of file +3216,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted" \ No newline at end of file diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 39b06fd979..33c19e02cc 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2889,11 +2889,6 @@ let isNameOfValRef g vref = // There is an internal version of typeof defined in prim-types.fs that needs to be detected || (g.compilingFslib && vref.LogicalName = "nameof") -let isTypeNameOfValRef g vref = - valRefEq g vref g.typenameof_vref - // There is an internal version of namef defined in prim-types.fs that needs to be detected - || (g.compilingFslib && vref.LogicalName = "typenameof") - let isTypeDefOfValRef g vref = valRefEq g vref g.typedefof_vref // There is an internal version of typenameof defined in prim-types.fs that needs to be detected @@ -2924,11 +2919,6 @@ let (|NameOfExpr|_|) g expr = | Expr.App(Expr.Val(vref,_,_),_,[ty],[],_) when isNameOfValRef 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 (|SeqExpr|_|) g expr = match expr with | Expr.App(Expr.Val(vref,_,_),_,_,_,_) when valRefEq g vref g.seq_vref -> Some() @@ -7764,8 +7754,7 @@ let IsSimpleSyntacticConstantExpr g inputExpr = | UncheckedDefaultOfExpr g _ | SizeOfExpr g _ | TypeOfExpr g _ - | NameOfExpr g _ - | TypeNameOfExpr g _ -> true + | NameOfExpr g _ -> true // All others are not simple constant expressions | _ -> false diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index eaebc6cb90..a81b9b8f81 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1410,7 +1410,6 @@ 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 (|TypeNameOfExpr|_|) : TcGlobals -> Expr -> TType option val (|SeqExpr|_|) : TcGlobals -> Expr -> unit option val EvalLiteralExprOrAttribArg: TcGlobals -> Expr -> Expr diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index 6c49417edc..0b2bd149c0 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -569,7 +569,6 @@ 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_typenameof_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "typenameof" , None , Some "TypeNameOf" ,[vara], ([], v_string_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)) @@ -1125,7 +1124,6 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d 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 typenameof_vref = ValRefForIntrinsic v_typenameof_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 @@ -1152,15 +1150,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 From 1ad0a0e2ff945ce063207d93e8fe6663c67cf527 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Thu, 19 Jan 2017 17:38:04 +0300 Subject: [PATCH 14/25] nameof(typeof<_>) works remove `typenameof and its tests --- .../Microsoft.FSharp.Core/NameOfTests.fs | 40 ++----------------- src/fsharp/FSharp.Core/prim-types.fs | 3 -- src/fsharp/FSharp.Core/prim-types.fsi | 5 --- src/fsharp/TastOps.fs | 2 +- src/fsharp/TypeChecker.fs | 1 + 5 files changed, 5 insertions(+), 46 deletions(-) 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 index 1c82fc8ef0..8b49e88d54 100644 --- 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 @@ -130,7 +130,7 @@ type FrameworkMethodTests() = [] member this.``library function name`` () = let b = nameof(List.map) - Assert.AreEqual("Map",b) + Assert.AreEqual("map",b) [] member this.``static class function name`` () = @@ -141,47 +141,13 @@ 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) + Assert.AreEqual("typeof",b) [] member this.``lookup name of + operator`` () = @@ -198,7 +164,7 @@ type OperatorNameTests() = [] member this.``lookup name of nameof operator`` () = let b = nameof(nameof) - Assert.AreEqual("NameOf",b) + Assert.AreEqual("nameof",b) [] type PatternMatchingOfOperatorNameTests() = diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 4feb09cf01..fb117c41f6 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,9 +4748,6 @@ 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") diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi index a13dbdad11..d33c4f0aca 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2320,11 +2320,6 @@ 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 diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 33c19e02cc..860e42164a 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2891,7 +2891,7 @@ let isNameOfValRef g vref = let isTypeDefOfValRef g vref = valRefEq g vref g.typedefof_vref - // There is an internal version of typenameof defined in prim-types.fs that needs to be detected + // There is an internal version of typedefof defined in prim-types.fs that needs to be detected || (g.compilingFslib && vref.LogicalName = "typedefof") let (|UncheckedDefaultOfExpr|_|) g expr = diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 8cb13bc1d4..cdcc024774 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8253,6 +8253,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( match stripParens expr with | SynExpr.Ident ident -> Some ident + | SynExpr.TypeApp(expr = SynExpr.Ident(ident)) -> Some ident | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents | _ -> None From 56577597f7178414a277ff51a887d0f890e8d2fc Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sat, 28 Jan 2017 16:55:22 +0300 Subject: [PATCH 15/25] fix QA tests --- src/fsharp/FSComp.txt | 2 +- src/fsharp/TypeChecker.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs | 2 +- .../DataExpressions/NameOf/E_NameOfAppliedFunction.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs | 2 +- .../DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs | 2 +- .../DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs | 2 +- .../DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs | 2 +- .../Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 5db6809f95..4a51a5d9ee 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1334,4 +1334,4 @@ 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,expressionHasNoName,"This expression does not have a name." -3216,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted" \ No newline at end of file +3216,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted." \ No newline at end of file diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index cdcc024774..cb9bfe277e 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8269,7 +8269,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // generate fake `range` for the constant the `nameof(..)` we are substituting let constRange = mkRange r.FileName r.Start (mkPos r.StartLine (r.StartColumn + argIdent.idText.Length + 2)) // `2` are for quotes TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed - | _ -> error (Error(FSComp.SR.expressionHasNoName(), synArg.Range)) + | _ -> error (Error(FSComp.SR.expressionHasNoName(), expr.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' diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs index f71add7dd7..f1405cf7a0 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//This expression does not have a name. let x = nameof(1+2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs index 6663899751..8e9efc6a51 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f() = 1 let x = nameof(f()) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs index f7e104cfe6..76acc5a4bb 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAsAFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof can't be used as a function. -//This expression does not have a name. +//First-class uses of the 'nameof' operator is not permitted let f = nameof diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs index 761b23cb3e..381335f059 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on dictionary lookup -//This expression does not have a name. +//This expression does not have a name. let dict = new System.Collections.Generic.Dictionary() let b = nameof(dict.[2]) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs index a5144348e0..2e5a153340 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const int -//This expression does not have a name. +//This expression does not have a name. let x = nameof 1 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs index 7fe241fe86..47db6146e7 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f x = 1 * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs index 5f24456195..d98087f547 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//This expression does not have a name. let f x y = x y let z x = 1 * x diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs index 4a572a983f..0d3a1cfae0 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on partially applied functions -//This expression does not have a name. +//This expression does not have a name. let f x y = y * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs index b30f702b1a..9576f489a6 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//This expression does not have a name. let x = nameof "string" diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs index f959420f99..cae86f5ea0 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfWithPipe.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof can't be used as a function. -//The nameof operator is not allowed in this position. +//First-class uses of the 'nameof' operator is not permitted. let curriedFunction x y = x * y let b = curriedFunction |> nameof From a732de06cb7c60b78c742ce7d82024a5a8cb8b4e Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Fri, 3 Feb 2017 23:41:08 +0300 Subject: [PATCH 16/25] remove nameof function form FSharp.Core --- .../SurfaceArea.net40.fs | 2 - .../SurfaceArea.portable259.fs | 2 - .../SurfaceArea.portable47.fs | 2 - .../SurfaceArea.portable7.fs | 2 - .../SurfaceArea.portable78.fs | 2 - src/fsharp/FSharp.Core/prim-types.fs | 3 -- src/fsharp/FSharp.Core/prim-types.fsi | 4 -- src/fsharp/PostInferenceChecks.fs | 1 - src/fsharp/TastOps.fs | 13 +---- src/fsharp/TastOps.fsi | 1 - src/fsharp/TcGlobals.fs | 4 +- src/fsharp/TypeChecker.fs | 52 ++++++++++--------- 12 files changed, 30 insertions(+), 58 deletions(-) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index d5a9e905f8..bacb36eb34 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs @@ -2632,10 +2632,8 @@ 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 b618478397..cf8156e3fc 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs @@ -2604,10 +2604,8 @@ 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 8078e44f42..01a15aff35 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs @@ -2606,10 +2606,8 @@ 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 a3db8830ef..7c003fea40 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs @@ -2617,10 +2617,8 @@ 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 799616f508..4f1d01c64b 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs @@ -2604,10 +2604,8 @@ 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 fb117c41f6..9fcc440268 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,9 +4748,6 @@ 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 d33c4f0aca..c943999a09 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -2320,10 +2320,6 @@ 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/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index e8afcd6dd0..5c07964406 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -514,7 +514,6 @@ 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 963e7c6c94..c1742f82ca 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2884,11 +2884,6 @@ 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 @@ -2914,11 +2909,6 @@ 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() @@ -7753,8 +7743,7 @@ let IsSimpleSyntacticConstantExpr g inputExpr = | Expr.Op (TOp.UnionCase _,_,[],_) // Nullary union cases | UncheckedDefaultOfExpr g _ | SizeOfExpr g _ - | TypeOfExpr g _ - | NameOfExpr g _ -> true + | TypeOfExpr g _ -> true // All others are not simple constant expressions | _ -> false diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index a81b9b8f81..4629ab97a6 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1409,7 +1409,6 @@ 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 diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index eb223c3386..489c985d31 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -572,8 +572,7 @@ 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)) @@ -1131,7 +1130,6 @@ 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 diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 11712da2cb..8c30959e5c 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8313,12 +8313,33 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents | _ -> None + let (|NameOfExpr|_|) expr = + match expr with + | Expr.App(Expr.Val(vref,_,_),_,_,[],_) when vref.CompiledName = "nameof" -> Some () + | _ -> None + // 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,_,[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 -> match expr with - | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> + | ApplicableExpr(_, NameOfExpr, _) -> match synArg with | LastPartOfLongIdentStripParens argIdent -> let r = expr.Range @@ -8327,30 +8348,13 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), expr.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' + // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' 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 - | SynExpr.CompExpr (false,_isNotNakedRefCell,comp,_m) -> - let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp - TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed - | _ -> - error (NotAFunction(denv,overallTy,mFunExpr,mArg)) + | SynExpr.CompExpr (false,_isNotNakedRefCell,comp,_m) -> + let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp + TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed + | _ -> + error (NotAFunction(denv,overallTy,mFunExpr,mArg)) //------------------------------------------------------------------------- // TcLongIdentThen : Typecheck "A.B.C.E.F ... " constructs From b7763a6283260b5ecdc3cfbe67b182d6bfdd2af7 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sat, 4 Feb 2017 20:30:50 +0300 Subject: [PATCH 17/25] Revert "remove nameof function form FSharp.Core" This reverts commit a732de06cb7c60b78c742ce7d82024a5a8cb8b4e. --- .../SurfaceArea.net40.fs | 1 + .../SurfaceArea.portable259.fs | 1 + .../SurfaceArea.portable47.fs | 1 + .../SurfaceArea.portable7.fs | 1 + .../SurfaceArea.portable78.fs | 1 + src/fsharp/FSharp.Core/prim-types.fs | 3 ++ src/fsharp/FSharp.Core/prim-types.fsi | 4 ++ src/fsharp/PostInferenceChecks.fs | 1 + src/fsharp/TastOps.fs | 13 ++++- src/fsharp/TastOps.fsi | 1 + src/fsharp/TcGlobals.fs | 4 +- src/fsharp/TypeChecker.fs | 52 +++++++++---------- 12 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index bacb36eb34..ca9752377a 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 01a15aff35..0be758f5f1 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 9fcc440268..fb117c41f6 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4748,6 +4748,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/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index 5c07964406..e8afcd6dd0 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 c1742f82ca..963e7c6c94 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -2884,6 +2884,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 @@ -2909,6 +2914,11 @@ 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() @@ -7743,7 +7753,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 4629ab97a6..a81b9b8f81 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -1409,6 +1409,7 @@ 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 diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index 489c985d31..eb223c3386 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -572,7 +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 +1131,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 diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index c988d4b320..d2785a9e7e 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8313,33 +8313,12 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents | _ -> None - let (|NameOfExpr|_|) expr = - match expr with - | Expr.App(Expr.Val(vref,_,_),_,_,[],_) when vref.CompiledName = "nameof" -> Some () - | _ -> None - // 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,_,[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 -> match expr with - | ApplicableExpr(_, NameOfExpr, _) -> + | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> match synArg with | LastPartOfLongIdentStripParens argIdent -> let r = expr.Range @@ -8348,13 +8327,30 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed | _ -> error (Error(FSComp.SR.expressionHasNoName(), expr.Range)) | _ -> - // OK, 'expr' doesn't have function type, but perhaps 'expr' is a computation expression builder, and 'arg' is '{ ... }' + // 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) -> - let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp - TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed - | _ -> - error (NotAFunction(denv,overallTy,mFunExpr,mArg)) + | 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 + | SynExpr.CompExpr (false,_isNotNakedRefCell,comp,_m) -> + let bodyOfCompExpr,tpenv = TcComputationOrSequenceExpression cenv env overallTy mFunExpr (Some(expr.Expr,exprty)) tpenv comp + TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr cenv.g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed + | _ -> + error (NotAFunction(denv,overallTy,mFunExpr,mArg)) //------------------------------------------------------------------------- // TcLongIdentThen : Typecheck "A.B.C.E.F ... " constructs From 906a934514a58075f7bfe8fea048ff161e826f80 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sat, 4 Feb 2017 21:18:54 +0300 Subject: [PATCH 18/25] Try to resolve the `nameof` operator argument to prevent passing anything to it. --- src/fsharp/TypeChecker.fs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index d2785a9e7e..58c609178e 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8308,9 +8308,9 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | _ -> expr match stripParens expr with - | SynExpr.Ident ident -> Some ident - | SynExpr.TypeApp(expr = SynExpr.Ident(ident)) -> Some ident - | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents + | SynExpr.Ident ident -> Some ([ident], ident) + | SynExpr.TypeApp(expr = SynExpr.Ident(ident)) -> Some ([ident], ident) + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> Some (idents, List.last idents) | _ -> None // If the type of 'synArg' unifies as a function type, then this is a function application, otherwise @@ -8320,11 +8320,14 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( match expr with | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> match synArg with - | LastPartOfLongIdentStripParens argIdent -> + | LastPartOfLongIdentStripParens (idents, lastIdent) -> + // Try to resolve the `nameof` operator argument to prevent passing anything to it. + ResolveExprLongIdent cenv.tcSink cenv.nameResolver mArg env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default idents |> ignore + 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 + argIdent.idText.Length + 2)) // `2` are for quotes - TcDelayed cenv overallTy env tpenv mExprAndArg (ApplicableExpr(cenv, Expr.Const(Const.String(argIdent.idText), constRange, cenv.g.string_ty), true)) cenv.g.string_ty ExprAtomicFlag.Atomic delayed + 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(), expr.Range)) | _ -> // Notice the special case 'seq { ... }'. In this case 'seq' is actually a function in the F# library. From a770e3c7ad1bec9ca31477dcadb4d448998c4f1b Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sat, 4 Feb 2017 22:18:00 +0300 Subject: [PATCH 19/25] nameof works on generic types --- .../Microsoft.FSharp.Core/NameOfTests.fs | 5 +++++ src/fsharp/TypeChecker.fs | 13 ++++++++----- .../NameOf/E_NameOfUnresolvableName.fs | 6 ++++++ .../Expressions/DataExpressions/NameOf/env.lst | 1 + 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs 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 index 8b49e88d54..7795b3f46f 100644 --- 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 @@ -195,6 +195,11 @@ type NameOfOperatorForGenerics() = 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() = [] diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 58c609178e..a9bfb931f3 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8307,11 +8307,14 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | SynExpr.Paren(expr, _, _, _) -> stripParens expr | _ -> expr - match stripParens expr with - | SynExpr.Ident ident -> Some ([ident], ident) - | SynExpr.TypeApp(expr = SynExpr.Ident(ident)) -> Some ([ident], ident) - | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> Some (idents, List.last idents) - | _ -> None + let rec findIdents expr = + match expr with + | SynExpr.Ident ident -> Some ([ident], ident) + | SynExpr.TypeApp (expr = expr) -> findIdents expr + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> Some (idents, List.last idents) + | _ -> None + + findIdents (stripParens 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 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..f55c969a6f --- /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 or constructor 'ff' is not defined. + +let b = nameof System.Collections.Generic.Listtt +exit 0 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst index 4b62ea892e..7e08cf92ea 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/env.lst @@ -8,3 +8,4 @@ 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 From 067955a0d0fe7136c46b1401aa65d1db191e57f0 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sat, 4 Feb 2017 23:21:00 +0300 Subject: [PATCH 20/25] fix error range in case of wrong `nameof`operator argument --- src/fsharp/FSComp.txt | 2 +- src/fsharp/TypeChecker.fs | 18 +++++++++--------- .../NameOf/E_NameOfAdditionExpr.fs | 2 +- .../NameOf/E_NameOfAppliedFunction.fs | 2 +- .../NameOf/E_NameOfDictLookup.fs | 2 +- .../DataExpressions/NameOf/E_NameOfIntConst.fs | 2 +- .../NameOf/E_NameOfIntegerAppliedFunction.fs | 2 +- .../NameOf/E_NameOfParameterAppliedFunction.fs | 2 +- .../NameOf/E_NameOfPartiallyAppliedFunction.fs | 2 +- .../NameOf/E_NameOfStringConst.fs | 2 +- .../NameOf/E_NameOfUnresolvableName.fs | 4 ++-- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 4a51a5d9ee..74a2619bef 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -1333,5 +1333,5 @@ tcTupleStructMismatch,"One tuple type is a struct tuple, the other is a referenc tcGlobalsSystemTypeNotFound,"The system type '%s' was required but no referenced system DLL contained this type" 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,expressionHasNoName,"This expression does not have a name." +3215,expressionHasNoName,"Expression does not have a name." 3216,chkNoFirstClassNameOf,"First-class uses of the 'nameof' operator is not permitted." \ No newline at end of file diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index a9bfb931f3..7b843ccdad 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8302,19 +8302,18 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( let mFunExpr = expr.Range let (|LastPartOfLongIdentStripParens|_|) expr = - let rec stripParens expr = - match expr with - | SynExpr.Paren(expr, _, _, _) -> stripParens expr - | _ -> expr - let rec findIdents expr = match expr with | SynExpr.Ident ident -> Some ([ident], ident) | SynExpr.TypeApp (expr = expr) -> findIdents expr | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> Some (idents, List.last idents) | _ -> None - - findIdents (stripParens expr) + 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 @@ -8322,7 +8321,8 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | Some (domainTy,resultTy) -> match expr with | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> - match synArg with + let cleanSynArg = stripParens synArg + match cleanSynArg with | LastPartOfLongIdentStripParens (idents, lastIdent) -> // Try to resolve the `nameof` operator argument to prevent passing anything to it. ResolveExprLongIdent cenv.tcSink cenv.nameResolver mArg env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default idents |> ignore @@ -8331,7 +8331,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( // 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(), expr.Range)) + | _ -> 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' diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs index f1405cf7a0..2e082efb21 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAdditionExpr.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//Expression does not have a name. let x = nameof(1+2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs index 8e9efc6a51..49095e69ed 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//Expression does not have a name. let f() = 1 let x = nameof(f()) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs index 381335f059..0a58a4bba7 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfDictLookup.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on dictionary lookup -//This expression does not have a name. +//Expression does not have a name. let dict = new System.Collections.Generic.Dictionary() let b = nameof(dict.[2]) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs index 2e5a153340..6b67627d67 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const int -//This expression does not have a name. +//Expression does not have a name. let x = nameof 1 diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs index 47db6146e7..4fe8db0547 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfIntegerAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//Expression does not have a name. let f x = 1 * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs index d98087f547..c24f7343a1 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfParameterAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on applied functions -//This expression does not have a name. +//Expression does not have a name. let f x y = x y let z x = 1 * x diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs index 0d3a1cfae0..71b66493b5 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfPartiallyAppliedFunction.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on partially applied functions -//This expression does not have a name. +//Expression does not have a name. let f x y = y * x let x = nameof(f 2) diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs index 9576f489a6..1190f1e8b3 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfStringConst.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that nameof doesn't work on const string -//This expression does not have a name. +//Expression does not have a name. let x = nameof "string" diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs index f55c969a6f..2f998cbb17 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/NameOf/E_NameOfUnresolvableName.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #DataExpressions // Verify that passing unresolvable symbol name results with compilation error. -//The value or constructor 'ff' is not defined. +//The value, constructor, namespace or type 'Unknown' is not defined. -let b = nameof System.Collections.Generic.Listtt +let b = nameof System.Collections.Generic.Unknown exit 0 From bfcc390c5563ba9994e9add43c0772229cfbdfae Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sun, 5 Feb 2017 17:18:18 +0300 Subject: [PATCH 21/25] notify name resolution sink about nameof operator argument Item in order to not loose its FSharpSymbolUse --- src/fsharp/NameResolution.fs | 2 +- src/fsharp/TypeChecker.fs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fsharp/NameResolution.fs b/src/fsharp/NameResolution.fs index 6182ab553c..c64fe0447b 100644 --- a/src/fsharp/NameResolution.fs +++ b/src/fsharp/NameResolution.fs @@ -1193,7 +1193,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/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 7b843ccdad..a913138a24 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8325,7 +8325,9 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( match cleanSynArg with | LastPartOfLongIdentStripParens (idents, lastIdent) -> // Try to resolve the `nameof` operator argument to prevent passing anything to it. - ResolveExprLongIdent cenv.tcSink cenv.nameResolver mArg env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default idents |> ignore + let item, _ = ResolveExprLongIdent cenv.tcSink cenv.nameResolver mArg env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default idents + // Notify name resolution sink about the resolved argument in order to not loose symbol use, which is used in IDE. + CallNameResolutionSink cenv.tcSink (cleanSynArg.Range, env.eNameResEnv, item, item, ItemOccurence.Use, env.DisplayEnv, env.eAccessRights) let r = expr.Range // generate fake `range` for the constant the `nameof(..)` we are substituting From 6a92a8039049e0efadcb5f83a2ea008bd3d615d2 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sun, 5 Feb 2017 18:33:37 +0300 Subject: [PATCH 22/25] fully type check `nameof` argument --- src/fsharp/TypeChecker.fs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index a913138a24..489b92c7a7 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8301,14 +8301,29 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( 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 = + let rec findIdents expr (isTypeApp : bool) = match expr with - | SynExpr.Ident ident -> Some ([ident], ident) - | SynExpr.TypeApp (expr = expr) -> findIdents expr - | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> Some (idents, List.last idents) + | SynExpr.Ident ident -> + if not isTypeApp then + TcExprOfUnknownType cenv env tpenv expr |> ignore + Some ident + | SynExpr.TypeApp (expr, _, typeNames, _, _, _, m) -> + TcExprOfUnknownType cenv env tpenv expr |> ignore + TcTypesOrMeasures None cenv ImplictlyBoundTyparsAllowed.NewTyparsOK CheckConstraints.NoCheckCxs ItemOccurence.Use env tpenv typeNames m |> ignore + findIdents expr true + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> + if not isTypeApp then + TcExprOfUnknownType cenv env tpenv expr |> ignore + List.tryLast idents | _ -> None - findIdents expr + findIdents expr false let rec stripParens expr = match expr with @@ -8323,12 +8338,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | ApplicableExpr(_, NameOfExpr cenv.g _, _) -> let cleanSynArg = stripParens synArg match cleanSynArg with - | LastPartOfLongIdentStripParens (idents, lastIdent) -> - // Try to resolve the `nameof` operator argument to prevent passing anything to it. - let item, _ = ResolveExprLongIdent cenv.tcSink cenv.nameResolver mArg env.eAccessRights env.eNameResEnv TypeNameResolutionInfo.Default idents - // Notify name resolution sink about the resolved argument in order to not loose symbol use, which is used in IDE. - CallNameResolutionSink cenv.tcSink (cleanSynArg.Range, env.eNameResEnv, item, item, ItemOccurence.Use, env.DisplayEnv, env.eAccessRights) - + | LastPartOfLongIdentStripParens lastIdent -> 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 From bcec6002d790d0973ccee13653b1f79dc7656be6 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Sun, 5 Feb 2017 18:58:39 +0300 Subject: [PATCH 23/25] try to type check arg again --- src/fsharp/TypeChecker.fs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 489b92c7a7..d973797e77 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8314,9 +8314,9 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( if not isTypeApp then TcExprOfUnknownType cenv env tpenv expr |> ignore Some ident - | SynExpr.TypeApp (expr, _, typeNames, _, _, _, m) -> - TcExprOfUnknownType cenv env tpenv expr |> ignore - TcTypesOrMeasures None cenv ImplictlyBoundTyparsAllowed.NewTyparsOK CheckConstraints.NoCheckCxs ItemOccurence.Use env tpenv typeNames m |> ignore + | SynExpr.TypeApp (expr, _, typeArgs, _, _, mTypeArgs, m) -> + TcExprOfUnknownTypeThen cenv env tpenv expr [ DelayedTypeApp (typeArgs, mTypeArgs, m) ] |> ignore + //TcTypesOrMeasures None cenv ImplictlyBoundTyparsAllowed.NewTyparsOK CheckConstraints.NoCheckCxs ItemOccurence.Use env tpenv typeNames m |> ignore findIdents expr true | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> if not isTypeApp then From 0c1cad2a8d43f24c34fae4ebc21a73dc2c44a377 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Mon, 6 Feb 2017 22:06:56 +0300 Subject: [PATCH 24/25] type check `nameof` argument more carefully --- src/fsharp/TypeChecker.fs | 42 ++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index d973797e77..d77361389f 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8308,22 +8308,35 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( /// /// * 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 (isTypeApp : bool) = + let rec findIdents expr = match expr with - | SynExpr.Ident ident -> - if not isTypeApp then - TcExprOfUnknownType cenv env tpenv expr |> ignore - Some ident - | SynExpr.TypeApp (expr, _, typeArgs, _, _, mTypeArgs, m) -> - TcExprOfUnknownTypeThen cenv env tpenv expr [ DelayedTypeApp (typeArgs, mTypeArgs, m) ] |> ignore - //TcTypesOrMeasures None cenv ImplictlyBoundTyparsAllowed.NewTyparsOK CheckConstraints.NoCheckCxs ItemOccurence.Use env tpenv typeNames m |> ignore - findIdents expr true - | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) when not (List.isEmpty idents) -> - if not isTypeApp then - TcExprOfUnknownType cenv env tpenv expr |> ignore - List.tryLast idents + | SynExpr.Ident ident -> Some ident + | SynExpr.TypeApp (expr = expr) -> findIdents expr + | SynExpr.LongIdent(_, LongIdentWithDots(idents, _), _, _) -> List.tryLast idents | _ -> None - findIdents expr false + findIdents expr + + let tcExpr = function + | 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) + | _ -> () let rec stripParens expr = match expr with @@ -8339,6 +8352,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( let cleanSynArg = stripParens synArg match cleanSynArg with | LastPartOfLongIdentStripParens lastIdent -> + tcExpr 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 From 588de2e4ca383d529e1cc092a29628a9d8375b74 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 1 Mar 2017 21:18:15 +0300 Subject: [PATCH 25/25] factor tcExpr to top level function add a multiple arguments overloaded method group test --- .../Microsoft.FSharp.Core/NameOfTests.fs | 11 ++++- src/fsharp/TypeChecker.fs | 49 ++++++++++--------- 2 files changed, 36 insertions(+), 24 deletions(-) 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 index 7795b3f46f..e545320b14 100644 --- 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 @@ -120,11 +120,20 @@ 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.``method group name lookup`` () = + 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() = [] diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 904d668660..87c222345a 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -8303,6 +8303,31 @@ 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 @@ -8328,28 +8353,6 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( | _ -> None findIdents expr - let tcExpr = function - | 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) - | _ -> () - let rec stripParens expr = match expr with | SynExpr.Paren(expr, _, _, _) -> stripParens expr @@ -8364,7 +8367,7 @@ and TcFunctionApplicationThen cenv overallTy env tpenv mExprAndArg expr exprty ( let cleanSynArg = stripParens synArg match cleanSynArg with | LastPartOfLongIdentStripParens lastIdent -> - tcExpr cleanSynArg + 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