From a1d48a3f4260cc41cd6353822b9c2622c37b048f Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 27 Jan 2015 16:09:31 +0000 Subject: [PATCH] Fix #89 - nested quotation literals --- .../FSharp.Core.Unittests/SurfaceArea.4.0.fs | 15 ++++++ src/fsharp/FSharp.Core/Linq.fs | 23 ++++++++-- src/fsharp/FSharp.Core/Linq.fsi | 3 ++ src/fsharp/FSharp.Core/Query.fs | 10 ++-- src/fsharp/FSharp.Core/quotations.fs | 32 +++++++++---- src/fsharp/FSharp.Core/quotations.fsi | 26 ++++++++++- src/fsharp/creflect.fs | 11 ++++- src/fsharp/sreflect.fs | 5 +- src/fsharp/sreflect.fsi | 1 + .../queriesLeafExpressionConvert/test.fsx | 9 ++++ tests/fsharp/core/quotes/test.fsx | 46 ++++++++++++++++++- tests/test.lst | 2 +- 12 files changed, 160 insertions(+), 23 deletions(-) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs index 5d587ed0a30..b9b0e49ec02 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.4.0.fs @@ -2795,14 +2795,17 @@ Microsoft.FSharp.Core.ReferenceEqualityAttribute: System.String ToString() Microsoft.FSharp.Core.ReferenceEqualityAttribute: System.Type GetType() Microsoft.FSharp.Core.ReferenceEqualityAttribute: Void .ctor() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Boolean Equals(System.Object) +Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Boolean IncludeValue Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Boolean IsDefaultAttribute() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Boolean Match(System.Object) +Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Boolean get_IncludeValue() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Int32 GetHashCode() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: System.Object TypeId Microsoft.FSharp.Core.ReflectedDefinitionAttribute: System.Object get_TypeId() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: System.String ToString() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: System.Type GetType() Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Void .ctor() +Microsoft.FSharp.Core.ReflectedDefinitionAttribute: Void .ctor(Boolean) Microsoft.FSharp.Core.RequireQualifiedAccessAttribute: Boolean Equals(System.Object) Microsoft.FSharp.Core.RequireQualifiedAccessAttribute: Boolean IsDefaultAttribute() Microsoft.FSharp.Core.RequireQualifiedAccessAttribute: Boolean Match(System.Object) @@ -3210,6 +3213,7 @@ Microsoft.FSharp.Linq.RuntimeHelpers.Grouping`2[K,T]: System.Type GetType() Microsoft.FSharp.Linq.RuntimeHelpers.Grouping`2[K,T]: Void .ctor(K, System.Collections.Generic.IEnumerable`1[T]) Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: Boolean Equals(System.Object) Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: Int32 GetHashCode() +Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: Microsoft.FSharp.Quotations.FSharpExpr SubstHelperRaw(Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar[], System.Object[]) Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: Microsoft.FSharp.Quotations.FSharpExpr`1[T] SubstHelper[T](Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar[], System.Object[]) Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: System.Linq.Expressions.Expression QuotationToExpression(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter: System.Linq.Expressions.Expression`1[T] ImplicitExpressionConversionHelper[T](T) @@ -3299,6 +3303,8 @@ Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr P Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr PropertySet(Microsoft.FSharp.Quotations.FSharpExpr, System.Reflection.PropertyInfo, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]]) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr PropertySet(System.Reflection.PropertyInfo, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]]) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Quote(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr QuoteRaw(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr QuoteTyped(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Sequential(Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Substitute(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr]]) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr TryFinally(Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpExpr) @@ -3307,12 +3313,16 @@ Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr T Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr TypeTest(Microsoft.FSharp.Quotations.FSharpExpr, System.Type) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr UnionCaseTest(Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Reflection.UnionCaseInfo) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Value(System.Object, System.Type) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr ValueWithName(System.Object, System.Type, System.String) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr ValueWithName[T](T, System.String) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Value[T](T) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr Var(Microsoft.FSharp.Quotations.FSharpVar) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr VarSet(Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr WhileLoop(Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr WithValue(System.Object, System.Type, Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr`1[T] Cast[T](Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr`1[T] GlobalVar[T](System.String) +Microsoft.FSharp.Quotations.FSharpExpr: Microsoft.FSharp.Quotations.FSharpExpr`1[T] WithValue[T](T, Microsoft.FSharp.Quotations.FSharpExpr`1[T]) Microsoft.FSharp.Quotations.FSharpExpr: System.Collections.Generic.IEnumerable`1[Microsoft.FSharp.Quotations.FSharpVar] GetFreeVars() Microsoft.FSharp.Quotations.FSharpExpr: System.String ToString() Microsoft.FSharp.Quotations.FSharpExpr: System.String ToString(Boolean) @@ -3320,6 +3330,7 @@ Microsoft.FSharp.Quotations.FSharpExpr: System.Type GetType() Microsoft.FSharp.Quotations.FSharpExpr: System.Type Type Microsoft.FSharp.Quotations.FSharpExpr: System.Type get_Type() Microsoft.FSharp.Quotations.FSharpExpr: Void RegisterReflectedDefinitions(System.Reflection.Assembly, System.String, Byte[]) +Microsoft.FSharp.Quotations.FSharpExpr: Void RegisterReflectedDefinitions(System.Reflection.Assembly, System.String, Byte[], System.Type[]) Microsoft.FSharp.Quotations.FSharpExpr`1[T]: Boolean Equals(System.Object) Microsoft.FSharp.Quotations.FSharpExpr`1[T]: Int32 GetHashCode() Microsoft.FSharp.Quotations.FSharpExpr`1[T]: Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr] CustomAttributes @@ -3350,6 +3361,8 @@ Microsoft.FSharp.Quotations.PatternsModule: Int32 GetHashCode() Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]] NewTuplePattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr] AddressOfPattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr] QuotePattern(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr] QuoteRawPattern(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr] QuoteTypedPattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpVar] VarPattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr]],Microsoft.FSharp.Quotations.FSharpExpr]] LetRecursivePattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`2[Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr],System.Reflection.FieldInfo]] FieldGetPattern(Microsoft.FSharp.Quotations.FSharpExpr) @@ -3374,6 +3387,8 @@ Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1 Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr],System.Reflection.PropertyInfo,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]]] PropertyGetPattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] IfThenElsePattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] LetPattern(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.Type,Microsoft.FSharp.Quotations.FSharpExpr]] WithValuePattern(Microsoft.FSharp.Quotations.FSharpExpr) +Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Object,System.Type,System.String]] ValueWithNamePattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`3[System.Type,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpVar],Microsoft.FSharp.Quotations.FSharpExpr]] NewDelegatePattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`4[Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Quotations.FSharpExpr],System.Reflection.PropertyInfo,Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Quotations.FSharpExpr]] PropertySetPattern(Microsoft.FSharp.Quotations.FSharpExpr) Microsoft.FSharp.Quotations.PatternsModule: Microsoft.FSharp.Core.FSharpOption`1[System.Tuple`4[Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpExpr]] ForIntegerRangeLoopPattern(Microsoft.FSharp.Quotations.FSharpExpr) diff --git a/src/fsharp/FSharp.Core/Linq.fs b/src/fsharp/FSharp.Core/Linq.fs index d2b8fcb8950..5245b7681c6 100644 --- a/src/fsharp/FSharp.Core/Linq.fs +++ b/src/fsharp/FSharp.Core/Linq.fs @@ -207,9 +207,11 @@ module LeafExpressionConverter = |> System.Reflection.MethodInfo.GetMethodFromHandle :?> MethodInfo - let SubstHelper<'T> (q:Expr, x:Var[], y:obj[]) : Expr<'T> = + let SubstHelperRaw (q:Expr, x:Var[], y:obj[]) : Expr = let d = Map.ofArray (Array.zip x y) - q.Substitute(fun v -> v |> d.TryFind |> Option.map (fun x -> Expr.Value(x, v.Type))) |> Expr.Cast + q.Substitute(fun v -> v |> d.TryFind |> Option.map (fun x -> Expr.Value(x, v.Type))) + + let SubstHelper<'T> (q:Expr, x:Var[], y:obj[]) : Expr<'T> = SubstHelperRaw(q,x,y) |> Expr.Cast let showAll = #if FX_RESHAPED_REFLECTION @@ -385,6 +387,12 @@ module LeafExpressionConverter = methodhandleof (fun (x:Expr,y:Var[],z:obj[]) -> SubstHelper (x,y,z)) |> System.Reflection.MethodInfo.GetMethodFromHandle :?> MethodInfo + + let substHelperRawMeth = + methodhandleof (fun (x:Expr,y:Var[],z:obj[]) -> SubstHelperRaw (x,y,z)) + |> System.Reflection.MethodInfo.GetMethodFromHandle + :?> MethodInfo + let (-->) ty1 ty2 = Reflection.FSharpType.MakeFunctionType(ty1, ty2) /// Extract member initialization expression stored in 'MemberInitializationHelper' (by QueryExtensions.fs) @@ -762,7 +770,7 @@ module LeafExpressionConverter = | Patterns.IfThenElse(g, t, e) -> Expression.Condition(ConvExprToLinqInContext env g, ConvExprToLinqInContext env t, ConvExprToLinqInContext env e) |> asExpr - | Patterns.Quote x -> + | Patterns.QuoteTyped x -> let fvs = x.GetFreeVars() Expression.Call(substHelperMeth.MakeGenericMethod [| x.Type |], @@ -771,6 +779,15 @@ module LeafExpressionConverter = (Expression.NewArrayInit(typeof, [| for fv in fvs -> Expression.Convert(env.varEnv.[fv], typeof) |> asExpr |]) |> asExpr) |]) |> asExpr + | Patterns.QuoteRaw x -> + let fvs = x.GetFreeVars() + + Expression.Call(substHelperRawMeth, + [| (Expression.Constant x) |> asExpr; + (Expression.NewArrayInit(typeof, [| for fv in fvs -> Expression.Constant fv |> asExpr |]) |> asExpr); + (Expression.NewArrayInit(typeof, [| for fv in fvs -> Expression.Convert(env.varEnv.[fv], typeof) |> asExpr |]) |> asExpr) |]) + |> asExpr + | Patterns.Let (v, e, b) -> let vP = ConvVarToLinq v let envinner = { env with varEnv = Map.add v (vP |> asExpr) env.varEnv } diff --git a/src/fsharp/FSharp.Core/Linq.fsi b/src/fsharp/FSharp.Core/Linq.fsi index 1c2cce23702..a8032e830f8 100644 --- a/src/fsharp/FSharp.Core/Linq.fsi +++ b/src/fsharp/FSharp.Core/Linq.fsi @@ -303,5 +303,8 @@ namespace Microsoft.FSharp.Linq.RuntimeHelpers /// A runtime helper used to evaluate nested quotation literals. val SubstHelper : Expr * Var[] * obj[] -> Expr<'T> + /// A runtime helper used to evaluate nested quotation literals. + val SubstHelperRaw : Expr * Var[] * obj[] -> Expr + val internal (|SpecificCallToMethod|_|) : System.RuntimeMethodHandle -> (Expr -> (Expr option * Type list * Expr list) option) #endif \ No newline at end of file diff --git a/src/fsharp/FSharp.Core/Query.fs b/src/fsharp/FSharp.Core/Query.fs index b04d3f10f2e..d1752d6ef18 100644 --- a/src/fsharp/FSharp.Core/Query.fs +++ b/src/fsharp/FSharp.Core/Query.fs @@ -1128,15 +1128,15 @@ module Query = let (|AnyNestedQuery|_|) e = match e with - | CallQueryBuilderRunValue (None, _, [_; Quote e ]) - | CallQueryBuilderRunEnumerable (None, _, [_; Quote e ]) - | CallQueryBuilderRunQueryable (Some _, _, [ Quote e ]) -> Some e + | CallQueryBuilderRunValue (None, _, [_; QuoteTyped e ]) + | CallQueryBuilderRunEnumerable (None, _, [_; QuoteTyped e ]) + | CallQueryBuilderRunQueryable (Some _, _, [ QuoteTyped e ]) -> Some e | _ -> None let (|EnumerableNestedQuery|_|) e = match e with - | CallQueryBuilderRunEnumerable (None, _, [_; Quote e ]) - | CallQueryBuilderRunQueryable (Some _, _, [ Quote e ]) -> Some e + | CallQueryBuilderRunEnumerable (None, _, [_; QuoteTyped e ]) + | CallQueryBuilderRunQueryable (Some _, _, [ QuoteTyped e ]) -> Some e | _ -> None /// Represents the result of TransInner - either a normal expression, or something we're about to turn into diff --git a/src/fsharp/FSharp.Core/quotations.fs b/src/fsharp/FSharp.Core/quotations.fs index 890ff29957c..6e11d914be7 100644 --- a/src/fsharp/FSharp.Core/quotations.fs +++ b/src/fsharp/FSharp.Core/quotations.fs @@ -179,7 +179,7 @@ and | CoerceOp of Type | NewArrayOp of Type | NewDelegateOp of Type - | QuoteOp + | QuoteOp of bool | SequentialOp | AddressOfOp | VarSetOp @@ -293,7 +293,7 @@ and [] | VarTerm(v) -> wordL v.Name | LambdaTerm(v,b) -> combL "Lambda" [varL v; expr b] | HoleTerm _ -> wordL "_" - | CombTerm(QuoteOp,args) -> combL "Quote" (exprs args) + | CombTerm(QuoteOp _,args) -> combL "Quote" (exprs args) | _ -> failwithf "Unexpected term in layout %A" x.Tree @@ -357,6 +357,7 @@ module Patterns = let mkArrayTy (t:Type) = t.MakeArrayType(); let mkExprTy (t:Type) = exprTyC.MakeGenericType([| t |]) + let rawExprTy = typeof //-------------------------------------------------------------------------- @@ -381,7 +382,13 @@ module Patterns = let (|Lambda|_|) (E x) = match x with LambdaTerm(a,b) -> Some (a,b) | _ -> None [] - let (|Quote|_|) (E x) = match x with CombTerm(QuoteOp,[a]) -> Some (a) | _ -> None + let (|Quote|_|) (E x) = match x with CombTerm(QuoteOp _,[a]) -> Some (a) | _ -> None + + [] + let (|QuoteRaw|_|) (E x) = match x with CombTerm(QuoteOp false,[a]) -> Some (a) | _ -> None + + [] + let (|QuoteTyped|_|) (E x) = match x with CombTerm(QuoteOp true,[a]) -> Some (a) | _ -> None [] let (|IfThenElse|_|) = function Comb3(IfThenElseOp,e1,e2,e3) -> Some(e1,e2,e3) | _ -> None @@ -577,14 +584,15 @@ module Patterns = | NewDelegateOp ty,_ -> ty | DefaultValueOp ty,_ -> ty | TypeTestOp _,_ -> typeof - | QuoteOp,[expr] -> mkExprTy (typeOf expr) + | QuoteOp true,[expr] -> mkExprTy (typeOf expr) + | QuoteOp false,[_] -> rawExprTy | TryFinallyOp,[e1;_] -> typeOf e1 | TryWithOp,[e1;_;_] -> typeOf e1 | WhileLoopOp,_ | VarSetOp,_ | AddressSetOp,_ -> typeof | AddressOfOp,_ -> raise <| System.InvalidOperationException (SR.GetString(SR.QcannotTakeAddress)) - | (QuoteOp | SequentialOp | TryWithOp | TryFinallyOp | IfThenElseOp | AppOp),_ -> failwith "unreachable" + | (QuoteOp _ | SequentialOp | TryWithOp | TryFinallyOp | IfThenElseOp | AppOp),_ -> failwith "unreachable" //-------------------------------------------------------------------------- @@ -656,7 +664,7 @@ module Patterns = // [Correct by definition] let mkVar v = E(VarTerm v ) - let mkQuote(a) = E(CombTerm(QuoteOp,[(a:>Expr)] )) + let mkQuote(a,isTyped) = E(CombTerm(QuoteOp isTyped,[(a:>Expr)] )) let mkValue (v,ty) = mkFE0 (ValueOp(v,ty,None)) let mkValueWithName (v,ty,nm) = mkFE0 (ValueOp(v,ty,Some nm)) @@ -1363,12 +1371,14 @@ module Patterns = let idx = u_int st (fun env -> E(HoleTerm(a env.typeInst , idx))) | 4 -> let a = u_Expr st - (fun env -> mkQuote(a env)) + (fun env -> mkQuote(a env, true)) | 5 -> let a = u_Expr st let attrs = u_list u_Expr st (fun env -> let e = (a env) in EA(e.Tree,(e.CustomAttributes @ List.map (fun attrf -> attrf env) attrs))) | 6 -> let a = u_dtype st (fun env -> mkVar(Var.Global("this", a env.typeInst))) + | 7 -> let a = u_Expr st + (fun env -> mkQuote(a env, false)) | _ -> failwith "u_Expr" and u_VarDecl st = @@ -1922,7 +1932,11 @@ type Expr with static member PropertySet (property:PropertyInfo, value:Expr, ?args) = mkStaticPropSet(property, defaultArg args [], value) - static member Quote (expr:Expr) = mkQuote expr + static member Quote (expr:Expr) = mkQuote (expr, true) + + static member QuoteRaw (expr:Expr) = mkQuote (expr, false) + + static member QuoteTyped (expr:Expr) = mkQuote (expr, true) static member Sequential (e1:Expr, e2:Expr) = mkSequential (e1, e2) @@ -2178,7 +2192,7 @@ module ExprShape = | WhileLoopOp,[e1;e2] -> mkWhileLoop(e1,e2) | TryFinallyOp,[e1;e2] -> mkTryFinally(e1,e2) | TryWithOp,[e1;Lambda(v1,e2);Lambda(v2,e3)] -> mkTryWith(e1,v1,e2,v2,e3) - | QuoteOp,[e1] -> mkQuote(e1) + | QuoteOp flg,[e1] -> mkQuote(e1,flg) | ValueOp(v,ty,None),[] -> mkValue(v,ty) | ValueOp(v,ty,Some nm),[] -> mkValueWithName(v,ty,nm) | WithValueOp(v,ty),[e] -> mkValueWithDefn(v,ty,e) diff --git a/src/fsharp/FSharp.Core/quotations.fsi b/src/fsharp/FSharp.Core/quotations.fsi index b01f7404319..262ed2a7a46 100644 --- a/src/fsharp/FSharp.Core/quotations.fsi +++ b/src/fsharp/FSharp.Core/quotations.fsi @@ -236,11 +236,22 @@ type Expr = /// The resulting expression. static member PropertySet: property:PropertyInfo * value:Expr * ?indexerArgs: Expr list -> Expr - /// Builds an expression that represents a nested quotation literal + /// Builds an expression that represents a nested typed or raw quotation literal /// The expression being quoted. /// The resulting expression. + [] static member Quote: inner:Expr -> Expr + /// Builds an expression that represents a nested raw quotation literal + /// The expression being quoted. + /// The resulting expression. + static member QuoteRaw: inner:Expr -> Expr + + /// Builds an expression that represents a nested typed quotation literal + /// The expression being quoted. + /// The resulting expression. + static member QuoteTyped: inner:Expr -> Expr + /// Builds an expression that represents the sequential execution of one expression followed by another /// The first expression. /// The second expression. @@ -552,8 +563,21 @@ module Patterns = /// The input expression to match against. /// Expr option [] + [] val (|Quote|_|) : input:Expr -> Expr option + /// An active pattern to recognize expressions that represent a nested raw quotation literal + /// The input expression to match against. + /// Expr option + [] + val (|QuoteRaw|_|) : input:Expr -> Expr option + + /// An active pattern to recognize expressions that represent a nested typed quotation literal + /// The input expression to match against. + /// Expr option + [] + val (|QuoteTyped|_|) : input:Expr -> Expr option + /// An active pattern to recognize expressions that represent sequential exeuction of one expression followed by another /// The input expression to match against. /// (Expr * Expr) option diff --git a/src/fsharp/creflect.fs b/src/fsharp/creflect.fs index 8ae7bf5ff3f..370b86fa80c 100644 --- a/src/fsharp/creflect.fs +++ b/src/fsharp/creflect.fs @@ -378,8 +378,15 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. let bR = ConvExpr cenv (BindVal env v) b QP.mkLambda(vR, bR) - | Expr.Quote(ast,_,_,_,_) -> - QP.mkQuote(ConvExpr cenv env ast) + | Expr.Quote(ast,_,_,_,ety) -> + // F# 2.0-3.1 had a bug with nested 'raw' quotations. F# 4.0 + FSharp.Core 4.4.0.0+ allows us to do the right thing. + if cenv.quotationFormat = QuotationSerializationFormat.FSharp_40_Plus && + // Look for a 'raw' quotation + tyconRefEq cenv.g (tcrefOfAppTy cenv.g ety) cenv.g.raw_expr_tcr + then + QP.mkQuoteRaw40(ConvExpr cenv env ast) + else + QP.mkQuote(ConvExpr cenv env ast) | Expr.TyLambda (_,_,_,m,_) -> wfail(Error(FSComp.SR.crefQuotationsCantContainGenericFunctions(), m)) diff --git a/src/fsharp/sreflect.fs b/src/fsharp/sreflect.fs index 09b9456e805..dde90bfb8c6 100644 --- a/src/fsharp/sreflect.fs +++ b/src/fsharp/sreflect.fs @@ -119,12 +119,14 @@ type ExprData = | LambdaExpr of VarData * ExprData | HoleExpr of TypeData * int | ThisVarExpr of TypeData + | QuoteRawExpr of ExprData let mkVar v = VarExpr v let mkHole (v,idx) = HoleExpr (v ,idx) let mkApp (a,b) = CombExpr(AppOp, [], [a; b]) let mkLambda (a,b) = LambdaExpr (a,b) -let mkQuote (a) = QuoteExpr (a) +let mkQuote (a) = QuoteExpr (a) +let mkQuoteRaw40 (a) = QuoteRawExpr (a) let mkCond (x1,x2,x3) = CombExpr(CondOp,[], [x1;x2;x3]) let mkModuleValueApp (tcref,nm,isProp,tyargs,args: ExprData list list) = CombExpr(ModuleValueOp(tcref,nm,isProp),tyargs,List.concat args) @@ -405,6 +407,7 @@ let rec p_expr x st = | QuoteExpr(tm) -> p_byte 4 st; p_expr tm st | AttrExpr(e,attrs) -> p_byte 5 st; p_tup2 p_expr (p_list p_expr) (e,attrs) st | ThisVarExpr(ty) -> p_byte 6 st; p_type ty st + | QuoteRawExpr(tm) -> p_byte 7 st; p_expr tm st type ModuleDefnData = { Module: NamedTypeData; diff --git a/src/fsharp/sreflect.fsi b/src/fsharp/sreflect.fsi index 4b5765944f7..f815d916ee5 100644 --- a/src/fsharp/sreflect.fsi +++ b/src/fsharp/sreflect.fsi @@ -61,6 +61,7 @@ val mkHole : TypeData * int -> ExprData val mkApp : ExprData * ExprData -> ExprData val mkLambda : VarData * ExprData -> ExprData val mkQuote : ExprData -> ExprData +val mkQuoteRaw40 : ExprData -> ExprData // only available for FSharp.Core 4.4.0.0+ val mkCond : ExprData * ExprData * ExprData -> ExprData val mkModuleValueApp : NamedTypeData * string * bool * TypeData list * ExprData list list -> ExprData val mkLetRec : (VarData * ExprData) list * ExprData -> ExprData diff --git a/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx b/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx index fe05bfec889..871321f208b 100644 --- a/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx +++ b/tests/fsharp/core/queriesLeafExpressionConvert/test.fsx @@ -839,6 +839,14 @@ module LeafExpressionEvaluationTests = checkEval "clkedw2" (<@ let x : int option = Some 1 in x.Value @>) 1 checkEval "clkedw3" (<@ let x : int option = Some 1 in x.ToString() @>) "Some(1)" + module NestedQuotes = + + open Microsoft.FSharp.Linq.NullableOperators + + checkEval "feoewjewjlejf1" <@ <@@ 1 @@> @> <@@ 1 @@> + checkEval "feoewjewjlejf2" <@ <@ 1 @> @> <@ 1 @> + checkEval "feoewjewjlejf3" <@ <@@ 1 @@>, <@ 2 @> @> (<@@ 1 @@> , <@ 2 @>) + module Extensions = type System.Object with member x.ExtensionMethod0() = 3 @@ -1129,6 +1137,7 @@ module LeafExpressionEvaluationTests = checkText "p2oin209v33x" <@ Nullable 2 ?%? Nullable () @> "(Convert(2) % new Nullable`1())" checkText "p2oin209v33x" <@ Nullable 2 ?% 3 @> "(Convert(2) % Convert(3))" + let aa = if not failures.IsEmpty then (printfn "Test Failed, failures = %A" failures; exit 1) else (stdout.WriteLine "Test Passed"; diff --git a/tests/fsharp/core/quotes/test.fsx b/tests/fsharp/core/quotes/test.fsx index 6f2d03fea74..6aeb71c58d6 100644 --- a/tests/fsharp/core/quotes/test.fsx +++ b/tests/fsharp/core/quotes/test.fsx @@ -1639,7 +1639,10 @@ module QuotationConstructionTests = check "vcknwwe099" (Expr.PropertySet(<@@ (new System.Windows.Forms.Form()) @@>, setof <@@ (new System.Windows.Forms.Form()).Text <- "2" @@>, <@@ "3" @@> )) <@@ (new System.Windows.Forms.Form()).Text <- "3" @@> #endif check "vcknwwe099" (Expr.PropertySet(<@@ (new Foo()) @@>, setof <@@ (new Foo()).[3] <- 1 @@>, <@@ 2 @@> , [ <@@ 3 @@> ] )) <@@ (new Foo()).[3] <- 2 @@> - check "vcknwwe0qq" (Expr.Quote(<@@ "1" @@>)) <@@ <@@ "1" @@> @@> + check "vcknwwe0qq1" (Expr.QuoteRaw(<@ "1" @>)) <@@ <@@ "1" @@> @@> + check "vcknwwe0qq2" (Expr.QuoteRaw(<@@ "1" @@>)) <@@ <@@ "1" @@> @@> + check "vcknwwe0qq3" (Expr.QuoteTyped(<@ "1" @>)) <@@ <@ "1" @> @@> + check "vcknwwe0qq4" (Expr.QuoteTyped(<@@ "1" @@>)) <@@ <@ "1" @> @@> check "vcknwwe0ww" (Expr.Sequential(<@@ () @@>, <@@ 1 @@>)) <@@ (); 1 @@> check "vcknwwe0ee" (Expr.TryFinally(<@@ 1 @@>, <@@ () @@>)) <@@ try 1 finally () @@> check "vcknwwe0rr" (match Expr.TryWith(<@@ 1 @@>, Var.Global("e1",typeof), <@@ 1 @@>, Var.Global("e2",typeof), <@@ 2 @@>) with TryWith(b,v1,ef,v2,eh) -> b = <@@ 1 @@> && eh = <@@ 2 @@> && ef = <@@ 1 @@> && v1 = Var.Global("e1",typeof) && v2 = Var.Global("e2",typeof)| _ -> false) true @@ -2641,6 +2644,47 @@ module TestsForUsingReflectedDefinitionArgumentsAsFirstClassValues = runAll() +module NestedQuotations = + open Microsoft.FSharp.Quotations + open System.Linq.Expressions + open System + + let unnested1 = <@ 100 @> + let unnested2 = <@@ 100 @@> + let nested1 = <@@ <@ 100 @> @@> + let nested2 = <@@ <@@ 100 @@> @@> + let nested3 = <@ <@ 100 @> @> + let nested4 = <@ <@@ 100 @@> @> + + let runAll() = + test "lfhwwlefkhelw-1a" (match nested1 with Quote _ -> true | _ -> false) + test "lfhwwlefkhelw-1b" (match nested1 with QuoteTyped _ -> true | _ -> false) + test "lfhwwlefkhelw-1c" (match nested1 with QuoteRaw _ -> false | _ -> true) + test "lfhwwlefkhelw-2a" (match nested2 with Quote _ -> true | _ -> false) + test "lfhwwlefkhelw-2b" (match nested2 with QuoteTyped _ -> false | _ -> true) + test "lfhwwlefkhelw-2c" (match nested2 with QuoteRaw _ -> true | _ -> false) + test "lfhwwlefkhelw-3a" (match nested3 with Quote _ -> true | _ -> false) + test "lfhwwlefkhelw-3b" (match nested3 with QuoteTyped _ -> true | _ -> true) + test "lfhwwlefkhelw-3c" (match nested3 with QuoteRaw _ -> false | _ -> true) + test "lfhwwlefkhelw-4a" (match nested4 with Quote _ -> true | _ -> false) + test "lfhwwlefkhelw-4b" (match nested4 with QuoteRaw _ -> true | _ -> false) + test "lfhwwlefkhelw-4c" (match nested4 with QuoteTyped _ -> false | _ -> true) + test "clenewjclkw-1" (match Expr.Quote unnested1 with QuoteTyped _ -> true | _ -> false) + test "clenewjclkw-2" (match Expr.QuoteRaw unnested1 with QuoteRaw _ -> true | _ -> false) + test "clenewjclkw-3" (match Expr.Quote unnested2 with QuoteTyped _ -> true | _ -> false) + test "clenewjclkw-4" (match Expr.QuoteRaw unnested2 with QuoteRaw _ -> true | _ -> false) + test "clenewjclkw-5" (unnested1.Type = typeof) + test "clenewjclkw-6" (unnested2.Type = typeof) + test "clenewjclkw-7" (Expr.Quote(unnested1).Type = typeof>) + test "clenewjclkw-8" (Expr.Quote(unnested2).Type = typeof>) + test "clenewjclkw-9" (Expr.QuoteTyped(unnested1).Type = typeof>) + test "clenewjclkw-10" (Expr.QuoteTyped(unnested2).Type = typeof>) + test "clenewjclkw-11" (Expr.QuoteRaw(unnested1).Type = typeof) + test "clenewjclkw-12" (Expr.QuoteRaw(unnested2).Type = typeof) + + runAll() + + let aa = if not failures.IsEmpty then (printfn "Test Failed, failures = %A" failures; exit 1) else (stdout.WriteLine "Test Passed"; diff --git a/tests/test.lst b/tests/test.lst index 86986c566f9..c1e19408801 100644 --- a/tests/test.lst +++ b/tests/test.lst @@ -59,7 +59,7 @@ Core05 fsharp\core\pinvoke Core05 fsharp\core\printf Core05 fsharp\core\printing Core05 fsharp\core\queriesCustomQueryOps -Core06 fsharp\core\queriesLeafExpressionConvert +Core06,CoreQuotes fsharp\core\queriesLeafExpressionConvert Core06 fsharp\core\queriesNullableOperators Core06 fsharp\core\queriesOverIEnumerable Core06 fsharp\core\queriesOverIQueryable