Skip to content

Commit

Permalink
Adjust FS-1075 : nullable interop - apply rule to all arguments, not …
Browse files Browse the repository at this point in the history
…just optional ones (dotnet#9316)

* adjust non-optional nullable interop

* adjust non-optional nullable interop

* fix error messages

* fix baseline

* fix baseline
  • Loading branch information
dsyme authored and nosami committed Feb 22, 2021
1 parent bbcc7f8 commit b2f90ac
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 59 deletions.
48 changes: 31 additions & 17 deletions src/fsharp/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,13 @@ let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnown
calledArgTy
else
match calledArg.OptArgInfo with
| NotOptional ->
// CSharpMethod(x = arg), non-optional C#-style argument, may have type Nullable<ty>.
| NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) ->
calledArgTy

// CSharpMethod(x = arg), optional C#-style argument, may have type Nullable<ty>.
// The arg should have type ty. However for backwards compat, we also allow arg to have type Nullable<ty>
| NotOptional
// CSharpMethod(x = arg), optional C#-style argument, may have type Nullable<ty>.
| CallerSide _ ->
if isNullableTy g calledArgTy && g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop then
// If inference has worked out it's a nullable then use this
Expand Down Expand Up @@ -1148,21 +1150,40 @@ let GetDefaultExpressionForOptionalArg tcFieldInit g (calledArg: CalledArg) eCal
let callerArg = CallerArg(calledArgTy, mMethExpr, false, expr)
preBinder, { NamedArgIdOpt = None; CalledArg = calledArg; CallerArg = callerArg }

let MakeNullableExprIfNeeded (infoReader: InfoReader) calledArgTy callerArgTy callerArgExpr m =
let g = infoReader.g
let amap = infoReader.amap
if isNullableTy g callerArgTy then
callerArgExpr
else
let calledNonOptTy = destNullableTy g calledArgTy
let minfo = GetIntrinsicConstructorInfosOfType infoReader m calledArgTy |> List.head
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr
MakeMethInfoCall amap m minfo [] [callerArgExprCoerced]

// Adjust all the optional arguments, filling in values for defaults,
let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoReader) (assignedArg: AssignedCalledArg<_>) =
let g = infoReader.g
let amap = infoReader.amap
let callerArg = assignedArg.CallerArg
let (CallerArg(callerArgTy, m, isOptCallerArg, callerArgExpr)) = callerArg
let calledArg = assignedArg.CalledArg
match calledArg.OptArgInfo with
| NotOptional ->
let calledArgTy = calledArg.CalledArgumentType
match calledArg.OptArgInfo with
| NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) ->
if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m))
assignedArg
| _ ->

| _ ->

let callerArgExpr2 =
match calledArg.OptArgInfo with
| NotOptional -> failwith "unreachable"
| NotOptional ->
// T --> Nullable<T> widening at callsites
if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m))
if isNullableTy g calledArgTy then
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m
else
callerArgExpr

| CallerSide dfltVal ->
let calledArgTy = calledArg.CalledArgumentType
Expand All @@ -1184,15 +1205,9 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe
else
if isNullableTy g calledArgTy then
// CSharpMethod(x=b) when 'x' has nullable type
if isNullableTy g callerArgTy then
// CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b)
callerArgExpr
else
// CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b))
let calledNonOptTy = destNullableTy g calledArgTy
let minfo = GetIntrinsicConstructorInfosOfType infoReader m calledArgTy |> List.head
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr
MakeMethInfoCall amap m minfo [] [callerArgExprCoerced]
// CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b)
// CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b))
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m
else
// CSharpMethod(x=b) --> CSharpMethod(?x=b)
callerArgExpr
Expand All @@ -1203,7 +1218,6 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe
callerArgExpr
else
// CSharpMethod(x=b) when CSharpMethod(A) --> CSharpMethod(?x=Some(b :> A))
let calledArgTy = assignedArg.CalledArg.CalledArgumentType
if isOptionTy g calledArgTy then
let calledNonOptTy = destOptionTy g calledArgTy
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr
Expand Down
Loading

0 comments on commit b2f90ac

Please sign in to comment.