Skip to content

Commit

Permalink
Fix #12860 by integrating Nullable code into FS-1093 code
Browse files Browse the repository at this point in the history
  • Loading branch information
NinoFloris committed Aug 18, 2022
1 parent 4b69a2e commit da5d49b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 61 deletions.
19 changes: 4 additions & 15 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5385,7 +5385,7 @@ and TcAdjustExprForTypeDirectedConversions (cenv: cenv) (overallTy: OverallTy) a
let g = cenv.g

match overallTy with
| MustConvertTo (_, reqdTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions ->
| MustConvertTo (isMethodArg, reqdTy) when g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions || (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop && isMethodArg) ->
let tcVal = LightweightTcValForUsingInBuildMethodCall g
AdjustExprForTypeDirectedConversions tcVal g cenv.amap cenv.infoReader env.AccessRights reqdTy actualTy m expr
| _ ->
Expand Down Expand Up @@ -9778,17 +9778,6 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo
if isOptCallerArg then
error(Error(FSComp.SR.tcInvalidOptionalAssignmentToPropertyOrField(), m))

let adjustCallerArgExpr calledArgTy tcVal =
if (g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop) &&
isNullableTy g calledArgTy && not (isNullableTy g callerArgTy) then
// T --> Nullable<T> widening at callsites
let calledNonOptTy = destNullableTy g calledArgTy
let argExprPrebinder, argExpr2 = MethodCalls.AdjustCallerArgExpr tcVal g cenv.amap cenv.infoReader ad false calledNonOptTy ReflectedArgInfo.None callerArgTy m argExpr
let callerArgTy2 = tyOfExpr g argExpr2
argExprPrebinder, MethodCalls.MakeNullableExprIfNeeded cenv.infoReader calledArgTy callerArgTy2 argExpr2 m
else
MethodCalls.AdjustCallerArgExpr tcVal g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr

let argExprPrebinder, action, defnItem =
match setter with
| AssignedPropSetter (propStaticTyOpt, pinfo, pminfo, pminst) ->
Expand All @@ -9799,7 +9788,7 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo
MethInfoChecks g cenv.amap true None [objExpr] ad m pminfo
let calledArgTy = List.head (List.head (pminfo.GetParamTypes(cenv.amap, m, pminst)))
let tcVal = LightweightTcValForUsingInBuildMethodCall g
let argExprPrebinder, argExpr = adjustCallerArgExpr calledArgTy tcVal
let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
let mut = (if isStructTy g (tyOfExpr g objExpr) then DefinitelyMutates else PossiblyMutates)
let action = BuildPossiblyConditionalMethodCall cenv env mut m true pminfo NormalValUse pminst [objExpr] [argExpr] propStaticTyOpt |> fst
argExprPrebinder, action, Item.Property (pinfo.PropertyName, [pinfo])
Expand All @@ -9809,7 +9798,7 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo
ILFieldInstanceChecks g cenv.amap ad m finfo
let calledArgTy = finfo.FieldType (cenv.amap, m)
let tcVal = LightweightTcValForUsingInBuildMethodCall g
let argExprPrebinder, argExpr = adjustCallerArgExpr calledArgTy tcVal
let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
let action = BuildILFieldSet g m objExpr finfo argExpr
argExprPrebinder, action, Item.ILField finfo

Expand All @@ -9818,7 +9807,7 @@ and TcSetterArgExpr (cenv: cenv) env denv objExpr ad assignedSetter calledFromCo
let calledArgTy = rfinfo.FieldType
CheckRecdFieldMutation m denv rfinfo
let tcVal = LightweightTcValForUsingInBuildMethodCall g
let argExprPrebinder, argExpr = adjustCallerArgExpr calledArgTy tcVal
let argExprPrebinder, argExpr = MethodCalls.AdjustCallerArgExpr tcVal g cenv.amap cenv.infoReader ad false calledArgTy ReflectedArgInfo.None callerArgTy m argExpr
let action = BuildRecdFieldSet g m objExpr rfinfo argExpr
argExprPrebinder, action, Item.RecdField rfinfo

Expand Down
76 changes: 33 additions & 43 deletions src/Compiler/Checking/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -279,16 +279,28 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad

// Adhoc int32 --> int64
elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.int64_ty reqdTy && typeEquiv g g.int32_ty actualTy then
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None

// Adhoc int32 --> nativeint
elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.nativeint_ty reqdTy && typeEquiv g g.int32_ty actualTy then
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None

// Adhoc int32 --> float64
elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions && typeEquiv g g.float_ty reqdTy && typeEquiv g g.int32_ty actualTy then
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None
g.int32_ty, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None

elif g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop && isMethodArg && isNullableTy g reqdTy && not (isNullableTy g actualTy) then
let underlyingTy = destNullableTy g reqdTy
// shortcut
if typeEquiv g underlyingTy actualTy then
actualTy, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None
else
let adjustedTy, _, _ = AdjustRequiredTypeForTypeDirectedConversions infoReader ad isMethodArg isConstraint underlyingTy actualTy m
if typeEquiv g adjustedTy actualTy then
actualTy, TypeDirectedConversionUsed.Yes(warn TypeDirectedConversion.BuiltIn), None
else
reqdTy, TypeDirectedConversionUsed.No, None

// Adhoc based on op_Implicit, perhaps returing a new equational type constraint to
// eliminate articifical constrained type variables.
elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions then
Expand Down Expand Up @@ -352,9 +364,8 @@ let AdjustCalledArgTypeForOptionals (infoReader: InfoReader) ad enforceNullableO

// If inference has worked out it's a struct (e.g. an int) then use this
elif isStructTy g callerArgTy then
let calledArgTy2 = destNullableTy g calledArgTy
AdjustRequiredTypeForTypeDirectedConversions infoReader ad true false calledArgTy2 callerArgTy m

AdjustRequiredTypeForTypeDirectedConversions infoReader ad true false calledArgTy callerArgTy m

// If neither and we are at the end of overload resolution then use the Nullable
elif enforceNullableOptionalsKnownTypes then
calledArgTy, TypeDirectedConversionUsed.No, None
Expand Down Expand Up @@ -1305,6 +1316,16 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade

mkCallToDoubleOperator g m actualTy expr

elif g.langVersion.SupportsFeature LanguageFeature.NullableOptionalInterop &&
isNullableTy g reqdTy && not (isNullableTy g actualTy) then

let underlyingTy = destNullableTy g reqdTy
let adjustedExpr = AdjustExprForTypeDirectedConversions tcVal g amap infoReader ad underlyingTy actualTy m expr
let adjustedActualTy = tyOfExpr g adjustedExpr

let minfo = GetIntrinsicConstructorInfosOfType infoReader m reqdTy |> List.head
let callerArgExprCoerced = mkCoerceIfNeeded g underlyingTy adjustedActualTy adjustedExpr
MakeMethInfoCall amap m minfo [] [callerArgExprCoerced] None
else
match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with
| Some (minfo, staticTy, _) ->
Expand All @@ -1313,9 +1334,7 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade
let callExpr, _ = BuildMethodCall tcVal g amap Mutates.NeverMutates m false minfo ValUseFlag.NormalValUse [] [] [expr] staticTyOpt
assert (let resTy = tyOfExpr g callExpr in typeEquiv g reqdTy resTy)
callExpr
| None -> mkCoerceIfNeeded g reqdTy actualTy expr
// TODO: consider Nullable

| None -> mkCoerceIfNeeded g reqdTy actualTy expr

// Handle adhoc argument conversions
let AdjustCallerArgExpr tcVal (g: TcGlobals) amap infoReader ad isOutArg calledArgTy (reflArgInfo: ReflectedArgInfo) callerArgTy m callerArgExpr =
Expand Down Expand Up @@ -1450,17 +1469,6 @@ 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] None

// Adjust all the optional arguments, filling in values for defaults,
let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader: InfoReader) ad (assignedArg: AssignedCalledArg<_>) =
let g = infoReader.g
Expand Down Expand Up @@ -1492,14 +1500,9 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader:
| NotOptional ->
// T --> Nullable<T> widening at callsites
if isOptCallerArg then errorR(Error(FSComp.SR.tcFormalArgumentIsNotOptional(), m))
if isNullableTy g calledArgTy then
if isNullableTy g callerArgTy then
callerArgExpr
else
let calledNonOptTy = destNullableTy g calledArgTy
let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr
let callerArgTy2 = tyOfExpr g callerArgExpr2
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy2 callerArgExpr2 m
if isNullableTy g calledArgTy then
// AdjustCallerArgExpr later on will deal with the nullable conversion
callerArgExpr
else
failwith "unreachable" // see case above

Expand All @@ -1521,21 +1524,8 @@ let AdjustCallerArgForOptional tcVal tcFieldInit eCallerMemberName (infoReader:
// This should be unreachable but the error will be reported elsewhere
callerArgExpr
else
if isNullableTy g calledArgTy then
if isNullableTy g callerArgTy then
// CSharpMethod(x=b) when 'x' has nullable type
// 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 _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledNonOptTy reflArgInfo callerArgTy m callerArgExpr
let callerArgTy2 = tyOfExpr g callerArgExpr2
MakeNullableExprIfNeeded infoReader calledArgTy callerArgTy2 callerArgExpr2 m
else
// CSharpMethod(x=b) --> CSharpMethod(?x=b)
let _, callerArgExpr2 = AdjustCallerArgExpr tcVal g amap infoReader ad isOutArg calledArgTy reflArgInfo callerArgTy m callerArgExpr
callerArgExpr2
// AdjustCallerArgExpr later on will deal with any nullable conversion
callerArgExpr

| CalleeSide ->
if isOptCallerArg then
Expand Down
3 changes: 0 additions & 3 deletions src/Compiler/Checking/MethodCalls.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,6 @@ val MakeMethInfoCall:
staticTyOpt: TType option ->
Expr

// Make an expression to construct a System.Nullable<'T> from callerArgExpr if callerArgTy is not Nullable<'T> yet.
val MakeNullableExprIfNeeded: infoReader: InfoReader -> calledArgTy: TType -> callerArgTy: TType -> callerArgExpr: Expr -> m: range -> Expr

/// Build an expression that calls a given method info.
/// This is called after overload resolution, and also to call other
/// methods such as 'setters' for properties.
Expand Down

0 comments on commit da5d49b

Please sign in to comment.