Nullness :: Improvement :: Overrides of generic methods with nullable type instantiations by T-Gro · Pull Request #18337 · dotnet/fsharp · GitHub
Skip to content
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
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/9.0.300.md
22 changes: 18 additions & 4 deletions src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,11 @@ let FreshenAbstractSlot g amap m synTyparDecls absMethInfo =

// Work out the required type of the member
let argTysFromAbsSlot = argTys |> List.mapSquared (instType typarInstFromAbsSlot)
let retTyFromAbsSlot = retTy |> GetFSharpViewOfReturnType g |> instType typarInstFromAbsSlot

let retTyFromAbsSlot =
retTy
|> GetFSharpViewOfReturnType g
|> instType typarInstFromAbsSlot
typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot

let CheckRecdExprDuplicateFields (elems: Ident list) =
Expand Down Expand Up @@ -11774,16 +11778,26 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (_: Val option) (a
match uniqueAbstractMethSigs with
| uniqueAbstractMeth :: _ ->

// Overrides can narrow the retTy from nullable to not-null.
// By changing nullness to be variable we do not get in the way of eliminating nullness (=good).
// We only keep a WithNull nullness if it was part of an explicit type instantiation
let canChangeNullableRetTy =
match g.checkNullness, renaming with
| false, _ -> false
| true, [] -> true
| true, _ -> not(uniqueAbstractMeth.HasGenericRetTy())

let uniqueAbstractMeth = uniqueAbstractMeth.Instantiate(cenv.amap, m, renaming)

let typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot =
FreshenAbstractSlot g cenv.amap m synTyparDecls uniqueAbstractMeth

let declaredTypars = (if typarsFromAbsSlotAreRigid then typarsFromAbsSlot else declaredTypars)

// Overrides can narrow the retTy from nullable to not-null.
// By changing nullness to be variable we do not get in the way of eliminating nullness (=good).
let retTyFromAbsSlot = retTyFromAbsSlot |> changeWithNullReqTyToVariable g
let retTyFromAbsSlot =
if canChangeNullableRetTy then
retTyFromAbsSlot |> changeWithNullReqTyToVariable g
else retTyFromAbsSlot

let absSlotTy = mkMethodTy g argTysFromAbsSlot retTyFromAbsSlot

Expand Down
14 changes: 14 additions & 0 deletions src/Compiler/Checking/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,20 @@ type MethInfo =
let (ParamAttribs(isParamArrayArg, isInArg, isOutArg, optArgInfo, callerInfo, reflArgInfo)) = info
ParamData(isParamArrayArg, isInArg, isOutArg, optArgInfo, callerInfo, nmOpt, reflArgInfo, pty)))

member x.HasGenericRetTy() =
match x with
| ILMeth(_g, ilminfo, _) -> ilminfo.RawMetadata.Return.Type.IsTypeVar
| FSMeth(g, _, vref, _) ->
let _, _, _, retTy, _ = GetTypeOfMemberInMemberForm g vref
match retTy with
| Some retTy -> isTyparTy g retTy
| None -> false
| MethInfoWithModifiedReturnType(_,retTy) -> false
| DefaultStructCtor _ -> false
#if !NO_TYPEPROVIDERS
| ProvidedMeth(amap, mi, _, m) -> false
#endif

/// Get the ParamData objects for the parameters of a MethInfo
member x.HasParamArrayArg(amap, m, minst) =
x.GetParamDatas(amap, m, minst) |> List.existsSquared (fun (ParamData(isParamArrayArg, _, _, _, _, _, _, _)) -> isParamArrayArg)
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Checking/infos.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,8 @@ type MethInfo =
/// Get the signature of an abstract method slot.
member GetSlotSig: amap: ImportMap * m: range -> SlotSig

member HasGenericRetTy: unit -> bool

/// Get the ParamData objects for the parameters of a MethInfo
member HasParamArrayArg: amap: ImportMap * m: range * minst: TType list -> bool

Expand Down