未验证 提交 55a5ddbc 编写于 作者: D Don Syme 提交者: GitHub

Fix for 12184 - correct pre-processing of type information from overloads...

Fix for 12184 - correct pre-processing of type information from overloads involving SRTP constraints (#12202)

* constraint fixes

* constraint fixes

* add test

* constraint fixes

* add testing

* add testing

* alternative fix, non-breaking

* alternative fix, non-breaking

* tweak tests

* update baseline

* pin down lang version behaviour

* pin down lang version behaviour

* disable tests that fail in debug, require release

* adjust cherry pick

* fix test logic

* fix baseline
上级 2708e585
......@@ -9133,10 +9133,21 @@ and TcMethodApplication
let lambdaPropagationInfo =
if preArgumentTypeCheckingCalledMethGroup.Length > 1 then
[| for meth in preArgumentTypeCheckingCalledMethGroup do
match ExamineMethodForLambdaPropagation meth ad with
match ExamineMethodForLambdaPropagation cenv.g mMethExpr meth ad with
| Some (unnamedInfo, namedInfo) ->
let calledObjArgTys = meth.CalledObjArgTys mMethExpr
if (calledObjArgTys, callerObjArgTys) ||> Seq.forall2 (fun calledTy callerTy -> AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv cenv.css mMethExpr calledTy callerTy) then
if (calledObjArgTys, callerObjArgTys) ||> Seq.forall2 (fun calledTy callerTy ->
let noEagerConstraintApplication = MethInfoHasAttribute cenv.g mMethExpr cenv.g.attrib_NoEagerConstraintApplicationAttribute meth.Method
// The logic associated with NoEagerConstraintApplicationAttribute is part of the
// Tasks and Resumable Code RFC
if noEagerConstraintApplication && not (cenv.g.langVersion.SupportsFeature LanguageFeature.ResumableStateMachines) then
errorR(Error(FSComp.SR.tcNoEagerConstraintApplicationAttribute(), mMethExpr))
let extraRigidTps = if noEagerConstraintApplication then Zset.ofList typarOrder (freeInTypeLeftToRight cenv.g true callerTy) else emptyFreeTypars
AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv cenv.css mMethExpr extraRigidTps calledTy callerTy) then
yield (List.toArraySquared unnamedInfo, List.toArraySquared namedInfo)
| None -> () |]
else
......@@ -9434,7 +9445,7 @@ and TcMethodNamedArg cenv env (lambdaPropagationInfo, tpenv) (CallerNamedArg(id,
let arg', (lambdaPropagationInfo, tpenv) = TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, arg)
CallerNamedArg(id, arg'), (lambdaPropagationInfo, tpenv)
and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, CallerArg(argTy, mArg, isOpt, argExpr)) =
and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoForArg, CallerArg(callerArgTy, mArg, isOpt, argExpr)) =
// Apply the F# 3.1 rule for extracting information for lambdas
//
......@@ -9469,9 +9480,9 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo
if AddCxTypeEqualsTypeUndoIfFailed env.DisplayEnv cenv.css mArg calledLambdaArgTy callerLambdaDomainTy then
loop callerLambdaRangeTy (lambdaVarNum + 1)
| _ -> ()
loop argTy 0
loop callerArgTy 0
let e', tpenv = TcExprFlex2 cenv argTy env true tpenv argExpr
let e', tpenv = TcExprFlex2 cenv callerArgTy env true tpenv argExpr
// After we have checked, propagate the info from argument into the overloads that receive it.
//
......@@ -9483,11 +9494,16 @@ and TcMethodArg cenv env (lambdaPropagationInfo, tpenv) (lambdaPropagationInfoFo
| ArgDoesNotMatch _ -> ()
| NoInfo | CallerLambdaHasArgTypes _ ->
yield info
| CalledArgMatchesType adjustedCalledTy ->
if AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed env.DisplayEnv cenv.css mArg adjustedCalledTy argTy then
| CalledArgMatchesType (adjustedCalledArgTy, noEagerConstraintApplication) ->
// If matching, we can solve 'tp1 --> tp2' but we can't transfer extra
// constraints from tp1 to tp2.
//
// The 'task' feature requires this fix to SRTP resolution.
let extraRigidTps = if noEagerConstraintApplication then Zset.ofList typarOrder (freeInTypeLeftToRight cenv.g true callerArgTy) else emptyFreeTypars
if AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed env.DisplayEnv cenv.css mArg extraRigidTps adjustedCalledArgTy callerArgTy then
yield info |]
CallerArg(argTy, mArg, isOpt, e'), (lambdaPropagationInfo, tpenv)
CallerArg(callerArgTy, mArg, isOpt, e'), (lambdaPropagationInfo, tpenv)
/// Typecheck "new Delegate(fun x y z -> ...)" constructs
and TcNewDelegateThen cenv (overallTy: OverallTy) env tpenv mDelTy mExprAndArg delegateTy arg atomicFlag delayed =
......
......@@ -309,13 +309,18 @@ type ConstraintSolverEnv =
// Is this speculative, with a trace allowing undo, and trial method overload resolution
IsSpeculativeForMethodOverloading: bool
/// Indicates that when unifying ty1 = ty2, only type variables in ty1 may be solved
/// Indicates that when unifying ty1 = ty2, only type variables in ty1 may be solved. Constraints
/// can't be added to type variables in ty2
MatchingOnly: bool
/// Indicates that special errors on unresolved SRTP constraint overloads may be generated. When
/// these are caught they result in postponed constraints.
ErrorOnFailedMemberConstraintResolution: bool
/// During MatchingOnly constraint solving, marks additional type variables as
/// rigid, preventing constraints flowing to those type variables.
ExtraRigidTypars: Zset<Typar>
m: range
EquivEnv: TypeEquivEnv
......@@ -339,7 +344,9 @@ let MakeConstraintSolverEnv contextInfo css m denv =
ErrorOnFailedMemberConstraintResolution = false
EquivEnv = TypeEquivEnv.Empty
DisplayEnv = denv
IsSpeculativeForMethodOverloading = false }
IsSpeculativeForMethodOverloading = false
ExtraRigidTypars = emptyFreeTypars
}
/// Check whether a type variable occurs in the r.h.s. of a type, e.g. to catch
/// infinite equations such as
......@@ -756,6 +763,10 @@ let SubstMeasureWarnIfRigid (csenv: ConstraintSolverEnv) trace (v: Typar) ms = t
()
}
let IsRigid (csenv: ConstraintSolverEnv) (tp: Typar) =
tp.Rigidity = TyparRigidity.Rigid
|| csenv.ExtraRigidTypars.Contains tp
/// Imperatively unify the unit-of-measure expression ms against 1.
/// There are three cases
/// - ms is (equivalent to) 1
......@@ -766,7 +777,7 @@ let UnifyMeasureWithOne (csenv: ConstraintSolverEnv) trace ms =
// Gather the rigid and non-rigid unit variables in this measure expression together with their exponents
let rigidVars, nonRigidVars =
ListMeasureVarOccsWithNonZeroExponents ms
|> List.partition (fun (v, _) -> v.Rigidity = TyparRigidity.Rigid)
|> List.partition (fun (v, _) -> IsRigid csenv v)
// If there is at least one non-rigid variable v with exponent e, then we can unify
match FindPreferredTypar nonRigidVars with
......@@ -918,7 +929,7 @@ let SimplifyMeasuresInTypeScheme g resultFirst (generalizable: Typar list) ty co
// Only bother if we're generalizing over at least one unit-of-measure variable
let uvars, vars =
generalizable
|> List.partition (fun v -> v.Kind = TyparKind.Measure && v.Rigidity <> TyparRigidity.Rigid)
|> List.partition (fun v -> v.Rigidity <> TyparRigidity.Rigid && v.Kind = TyparKind.Measure)
match uvars with
| [] -> generalizable
......@@ -1103,14 +1114,24 @@ and SolveTypeEqualsType (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTr
let sty2 = stripTyEqnsA csenv.g canShortcut ty2
match sty1, sty2 with
// type vars inside forall-types may be alpha-equivalent
| TType_var tp1, TType_var tp2 when typarEq tp1 tp2 || (match aenv.EquivTypars.TryFind tp1 with | Some v when typeEquiv g v ty2 -> true | _ -> false) -> CompleteD
| TType_var tp1, TType_var tp2 when typarEq tp1 tp2 || (match aenv.EquivTypars.TryFind tp1 with | Some v when typeEquiv g v ty2 -> true | _ -> false) ->
CompleteD
// 'v1 = 'v2
| TType_var tp1, TType_var tp2 when PreferUnifyTypar tp1 tp2 ->
SolveTyparEqualsType csenv ndeep m2 trace sty1 ty2
| TType_var tp1, TType_var tp2 when PreferUnifyTypar tp1 tp2 -> SolveTyparEqualsType csenv ndeep m2 trace sty1 ty2
| TType_var tp1, TType_var tp2 when not csenv.MatchingOnly && PreferUnifyTypar tp2 tp1 -> SolveTyparEqualsType csenv ndeep m2 trace sty2 ty1
// 'v1 = 'v2
| TType_var tp1, TType_var tp2 when not csenv.MatchingOnly && PreferUnifyTypar tp2 tp1 ->
SolveTyparEqualsType csenv ndeep m2 trace sty2 ty1
| TType_var r, _ when (r.Rigidity <> TyparRigidity.Rigid) -> SolveTyparEqualsType csenv ndeep m2 trace sty1 ty2
| _, TType_var r when (r.Rigidity <> TyparRigidity.Rigid) && not csenv.MatchingOnly -> SolveTyparEqualsType csenv ndeep m2 trace sty2 ty1
| TType_var r, _ when not (IsRigid csenv r) ->
SolveTyparEqualsType csenv ndeep m2 trace sty1 ty2
| _, TType_var r when not csenv.MatchingOnly && not (IsRigid csenv r) ->
SolveTyparEqualsType csenv ndeep m2 trace sty2 ty1
// Catch float<_>=float<1>, float32<_>=float32<1> and decimal<_>=decimal<1>
| _, TType_app (tc2, [ms]) when (tc2.IsMeasureableReprTycon && typeEquiv csenv.g sty1 (reduceTyconRefMeasureableOrProvided csenv.g tc2 [ms]))
......@@ -2061,7 +2082,7 @@ 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 IsRigid csenv tp 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
......@@ -3273,10 +3294,10 @@ let AddCxTypeMustSubsumeTypeUndoIfFailed denv css m ty1 ty2 =
let csenv = { csenv with ErrorOnFailedMemberConstraintResolution = true }
SolveTypeSubsumesTypeKeepAbbrevs csenv 0 m (WithTrace trace) None ty1 ty2)
let AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv css m ty1 ty2 =
let AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed denv css m extraRigidTypars ty1 ty2 =
UndoIfFailed (fun trace ->
let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv
let csenv = { csenv with MatchingOnly = true; ErrorOnFailedMemberConstraintResolution = true }
let csenv = { csenv with MatchingOnly = true; ErrorOnFailedMemberConstraintResolution = true; ExtraRigidTypars=extraRigidTypars }
SolveTypeSubsumesTypeKeepAbbrevs csenv 0 m (WithTrace trace) None ty1 ty2)
let AddCxTypeMustSubsumeType contextInfo denv css m trace ty1 ty2 =
......
......@@ -182,7 +182,7 @@ val AddCxTypeMustSubsumeType: ContextInfo -> DisplayEnv -> ConstraintSolverState
val AddCxTypeMustSubsumeTypeUndoIfFailed: DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool
val AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed: DisplayEnv -> ConstraintSolverState -> range -> TType -> TType -> bool
val AddCxTypeMustSubsumeTypeMatchingOnlyUndoIfFailed: DisplayEnv -> ConstraintSolverState -> range -> extraRigidTypars: FreeTypars -> TType -> TType -> bool
val AddCxMethodConstraint: DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TraitConstraintInfo -> unit
......
......@@ -1615,6 +1615,7 @@ forFormatInvalidForInterpolated4,"Interpolated strings used as type IFormattable
3501,tcResumableCodeArgMustHaveRightKind,"Invalid resumable code. A resumable code parameter must be of delegate or function type"
3501,tcResumableCodeContainsLetRec,"Invalid resumable code. A 'let rec' occured in the resumable code specification"
3510,tcResumableCodeNotSupported,"Using resumable code or resumable state machines requires /langversion:preview"
3510,tcNoEagerConstraintApplicationAttribute,"Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later"
3511,reprStateMachineNotCompilable,"This state machine is not statically compilable. %s. An alternative dynamic implementation will be used, which may be slower. Consider adjusting your code to ensure this state machine is statically compilable, or else suppress this warning."
3512,reprStateMachineNotCompilableNoAlternative,"This state machine is not statically compilable and no alternative is available. %s. Use an 'if __useResumableCode then <state-machine> else <alternative>' to give an alternative."
3513,tcResumableCodeInvocation,"Resumable code invocation. Suppress this warning if you are defining new low-level resumable code in terms of existing resumable code."
......
......@@ -20,6 +20,11 @@ open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Control
open Microsoft.FSharp.Collections
[<AttributeUsage (AttributeTargets.Method, AllowMultiple=false)>]
[<Sealed>]
type NoEagerConstraintApplicationAttribute() =
inherit System.Attribute()
type IResumableStateMachine<'Data> =
abstract ResumptionPoint: int
abstract Data: 'Data with get, set
......
......@@ -201,4 +201,40 @@ module StateMachineHelpers =
afterCode: AfterCode<'Data, 'Result>
-> 'Result
/// <summary>Adding this attribute to the method adjusts the processing of some generic methods
/// during overload resolution.</summary>
///
/// <remarks>During overload resolution, caller arguments are matched with called arguments
/// to extract type information. By default, when the caller argument type is unconstrained (for example
/// a simple value <c>x</c> without known type information), and a method qualifies for
/// lambda constraint propagation, then member trait constraints from a method overload
/// are eagerly applied to the caller argument type. This causes that overload to be preferred,
/// regardless of other method overload resolution rules. Using this attribute suppresses this behaviour.
/// </remarks>
///
/// <example>
/// Consider the following overloads:
/// <code>
/// type OverloadsWithSrtp() =
/// [&lt;NoEagerConstraintApplicationAttribute&gt;]
/// static member inline SomeMethod&lt; ^T when ^T : (member Number: int) &gt; (x: ^T, f: ^T -> int) = 1
/// static member SomeMethod(x: 'T list, f: 'T list -> int) = 2
///
/// let inline f x =
/// OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
/// </code>
/// With the attribute, the overload resolution fails, because both members are applicable.
/// Without the attribute, the overload resolution succeeds, because the member constraint is
/// eagerly applied, making the second member non-applicable.
/// </example>
/// <category>Attributes</category>
[<AttributeUsage (AttributeTargets.Method,AllowMultiple=false)>]
[<Sealed>]
type NoEagerConstraintApplicationAttribute =
inherit Attribute
/// <summary>Creates an instance of the attribute</summary>
/// <returns>NoEagerConstraintApplicationAttribute</returns>
new : unit -> NoEagerConstraintApplicationAttribute
#endif
......@@ -42,8 +42,8 @@ namespace Microsoft.FSharp.Control
type TaskBuilderBase() =
member inline _.Delay(f : unit -> TaskCode<'TOverall, 'T>) : TaskCode<'TOverall, 'T> =
TaskCode<'TOverall, 'T>(fun sm -> (f()).Invoke(&sm))
member inline _.Delay(generator : unit -> TaskCode<'TOverall, 'T>) : TaskCode<'TOverall, 'T> =
TaskCode<'TOverall, 'T>(fun sm -> (generator()).Invoke(&sm))
/// Used to represent no-ops like the implicit empty "else" branch of an "if" expression.
[<DefaultValue>]
......@@ -258,6 +258,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
// Low priority extensions
type TaskBuilderBase with
[<NoEagerConstraintApplication>]
static member inline BindDynamic< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter , 'TOverall
when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
and ^Awaiter :> ICriticalNotifyCompletion
......@@ -280,6 +281,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
sm.ResumptionDynamicInfo.ResumptionFunc <- cont
false
[<NoEagerConstraintApplication>]
member inline _.Bind< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter , 'TOverall
when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
and ^Awaiter :> ICriticalNotifyCompletion
......@@ -311,6 +313,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
//-- RESUMABLE CODE END
)
[<NoEagerConstraintApplication>]
member inline this.ReturnFrom< ^TaskLike, ^Awaiter, 'T
when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
and ^Awaiter :> ICriticalNotifyCompletion
......
......@@ -24,13 +24,13 @@ namespace Microsoft.FSharp.Control
/// Holds the final result of the state machine
/// </summary>
[<DefaultValue(false)>]
val mutable Result : 'T
val mutable Result: 'T
/// <summary>
/// Holds the MethodBuilder for the state machine
/// </summary>
[<DefaultValue(false)>]
val mutable MethodBuilder : AsyncTaskMethodBuilder<'T>
val mutable MethodBuilder: AsyncTaskMethodBuilder<'T>
/// <summary>
/// This is used by the compiler as a template for creating state machine structs
......@@ -71,7 +71,7 @@ namespace Microsoft.FSharp.Control
/// Specifies the delayed execution of a unit of task code.
/// </summary>
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
member inline Delay: f: (unit -> TaskCode<'TOverall, 'T>) -> TaskCode<'TOverall, 'T>
member inline Delay: generator: (unit -> TaskCode<'TOverall, 'T>) -> TaskCode<'TOverall, 'T>
/// <summary>
/// Specifies the iterative execution of a unit of task code.
......@@ -193,6 +193,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
open System.Threading.Tasks
open Microsoft.FSharp.Core
open Microsoft.FSharp.Control
open Microsoft.FSharp.Core.CompilerServices
/// <summary>
/// Contains low-priority overloads for the `task` computation expression builder.
......@@ -212,6 +213,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
/// satisfying the GetAwaiter pattern and calls a continuation.
/// </summary>
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
[<NoEagerConstraintApplication>]
member inline Bind< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter, 'TOverall > :
task: ^TaskLike *
continuation: ( 'TResult1 -> TaskCode<'TOverall, 'TResult2>)
......@@ -226,6 +228,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
/// satisfying the GetAwaiter pattern.
/// </summary>
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
[<NoEagerConstraintApplication>]
member inline ReturnFrom< ^TaskLike, ^Awaiter, 'T> :
task: ^TaskLike
-> TaskCode< 'T, 'T >
......@@ -238,6 +241,7 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
/// The entry point for the dynamic implementation of the corresponding operation. Do not use directly, only used when executing quotations that involve tasks or other reflective execution of F# code.
/// </summary>
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
[<NoEagerConstraintApplication>]
static member inline BindDynamic< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter, 'TOverall > :
sm: byref<TaskStateMachine<'TOverall>> *
task: ^TaskLike *
......@@ -252,7 +256,10 @@ namespace Microsoft.FSharp.Control.TaskBuilderExtensions
/// Specifies a unit of task code which binds to the resource implementing IDisposable and disposes it synchronously
/// </summary>
[<Experimental("Experimental library feature, requires '--langversion:preview'")>]
member inline Using: resource: 'Resource * body: ('Resource -> TaskCode<'TOverall, 'T>) -> TaskCode<'TOverall, 'T> when 'Resource :> IDisposable
member inline Using:
resource: 'Resource *
body: ('Resource -> TaskCode<'TOverall, 'T>)
-> TaskCode<'TOverall, 'T> when 'Resource :> IDisposable
/// <summary>
/// Contains medium-priority overloads for the `task` computation expression builder.
......
......@@ -800,7 +800,7 @@ type ArgumentAnalysis =
| NoInfo
| ArgDoesNotMatch
| CallerLambdaHasArgTypes of TType list
| CalledArgMatchesType of TType
| CalledArgMatchesType of adjustedCalledArgTy: TType * noEagerConstraintApplication: bool
let InferLambdaArgsForLambdaPropagation origRhsExpr =
let rec loop e =
......@@ -810,7 +810,7 @@ let InferLambdaArgsForLambdaPropagation origRhsExpr =
| _ -> 0
loop origRhsExpr
let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) ad (arg: AssignedCalledArg<SynExpr>) =
let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) ad noEagerConstraintApplication (arg: AssignedCalledArg<SynExpr>) =
let g = infoReader.g
// Find the explicit lambda arguments of the caller. Ignore parentheses.
......@@ -833,12 +833,18 @@ let ExamineArgumentForLambdaPropagation (infoReader: InfoReader) ad (arg: Assign
NoInfo
else
// not a lambda on the caller side - push information from caller to called
CalledArgMatchesType(adjustedCalledArgTy)
CalledArgMatchesType(adjustedCalledArgTy, noEagerConstraintApplication)
let ExamineMethodForLambdaPropagation (g: TcGlobals) m (meth: CalledMeth<SynExpr>) ad =
let noEagerConstraintApplication = MethInfoHasAttribute g m g.attrib_NoEagerConstraintApplicationAttribute meth.Method
let ExamineMethodForLambdaPropagation (x: CalledMeth<SynExpr>) ad =
let unnamedInfo = x.AssignedUnnamedArgs |> List.mapSquared (ExamineArgumentForLambdaPropagation x.infoReader ad)
let namedInfo = x.AssignedNamedArgs |> List.mapSquared (fun arg -> (arg.NamedArgIdOpt.Value, ExamineArgumentForLambdaPropagation x.infoReader ad arg))
// The logic associated with NoEagerConstraintApplicationAttribute is part of the
// Tasks and Resumable Code RFC
if noEagerConstraintApplication && not (g.langVersion.SupportsFeature LanguageFeature.ResumableStateMachines) then
errorR(Error(FSComp.SR.tcNoEagerConstraintApplicationAttribute(), m))
let unnamedInfo = meth.AssignedUnnamedArgs |> List.mapSquared (ExamineArgumentForLambdaPropagation meth.infoReader ad noEagerConstraintApplication)
let namedInfo = meth.AssignedNamedArgs |> List.mapSquared (fun arg -> (arg.NamedArgIdOpt.Value, ExamineArgumentForLambdaPropagation meth.infoReader ad noEagerConstraintApplication arg))
if unnamedInfo |> List.existsSquared (function CallerLambdaHasArgTypes _ -> true | _ -> false) ||
namedInfo |> List.existsSquared (function _, CallerLambdaHasArgTypes _ -> true | _ -> false) then
Some (unnamedInfo, namedInfo)
......
......@@ -289,9 +289,9 @@ type ArgumentAnalysis =
| NoInfo
| ArgDoesNotMatch
| CallerLambdaHasArgTypes of TType list
| CalledArgMatchesType of TType
| CalledArgMatchesType of adjustedCalledArgTy: TType * noEagerConstraintApplication: bool
val ExamineMethodForLambdaPropagation: x:CalledMeth<SynExpr> -> ad:AccessorDomain -> (ArgumentAnalysis list list * (Ident * ArgumentAnalysis) list list) option
val ExamineMethodForLambdaPropagation: g: TcGlobals -> m: range -> meth:CalledMeth<SynExpr> -> ad:AccessorDomain -> (ArgumentAnalysis list list * (Ident * ArgumentAnalysis) list list) option
/// Is this a 'base' call
val IsBaseCall: objArgs:Expr list -> bool
......
......@@ -556,6 +556,9 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d
let mk_MFCore_attrib nm : BuiltinAttribInfo =
AttribInfo(mkILTyRef(ilg.fsharpCoreAssemblyScopeRef, FSharpLib.Core + "." + nm), mk_MFCore_tcref fslibCcu nm)
let mk_MFCompilerServices_attrib nm : BuiltinAttribInfo =
AttribInfo(mkILTyRef(ilg.fsharpCoreAssemblyScopeRef, FSharpLib.Core + "." + nm), mk_MFCompilerServices_tcref fslibCcu nm)
let mk_doc filename = ILSourceDocument.Create(language=None, vendor=None, documentType=None, file=filename)
// Build the memoization table for files
let v_memoize_file = MemoizationTable<int, ILSourceDocument>((fileOfFileIndex >> FileSystem.GetFullFilePathInDirectoryShim directoryToResolveRelativePaths >> mk_doc), keyComparer=HashIdentity.Structural)
......@@ -1208,6 +1211,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d
member val attrib_ThreadStaticAttribute = tryFindSysAttrib "System.ThreadStaticAttribute"
member val attrib_SpecialNameAttribute = tryFindSysAttrib "System.Runtime.CompilerServices.SpecialNameAttribute"
member val attrib_VolatileFieldAttribute = mk_MFCore_attrib "VolatileFieldAttribute"
member val attrib_NoEagerConstraintApplicationAttribute = mk_MFCompilerServices_attrib "NoEagerConstraintApplicationAttribute"
member val attrib_ContextStaticAttribute = tryFindSysAttrib "System.ContextStaticAttribute"
member val attrib_FlagsAttribute = findSysAttrib "System.FlagsAttribute"
member val attrib_DefaultMemberAttribute = findSysAttrib "System.Reflection.DefaultMemberAttribute"
......
......@@ -692,6 +692,11 @@
<target state="translated">K hodnotě označené jako literál se {0} nedá přiřadit.</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Tento výraz podporuje indexování, třeba expr.[index]. Syntaxe expr[index] vyžaduje /langversion:preview. Více informací: https://aka.ms/fsharp-index-notation</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">"{0}" kann keinem als Literal markierten Wert zugewiesen werden.</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Dieser Ausdruck unterstützt die Indizierung, z. B. "expr.[index]". Die Syntax "expr[index]" erfordert /langversion:preview. Siehe https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">No se puede asignar "{0}" a un valor marcado como literal</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Esta expresión admite indexación, por ejemplo "expr.[index]". La sintaxis "expr[index]" requiere /langversion:preview. Ver https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Impossible d'affecter '{0}' à une valeur marquée comme littérale</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Cette expression prend en charge l’indexation, par exemple « expr.[index] ». La syntaxe « expr[index] » requiert /langversion:preview. Voir https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Non è possibile assegnare '{0}' a un valore contrassegnato come letterale</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Questa espressione supporta l'indicizzazione, ad esempio 'expr.[index]'. La sintassi 'expr[index]' richiede/langversion:preview. Vedere https://aka.ms/fsharp-index-notation..</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">リテラルとしてマークされた値に '{0}' を割り当てることはできません</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">この式は、'expr. [index]' などのインデックスをサポートしています。構文 'expr[index]' には /langversion:preview が必要です。https://aka.ms/fsharp-index-notation を参照してください。</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">리터럴로 표시된 값에 '{0}'을(를) 할당할 수 없습니다.</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">이 식은 인덱싱을 지원합니다. 'expr.[index]'. 'expr[index]' 구문에는 /langversion:preview가 필요합니다. https://aka.ms/fsharp-index-notation을 참조하세요.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Nie można przypisać elementu „{0}” do wartości oznaczonej jako literał</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">To wyrażenie obsługuje indeksowanie, np. „expr.[index]”. Składnia wyrażenia „expr[index]” wymaga parametru /langversion:preview. Zobacz: https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Não é possível atribuir '{0}' a um valor marcado como literal</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Essa expressão oferece suporte à indexação, por exemplo, 'expr. [index]'. A sintaxe 'expr[index]' requer /langversion:preview. Consulte https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Невозможно присвоить "{0}" значению, помеченному как литерал</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Это выражение поддерживает индексирование, например, "expr. [index]". Для синтаксиса "expr[index]" требуется /langversion:preview. См. https://aka.ms/fsharp-index-notation.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">Sabit değer olarak işaretlenen bir değere '{0}' atanamaz</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">Bu ifade dizin oluşturmayı destekler, örn. “expr.[index]”. Söz dizimi “expr.[index]” /langversion:preview gerektirir. https://aka.ms/fsharp-index-notation'a bakın.</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">无法将“{0}”分配给标记为文本的值</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">此表达式支持索引,例如“expr.[index]”。语法“expr[index]”需要 /langversion:preview。请参阅 https://aka.ms/fsharp-index-notation。</target>
......
......@@ -692,6 +692,11 @@
<target state="translated">無法將 '{0}' 指派給標記為常值的值</target>
<note />
</trans-unit>
<trans-unit id="tcNoEagerConstraintApplicationAttribute">
<source>Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</source>
<target state="new">Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later</target>
<note />
</trans-unit>
<trans-unit id="tcNotAFunctionButIndexerIndexingNotYetEnabled">
<source>This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation.</source>
<target state="translated">此運算式支援編製索引,例如 'expr.[index]'。語法 'expr[index]' 需要 /langversion:preview。請參閱 https://aka.ms/fsharp-index-notation。</target>
......
......@@ -5,6 +5,7 @@ namespace FSharp.Compiler.ComponentTests.EmittedIL
open Xunit
open FSharp.Test.Compiler
#if !DEBUG // sensitive to debug-level code coming across from debug FSharp.Core
module ``StringFormatAndInterpolation`` =
[<Fact>]
let ``Interpolated string with no holes is reduced to a string or simple format when used in printf``() =
......@@ -30,3 +31,6 @@ IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintF
class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0,class [runtime]System.IO.TextWriter,class [FSharp.Core]Microsoft.FSharp.Core.Unit,class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
IL_0016: pop
IL_0017: ret"""]
#endif
......@@ -710,6 +710,7 @@ public static int z()
#if !DEBUG // sensitive to debug-level code coming across from debug FSharp.Core
[<Fact>]
let ``Branching let binding of tuple with capture doesn't promote``() =
......@@ -760,7 +761,7 @@ let testFunction(a,b) =
""" ]
#endif
[<Fact>]
......
......@@ -188,7 +188,6 @@ type SmokeTestsForCompilation() =
t.Wait()
if t.Result <> 5 then failwith "failed"
exception TestException of string
[<AutoOpen>]
......@@ -1265,6 +1264,69 @@ type BasicsNotInParallel() =
require ran "never ran")
taskOuter.Wait()
type Issue12184() =
member this.TaskMethod() =
task {
// The overload resolution for Bind commits to 'Async<int>' since the type annotation is present.
let! result = this.AsyncMethod(21)
return result
}
member _.AsyncMethod(value: int) : Async<int> =
async {
return (value * 2)
}
type Issue12184b() =
member this.TaskMethod() =
task {
// The overload resolution for Bind commits to 'YieldAwaitable' since the type annotation is present.
let! result = this.AsyncMethod(21)
return result
}
member _.AsyncMethod(_value: int) : System.Runtime.CompilerServices.YieldAwaitable =
Task.Yield()
// check this compiles
module Issue12184c =
let TaskMethod(t) =
task {
// The overload resolution for Bind commits to 'Task<_>' via overload since no type annotation is available
//
// This should not do an early commit to "task like" nor propogate SRTP constraints from the task-like overload for Bind.
let! result = t
return result
}
#if NETCOREAPP
// check this compiles
module Issue12184d =
let TaskMethod(t: ValueTask) =
task {
// The overload resolution for Bind commits to 'ValueTask' via SRTP pattern since the type annotation is available
let! result = t
return result
}
// check this compiles
module Issue12184e =
let TaskMethod(t: ValueTask<int>) =
task {
// The overload resolution for Bind commits to 'ValueTask<_>' via SRTP pattern since the type annotation is available
let! result = t
return result
}
#endif
// check this compiles
module Issue12184f =
let TaskMethod(t: Task) =
task {
// The overload resolution for Bind commits to 'Task' via SRTP pattern since the type annotation is available
let! result = t
return result
}
#if STANDALONE
module M =
......
......@@ -811,6 +811,7 @@ Microsoft.FSharp.Core.CompilerServices.MoveNextMethodImpl`1[TData]: System.IAsyn
Microsoft.FSharp.Core.CompilerServices.MoveNextMethodImpl`1[TData]: Void .ctor(System.Object, IntPtr)
Microsoft.FSharp.Core.CompilerServices.MoveNextMethodImpl`1[TData]: Void EndInvoke(System.IAsyncResult)
Microsoft.FSharp.Core.CompilerServices.MoveNextMethodImpl`1[TData]: Void Invoke(Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[TData] ByRef)
Microsoft.FSharp.Core.CompilerServices.NoEagerConstraintApplicationAttribute: Void .ctor()
Microsoft.FSharp.Core.CompilerServices.ResumableCode: Boolean CombineDynamic[TData,T](Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[TData] ByRef, Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,T])
Microsoft.FSharp.Core.CompilerServices.ResumableCode: Boolean TryFinallyAsyncDynamic[TData,T](Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[TData] ByRef, Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,T], Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,Microsoft.FSharp.Core.Unit])
Microsoft.FSharp.Core.CompilerServices.ResumableCode: Boolean TryWithDynamic[TData,T](Microsoft.FSharp.Core.CompilerServices.ResumableStateMachine`1[TData] ByRef, Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,T], Microsoft.FSharp.Core.FSharpFunc`2[System.Exception,Microsoft.FSharp.Core.CompilerServices.ResumableCode`2[TData,T]])
......
......@@ -7,6 +7,7 @@ open NUnit.Framework
open System
#if !DEBUG // sensitive to debug-level code coming across from debug FSharp.Core
[<TestFixture>]
module ComputationExpressionOptimizations =
......@@ -315,3 +316,4 @@ module Examples =
"""
])
#endif
\ No newline at end of file
......@@ -5,6 +5,7 @@ namespace FSharp.Compiler.UnitTests.CodeGen.EmittedIL
open FSharp.Test
open NUnit.Framework
#if !DEBUG // sensitive to debug-level code coming across from debug FSharp.Core
[<TestFixture>]
module DelegateAndFuncOptimizations =
......@@ -528,3 +529,4 @@ let ApplyComputedDelegate(c: int) =
"""
])
#endif
......@@ -5,6 +5,7 @@ namespace FSharp.Compiler.UnitTests
open NUnit.Framework
open FSharp.Test
#if !DEBUG // requires release version of compiler to avoid very deep stacks
[<TestFixture>]
module LargeExprTests =
......@@ -5515,3 +5516,4 @@ let test () : unit =
test ()
"""
CompilerAssert.RunScript source []
#endif
\ No newline at end of file
......@@ -2468,6 +2468,13 @@ module TypecheckTests =
peverify cfg "pos39.exe"
exec cfg ("." ++ "pos39.exe") ""
[<Test>]
let ``sigs pos40`` () =
let cfg = testConfig "typecheck/sigs"
fsc cfg "%s --langversion:preview --target:exe -o:pos40.exe" cfg.fsc_flags ["pos40.fs"]
peverify cfg "pos40.exe"
exec cfg ("." ++ "pos40.exe") ""
[<Test>]
let ``sigs pos23`` () =
let cfg = testConfig "typecheck/sigs"
......@@ -2763,8 +2770,10 @@ module TypecheckTests =
[<Test>]
let ``type check neg44`` () = singleNegTest (testConfig "typecheck/sigs") "neg44"
#if !DEBUG // requires release version of compiler to avoid very deep stacks
[<Test>]
let ``type check neg45`` () = singleNegTest (testConfig "typecheck/sigs") "neg45"
#endif
[<Test>]
let ``type check neg46`` () = singleNegTest (testConfig "typecheck/sigs") "neg46"
......@@ -3027,6 +3036,12 @@ module TypecheckTests =
[<Test>]
let ``type check neg130`` () = singleNegTest (testConfig "typecheck/sigs") "neg130"
[<Test>]
let ``type check neg131`` () = singleVersionedNegTest (testConfig "typecheck/sigs") "preview" "neg131"
[<Test>]
let ``type check neg132`` () = singleVersionedNegTest (testConfig "typecheck/sigs") "5.0" "neg132"
[<Test>]
let ``type check neg_anon_1`` () = singleNegTest (testConfig "typecheck/sigs") "neg_anon_1"
......
neg131.fs(15,9,15,55): typecheck error FS0041: A unique overload for method 'SomeMethod' could not be determined based on type information prior to this program point. A type annotation may be needed.
Known types of arguments: 'a * ('b -> int)
Candidates:
- static member OverloadsWithSrtp.SomeMethod: x: ^T * f: ( ^T -> int) -> int when ^T: (member get_Length: ^T -> int)
- static member OverloadsWithSrtp.SomeMethod: x: 'T list * f: ('T list -> int) -> int
module Neg131
open System
open FSharp.Core.CompilerServices
module TestOverloadsWithSrtpThatDontResolve1 =
type OverloadsWithSrtp() =
[<NoEagerConstraintApplication>]
static member inline SomeMethod< ^T when ^T : (member Length: int) > (x: ^T, f: ^T -> int) = 1
static member SomeMethod(x: 'T list, f: 'T list -> int) = 2
// 'x' doesn't contain any type information so the overload doesn't resolve.
let inline f x =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
neg132.fs(15,9,15,55): typecheck error FS3510: Using methods with 'NoEagerConstraintApplicationAttribute' requires /langversion:preview or later
neg132.fs(15,9,15,55): typecheck error FS0041: A unique overload for method 'SomeMethod' could not be determined based on type information prior to this program point. A type annotation may be needed.
Known types of arguments: 'a * ('b -> int)
Candidates:
- static member OverloadsWithSrtp.SomeMethod: x: ^T * f: ( ^T -> int) -> int when ^T: (member get_Length: ^T -> int)
- static member OverloadsWithSrtp.SomeMethod: x: 'T list * f: ('T list -> int) -> int
module Neg132
open System
open FSharp.Core.CompilerServices
module TestOverloadsWithSrtpThatDontResolve1 =
type OverloadsWithSrtp() =
[<NoEagerConstraintApplication>]
static member inline SomeMethod< ^T when ^T : (member Length: int) > (x: ^T, f: ^T -> int) = 1
static member SomeMethod(x: 'T list, f: 'T list -> int) = 2
// this will give a "requires version 6.0 or greater" error
let inline f x =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
module Pos40
open FSharp.Core.CompilerServices
// Test a number of cases relating to https://github.com/dotnet/fsharp/pull/12202/files
module TestOverloadsWithSrtpThatDoResolve1 =
type OverloadsWithSrtp() =
// Note: no attribute
//[<NoEagerConstraintApplication>]
static member inline SomeMethod< ^T when ^T : (member Foo: int) > (x: ^T, f: ^T -> int) = 1
static member SomeMethod(x: string, f: string -> int) = 2
// Here, 'x' doesn't contain any type information. However the presence of an SRTP-constrained
// method causes the Foo constraint to be applied to the caller argument type and the
// method is resolved to the first overload.
let inline f x =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
type C() =
member x.Foo = 3
let v = f (C()) // this should now resolve
// Here, 'x' contains enough type informationto resolve the overload.
// Lambda propagation applies and the lambda argument 'a' gets known type 'string'.
let f4 (x: string) =
OverloadsWithSrtp.SomeMethod (x, (fun a -> a.Length))
module TestOverloadsWithSrtpThatDoResolve2 =
type OverloadsWithSrtp() =
[<NoEagerConstraintApplication>]
static member inline SomeMethod< ^T when ^T : (member Foo: int) > (x: ^T, f: ^T -> int) = 1
static member SomeMethod(x: string, f: string -> int) = 2
// Here, 'x' doesn't contain any type information. The presence of an SRTP-constrained
// method does not causes the Foo constraint to be applied to the caller argument type because NoEagerConstraintApplication is present.
//
// Overload resolution proceeds. The second overload is not generic so is preferred according to standard overloading rules.
let f x =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
let v = f "hello" // this should now resolve since 'x' was inferred to have type 'string'
// Here, 'x' contains enough type informationto resolve the overload.
// Lambda propagation applies and the lambda argument 'a' gets known type 'string'.
let f4 (x: string) =
OverloadsWithSrtp.SomeMethod (x, (fun a -> a.Length))
module TestOverloadsWithSrtpThatDoResolve3 =
type OverloadsWithSrtp() =
[<NoEagerConstraintApplication>]
static member inline SomeMethod< ^T when ^T : (member Length: int) > (x: ^T, f: ^T -> int) = 1
static member SomeMethod(x: string, f: string -> int) = 2
// Here, 'x' contains enough type informationto resolve the overload.
// The lambda argument 'a' gets constrained type
let inline f2< ^T when ^T : (member Length: int)> (x: ^T) =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 1))
let v1 = f2 [1]
let v2 = f2 [| 1 |]
// Here, 'x' contains enough type informationto resolve the overload
// The lambda argument 'a' gets constrained type
let inline f3< ^T when ^T : (member Length: int) and ^T : (member Length2: int)> (x: ^T) =
OverloadsWithSrtp.SomeMethod (x, (fun a -> 2))
// Here, 'x' contains enough type informationto resolve the overload
// The lambda argument 'a' gets type 'int'
let f4 (x: int list) =
OverloadsWithSrtp.SomeMethod (x, (fun a -> a.Length))
let v4 = f4 [ 1 ]
printfn "test completed"
exit 0
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册