Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
f26d790
Add failing tests + strings + ContextInfo for dot-access nullness war…
T-Gro May 15, 2026
2a60e44
Emit dot-access-specific nullness warning with receiver range (#19658…
T-Gro May 15, 2026
280918b
Update baselines, surface area, and release notes for dot-access null…
T-Gro May 15, 2026
8257d52
Address review findings: dedupe helper, trim comments, add edge-case …
T-Gro May 19, 2026
5e73972
Strip MemberAccessOnNullable context before recursing in SolveTypeSub…
T-Gro May 20, 2026
08784a8
Gate objArgInfo construction and withObjArgContext on g.checkNullness…
T-Gro May 20, 2026
4490365
Emit SeeAlso pointing at member call when receiver is on a different …
T-Gro May 20, 2026
ed0b095
Walk through Coerce wrappers and filter compiler-generated receiver n…
T-Gro May 20, 2026
f043eff
Add coverage + gap-documenting tests for dot-access nullness warning …
T-Gro May 20, 2026
0c15fbd
Introduce ObjArgInfo record and extract applyObjArgContext helper
T-Gro May 20, 2026
b422bc6
Flip csenv default in SolveTypeSubsumesType (#19658)
T-Gro May 21, 2026
88f346b
Collapse Issue 19658 tests into Theory; drop misleading KNOWN GAP lab…
T-Gro May 21, 2026
a6b963a
Remove objArgInfo parameter threading; carry context via eContextInfo…
T-Gro May 21, 2026
01b6fa9
Extract stripMemberAccessOnNullableCtx helper to dedupe 5 inline copi…
T-Gro May 21, 2026
4a0ec70
Show correct nullable type in dot-access warning message (#19658)
T-Gro May 22, 2026
68fab52
Remove range parameter from Entity.Typars; fix shared entity typar race
T-Gro May 25, 2026
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
4 changes: 4 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
* Added warning FS3884 when a function or delegate value is used as an interpolated string argument. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289))
* Add `#version;;` directive to F# Interactive to display version and environment information. ([Issue #13307](https://github.com/dotnet/fsharp/issues/13307), [PR #19332](https://github.com/dotnet/fsharp/pull/19332))

### Improved

* Nullness warning FS3261 on dotted method or property access (e.g. `x.Member`) now underlines the receiver expression and includes the member name and (when known) the binding name in the message. ([Issue #19658](https://github.com/dotnet/fsharp/issues/19658))

### Changed

* Improvements in error and warning messages: new error FS3885 when `let!`/`use!` is the final expression in a computation expression; new warning FS3886 when a list literal contains a single tuple element (likely missing `;` separator); improved wording for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and SRTP operator-not-in-scope hints. ([PR #19398](https://github.com/dotnet/fsharp/pull/19398))
Expand Down
27 changes: 12 additions & 15 deletions src/Compiler/Checking/AugmentWithHashCompare.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ let unaryArg = [ ValReprInfo.unnamedTopArg ]
let tupArg = [ [ ValReprInfo.unnamedTopArg1; ValReprInfo.unnamedTopArg1 ] ]

let mkValSpecAux g m (tcref: TyconRef) ty vis slotsig methn valTy argData isGetter isCompGen =
let tps = tcref.Typars m
let tps = tcref.Typars

let membInfo =
match slotsig with
Expand Down Expand Up @@ -1298,18 +1298,16 @@ let mkImpliedValSpec g m tcref ty vis slotsig methn valTy argData isGetter =
v

let MakeValsForCompareAugmentation g (tcref: TyconRef) =
let m = tcref.Range
let _, ty = mkMinimalTy g tcref
let tps = tcref.Typars m
let tps = tcref.Typars
let vis = tcref.TypeReprAccessibility

mkValSpec g tcref ty vis (Some(mkIComparableCompareToSlotSig g)) "CompareTo" (tps +-> (mkCompareObjTy g ty)) unaryArg false,
mkValSpec g tcref ty vis (Some(mkGenericIComparableCompareToSlotSig g ty)) "CompareTo" (tps +-> (mkCompareTy g ty)) unaryArg false

let MakeValsForCompareWithComparerAugmentation g (tcref: TyconRef) =
let m = tcref.Range
let _, ty = mkMinimalTy g tcref
let tps = tcref.Typars m
let tps = tcref.Typars
let vis = tcref.TypeReprAccessibility

mkValSpec
Expand All @@ -1324,10 +1322,9 @@ let MakeValsForCompareWithComparerAugmentation g (tcref: TyconRef) =
false

let MakeValsForEqualsAugmentation g (tcref: TyconRef) =
let m = tcref.Range
let _, ty = mkMinimalTy g tcref
let vis = tcref.Accessibility
let tps = tcref.Typars m
let tps = tcref.Typars

let objEqualsVal =
mkValSpec g tcref ty vis (Some(mkEqualsSlotSig g)) "Equals" (tps +-> (mkEqualsObjTy g ty)) unaryArg false
Expand All @@ -1352,7 +1349,7 @@ let MakeValsForEqualsAugmentation g (tcref: TyconRef) =
let MakeValsForEqualityWithComparerAugmentation g (tcref: TyconRef) =
let _, ty = mkMinimalTy g tcref
let vis = tcref.Accessibility
let tps = tcref.Typars tcref.Range
let tps = tcref.Typars

let objGetHashCodeVal =
mkValSpec g tcref ty vis (Some(mkGetHashCodeSlotSig g)) "GetHashCode" (tps +-> (mkHashTy g ty)) unitArg false
Expand Down Expand Up @@ -1395,7 +1392,7 @@ let MakeValsForEqualityWithComparerAugmentation g (tcref: TyconRef) =
let MakeBindingsForCompareAugmentation g (tycon: Tycon) =
let tcref = mkLocalTyconRef tycon
let m = tycon.Range
let tps = tycon.Typars m
let tps = tycon.Typars

let mkCompare comparef =
match tycon.GeneratedCompareToValues with
Expand Down Expand Up @@ -1439,7 +1436,7 @@ let MakeBindingsForCompareAugmentation g (tycon: Tycon) =
let MakeBindingsForCompareWithComparerAugmentation g (tycon: Tycon) =
let tcref = mkLocalTyconRef tycon
let m = tycon.Range
let tps = tycon.Typars m
let tps = tycon.Typars

let mkCompare comparef =
match tycon.GeneratedCompareToWithComparerValues with
Expand Down Expand Up @@ -1471,7 +1468,7 @@ let MakeBindingsForCompareWithComparerAugmentation g (tycon: Tycon) =
let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon) =
let tcref = mkLocalTyconRef tycon
let m = tycon.Range
let tps = tycon.Typars m
let tps = tycon.Typars

let mkStructuralEquatable hashf equalsf =
match tycon.GeneratedHashAndEqualsWithComparerValues with
Expand Down Expand Up @@ -1590,7 +1587,7 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon
let MakeBindingsForEqualsAugmentation (g: TcGlobals) (tycon: Tycon) =
let tcref = mkLocalTyconRef tycon
let m = tycon.Range
let tps = tycon.Typars m
let tps = tycon.Typars

let mkEquals equalsf =
match tycon.GeneratedHashAndEqualsValues with
Expand Down Expand Up @@ -1668,15 +1665,15 @@ let rec TypeDefinitelyHasEquality g ty =
)
&&
// Check the (possibly inferred) structural dependencies
(tinst, tcref.TyparsNoRange)
(tinst, tcref.Typars)
||> List.lengthsEqAndForall2 (fun ty tp -> not tp.EqualityConditionalOn || TypeDefinitelyHasEquality g ty)
| _ -> false

let MakeValsForUnionAugmentation g (tcref: TyconRef) =
let m = tcref.Range
let _, tmty = mkMinimalTy g tcref
let vis = tcref.TypeReprAccessibility
let tps = tcref.Typars m
let tps = tcref.Typars

tcref.UnionCasesAsList
|> List.map (fun uc ->
Expand All @@ -1690,7 +1687,7 @@ let MakeValsForUnionAugmentation g (tcref: TyconRef) =
let MakeBindingsForUnionAugmentation g (tycon: Tycon) (vals: ValRef list) =
let tcref = mkLocalTyconRef tycon
let m = tycon.Range
let tps = tycon.Typars m
let tps = tycon.Typars
let tinst, ty = mkMinimalTy g tcref
let thisv, thise = mkThisVar g m ty
let unitv, _ = mkCompGenLocal m "unitArg" g.unit_ty
Expand Down
42 changes: 20 additions & 22 deletions src/Compiler/Checking/CheckDeclarations.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1701,7 +1701,7 @@ module MutRecBindingChecking =
let thisValOpt = GetInstanceMemberThisVariable (v, x)

// Members have at least as many type parameters as the enclosing class. Just grab the type variables for the type.
let thisTyInst = List.map mkTyparTy (List.truncate (tcref.Typars(v.Range).Length) v.Typars)
let thisTyInst = List.map mkTyparTy (List.truncate (tcref.Typars.Length) v.Typars)

let x = localReps.FixupIncrClassExprPhase2C cenv thisValOpt safeStaticInitInfo thisTyInst x

Expand Down Expand Up @@ -2153,7 +2153,7 @@ module TyconConstraintInference =
| ValueSome tp ->
// Within structural types, type parameters can be optimistically assumed to have comparison
// We record the ones for which we have made this assumption.
if tycon.TyparsNoRange |> List.exists (fun tp2 -> typarRefEq tp tp2) then
if tycon.Typars |> List.exists (fun tp2 -> typarRefEq tp tp2) then
assumedTyparsAcc <- assumedTyparsAcc.Add(tp.Stamp)
true
else
Expand All @@ -2180,7 +2180,7 @@ module TyconConstraintInference =
not (EntityHasWellKnownAttribute g WellKnownEntityAttributes.NoComparisonAttribute tcref.Deref)
&&
// Check the structural dependencies
(tinst, tcref.TyparsNoRange) ||> List.lengthsEqAndForall2 (fun ty tp ->
(tinst, tcref.Typars) ||> List.lengthsEqAndForall2 (fun ty tp ->
if tp.ComparisonConditionalOn || assumedTypars.Contains tp.Stamp then
checkIfFieldTypeSupportsComparison tycon ty
else
Expand Down Expand Up @@ -2239,7 +2239,7 @@ module TyconConstraintInference =
// OK, we're done, Record the results for the type variable which provide the support
for tyconStamp in uneliminatedTycons do
let tycon, _ = tab[tyconStamp]
for tp in tycon.Typars(tycon.Range) do
for tp in tycon.Typars do
if assumedTyparsActual.Contains(tp.Stamp) then
tp.SetComparisonDependsOn true

Expand Down Expand Up @@ -2274,7 +2274,7 @@ module TyconConstraintInference =
| ValueSome tp ->
// Within structural types, type parameters can be optimistically assumed to have equality
// We record the ones for which we have made this assumption.
if tycon.Typars(tycon.Range) |> List.exists (fun tp2 -> typarRefEq tp tp2) then
if tycon.Typars |> List.exists (fun tp2 -> typarRefEq tp tp2) then
assumedTyparsAcc <- assumedTyparsAcc.Add(tp.Stamp)
true
else
Expand All @@ -2300,7 +2300,7 @@ module TyconConstraintInference =
not (EntityHasWellKnownAttribute g WellKnownEntityAttributes.NoEqualityAttribute tcref.Deref)
&&
// Check the structural dependencies
(tinst, tcref.TyparsNoRange) ||> List.lengthsEqAndForall2 (fun ty tp ->
(tinst, tcref.Typars) ||> List.lengthsEqAndForall2 (fun ty tp ->
if tp.EqualityConditionalOn || assumedTypars.Contains tp.Stamp then
checkIfFieldTypeSupportsEquality tycon ty
else
Expand Down Expand Up @@ -2360,7 +2360,7 @@ module TyconConstraintInference =
// OK, we're done, Record the results for the type variable which provide the support
for tyconStamp in uneliminatedTycons do
let tycon, _ = tab[tyconStamp]
for tp in tycon.Typars(tycon.Range) do
for tp in tycon.Typars do
if assumedTyparsActual.Contains(tp.Stamp) then
tp.SetEqualityDependsOn true

Expand Down Expand Up @@ -2604,8 +2604,7 @@ module EstablishTypeDefinitionCores =
let private GetStructuralElementsOfTyconDefn (cenv: cenv) env tpenv (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, _, _, _, _)) tycon =
let thisTyconRef = mkLocalTyconRef tycon
let g = cenv.g
let m = tycon.Range
let env = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) env
let env = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars) env
let env = MakeInnerEnvForTyconRef env thisTyconRef false
[ match synTyconRepr with
| SynTypeDefnSimpleRepr.None _ -> ()
Expand Down Expand Up @@ -2646,7 +2645,7 @@ module EstablishTypeDefinitionCores =
for arg in ctorArgNames do
let ty = names[arg].Type
let m = names[arg].Ident.idRange
if not (isNil (ListSet.subtract typarEq (freeInTypeLeftToRight g false ty) tycon.TyparsNoRange)) then
if not (isNil (ListSet.subtract typarEq (freeInTypeLeftToRight g false ty) tycon.Typars)) then
errorR(Error(FSComp.SR.tcStructsMustDeclareTypesOfImplicitCtorArgsExplicitly(), m))
yield (ty, m)

Expand Down Expand Up @@ -3194,7 +3193,7 @@ module EstablishTypeDefinitionCores =

let hasMeasureAttr = attribsHaveEntityFlag g WellKnownEntityAttributes.MeasureAttribute attrs
let hasMeasureableAttr = attribsHaveEntityFlag g WellKnownEntityAttributes.MeasureableAttribute attrs
let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars) envinner
let envinner = MakeInnerEnvForTyconRef envinner thisTyconRef false

match synTyconRepr with
Expand All @@ -3205,7 +3204,7 @@ module EstablishTypeDefinitionCores =
// "type x = | A" can always be used instead.
| TyconCoreAbbrevThatIsReallyAUnion (hasMeasureAttr, envinner, id) _ -> ()

| SynTypeDefnSimpleRepr.TypeAbbrev(ParserDetail.Ok, rhsType, m) ->
| SynTypeDefnSimpleRepr.TypeAbbrev(ParserDetail.Ok, rhsType, _m) ->

#if !NO_TYPEPROVIDERS
// Check we have not already decided that this is a generative provided type definition. If we have already done this (i.e. this is the second pass
Expand Down Expand Up @@ -3254,7 +3253,7 @@ module EstablishTypeDefinitionCores =

if not firstPass then
let ftyvs = freeInTypeLeftToRight g false ty
let typars = tycon.Typars m
let typars = tycon.Typars
if ftyvs.Length <> typars.Length then
errorR(Deprecated(FSComp.SR.tcTypeAbbreviationHasTypeParametersMissingOnType(), tycon.Range))

Expand All @@ -3279,9 +3278,8 @@ module EstablishTypeDefinitionCores =
match origInfo, tyconAndAttrsOpt with
| (typeDefCore, _, _), Some (tycon, (attrs, _)) ->
let (MutRecDefnsPhase1DataForTycon(_, synTyconRepr, explicitImplements, _, _, _)) = typeDefCore
let m = tycon.Range
let tcref = mkLocalTyconRef tycon
let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars) envinner
let envinner = MakeInnerEnvForTyconRef envinner tcref false

let implementedTys, _ = List.mapFold (mapFoldFst (TcTypeAndRecover cenv NoNewTypars checkConstraints ItemOccurrence.UseInType WarnOnIWSAM.No envinner)) tpenv explicitImplements
Expand Down Expand Up @@ -3442,7 +3440,7 @@ module EstablishTypeDefinitionCores =
if allowed then
if kind = explicitKind then
warning(PossibleUnverifiableCode m)
elif List.isEmpty (thisTyconRef.Typars m) then
elif List.isEmpty (thisTyconRef.Typars) then
errorR (Error(FSComp.SR.tcOnlyStructsCanHaveStructLayout(), m))
else
errorR (Error(FSComp.SR.tcGenericTypesCannotHaveStructLayout(), m))
Expand Down Expand Up @@ -3474,7 +3472,7 @@ module EstablishTypeDefinitionCores =
if not ctorArgNames.IsEmpty then
errorR (Error(FSComp.SR.parsOnlyClassCanTakeValueArguments(), pat.Range))

let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envinner
let envinner = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars) envinner
let envinner = MakeInnerEnvForTyconRef envinner thisTyconRef false

let multiCaseUnionStructCheck (unionCases: UnionCase list) =
Expand Down Expand Up @@ -3640,7 +3638,7 @@ module EstablishTypeDefinitionCores =
writeFakeRecordFieldsToSink userFields

let superTy = tycon.TypeContents.tcaug_super
let containerInfo = TyconContainerInfo(innerParent, thisTyconRef, thisTyconRef.Typars m, NoSafeInitInfo)
let containerInfo = TyconContainerInfo(innerParent, thisTyconRef, thisTyconRef.Typars, NoSafeInitInfo)
let kind = InferTyconKind g (kind, attrs, slotsigs, fields, inSig, isConcrete, m)
match kind with
| SynTypeDefnKind.Opaque ->
Expand Down Expand Up @@ -3712,7 +3710,7 @@ module EstablishTypeDefinitionCores =
let _, _, curriedArgInfos, returnTy, _ = GetValReprTypeInCompiledForm g (arity |> TranslateSynValInfo cenv m (TcAttributes cenv envinner) |> TranslatePartialValReprInfo []) 0 tyR m
if curriedArgInfos.Length < 1 then error(Error(FSComp.SR.tcInvalidDelegateSpecification(), m))
if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcDelegatesCannotBeCurried(), m))
let ttps = thisTyconRef.Typars m
let ttps = thisTyconRef.Typars
let fparams =
curriedArgInfos.Head
|> List.map (fun (ty, argInfo: ArgReprInfo) ->
Expand Down Expand Up @@ -4028,7 +4026,7 @@ module EstablishTypeDefinitionCores =
let (MutRecDefnsPhase1DataForTycon(synTyconInfo, _, _, _, _, _)) = typeDefCore
let (SynComponentInfo(_, TyparsAndConstraints (_, cs1), cs2, _, _, _, _, _)) = synTyconInfo
let synTyconConstraints = cs1 @ cs2
let envForTycon = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars m) envForDecls
let envForTycon = AddDeclaredTypars CheckForDuplicateTypars (tycon.Typars) envForDecls
let thisTyconRef = mkLocalTyconRef tycon
let envForTycon = MakeInnerEnvForTyconRef envForTycon thisTyconRef false
try
Expand Down Expand Up @@ -4143,7 +4141,7 @@ module EstablishTypeDefinitionCores =

// No inferred constraints allowed on declared typars
(envMutRecPrelim, withEnvs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (_, tyconOpt) ->
tyconOpt |> Option.iter (fun tycon -> tycon.Typars m |> List.iter (SetTyparRigid envForDecls.DisplayEnv m)))
tyconOpt |> Option.iter (fun tycon -> tycon.Typars |> List.iter (SetTyparRigid envForDecls.DisplayEnv m)))

// Phase1E. OK, now recheck the abbreviations, super/interface and explicit constraints types (this time checking constraints)
(envMutRecPrelim, withAttrs) ||> MutRecShapes.iterTyconsWithEnv (fun envForDecls (origInfo, tyconAndAttrsOpt) ->
Expand Down Expand Up @@ -4246,7 +4244,7 @@ module TcDeclarations =
tcref.Deref.IsFSharpDelegateTycon ||
tcref.Deref.IsFSharpEnumTycon

let reqTypars = tcref.Typars m
let reqTypars = tcref.Typars

// Member definitions are intrinsic (added directly to the type) if:
// a) For interfaces, only if it is in the original defn.
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckIncrementalClasses.fs
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ type IncrClassReprInfo =
let ctorDeclaredTypars = staticCtorInfo.GetNormalizedIncrCtorDeclaredTypars cenv denv staticCtorInfo.TyconRef.Range

// Note: tcrefObjTy contains the original "formal" typars, thisTy is the "fresh" one... f<>fresh.
let revTypeInst = List.zip ctorDeclaredTypars (tcref.TyparsNoRange |> List.map mkTyparTy)
let revTypeInst = List.zip ctorDeclaredTypars (tcref.Typars |> List.map mkTyparTy)

yield MakeIncrClassField(localRep.RepInfoTcGlobals, cpath, revTypeInst, v, isStatic, rfref)
| _ ->
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/CheckPatterns.fs
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ and TcRecordPat warnOnUpper (cenv: cenv) env vFlags patEnv ty fieldPats m =
| Some(tinst, tcref, fldsmap, _fldsList) ->

let gtyp = mkWoNullAppTy tcref tinst
let inst = List.zip (tcref.Typars m) tinst
let inst = List.zip (tcref.Typars) tinst

UnifyTypes cenv env m ty gtyp

Expand Down Expand Up @@ -658,7 +658,7 @@ and ApplyUnionCaseOrExn m (cenv: cenv) env overallTy item =
CheckUnionCaseAttributes g ucref m |> CommitOperationResult
CheckUnionCaseAccessible cenv.amap m ad ucref |> ignore
let resTy = actualResultTyOfUnionCase ucinfo.TypeInst ucref
let inst = mkTyparInst ucref.TyconRef.TyparsNoRange ucinfo.TypeInst
let inst = mkTyparInst ucref.TyconRef.Typars ucinfo.TypeInst
let mkf =
try
UnifyTypes cenv env m overallTy resTy
Expand Down
Loading
Loading