Skip to content

Commit daffd3f

Browse files
dsymebaronfel
authored andcommitted
Adjust FS-1075 : nullable interop - apply rule to all arguments, not just optional ones (#9316)
* adjust non-optional nullable interop * adjust non-optional nullable interop * fix error messages * fix baseline * fix baseline
1 parent 2cdb78c commit daffd3f

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

src/fsharp/MethodCalls.fs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,13 @@ let AdjustCalledArgTypeForOptionals (g: TcGlobals) enforceNullableOptionalsKnown
191191
calledArgTy
192192
else
193193
match calledArg.OptArgInfo with
194-
| NotOptional ->
194+
// CSharpMethod(x = arg), non-optional C#-style argument, may have type Nullable<ty>.
195+
| NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) ->
195196
calledArgTy
196197

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

1153+
let MakeNullableExprIfNeeded (infoReader: InfoReader) calledArgTy callerArgTy callerArgExpr m =
1154+
let g = infoReader.g
1155+
let amap = infoReader.amap
1156+
if isNullableTy g callerArgTy then
1157+
callerArgExpr
1158+
else
1159+
let calledNonOptTy = destNullableTy g calledArgTy
1160+
let minfo = GetIntrinsicConstructorInfosOfType infoReader m calledArgTy |> List.head
1161+
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr
1162+
MakeMethInfoCall amap m minfo [] [callerArgExprCoerced]
1163+
11511164
// Adjust all the optional arguments, filling in values for defaults,
11521165
let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoReader) (assignedArg: AssignedCalledArg<_>) =
11531166
let g = infoReader.g
1154-
let amap = infoReader.amap
11551167
let callerArg = assignedArg.CallerArg
11561168
let (CallerArg(callerArgTy, m, isOptCallerArg, callerArgExpr)) = callerArg
11571169
let calledArg = assignedArg.CalledArg
1158-
match calledArg.OptArgInfo with
1159-
| NotOptional ->
1170+
let calledArgTy = calledArg.CalledArgumentType
1171+
match calledArg.OptArgInfo with
1172+
| NotOptional when not (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) ->
11601173
if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m))
11611174
assignedArg
1162-
| _ ->
1175+
1176+
| _ ->
1177+
11631178
let callerArgExpr2 =
11641179
match calledArg.OptArgInfo with
1165-
| NotOptional -> failwith "unreachable"
1180+
| NotOptional ->
1181+
// T --> Nullable<T> widening at callsites
1182+
if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m))
1183+
if isNullableTy g calledArgTy then
1184+
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m
1185+
else
1186+
callerArgExpr
11661187

11671188
| CallerSide dfltVal ->
11681189
let calledArgTy = calledArg.CalledArgumentType
@@ -1184,15 +1205,9 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe
11841205
else
11851206
if isNullableTy g calledArgTy then
11861207
// CSharpMethod(x=b) when 'x' has nullable type
1187-
if isNullableTy g callerArgTy then
1188-
// CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b)
1189-
callerArgExpr
1190-
else
1191-
// CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b))
1192-
let calledNonOptTy = destNullableTy g calledArgTy
1193-
let minfo = GetIntrinsicConstructorInfosOfType infoReader m calledArgTy |> List.head
1194-
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr
1195-
MakeMethInfoCall amap m minfo [] [callerArgExprCoerced]
1208+
// CSharpMethod(x=b) when both 'x' and 'b' have nullable type --> CSharpMethod(x=b)
1209+
// CSharpMethod(x=b) when 'x' has nullable type and 'b' does not --> CSharpMethod(x=Nullable(b))
1210+
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy callerArgExpr m
11961211
else
11971212
// CSharpMethod(x=b) --> CSharpMethod(?x=b)
11981213
callerArgExpr
@@ -1203,7 +1218,6 @@ let AdjustCallerArgForOptional tcFieldInit eCallerMemberName (infoReader: InfoRe
12031218
callerArgExpr
12041219
else
12051220
// CSharpMethod(x=b) when CSharpMethod(A) --> CSharpMethod(?x=Some(b :> A))
1206-
let calledArgTy = assignedArg.CalledArg.CalledArgumentType
12071221
if isOptionTy g calledArgTy then
12081222
let calledNonOptTy = destOptionTy g calledArgTy
12091223
let callerArgExprCoerced = mkCoerceIfNeeded g calledNonOptTy callerArgTy callerArgExpr

0 commit comments

Comments
 (0)