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

Adjust FS-1075 : nullable interop - apply rule to all arguments, not just optional ones #9316

Merged
merged 5 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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