@@ -2289,14 +2289,15 @@ and ArgsMustSubsumeOrConvert
2289
2289
trace
2290
2290
cxsln
2291
2291
isConstraint
2292
+ enforceNullableOptionalsKnownTypes // use known types from nullable optional args?
2292
2293
( calledArg : CalledArg )
2293
2294
( callerArg : CallerArg < 'T >) = trackErrors {
2294
2295
2295
2296
let g = csenv.g
2296
2297
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
2300
2301
return ! ErrorD( Error( FSComp.SR.csMethodExpectsParams(), m))
2301
2302
else ()
2302
2303
}
@@ -2308,14 +2309,14 @@ and MustUnifyInsideUndo csenv ndeep trace cxsln ty1 ty2 =
2308
2309
SolveTypeEqualsTypeWithReport csenv ndeep csenv.m ( WithTrace trace) cxsln ty1 ty2
2309
2310
2310
2311
and 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
2312
2313
SolveTypeSubsumesTypeWithReport csenv ndeep m ( WithTrace trace) cxsln calledArgTy callerArgTy
2313
2314
2314
2315
and TypesMustSubsumeOrConvertInsideUndo ( csenv : ConstraintSolverEnv ) ndeep trace cxsln m calledArgTy callerArgTy =
2315
2316
SolveTypeSubsumesTypeWithReport csenv ndeep m trace cxsln calledArgTy callerArgTy
2316
2317
2317
2318
and 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
2319
2320
if typeEquiv csenv.g calledArgTy callerArgTy then CompleteD else ErrorD( Error( FSComp.SR.csArgumentTypesDoNotMatch(), m))
2320
2321
2321
2322
and ReportNoCandidatesError ( csenv : ConstraintSolverEnv ) ( nUnnamedCallerArgs , nNamedCallerArgs ) methodName ad ( calledMethGroup : CalledMeth < _ > list ) isSequential =
@@ -2593,11 +2594,18 @@ and ResolveOverloading
2593
2594
| _ when isInByrefTy csenv.g ty2 && typeEquiv csenv.g ty1 ( destByrefTy csenv.g ty2) ->
2594
2595
true
2595
2596
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
+
2596
2603
| _ -> false )
2597
2604
2598
2605
if c <> 0 then c else
2599
2606
0
2600
2607
2608
+ /// Check whether one overload is better than another
2601
2609
let better ( candidate : CalledMeth < _ >, candidateWarnings , _ ) ( other : CalledMeth < _ >, otherWarnings , _ ) =
2602
2610
let candidateWarnCount = List.length candidateWarnings
2603
2611
let otherWarnCount = List.length otherWarnings
@@ -2614,7 +2622,7 @@ and ResolveOverloading
2614
2622
// Prefer methods with more precise param array arg type
2615
2623
let c =
2616
2624
if candidate.UsesParamArrayConversion && other.UsesParamArrayConversion then
2617
- compareTypes candidate.ParamArrayElementType other.ParamArrayElementType
2625
+ compareTypes ( candidate.GetParamArrayElementType ()) ( other.GetParamArrayElementType ())
2618
2626
else
2619
2627
0
2620
2628
if c <> 0 then c else
@@ -2629,7 +2637,7 @@ and ResolveOverloading
2629
2637
let c = compare ( not candidate.HasOptArgs) ( not other.HasOptArgs)
2630
2638
if c <> 0 then c else
2631
2639
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
2633
2641
let c =
2634
2642
if candidate.TotalNumUnnamedCalledArgs = other.TotalNumUnnamedCalledArgs then
2635
2643
// For extension members, we also include the object argument type, if any in the comparison set
@@ -2670,12 +2678,37 @@ and ResolveOverloading
2670
2678
0
2671
2679
if c <> 0 then c else
2672
2680
2673
-
2674
2681
// Prefer non-generic methods
2675
2682
// Note: Relies on 'compare' respecting true > false
2676
2683
let c = compare candidate.CalledTyArgs.IsEmpty other.CalledTyArgs.IsEmpty
2677
2684
if c <> 0 then c else
2678
2685
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
+
2679
2712
0
2680
2713
2681
2714
@@ -2734,7 +2767,7 @@ and ResolveOverloading
2734
2767
true
2735
2768
( MustUnify csenv ndeep trace cxsln)
2736
2769
( 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 )
2738
2771
reqdRetTyOpt
2739
2772
calledMeth
2740
2773
| WithTrace calledMethTrc ->
@@ -2787,7 +2820,7 @@ let UnifyUniqueOverloading
2787
2820
true // always check return type
2788
2821
( MustUnify csenv ndeep NoTrace None)
2789
2822
( 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
2791
2824
( Some reqdRetTy)
2792
2825
calledMeth
2793
2826
return true
0 commit comments