@@ -2289,14 +2289,15 @@ and ArgsMustSubsumeOrConvert
22892289 trace
22902290 cxsln
22912291 isConstraint
2292+ enforceNullableOptionalsKnownTypes // use known types from nullable optional args?
22922293 ( calledArg : CalledArg )
22932294 ( callerArg : CallerArg < 'T >) = trackErrors {
22942295
22952296 let g = csenv.g
22962297 let m = callerArg.Range
2297- let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint calledArg callerArg
2298- do ! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArg.Type
2299- if calledArg.IsParamArray && isArray1DTy g calledArgTy && not ( isArray1DTy g callerArg.Type ) then
2298+ let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint enforceNullableOptionalsKnownTypes calledArg callerArg
2299+ do ! SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArg.CallerArgumentType
2300+ if calledArg.IsParamArray && isArray1DTy g calledArgTy && not ( isArray1DTy g callerArg.CallerArgumentType ) then
23002301 return ! ErrorD( Error( FSComp.SR.csMethodExpectsParams(), m))
23012302 else ()
23022303 }
@@ -2308,14 +2309,14 @@ and MustUnifyInsideUndo csenv ndeep trace cxsln ty1 ty2 =
23082309 SolveTypeEqualsTypeWithReport csenv ndeep csenv.m ( WithTrace trace) cxsln ty1 ty2
23092310
23102311and ArgsMustSubsumeOrConvertInsideUndo ( csenv : ConstraintSolverEnv ) ndeep trace cxsln isConstraint calledArg ( CallerArg ( callerArgTy , m , _ , _ ) as callerArg ) =
2311- let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint calledArg callerArg
2312+ let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg
23122313 SolveTypeSubsumesTypeWithReport csenv ndeep m ( WithTrace trace) cxsln calledArgTy callerArgTy
23132314
23142315and TypesMustSubsumeOrConvertInsideUndo ( csenv : ConstraintSolverEnv ) ndeep trace cxsln m calledArgTy callerArgTy =
23152316 SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy
23162317
23172318and ArgsEquivInsideUndo ( csenv : ConstraintSolverEnv ) isConstraint calledArg ( CallerArg ( callerArgTy , m , _ , _ ) as callerArg ) =
2318- let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint calledArg callerArg
2319+ let calledArgTy = AdjustCalledArgType csenv.InfoReader isConstraint true calledArg callerArg
23192320 if typeEquiv csenv.g calledArgTy callerArgTy then CompleteD else ErrorD( Error( FSComp.SR.csArgumentTypesDoNotMatch(), m))
23202321
23212322and ReportNoCandidatesError ( csenv : ConstraintSolverEnv ) ( nUnnamedCallerArgs , nNamedCallerArgs ) methodName ad ( calledMethGroup : CalledMeth < _ > list ) isSequential =
@@ -2593,11 +2594,18 @@ and ResolveOverloading
25932594 | _ when isInByrefTy csenv.g ty2 && typeEquiv csenv.g ty1 ( destByrefTy csenv.g ty2) ->
25942595 true
25952596
2597+ // T is always better than Nullable<T> from F# 5.0 onwards
2598+ | _ when g.langVersion.SupportsFeature( Features.LanguageFeature.NullableOptionalInterop) &&
2599+ isNullableTy csenv.g ty2 &&
2600+ typeEquiv csenv.g ty1 ( destNullableTy csenv.g ty2) ->
2601+ true
2602+
25962603 | _ -> false )
25972604
25982605 if c <> 0 then c else
25992606 0
26002607
2608+ /// Check whether one overload is better than another
26012609 let better ( candidate : CalledMeth < _ >, candidateWarnings , _ ) ( other : CalledMeth < _ >, otherWarnings , _ ) =
26022610 let candidateWarnCount = List.length candidateWarnings
26032611 let otherWarnCount = List.length otherWarnings
@@ -2614,7 +2622,7 @@ and ResolveOverloading
26142622 // Prefer methods with more precise param array arg type
26152623 let c =
26162624 if candidate.UsesParamArrayConversion && other.UsesParamArrayConversion then
2617- compareTypes candidate.ParamArrayElementType other.ParamArrayElementType
2625+ compareTypes ( candidate.GetParamArrayElementType ()) ( other.GetParamArrayElementType ())
26182626 else
26192627 0
26202628 if c <> 0 then c else
@@ -2629,7 +2637,7 @@ and ResolveOverloading
26292637 let c = compare ( not candidate.HasOptArgs) ( not other.HasOptArgs)
26302638 if c <> 0 then c else
26312639
2632- // check regular args. The argument counts will only be different if one is using param args
2640+ // check regular unnamed args. The argument counts will only be different if one is using param args
26332641 let c =
26342642 if candidate.TotalNumUnnamedCalledArgs = other.TotalNumUnnamedCalledArgs then
26352643 // For extension members, we also include the object argument type, if any in the comparison set
@@ -2670,12 +2678,37 @@ and ResolveOverloading
26702678 0
26712679 if c <> 0 then c else
26722680
2673-
26742681 // Prefer non-generic methods
26752682 // Note: Relies on 'compare' respecting true > false
26762683 let c = compare candidate.CalledTyArgs.IsEmpty other.CalledTyArgs.IsEmpty
26772684 if c <> 0 then c else
26782685
2686+ // F# 5.0 rule - prior to F# 5.0 named arguments (on the caller side) were not being taken
2687+ // into account when comparing overloads. So adding a name to an argument might mean
2688+ // overloads ould no longer be distinguished. We thus look at *all* arguments (whether
2689+ // optional or not) as an additional comparison technique.
2690+ let c =
2691+ if g.langVersion.SupportsFeature( Features.LanguageFeature.NullableOptionalInterop) then
2692+ let cs =
2693+ let args1 = candidate.AllCalledArgs |> List.concat
2694+ let args2 = other.AllCalledArgs |> List.concat
2695+ if args1.Length = args2.Length then
2696+ ( args1, args2) ||> List.map2 compareArg
2697+ else
2698+ []
2699+ // "all args are at least as good, and one argument is actually better"
2700+ if cs |> List.forall ( fun x -> x >= 0 ) && cs |> List.exists ( fun x -> x > 0 ) then
2701+ 1
2702+ // "all args are at least as bad, and one argument is actually worse"
2703+ elif cs |> List.forall ( fun x -> x <= 0 ) && cs |> List.exists ( fun x -> x < 0 ) then
2704+ - 1
2705+ // "argument lists are incomparable"
2706+ else
2707+ 0
2708+ else
2709+ 0
2710+ if c <> 0 then c else
2711+
26792712 0
26802713
26812714
@@ -2734,7 +2767,7 @@ and ResolveOverloading
27342767 true
27352768 ( MustUnify csenv ndeep trace cxsln)
27362769 ( TypesMustSubsumeOrConvertInsideUndo csenv ndeep trace cxsln m) // REVIEW: this should not be an "InsideUndo" operation
2737- ( ArgsMustSubsumeOrConvert csenv ndeep trace cxsln cx.IsSome)
2770+ ( ArgsMustSubsumeOrConvert csenv ndeep trace cxsln cx.IsSome true )
27382771 reqdRetTyOpt
27392772 calledMeth
27402773 | WithTrace calledMethTrc ->
@@ -2787,7 +2820,7 @@ let UnifyUniqueOverloading
27872820 true // always check return type
27882821 ( MustUnify csenv ndeep NoTrace None)
27892822 ( TypesMustSubsumeOrConvertInsideUndo csenv ndeep NoTrace None m)
2790- ( ArgsMustSubsumeOrConvert csenv ndeep NoTrace None false ) // UnifyUniqueOverloading is not called in case of trait call - pass isConstraint=false
2823+ ( ArgsMustSubsumeOrConvert csenv ndeep NoTrace None false false ) // UnifyUniqueOverloading is not called in case of trait call - pass isConstraint=false
27912824 ( Some reqdRetTy)
27922825 calledMeth
27932826 return true
0 commit comments