@@ -5,6 +5,7 @@ namespace FSharp.Compiler.SourceCodeServices
55open FSharp.Compiler
66open FSharp.Compiler .AbstractIL .Internal .Library
77open FSharp.Compiler .AbstractIL .IL
8+ open FSharp.Compiler .ErrorLogger
89open FSharp.Compiler .Lib
910open FSharp.Compiler .Infos
1011open FSharp.Compiler .QuotationTranslator
@@ -35,13 +36,26 @@ module ExprTranslationImpl =
3536 isinstVals: ValMap < TType * Expr >
3637
3738 substVals: ValMap < Expr >
39+
40+ /// Indicates that we disable generation of witnesses
41+ suppressWitnesses: bool
42+
43+ /// All witnesses in scope and their mapping to lambda variables.
44+ //
45+ // Note: this uses an immutable HashMap/Dictionary with an IEqualityComparer that captures TcGlobals, see
46+ // the point where the empty initial object is created.
47+ witnessesInScope: TraitWitnessInfoHashMap < int >
48+
3849 }
3950
40- static member Empty =
51+ static member Empty g =
4152 { vs= ValMap<_>. Empty
42- tyvs = Map.empty ;
53+ tyvs = Map.empty
4354 isinstVals = ValMap<_>. Empty
44- substVals = ValMap<_>. Empty }
55+ substVals = ValMap<_>. Empty
56+ suppressWitnesses = false
57+ witnessesInScope = EmptyTraitWitnessInfoHashMap g
58+ }
4559
4660 member env.BindTypar ( v : Typar , gp ) =
4761 { env with tyvs = env.tyvs.Add( v.Stamp, gp ) }
@@ -81,7 +95,7 @@ type E =
8195 | IfThenElse of FSharpExpr * FSharpExpr * FSharpExpr
8296 | DecisionTree of FSharpExpr * ( FSharpMemberOrFunctionOrValue list * FSharpExpr ) list
8397 | DecisionTreeSuccess of int * FSharpExpr list
84- | Call of FSharpExpr option * FSharpMemberOrFunctionOrValue * FSharpType list * FSharpType list * FSharpExpr list
98+ | Call of FSharpExpr option * FSharpMemberOrFunctionOrValue * FSharpType list * FSharpType list * FSharpExpr list * FSharpExpr list
8599 | NewObject of FSharpMemberOrFunctionOrValue * FSharpType list * FSharpExpr list
86100 | LetRec of ( FSharpMemberOrFunctionOrValue * FSharpExpr ) list * FSharpExpr
87101 | Let of ( FSharpMemberOrFunctionOrValue * FSharpExpr ) * FSharpExpr
@@ -117,6 +131,7 @@ type E =
117131 | ILFieldGet of FSharpExpr option * FSharpType * string
118132 | ILFieldSet of FSharpExpr option * FSharpType * string * FSharpExpr
119133 | ILAsm of string * FSharpType list * FSharpExpr list
134+ | WitnessArg of int
120135
121136/// Used to represent the information at an object expression member
122137and [<Sealed>] FSharpObjectExprOverride ( sgn : FSharpAbstractSignature , gps : FSharpGenericParameter list , args : FSharpMemberOrFunctionOrValue list list , body : FSharpExpr ) =
@@ -128,10 +143,11 @@ and [<Sealed>] FSharpObjectExprOverride(sgn: FSharpAbstractSignature, gps: FSha
128143/// The type of expressions provided through the compiler API.
129144and [<Sealed>] FSharpExpr ( cenv , f : ( unit -> FSharpExpr ) option , e : E , m : range , ty ) =
130145
146+ let mutable e = match f with None -> e | Some _ -> Unchecked.defaultof< E>
131147 member x.Range = m
132148 member x.Type = FSharpType( cenv, ty)
133149 member x.cenv = cenv
134- member x.E = match f with None -> e | Some f -> f () .E
150+ member x.E = match box e with null -> ( e <- f.Value () .E); e | _ -> e
135151 override x.ToString () = sprintf " %+A " x.E
136152
137153 member x.ImmediateSubExpressions =
@@ -150,7 +166,7 @@ and [<Sealed>] FSharpExpr (cenv, f: (unit -> FSharpExpr) option, e: E, m: range,
150166 | E.NewUnionCase (_ unionType, _ unionCase, es) -> es
151167 | E.NewTuple (_ tupleType, es) -> es
152168 | E.TupleGet (_ tupleType, _ itemIndex, tupleExpr) -> [ tupleExpr]
153- | E.Call ( objOpt, _ b, _ c, _ d, es) -> ( match objOpt with None -> es | Some x -> x :: es)
169+ | E.Call ( objOpt, _ b, _ c, _ d, ws , es) -> ( match objOpt with None -> ws @ es | Some x -> x :: ws @ es)
154170 | E.NewObject (_ a, _ b, c) -> c
155171 | E.FSharpFieldGet ( objOpt, _ b, _ c) -> ( match objOpt with None -> [] | Some x -> [ x])
156172 | E.FSharpFieldSet ( objOpt, _ b, _ c, d) -> ( match objOpt with None -> [ d] | Some x -> [ x; d])
@@ -187,7 +203,7 @@ and [<Sealed>] FSharpExpr (cenv, f: (unit -> FSharpExpr) option, e: E, m: range,
187203 | E.UnionCaseSet ( obj, _ unionType, _ unionCase, _ unionField, valueExpr) -> [ yield obj; yield valueExpr ]
188204 | E.TraitCall (_ sourceTypes, _ traitName, _ memberFlags, _ paramTypes, _ retTypes, args) -> args
189205 | E.Unused -> [] // unexpected
190-
206+ | E.WitnessArg _ n -> []
191207
192208/// The implementation of the conversion operation
193209module FSharpExprConvert =
@@ -409,19 +425,19 @@ module FSharpExprConvert =
409425 let ( numEnclTypeArgs , _ , isNewObj , _valUseFlags , _isSelfInit , takesInstanceArg , _isPropGet , _isPropSet ) =
410426 GetMemberCallInfo cenv.g ( vref, vFlags)
411427
412- let isMember , curriedArgInfos =
428+ let isMember , tps , curriedArgInfos =
413429
414430 match vref.MemberInfo with
415431 | Some _ when not vref.IsExtensionMember ->
416432 // This is an application of a member method
417433 // We only count one argument block for these.
418- let _tps , curriedArgInfos , _ , _ = GetTypeOfMemberInFSharpForm cenv.g vref
419- true , curriedArgInfos
434+ let tps , curriedArgInfos , _ , _ = GetTypeOfMemberInFSharpForm cenv.g vref
435+ true , tps , curriedArgInfos
420436 | _ ->
421437 // This is an application of a module value or extension member
422438 let arities = arityOfVal vref.Deref
423- let _tps , curriedArgInfos , _ , _ = GetTopValTypeInFSharpForm cenv.g arities vref.Type m
424- false , curriedArgInfos
439+ let tps , curriedArgInfos , _ , _ = GetTopValTypeInFSharpForm cenv.g arities vref.Type m
440+ false , tps , curriedArgInfos
425441
426442 // Compute the object arguments as they appear in a compiled call
427443 // Strip off the object argument, if any. The curriedArgInfos are already adjusted to compiled member form
@@ -467,12 +483,35 @@ module FSharpExprConvert =
467483 if isMember then
468484 let callArgs = ( objArgs :: untupledCurriedArgs) |> List.concat
469485 let enclTyArgs , methTyArgs = List.splitAfter numEnclTypeArgs tyargs
486+ let witnessArgsR = GetWitnessArgs cenv env vref m tps tyargs
470487 // tailcall
471- ConvObjectModelCallLinear cenv env ( isNewObj, FSharpMemberOrFunctionOrValue( cenv, vref), enclTyArgs, methTyArgs, callArgs) contf2
488+ ConvObjectModelCallLinear cenv env ( isNewObj, FSharpMemberOrFunctionOrValue( cenv, vref), enclTyArgs, methTyArgs, witnessArgsR , callArgs) contf2
472489 else
473490 let v = FSharpMemberOrFunctionOrValue( cenv, vref)
491+ let witnessArgsR = GetWitnessArgs cenv env vref m vref.Typars tyargs
474492 // tailcall
475- ConvObjectModelCallLinear cenv env ( false , v, [], tyargs, List.concat untupledCurriedArgs) contf2
493+ ConvObjectModelCallLinear cenv env ( false , v, [], tyargs, witnessArgsR, List.concat untupledCurriedArgs) contf2
494+
495+ and GetWitnessArgs cenv ( env : ExprTranslationEnv ) ( vref : ValRef ) m tps tyargs : FSharpExpr list =
496+ let g = cenv.g
497+ if cenv.g.langVersion.SupportsFeature( Features.LanguageFeature.WitnessPassing) && not env.suppressWitnesses then
498+ let witnessExprs =
499+ match ConstraintSolver.CodegenWitnessesForTyparInst cenv.tcValF g cenv.amap m tps tyargs with
500+ // There is a case where optimized code makes expressions that do a shift-left on the 'char'
501+ // type. There is no witness for this case. This is due to the code
502+ // let inline HashChar (x:char) = (# "or" (# "shl" x 16 : int #) x : int #)
503+ // in FSharp.Core.
504+ | ErrorResult _ when vref.LogicalName = " op_LeftShift" && tyargs.Length = 1 -> []
505+ | res -> CommitOperationResult res
506+ let env = { env with suppressWitnesses = true }
507+ witnessExprs |> List.map ( fun arg ->
508+ match arg with
509+ | Choice1Of2 traitInfo ->
510+ ConvWitnessInfo cenv env m traitInfo
511+ | Choice2Of2 arg ->
512+ ConvExpr cenv env arg)
513+ else
514+ []
476515
477516 and ConvExprPrim ( cenv : SymbolEnv ) ( env : ExprTranslationEnv ) expr =
478517 // Eliminate integer 'for' loops
@@ -554,7 +593,7 @@ module FSharpExprConvert =
554593 let vslR = List.map ( List.map ( ConvVal cenv)) tmvs
555594 let sgn = FSharpAbstractSignature( cenv, slotsig)
556595 let tpsR = [ for tp in tps -> FSharpGenericParameter( cenv, tp) ]
557- let env = ExprTranslationEnv.Empty .BindTypars ( Seq.zip tps tpsR |> Seq.toList)
596+ let env = env .BindTypars ( Seq.zip tps tpsR |> Seq.toList)
558597 let env = env.BindCurriedVals tmvs
559598 let bodyR = ConvExpr cenv env body
560599 FSharpObjectExprOverride( sgn, tpsR, vslR, bodyR) ]
@@ -841,9 +880,29 @@ module FSharpExprConvert =
841880 ConvExprPrim cenv env replExpr
842881
843882 | _ -> wfail ( sprintf " unhandled construct in AST" , m)
883+ | Expr.WitnessArg ( traitInfo, _ m) ->
884+ ConvWitnessInfoPrim cenv env traitInfo
844885 | _ ->
845886 wfail ( sprintf " unhandled construct in AST" , expr.Range)
846887
888+ and ConvWitnessInfoPrim _cenv env traitInfo : E =
889+ let witnessInfo = traitInfo.TraitKey
890+ let env = { env with suppressWitnesses = true }
891+ // First check if this is a witness in ReflectedDefinition code
892+ if env.witnessesInScope.ContainsKey witnessInfo then
893+ let witnessArgIdx = env.witnessesInScope.[ witnessInfo]
894+ E.WitnessArg( witnessArgIdx)
895+ // Otherwise it is a witness in a quotation literal
896+ else
897+ //failwith "witness not found"
898+ E.WitnessArg(- 1 )
899+
900+ and ConvWitnessInfo cenv env m traitInfo : FSharpExpr =
901+ let g = cenv.g
902+ let witnessInfo = traitInfo.TraitKey
903+ let witnessTy = GenWitnessTy g witnessInfo
904+ let traitInfoR = ConvWitnessInfoPrim cenv env traitInfo
905+ Mk cenv m witnessTy traitInfoR
847906
848907 and ConvLetBind cenv env ( bind : Binding ) =
849908 match bind.Expr with
@@ -895,7 +954,7 @@ module FSharpExprConvert =
895954 let enclosingType = generalizedTyconRef tcref
896955
897956 let makeCall minfo =
898- ConvObjectModelCallLinear cenv env ( isNewObj, minfo, enclTypeArgs, methTypeArgs, callArgs) id
957+ ConvObjectModelCallLinear cenv env ( isNewObj, minfo, enclTypeArgs, methTypeArgs, [], callArgs) id
899958
900959 let makeFSCall isMember ( vr : ValRef ) =
901960 let memOrVal =
@@ -1079,7 +1138,7 @@ module FSharpExprConvert =
10791138 with e ->
10801139 failwithf " An IL call to '%s ' could not be resolved: %s " ( ilMethRef.ToString()) e.Message
10811140
1082- and ConvObjectModelCallLinear cenv env ( isNewObj , v : FSharpMemberOrFunctionOrValue , enclTyArgs , methTyArgs , callArgs ) contF =
1141+ and ConvObjectModelCallLinear cenv env ( isNewObj , v : FSharpMemberOrFunctionOrValue , enclTyArgs , methTyArgs , witnessArgsR : FSharpExpr list , callArgs ) contF =
10831142 let enclTyArgsR = ConvTypes cenv enclTyArgs
10841143 let methTyArgsR = ConvTypes cenv methTyArgs
10851144 let obj , callArgs =
@@ -1095,8 +1154,7 @@ module FSharpExprConvert =
10951154 if isNewObj then
10961155 E.NewObject( v, enclTyArgsR, callArgsR)
10971156 else
1098- E.Call( objR, v, enclTyArgsR, methTyArgsR, callArgsR))
1099-
1157+ E.Call( objR, v, enclTyArgsR, methTyArgsR, witnessArgsR, callArgsR))
11001158
11011159 and ConvExprs cenv env args = List.map ( ConvExpr cenv env) args
11021160
@@ -1255,7 +1313,7 @@ and FSharpImplementationFileContents(cenv, mimpl) =
12551313 let v = FSharpMemberOrFunctionOrValue( cenv, mkLocalValRef v)
12561314 let gps = v.GenericParameters
12571315 let vslR = List.map ( List.map ( FSharpExprConvert.ConvVal cenv)) vsl
1258- let env = ExprTranslationEnv.Empty.BindTypars ( Seq.zip tps gps |> Seq.toList)
1316+ let env = ExprTranslationEnv.Empty( cenv.g ) .BindTypars ( Seq.zip tps gps |> Seq.toList)
12591317 let env = env.BindCurriedVals vsl
12601318 let e = FSharpExprConvert.ConvExprOnDemand cenv env body
12611319 FSharpImplementationFileDeclaration.MemberOrFunctionOrValue( v, vslR, e)
@@ -1277,7 +1335,7 @@ and FSharpImplementationFileContents(cenv, mimpl) =
12771335 | TMDefLet( bind, _ m) ->
12781336 [ yield getBind bind ]
12791337 | TMDefDo( expr, _ m) ->
1280- [ let expr = FSharpExprConvert.ConvExprOnDemand cenv ExprTranslationEnv.Empty expr
1338+ [ let expr = FSharpExprConvert.ConvExprOnDemand cenv ( ExprTranslationEnv.Empty( cenv.g )) expr
12811339 yield FSharpImplementationFileDeclaration.InitAction expr ]
12821340 | TMDefs mdefs ->
12831341 [ for mdef in mdefs do yield ! getDecls mdef ]
@@ -1303,7 +1361,8 @@ module BasicPatterns =
13031361 let (| NewUnionCase | _ |) ( e : FSharpExpr ) = match e.E with E.NewUnionCase ( e, tys, es) -> Some ( e, tys, es) | _ -> None
13041362 let (| NewTuple | _ |) ( e : FSharpExpr ) = match e.E with E.NewTuple ( ty, es) -> Some ( ty, es) | _ -> None
13051363 let (| TupleGet | _ |) ( e : FSharpExpr ) = match e.E with E.TupleGet ( ty, n, es) -> Some ( ty, n, es) | _ -> None
1306- let (| Call | _ |) ( e : FSharpExpr ) = match e.E with E.Call ( a, b, c, d, e) -> Some ( a, b, c, d, e) | _ -> None
1364+ let (| Call | _ |) ( e : FSharpExpr ) = match e.E with E.Call ( a, b, c, d, _ e, f) -> Some ( a, b, c, d, f) | _ -> None
1365+ let (| CallWithWitnesses | _ |) ( e : FSharpExpr ) = match e.E with E.Call ( a, b, c, d, e, f) -> Some ( a, b, c, d, e, f) | _ -> None
13071366 let (| NewObject | _ |) ( e : FSharpExpr ) = match e.E with E.NewObject ( a, b, c) -> Some ( a, b, c) | _ -> None
13081367 let (| FSharpFieldGet | _ |) ( e : FSharpExpr ) = match e.E with E.FSharpFieldGet ( a, b, c) -> Some ( a, b, c) | _ -> None
13091368 let (| AnonRecordGet | _ |) ( e : FSharpExpr ) = match e.E with E.AnonRecordGet ( a, b, c) -> Some ( a, b, c) | _ -> None
@@ -1335,4 +1394,5 @@ module BasicPatterns =
13351394 let (| DecisionTreeSuccess | _ |) ( e : FSharpExpr ) = match e.E with E.DecisionTreeSuccess ( a, b) -> Some ( a, b) | _ -> None
13361395 let (| UnionCaseSet | _ |) ( e : FSharpExpr ) = match e.E with E.UnionCaseSet ( a, b, c, d, e) -> Some ( a, b, c, d, e) | _ -> None
13371396 let (| TraitCall | _ |) ( e : FSharpExpr ) = match e.E with E.TraitCall ( a, b, c, d, e, f) -> Some ( a, b, c, d, e, f) | _ -> None
1397+ let (| WitnessArg | _ |) ( e : FSharpExpr ) = match e.E with E.WitnessArg n -> Some n | _ -> None
13381398
0 commit comments