Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC FS-1071] Witnesses passing for trait-constraints w.r.t. quotations #6810

Merged
merged 55 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
c4d65ea
cleanup for feature/witness-passing
dsyme Apr 17, 2020
b5154a2
witness passing implementation
dsyme Apr 17, 2020
9754e4b
fix build
dsyme Apr 17, 2020
65b002c
Merge branch 'master' of https://github.com/dotnet/fsharp into featur…
dsyme Apr 17, 2020
14e3785
Merge branch 'feature/witness-passing-cleanup' of https://github.com/…
dsyme Apr 17, 2020
5ed3392
cleanup for feature/witness-passing
dsyme Apr 17, 2020
f138f00
Merge branch 'feature/witness-passing-cleanup' of https://github.com/…
dsyme Apr 17, 2020
f7dc2a8
Merge commit 'ad1ad7712ae92ddc33932094d67947c58246a45e' of https://gi…
dsyme Apr 20, 2020
634c8cb
Merge commit '274379f1016491358e159d11f75d46fb5ec195a9' of https://gi…
dsyme Apr 20, 2020
4af0468
Merge branch 'master' of https://github.com/dotnet/fsharp into featur…
dsyme Apr 20, 2020
71521e4
simplify code
dsyme Apr 20, 2020
c861248
Merge pull request #9012 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 22, 2020
e09b5bc
Merge pull request #9027 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 22, 2020
0314542
Merge pull request #9033 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 23, 2020
bf486e2
Merge pull request #9043 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 25, 2020
1e787d6
Merge branch 'master' of https://github.com/dotnet/fsharp into featur…
dsyme Apr 27, 2020
937f4b3
remove NoDynamicInvocation attribute from signature files
dsyme Apr 27, 2020
cceb94e
Merge pull request #9056 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 27, 2020
b969432
Merge pull request #9072 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 29, 2020
640d3a0
Merge pull request #9077 from dotnet/merges/master-to-feature/witness…
KevinRansom Apr 30, 2020
f6ecd92
Merge pull request #9082 from dotnet/merges/master-to-feature/witness…
KevinRansom May 1, 2020
6252f77
Merge pull request #9092 from dotnet/merges/master-to-feature/witness…
KevinRansom May 1, 2020
355b8a5
Merge pull request #9096 from dotnet/merges/master-to-feature/witness…
KevinRansom May 4, 2020
df7b82d
Merge pull request #9129 from dotnet/merges/master-to-feature/witness…
KevinRansom May 5, 2020
b90becc
Merge branch 'master' of https://github.com/dotnet/fsharp into featur…
dsyme May 5, 2020
832baf1
fix quotations in inline code that pass witness args
dsyme May 5, 2020
9690386
Merge branch 'feature/witness-passing' of https://github.com/dotnet/f…
dsyme May 5, 2020
4ade851
isLegacy internal
dsyme May 5, 2020
5989abb
cleanup WitnessArg and add documentation
dsyme May 6, 2020
050b022
fix test
dsyme May 6, 2020
d405ac6
Merge pull request #9158 from dotnet/merges/master-to-feature/witness…
KevinRansom May 11, 2020
17be08e
Merge pull request #9171 from dotnet/merges/master-to-feature/witness…
KevinRansom May 13, 2020
3a191b0
Merge pull request #9180 from dotnet/merges/master-to-feature/witness…
KevinRansom May 14, 2020
c079b66
Merge pull request #9189 from dotnet/merges/master-to-feature/witness…
KevinRansom May 14, 2020
bcf2464
Merge pull request #9195 from dotnet/merges/master-to-feature/witness…
KevinRansom May 15, 2020
e8f1129
Merge pull request #9203 from dotnet/merges/master-to-feature/witness…
KevinRansom May 16, 2020
f1b9dcf
Merge pull request #9209 from dotnet/merges/master-to-feature/witness…
KevinRansom May 16, 2020
a70b723
Merge pull request #9213 from dotnet/merges/master-to-feature/witness…
KevinRansom May 17, 2020
05ba6e0
fix abs bug and test calling it
dsyme May 20, 2020
2e04e6d
Merge pull request #9237 from dotnet/merges/master-to-feature/witness…
KevinRansom May 20, 2020
dd05208
Merge pull request #9248 from dotnet/merges/master-to-feature/witness…
KevinRansom May 23, 2020
b2543cd
Merge branch 'master' into feature/witness-passing
dsyme May 26, 2020
e0e9426
Merge pull request #9305 from dotnet/merges/master-to-feature/witness…
KevinRansom May 26, 2020
878d4eb
Merge pull request #9310 from dotnet/merges/master-to-feature/witness…
KevinRansom May 27, 2020
debf17a
code review feedback
dsyme May 28, 2020
7f05686
Merge pull request #9319 from dotnet/merges/master-to-feature/witness…
KevinRansom May 28, 2020
2f70685
Merge pull request #9325 from dotnet/merges/master-to-feature/witness…
KevinRansom May 28, 2020
48512f1
Merge pull request #9330 from dotnet/merges/master-to-feature/witness…
KevinRansom May 29, 2020
4b0235c
Merge pull request #9343 from dotnet/merges/master-to-feature/witness…
KevinRansom Jun 1, 2020
ac0476c
Merge pull request #9352 from dotnet/merges/master-to-feature/witness…
KevinRansom Jun 1, 2020
a60ab5a
fix build
dsyme Jun 1, 2020
2d74d24
clarify code
dsyme Jun 1, 2020
51dc071
Merge pull request #9359 from dotnet/merges/master-to-feature/witness…
KevinRansom Jun 2, 2020
a51f7a4
Merge pull request #9365 from dotnet/merges/master-to-feature/witness…
KevinRansom Jun 2, 2020
9a61860
Merge pull request #9372 from dotnet/merges/master-to-feature/witness…
KevinRansom Jun 2, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions src/fsharp/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ type ConstraintSolverState =
/// The function used to freshen values we encounter during trait constraint solving
TcVal: TcValF

/// Indicates if the constraint solver is being run after type checking is complete,
/// e.g. during codegen to determine solutions and witnesses for trait constraints.
/// Suppresses the generation of certain errors such as missing constraint warnings.
codegen: bool

/// This table stores all unsolved, ungeneralized trait constraints, indexed by free type variable.
/// That is, there will be one entry in this table for each free type variable in
/// each outstanding, unsolved, ungeneralized trait constraint. Constraints are removed from the table and resolved
Expand All @@ -257,6 +262,7 @@ type ConstraintSolverState =
amap = amap
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
InfoReader = infoReader
codegen = false
TcVal = tcVal }

type ConstraintSolverEnv =
Expand Down Expand Up @@ -1939,14 +1945,14 @@ and AddConstraint (csenv: ConstraintSolverEnv) ndeep m2 trace tp newConstraint
| (TyparRigidity.Rigid | TyparRigidity.WillBeRigid), TyparConstraint.DefaultsTo _ -> true
| _ -> false) then
()
elif tp.Rigidity = TyparRigidity.Rigid then
elif tp.Rigidity = TyparRigidity.Rigid && not csenv.SolverState.codegen then
return! ErrorD (ConstraintSolverMissingConstraint(denv, tp, newConstraint, m, m2))
else
// It is important that we give a warning if a constraint is missing from a
// will-be-made-rigid type variable. This is because the existence of these warnings
// is relevant to the overload resolution rules (see 'candidateWarnCount' in the overload resolution
// implementation).
if tp.Rigidity.WarnIfMissingConstraint then
if tp.Rigidity.WarnIfMissingConstraint && not csenv.SolverState.codegen then
do! WarnD (ConstraintSolverMissingConstraint(denv, tp, newConstraint, m, m2))

let newConstraints =
Expand Down Expand Up @@ -3059,20 +3065,36 @@ let CreateCodegenState tcVal g amap =
amap = amap
TcVal = tcVal
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
InfoReader = new InfoReader(g, amap) }
InfoReader = new InfoReader(g, amap)
codegen = true }

/// Generate a witness expression if none is otherwise available, e.g. in legacy non-witness-passing code
let CodegenWitnessForTraitConstraint tcVal g amap m (traitInfo: TraitConstraintInfo) argExprs = trackErrors {
let CodegenWitnessForTraitConstraint tcVal g amap m (traitInfo:TraitConstraintInfo) argExprs = trackErrors {
let css = CreateCodegenState tcVal g amap

let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)

let! _res = SolveMemberConstraint csenv true PermitWeakResolution.Yes 0 m NoTrace traitInfo

let sln = GenWitnessExpr amap g m traitInfo argExprs
return sln
}

/// Generate the lambda argument passed for a use of a generic construct that accepts trait witnesses
let CodegenWitnessesForTyparInst tcVal g amap m typars tyargs = trackErrors {
let css = CreateCodegenState tcVal g amap
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)
let ftps, _renaming, tinst = FreshenTypeInst m typars
let traitInfos = GetTraitConstraintInfosOfTypars g ftps
do! SolveTypeEqualsTypeEqns csenv 0 m NoTrace None tinst tyargs
return MethodCalls.GenWitnessArgs amap g m traitInfos
}

/// Generate the lambda argument passed for a use of a generic construct that accepts trait witnesses
let CodegenWitnessesForTraitWitness tcVal g amap m traitInfo = trackErrors {
let css = CreateCodegenState tcVal g amap
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)
let! _res = SolveMemberConstraint csenv true PermitWeakResolution.Yes 0 m NoTrace traitInfo
return MethodCalls.GenWitnessExprLambda amap g m traitInfo
}

/// For some code like "let f() = ([] = [])", a free choice is made for a type parameter
/// for an interior type variable. This chooses a solution for a type parameter subject
/// to its constraints and applies that solution by using a constraint.
Expand Down Expand Up @@ -3118,6 +3140,7 @@ let IsApplicableMethApprox g amap m (minfo: MethInfo) availObjTy =
amap = amap
TcVal = (fun _ -> failwith "should not be called")
ExtraCxs = HashMultiMap(10, HashIdentity.Structural)
codegen = false
InfoReader = new InfoReader(g, amap) }
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g)
let minst = FreshenMethInfo m minfo
Expand Down
10 changes: 8 additions & 2 deletions src/fsharp/ConstraintSolver.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,18 @@ val SolveTypeAsError: DisplayEnv -> ConstraintSolverState -> range -> TType -> u
val ApplyTyparDefaultAtPriority: DisplayEnv -> ConstraintSolverState -> priority: int -> Typar -> unit

/// Generate a witness expression if none is otherwise available, e.g. in legacy non-witness-passing code
val CodegenWitnessForTraitConstraint: TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> Expr list -> OperationResult<Expr option>
val CodegenWitnessForTraitConstraint : TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> Expr list -> OperationResult<Expr option>

/// Generate the arguments passed when using a generic construct that accepts traits witnesses
val CodegenWitnessesForTyparInst : TcValF -> TcGlobals -> ImportMap -> range -> Typars -> TType list -> OperationResult<Choice<TraitConstraintInfo, Expr> list>

/// Generate the lambda argument passed for a use of a generic construct that accepts trait witnesses
val CodegenWitnessesForTraitWitness : TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> OperationResult<Choice<TraitConstraintInfo, Expr>>

/// For some code like "let f() = ([] = [])", a free choice is made for a type parameter
/// for an interior type variable. This chooses a solution for a type parameter subject
/// to its constraints and applies that solution by using a constraint.
val ChooseTyparSolutionAndSolve: ConstraintSolverState -> DisplayEnv -> Typar -> unit
val ChooseTyparSolutionAndSolve : ConstraintSolverState -> DisplayEnv -> Typar -> unit

val IsApplicableMethApprox: TcGlobals -> ImportMap -> range -> MethInfo -> TType -> bool

Expand Down
1 change: 1 addition & 0 deletions src/fsharp/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1512,3 +1512,4 @@ featureFixedIndexSlice3d4d,"fixed-index slice 3d/4d"
featureAndBang,"applicative computation expressions"
featureNullableOptionalInterop,"nullable optional interop"
featureDefaultInterfaceMemberConsumption,"default interface member consumption"
featureWitnessPassing,"witness passing"
Original file line number Diff line number Diff line change
Expand Up @@ -406,10 +406,10 @@
<Link>TypedTree\TypedTreeOps.fs</Link>
</Compile>
<Compile Include="..\TypedTreePickle.fsi">
<Link>TypedTree\.TypedTreePickle.fsi</Link>
<Link>TypedTree\TypedTreePickle.fsi</Link>
</Compile>
<Compile Include="..\TypedTreePickle.fs">
<Link>TypedTree\.TypedTreePickle.fs</Link>
<Link>TypedTree\TypedTreePickle.fs</Link>
</Compile>
<Compile Include="..\import.fsi">
<Link>Logic\import.fsi</Link>
Expand Down
38 changes: 23 additions & 15 deletions src/fsharp/FSharp.Core/Linq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ module LeafExpressionConverter =
| NullableGreaterEqNullableQ _ -> transBinOp inp env false args false Expression.GreaterThanOrEqual
| NullableLessNullableQ _ -> transBinOp inp env false args false Expression.LessThan
| NullableLessEqNullableQ _ -> transBinOp inp env false args false Expression.LessThanOrEqual

// Detect the F# quotation encoding of decimal literals
| MakeDecimalQ (_, _, [Int32 lo; Int32 med; Int32 hi; Bool isNegative; Byte scale]) ->
Expression.Constant (new System.Decimal(lo, med, hi, isNegative, scale)) |> asExpr
Expand All @@ -414,33 +414,33 @@ module LeafExpressionConverter =
| BitwiseOrQ _ -> transBinOp inp env false args false Expression.Or
| BitwiseXorQ _ -> transBinOp inp env false args false Expression.ExclusiveOr
| BitwiseNotQ (_, _, [x1]) -> Expression.Not(ConvExprToLinqInContext env x1) |> asExpr

| CheckedNeg (_, _, [x1]) -> Expression.NegateChecked(ConvExprToLinqInContext env x1) |> asExpr
| CheckedNeg (_, _, [x1]) -> Expression.NegateChecked(ConvExprToLinqInContext env x1) |> asExpr
| CheckedPlusQ _ -> transBinOp inp env false args false Expression.AddChecked
| CheckedMinusQ _ -> transBinOp inp env false args false Expression.SubtractChecked
| CheckedMultiplyQ _ -> transBinOp inp env false args false Expression.MultiplyChecked

| NullablePlusQ _ -> transBinOp inp env false args true Expression.Add
| PlusNullableQ _ -> transBinOp inp env true args false Expression.Add
| NullablePlusNullableQ _ -> transBinOp inp env false args false Expression.Add

| NullableMinusQ _ -> transBinOp inp env false args true Expression.Subtract
| MinusNullableQ _ -> transBinOp inp env true args false Expression.Subtract
| NullableMinusNullableQ _ -> transBinOp inp env false args false Expression.Subtract

| NullableMultiplyQ _ -> transBinOp inp env false args true Expression.Multiply
| MultiplyNullableQ _ -> transBinOp inp env true args false Expression.Multiply
| NullableMultiplyNullableQ _ -> transBinOp inp env false args false Expression.Multiply

| NullableDivideQ _ -> transBinOp inp env false args true Expression.Divide
| DivideNullableQ _ -> transBinOp inp env true args false Expression.Divide
| NullableDivideNullableQ _ -> transBinOp inp env false args false Expression.Divide

| NullableModuloQ _ -> transBinOp inp env false args true Expression.Modulo
| ModuloNullableQ _ -> transBinOp inp env true args false Expression.Modulo
| NullableModuloNullableQ _ -> transBinOp inp env false args false Expression.Modulo

| ConvNullableCharQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof<Nullable<char>>) |> asExpr
| ConvNullableCharQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof<Nullable<char>>) |> asExpr
| ConvNullableDecimalQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof<Nullable<decimal>>) |> asExpr
| ConvNullableFloatQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof<Nullable<float>>) |> asExpr
| ConvNullableDoubleQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof<Nullable<double>>) |> asExpr
Expand Down Expand Up @@ -496,10 +496,19 @@ module LeafExpressionConverter =
// Throw away markers inserted to satisfy C#'s design where they pass an argument
// or type T to an argument expecting Expression<T>.
| ImplicitExpressionConversionHelperQ (_, [_], [x1]) -> ConvExprToLinqInContext env x1

| _ ->
let argsP = ConvExprsToLinq env args
Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> asExpr

/// Use witnesses if they are available
| CallWithWitnesses (objArgOpt, _, minfo2, witnessArgs, args) ->
let fullArgs = witnessArgs @ args
let replacementExpr =
match objArgOpt with
| None -> Expr.Call(minfo2, fullArgs)
| Some objArg -> Expr.Call(objArg, minfo2, fullArgs)
ConvExprToLinqInContext env replacementExpr

| _ ->
let argsP = ConvExprsToLinq env args
Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> asExpr

#if !NO_CURRIED_FUNCTION_OPTIMIZATIONS
// f x1 x2 x3 x4 --> InvokeFast4
Expand Down Expand Up @@ -650,12 +659,11 @@ module LeafExpressionConverter =
let convType = lambdaTy.MakeGenericType tyargs
let convDelegate = Expression.Lambda(convType, bodyP, [| vP |]) |> asExpr
Expression.Call(typeof<FuncConvert>, "ToFSharpFunc", tyargs, [| convDelegate |]) |> asExpr

| _ ->
failConvert inp

and failConvert inp =
raise (new NotSupportedException(Printf.sprintf "Could not convert the following F# Quotation to a LINQ Expression Tree\n--------\n%A\n-------------\n" inp))
raise (new NotSupportedException(Printf.sprintf "Could not convert the following F# Quotation to a LINQ Expression Tree\n--------\n%A\n-------------\n" inp))

and transBinOp inp env addConvertLeft args addConvertRight (exprErasedConstructor : _ * _ -> _) =
match args with
Expand Down
11 changes: 0 additions & 11 deletions src/fsharp/FSharp.Core/nativeptr.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,27 @@ namespace Microsoft.FSharp.NativeInterop
module NativePtr =

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("OfNativeIntInlined")>]
/// <summary>Returns a typed native pointer for a given machine address.</summary>
/// <param name="address">The pointer address.</param>
/// <returns>A typed pointer.</returns>
val inline ofNativeInt : address:nativeint -> nativeptr<'T>

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("ToVoidPtrInlined")>]
/// <summary>Returns an untyped native pointer for a given typed pointer.</summary>
/// <param name="address">The pointer address.</param>
/// <returns>A typed pointer.</returns>
val inline toVoidPtr : address:nativeptr<'T> -> voidptr

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("OfVoidPtrInlined")>]
/// <summary>Returns a typed native pointer for a untyped native pointer.</summary>
/// <param name="address">The untyped pointer.</param>
/// <returns>A typed pointer.</returns>
val inline ofVoidPtr : voidptr -> nativeptr<'T>

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("ToNativeIntInlined")>]
/// <summary>Returns a machine address for a given typed native pointer.</summary>
/// <param name="address">The input pointer.</param>
Expand All @@ -45,7 +41,6 @@ namespace Microsoft.FSharp.NativeInterop


[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("AddPointerInlined")>]
/// <summary>Returns a typed native pointer by adding index * sizeof&lt;'T&gt; to the
/// given input pointer.</summary>
Expand All @@ -55,7 +50,6 @@ namespace Microsoft.FSharp.NativeInterop
val inline add : address:nativeptr<'T> -> index:int -> nativeptr<'T>

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("GetPointerInlined")>]
/// <summary>Dereferences the typed native pointer computed by adding index * sizeof&lt;'T&gt; to the
/// given input pointer.</summary>
Expand All @@ -65,23 +59,20 @@ namespace Microsoft.FSharp.NativeInterop
val inline get : address:nativeptr<'T> -> index:int -> 'T

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("ReadPointerInlined")>]
/// <summary>Dereferences the given typed native pointer.</summary>
/// <param name="address">The input pointer.</param>
/// <returns>The value at the pointer address.</returns>
val inline read : address:nativeptr<'T> -> 'T

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("WritePointerInlined")>]
/// <summary>Assigns the <c>value</c> into the memory location referenced by the given typed native pointer.</summary>
/// <param name="address">The input pointer.</param>
/// <param name="value">The value to assign.</param>
val inline write : address:nativeptr<'T> -> value:'T -> unit

[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("SetPointerInlined")>]
/// <summary>Assigns the <c>value</c> into the memory location referenced by the typed native
/// pointer computed by adding index * sizeof&lt;'T&gt; to the given input pointer.</summary>
Expand All @@ -94,14 +85,12 @@ namespace Microsoft.FSharp.NativeInterop
/// <param name="count">The number of objects of type T to allocate.</param>
/// <returns>A typed pointer to the allocated memory.</returns>
[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("StackAllocate")>]
val inline stackalloc : count:int -> nativeptr<'T>

/// <summary>Converts a given typed native pointer to a managed pointer.</summary>
/// <param name="address">The input pointer.</param>
/// <returns>The managed pointer.</returns>
[<Unverifiable>]
[<NoDynamicInvocation>]
[<CompiledName("ToByRefInlined")>]
val inline toByRef : nativeptr<'T> -> byref<'T>
Loading