diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md index 5d0a107d4f1..bd1a089cab1 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -65,6 +65,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)) diff --git a/src/Compiler/Checking/AugmentWithHashCompare.fs b/src/Compiler/Checking/AugmentWithHashCompare.fs index 0d3c12b7599..c5ae2d1459f 100644 --- a/src/Compiler/Checking/AugmentWithHashCompare.fs +++ b/src/Compiler/Checking/AugmentWithHashCompare.fs @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -1668,7 +1665,7 @@ 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 @@ -1676,7 +1673,7 @@ 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 -> @@ -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 diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 4a4361e9808..9798f00be3a 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 _ -> () @@ -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) @@ -3215,7 +3214,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 @@ -3226,7 +3225,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 @@ -3275,7 +3274,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)) @@ -3300,9 +3299,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 @@ -3463,7 +3461,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)) @@ -3495,7 +3493,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) = @@ -3661,7 +3659,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 -> @@ -3733,7 +3731,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) -> @@ -4049,7 +4047,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 @@ -4170,7 +4168,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) -> @@ -4273,7 +4271,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. diff --git a/src/Compiler/Checking/CheckIncrementalClasses.fs b/src/Compiler/Checking/CheckIncrementalClasses.fs index 846aa5f9085..556e4b9cb59 100644 --- a/src/Compiler/Checking/CheckIncrementalClasses.fs +++ b/src/Compiler/Checking/CheckIncrementalClasses.fs @@ -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) | _ -> diff --git a/src/Compiler/Checking/CheckPatterns.fs b/src/Compiler/Checking/CheckPatterns.fs index e6d0e5c7dce..4023253ed34 100644 --- a/src/Compiler/Checking/CheckPatterns.fs +++ b/src/Compiler/Checking/CheckPatterns.fs @@ -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 @@ -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 diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 8a567e0ecef..be783e68b4a 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -127,7 +127,7 @@ let FreshMethInst g m fctps tinst tpsorig = FreshenAndFixupTypars g m TyparRigidity.Flexible fctps tinst tpsorig let FreshenMethInfo m (minfo: MethInfo) = - let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType m) minfo.DeclaringTypeInst minfo.FormalMethodTypars + let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType()) minfo.DeclaringTypeInst minfo.FormalMethodTypars tpTys //------------------------------------------------------------------------- @@ -186,6 +186,17 @@ type ContextInfo = /// The range points to the original argument location. | NullnessCheckOfCapturedArg of range + /// Obj-argument type check in a dotted member access on a nullable receiver. + | MemberAccessOnNullable of ObjArgInfo + +/// Receiver information for a dotted member access, used to produce +/// targeted nullness warnings (e.g. "Possible dereference of null when +/// accessing member 'M' on the nullable value 'x'"). +and ObjArgInfo = + { ObjExprRange: range + MemberName: string + BindingName: string option } + /// Captures relevant information for a particular failed overload resolution. type OverloadInformation = { @@ -236,6 +247,8 @@ exception ConstraintSolverNullnessWarningWithType of DisplayEnv * TType * Nullne exception ConstraintSolverNullnessWarning of string * range * range +exception ConstraintSolverNullnessWarningOnDotAccess of DisplayEnv * objTy: TType * memberName: string * bindingName: string option * objExprRange: range * mMethod: range + exception ConstraintSolverError of string * range * range exception ErrorFromApplyingDefault of tcGlobals: TcGlobals * displayEnv: DisplayEnv * Typar * TType * error: exn * range: range @@ -358,6 +371,15 @@ let MakeConstraintSolverEnv contextInfo css m denv = ExtraRigidTypars = emptyFreeTypars } +/// Strip a MemberAccessOnNullable context before recursing into inner type +/// components. That context describes the OUTER receiver of a dot-access and +/// must not leak into recursive subsumption/unification of inner types +/// (tuple components, type args, fun domain/range, ...). See #19658. +let stripMemberAccessOnNullableCtx (csenv: ConstraintSolverEnv) = + match csenv.eContextInfo with + | ContextInfo.MemberAccessOnNullable _ -> { csenv with eContextInfo = ContextInfo.NoContext } + | _ -> csenv + /// Check whether a type variable occurs in the r.h.s. of a type, e.g. to catch /// infinite equations such as /// 'a = 'a list @@ -1041,6 +1063,7 @@ and shouldWarnUselessNullCheck (csenv:ConstraintSolverEnv) = and getNullnessWarningRange (csenv: ConstraintSolverEnv) = match csenv.eContextInfo with | ContextInfo.NullnessCheckOfCapturedArg capturedArgRange -> capturedArgRange + | ContextInfo.MemberAccessOnNullable info -> info.ObjExprRange | _ -> csenv.m // nullness1: actual @@ -1116,7 +1139,11 @@ and SolveNullnessSubsumesNullness (csenv: ConstraintSolverEnv) m2 (trace: Option CompleteD | NullnessInfo.WithoutNull, NullnessInfo.WithNull -> if csenv.g.checkNullness then - WarnD(ConstraintSolverNullnessWarningWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, getNullnessWarningRange csenv, m2)) + match csenv.eContextInfo with + | ContextInfo.MemberAccessOnNullable info -> + WarnD(ConstraintSolverNullnessWarningOnDotAccess(csenv.DisplayEnv, ty2, info.MemberName, info.BindingName, info.ObjExprRange, m2)) + | _ -> + WarnD(ConstraintSolverNullnessWarningWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, getNullnessWarningRange csenv, m2)) else CompleteD | Nullness.KnownFromConstructor, _ | _, Nullness.KnownFromConstructor -> CompleteD // Unreachable after Normalize() @@ -1495,7 +1522,19 @@ and SolveTypeSubsumesType (csenv: ConstraintSolverEnv) ndeep m2 (trace: Optional elif isObjTyAnyNullness g ty1 && not csenv.MatchingOnly && not(isTyparTy g ty2) then let nullness t = t |> stripTyEqnsA g canShortcut |> nullnessOfTy g SolveNullnessSubsumesNullness csenv m2 trace ty1 ty2 (nullness ty1) (nullness ty2) - else + else + // Keep the caller's csenv available for the *outer* nullness check + // on the same-tycon branch below. + let csenvOuter = csenv + + // Inside the recursion we describe the *inner* types (tuple components, + // type args, fun domain/range, ...). A MemberAccessOnNullable context + // describes the OUTER receiver only; recursing with it would attach the + // dot-access message to a deep mismatch (wrong message AND wrong range). + // Strip it once here so all recursive callsites below default to the + // safe behavior. See #19658. + let csenv = stripMemberAccessOnNullableCtx csenv + let sty1 = stripTyEqnsA csenv.g canShortcut ty1 let sty2 = stripTyEqnsA csenv.g canShortcut ty2 let amap = csenv.amap @@ -1568,18 +1607,18 @@ and SolveTypeSubsumesType (csenv: ConstraintSolverEnv) ndeep m2 (trace: Optional (tyconRefEq g tagc1 g.byrefkind_In_tcr || tyconRefEq g tagc1 g.byrefkind_Out_tcr) ) -> () | _ -> return! SolveTypeEqualsType csenv ndeep m2 trace cxsln tag1 tag2 } - | _ -> SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.TyparsNoRange tc1 + | _ -> SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.Typars tc1 // Special handling for delegate types - ignore nullness differences // Delegates from C# interfaces without nullable annotations should match F# events // See https://github.com/dotnet/fsharp/issues/18361 and https://github.com/dotnet/fsharp/issues/18349 | TType_app (tc1, l1, _), TType_app (tc2, l2, _) when tyconRefEq g tc1 tc2 && isDelegateTy g sty1 -> - SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.TyparsNoRange tc1 + SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.Typars tc1 | TType_app (tc1, l1, _) , TType_app (tc2, l2, _) when tyconRefEq g tc1 tc2 -> trackErrors { - do! SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.TyparsNoRange tc1 - do! SolveNullnessSubsumesNullness csenv m2 trace ty1 ty2 (nullnessOfTy g sty1) (nullnessOfTy g sty2) + do! SolveTypeEqualsTypeWithContravarianceEqns csenv ndeep m2 trace cxsln l1 l2 tc1.Typars tc1 + do! SolveNullnessSubsumesNullness csenvOuter m2 trace ty1 ty2 (nullnessOfTy g sty1) (nullnessOfTy g sty2) } | TType_ucase (uc1, l1), TType_ucase (uc2, l2) when g.unionCaseRefEq uc1 uc2 -> @@ -1619,7 +1658,7 @@ and SolveTypeSubsumesType (csenv: ConstraintSolverEnv) ndeep m2 (trace: Optional // may feasibly convert to Head. match FindUniqueFeasibleSupertype g amap m ty1 ty2 with | None -> ErrorD(ConstraintSolverTypesNotInSubsumptionRelation(denv, ty1, ty2, m, m2)) - | Some t -> SolveTypeSubsumesType csenv ndeep m2 trace cxsln ty1 t + | Some t -> SolveTypeSubsumesType csenvOuter ndeep m2 trace cxsln ty1 t and SolveTypeSubsumesTypeKeepAbbrevs csenv ndeep m2 trace cxsln ty1 ty2 = let denv = csenv.DisplayEnv @@ -2833,7 +2872,7 @@ and SolveTypeSupportsComparison (csenv: ConstraintSolverEnv) ndeep m2 trace ty = match ty with | AppTy g (tcref, tinst) -> // Check the (possibly inferred) structural dependencies - (tinst, tcref.TyparsNoRange) ||> Iterate2D (fun ty tp -> + (tinst, tcref.Typars) ||> Iterate2D (fun ty tp -> if tp.ComparisonConditionalOn then SolveTypeSupportsComparison (csenv: ConstraintSolverEnv) ndeep m2 trace ty else @@ -2880,7 +2919,7 @@ and SolveTypeSupportsEquality (csenv: ConstraintSolverEnv) ndeep m2 trace ty = ErrorD (ConstraintSolverError(FSComp.SR.csTypeDoesNotSupportEquality3(NicePrint.minimalStringOfType denv ty), m, m2)) else // Check the (possibly inferred) structural dependencies - (tinst, tcref.TyparsNoRange) ||> Iterate2D (fun ty tp -> + (tinst, tcref.Typars) ||> Iterate2D (fun ty tp -> if tp.EqualityConditionalOn then SolveTypeSupportsEquality csenv ndeep m2 trace ty else @@ -3508,15 +3547,16 @@ and ResolveOverloadingCore let exactMatchCandidates = candidates |> FilterEachThenUndo (fun newTrace calledMeth -> let csenv = { csenv with IsSpeculativeForMethodOverloading = true } - let cxsln = AssumeMethodSolvesTrait csenv cx m (WithTrace newTrace) calledMeth + let csenvNoCtx = stripMemberAccessOnNullableCtx csenv + let cxsln = AssumeMethodSolvesTrait csenvNoCtx cx m (WithTrace newTrace) calledMeth CanMemberSigsMatchUpToCheck - csenv + csenvNoCtx permitOptArgs alwaysCheckReturn - (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent + (TypesEquiv csenvNoCtx ndeep (WithTrace newTrace) cxsln) // instantiations equivalent (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume - (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert - (ArgsEquivOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome) // args exact + (ReturnTypesMustSubsumeOrConvert csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (ArgsEquivOrConvert csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome) // args exact reqdRetTyOpt calledMeth) @@ -3531,15 +3571,16 @@ and ResolveOverloadingCore let applicable = candidates |> FilterEachThenUndo (fun newTrace candidate -> let csenv = { csenv with IsSpeculativeForMethodOverloading = true } - let cxsln = AssumeMethodSolvesTrait csenv cx m (WithTrace newTrace) candidate + let csenvNoCtx = stripMemberAccessOnNullableCtx csenv + let cxsln = AssumeMethodSolvesTrait csenvNoCtx cx m (WithTrace newTrace) candidate CanMemberSigsMatchUpToCheck - csenv + csenvNoCtx permitOptArgs alwaysCheckReturn - (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) // instantiations equivalent + (TypesEquiv csenvNoCtx ndeep (WithTrace newTrace) cxsln) // instantiations equivalent (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) // obj can subsume - (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert - (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome candidate) // args can subsume + (ReturnTypesMustSubsumeOrConvert csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) // return can subsume or convert + (ArgsMustSubsumeOrConvertWithContextualReport csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome candidate) // args can subsume reqdRetTyOpt candidate) @@ -3553,15 +3594,16 @@ and ResolveOverloadingCore |> List.choose (fun calledMeth -> match CollectThenUndo (fun newTrace -> let csenv = { csenv with IsSpeculativeForMethodOverloading = true } - let cxsln = AssumeMethodSolvesTrait csenv cx m (WithTrace newTrace) calledMeth + let csenvNoCtx = stripMemberAccessOnNullableCtx csenv + let cxsln = AssumeMethodSolvesTrait csenvNoCtx cx m (WithTrace newTrace) calledMeth CanMemberSigsMatchUpToCheck - csenv + csenvNoCtx permitOptArgs alwaysCheckReturn - (TypesEquiv csenv ndeep (WithTrace newTrace) cxsln) + (TypesEquiv csenvNoCtx ndeep (WithTrace newTrace) cxsln) (TypesMustSubsume csenv ndeep (WithTrace newTrace) cxsln m) - (ReturnTypesMustSubsumeOrConvert csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) - (ArgsMustSubsumeOrConvertWithContextualReport csenv ad ndeep (WithTrace newTrace) cxsln cx.IsSome calledMeth) + (ReturnTypesMustSubsumeOrConvert csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome m) + (ArgsMustSubsumeOrConvertWithContextualReport csenvNoCtx ad ndeep (WithTrace newTrace) cxsln cx.IsSome calledMeth) reqdRetTyOpt calledMeth) with | OkResult _ -> None @@ -3687,18 +3729,19 @@ and ResolveOverloading calledMethOpt, trackErrors { do! errors - let cxsln = AssumeMethodSolvesTrait csenv cx m trace calledMeth + let csenvNoCtx = stripMemberAccessOnNullableCtx csenv + let cxsln = AssumeMethodSolvesTrait csenvNoCtx cx m trace calledMeth match calledMethTrace with | NoTrace -> let! _usesTDC = CanMemberSigsMatchUpToCheck - csenv + csenvNoCtx permitOptArgs true - (TypesEquiv csenv ndeep trace cxsln) // instantiations equal + (TypesEquiv csenvNoCtx ndeep trace cxsln) // instantiations equal (TypesMustSubsume csenv ndeep trace cxsln m) // obj can subsume - (ReturnTypesMustSubsumeOrConvert csenv ad ndeep trace cxsln cx.IsSome m) // return can subsume or convert - (ArgsMustSubsumeOrConvert csenv ad ndeep trace cxsln cx.IsSome true) // args can subsume or convert + (ReturnTypesMustSubsumeOrConvert csenvNoCtx ad ndeep trace cxsln cx.IsSome m) // return can subsume or convert + (ArgsMustSubsumeOrConvert csenvNoCtx ad ndeep trace cxsln cx.IsSome true) // args can subsume or convert reqdRetTyOpt calledMeth return () @@ -3959,8 +4002,15 @@ and GetMostApplicableOverload csenv ndeep candidates applicableMeths calledMethG let err = FailOverloading csenv calledMethGroup reqdRetTyOpt isOpConversion callerArgs (PossibleCandidates(methodName, methods,cx)) m None, ErrorD err, NoTrace -let ResolveOverloadingForCall denv css m methodName callerArgs ad calledMethGroup permitOptArgs reqdRetTy = - let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv +let ResolveOverloadingForCall denv css m objArgInfo methodName callerArgs ad calledMethGroup permitOptArgs reqdRetTy = + let csenvNoCtx = MakeConstraintSolverEnv ContextInfo.NoContext css m denv + let csenv = + match objArgInfo with + | Some info when csenvNoCtx.g.checkNullness -> + { csenvNoCtx with + eContextInfo = + ContextInfo.MemberAccessOnNullable info } + | _ -> csenvNoCtx ResolveOverloading csenv NoTrace methodName 0 None callerArgs ad calledMethGroup permitOptArgs (Some reqdRetTy) /// This is used before analyzing the types of arguments in a single overload resolution @@ -3969,12 +4019,20 @@ let UnifyUniqueOverloading css m callerArgCounts + objArgInfo methodName ad (calledMethGroup: CalledMeth list) reqdRetTy // The expected return type, if known = - let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m denv + let csenvNoCtx = MakeConstraintSolverEnv ContextInfo.NoContext css m denv + let csenv = + match objArgInfo with + | Some info when csenvNoCtx.g.checkNullness -> + { csenvNoCtx with + eContextInfo = + ContextInfo.MemberAccessOnNullable info } + | _ -> csenvNoCtx let m = csenv.m // See what candidates we have based on name and arity let candidates = calledMethGroup |> List.filter (fun cmeth -> cmeth.IsCandidate(m, ad)) @@ -3984,13 +4042,13 @@ let UnifyUniqueOverloading let! _usesTDC = // Only one candidate found - we thus know the types we expect of arguments CanMemberSigsMatchUpToCheck - csenv + csenvNoCtx true // permitOptArgs true // always check return type - (TypesEquiv csenv ndeep NoTrace None) + (TypesEquiv csenvNoCtx ndeep NoTrace None) (TypesMustSubsume csenv ndeep NoTrace None m) - (ReturnTypesMustSubsumeOrConvert csenv ad ndeep NoTrace None false m) - (ArgsMustSubsumeOrConvert csenv ad ndeep NoTrace None false false) + (ReturnTypesMustSubsumeOrConvert csenvNoCtx ad ndeep NoTrace None false m) + (ArgsMustSubsumeOrConvert csenvNoCtx ad ndeep NoTrace None false false) (Some reqdRetTy) calledMeth return true diff --git a/src/Compiler/Checking/ConstraintSolver.fsi b/src/Compiler/Checking/ConstraintSolver.fsi index 8d21270f901..eebd72c2e60 100644 --- a/src/Compiler/Checking/ConstraintSolver.fsi +++ b/src/Compiler/Checking/ConstraintSolver.fsi @@ -66,6 +66,17 @@ type ContextInfo = /// The range points to the original argument location. | NullnessCheckOfCapturedArg of range + /// Obj-argument type check in a dotted member access on a nullable receiver. + | MemberAccessOnNullable of ObjArgInfo + +/// Receiver information for a dotted member access, used to produce +/// targeted nullness warnings (e.g. "Possible dereference of null when +/// accessing member 'M' on the nullable value 'x'"). +and ObjArgInfo = + { ObjExprRange: range + MemberName: string + BindingName: string option } + /// Captures relevant information for a particular failed overload resolution. type OverloadInformation = { methodSlot: CalledMeth @@ -146,6 +157,14 @@ exception ConstraintSolverNullnessWarningWithType of DisplayEnv * TType * Nullne exception ConstraintSolverNullnessWarning of string * range * range +exception ConstraintSolverNullnessWarningOnDotAccess of + DisplayEnv * + objTy: TType * + memberName: string * + bindingName: string option * + objExprRange: range * + mMethod: range + exception ConstraintSolverError of string * range * range exception ErrorFromApplyingDefault of @@ -246,6 +265,7 @@ val ResolveOverloadingForCall: DisplayEnv -> ConstraintSolverState -> range -> + objArgInfo: ObjArgInfo option -> methodName: string -> callerArgs: CallerArgs -> AccessorDomain -> @@ -259,6 +279,7 @@ val UnifyUniqueOverloading: ConstraintSolverState -> range -> int * int -> + objArgInfo: ObjArgInfo option -> string -> AccessorDomain -> CalledMeth list -> diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index d3b1e26497f..5be255a0d52 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -604,7 +604,8 @@ let ShrinkContext env oldRange newRange = | ContextInfo.RuntimeTypeTest _ | ContextInfo.DowncastUsedInsteadOfUpcast _ | ContextInfo.SequenceExpression _ - | ContextInfo.NullnessCheckOfCapturedArg _ -> + | ContextInfo.NullnessCheckOfCapturedArg _ + | ContextInfo.MemberAccessOnNullable _ -> env | ContextInfo.CollectionElement (b,m) -> if not (equals m oldRange) then env else @@ -1922,7 +1923,7 @@ let FreshenPossibleForallTy g m rigid ty = origTypars, tps, tinst, instType renaming tau let FreshenTyconRef2 (g: TcGlobals) m (tcref: TyconRef) = - let tps, renaming, tinst = FreshenTypeInst g m (tcref.Typars m) + let tps, renaming, tinst = FreshenTypeInst g m (tcref.Typars) tps, renaming, tinst, TType_app (tcref, tinst, g.knownWithoutNull) /// Given a abstract method, which may be a generic method, freshen the type in preparation @@ -1946,7 +1947,7 @@ let FreshenAbstractSlot g amap m synTyparDecls absMethInfo = // If the virtual method is a generic method then copy its type parameters let typarsFromAbsSlot, typarInstFromAbsSlot, _ = - let ttps = absMethInfo.GetFormalTyparsOfDeclaringType m + let ttps = absMethInfo.GetFormalTyparsOfDeclaringType() let ttinst = argsOfAppTy g absMethInfo.ApparentEnclosingType let rigid = if typarsFromAbsSlotAreRigid then TyparRigidity.Rigid else TyparRigidity.Flexible FreshenAndFixupTypars g m rigid ttps ttinst fmtps @@ -2077,7 +2078,7 @@ let ApplyUnionCaseOrExn (makerForUnionCase, makerForExnTag) m (cenv: cenv) env o 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 UnifyTypes cenv env m overallTy resTy let mkf = makerForUnionCase(ucref, ucinfo.TypeInst) mkf, actualTysOfUnionCaseFields inst ucref, [ for f in ucref.AllFieldsAsList -> f.Id ] @@ -4224,7 +4225,7 @@ let rec TcTyparConstraint ridx (cenv: cenv) newOk checkConstraints occ (env: TcE match checkConstraints with | NoCheckCxs -> //let formalEnclosingTypars = [] - let tpsorig = tcref.Typars(m) //List.map (destTyparTy g) inst //, _, tinst, _ = FreshenTyconRef2 g m tcref + let tpsorig = tcref.Typars //List.map (destTyparTy g) inst //, _, tinst, _ = FreshenTyconRef2 g m tcref let tps = List.map (destTyparTy g) tinst //, _, tinst, _ = FreshenTyconRef2 g m tcref let tprefInst, _tptys = mkTyparToTyparRenaming tpsorig tps //let tprefInst = mkTyparInst formalEnclosingTypars tinst @ renaming @@ -4707,7 +4708,7 @@ and TcLongIdentAppType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env TType_measure (NewErrorMeasure ()), tpenv | _, TyparKind.Type -> - if postfix && tcref.Typars m |> List.exists (fun tp -> match tp.Kind with TyparKind.Measure -> true | _ -> false) then + if postfix && tcref.Typars |> List.exists (fun tp -> match tp.Kind with TyparKind.Measure -> true | _ -> false) then error(Error(FSComp.SR.tcInvalidUnitsOfMeasurePrefix(), m)) TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinstEnclosing args inst @@ -10193,6 +10194,7 @@ and TcMethodApplication_UniqueOverloadInference objTyOpt isCheckingAttributeCall callerObjArgTys + objArgInfo methodName curriedCallerArgsOpt candidateMethsAndProps @@ -10269,7 +10271,7 @@ and TcMethodApplication_UniqueOverloadInference yield makeOneCalledMeth (minfo, pinfoOpt, false) ] let uniquelyResolved = - UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts methodName ad preArgumentTypeCheckingCalledMethGroup returnTy + UnifyUniqueOverloading denv cenv.css mMethExpr callerArgCounts objArgInfo methodName ad preArgumentTypeCheckingCalledMethGroup returnTy uniquelyResolved, preArgumentTypeCheckingCalledMethGroup @@ -10427,6 +10429,27 @@ and TcMethodApplication let callerObjArgTys = objArgs |> List.map (tyOfExpr g) let calledMeths = calledMethsAndProps |> List.map fst + let objArgInfo: ObjArgInfo option = + if g.checkNullness then + match objArgs with + | [objExpr] -> + // Receiver may be wrapped in a debug point and/or an interface + // upcast (Expr.Op(TOp.Coerce, ...)). Drill through both. Filter + // out compiler-generated vals (e.g. _arg1, matchValue, + // copyOfStruct, tupledArg) so internal names never leak into + // user-facing nullness warnings. + let rec tryGetBindingName expr = + match stripDebugPoints expr with + | Expr.Val (vref, _, _) when not vref.IsCompilerGenerated -> + Some vref.DisplayName + | Expr.Op (TOp.Coerce, _, [innerExpr], _) -> + tryGetBindingName innerExpr + | _ -> None + let bindingName = tryGetBindingName objExpr + Some { ObjExprRange = objExpr.Range; MemberName = methodName; BindingName = bindingName } + | _ -> None + else None + // Uses of curried members are ALWAYS treated as if they are first class uses of members. // Curried members may not be overloaded (checked at use-site for curried members brought into scope through extension members) let curriedCallerArgs, exprTy, delayed = @@ -10457,7 +10480,7 @@ and TcMethodApplication // Extract what we know about the caller arguments, either type-directed if // no arguments are given or else based on the syntax of the arguments. let uniquelyResolved, preArgumentTypeCheckingCalledMethGroup = - TcMethodApplication_UniqueOverloadInference cenv env exprTy tyArgsOpt ad objTyOpt isCheckingAttributeCall callerObjArgTys methodName curriedCallerArgsOpt candidateMethsAndProps candidates mMethExpr mItem staticTyOpt + TcMethodApplication_UniqueOverloadInference cenv env exprTy tyArgsOpt ad objTyOpt isCheckingAttributeCall callerObjArgTys objArgInfo methodName curriedCallerArgsOpt candidateMethsAndProps candidates mMethExpr mItem staticTyOpt // STEP 2. Check arguments let unnamedCurriedCallerArgs, namedCurriedCallerArgs, lambdaVars, returnTy, tpenv = @@ -10496,7 +10519,7 @@ and TcMethodApplication CanonicalizePartialInferenceProblem cenv.css denv mItem (unnamedCurriedCallerArgs |> List.collectSquared (fun callerArg -> freeInTypeLeftToRight g false callerArg.CallerArgumentType)) - let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr methodName callerArgs ad postArgumentTypeCheckingCalledMethGroup true returnTy + let result, errors = ResolveOverloadingForCall denv cenv.css mMethExpr objArgInfo methodName callerArgs ad postArgumentTypeCheckingCalledMethGroup true returnTy // #14284 - mItem already carries the narrow terminal-identifier range, so rewrap to it let errors = diff --git a/src/Compiler/Checking/InfoReader.fs b/src/Compiler/Checking/InfoReader.fs index 121b087f5e5..2a4e75135f1 100644 --- a/src/Compiler/Checking/InfoReader.fs +++ b/src/Compiler/Checking/InfoReader.fs @@ -1163,13 +1163,13 @@ let PropTypeOfEventInfo (infoReader: InfoReader) m ad (einfo: EventInfo) = mkIEventType g delTy argsTy /// Try to find the name of the metadata file for this external definition -let TryFindMetadataInfoOfExternalEntityRef (infoReader: InfoReader) m eref = +let TryFindMetadataInfoOfExternalEntityRef (infoReader: InfoReader) eref = let g = infoReader.g match eref with | ERefLocal _ -> None | ERefNonLocal nlref -> // Generalize to get a formal signature - let formalTypars = eref.Typars m + let formalTypars = eref.Typars let formalTypeInst = generalizeTypars formalTypars let ty = TType_app(eref, formalTypeInst, KnownAmbivalentToNull) if isILAppTy g ty then @@ -1189,9 +1189,9 @@ let private libFileOfEntityRef x = | ERefLocal _ -> None | ERefNonLocal nlref -> nlref.Ccu.FileName -let GetXmlDocSigOfEntityRef infoReader m (eref: EntityRef) = +let GetXmlDocSigOfEntityRef infoReader (eref: EntityRef) = if eref.IsILTycon then - match TryFindMetadataInfoOfExternalEntityRef infoReader m eref with + match TryFindMetadataInfoOfExternalEntityRef infoReader eref with | None -> None | Some (ccuFileName, _, formalTypeInfo) -> Some(ccuFileName, "T:"+formalTypeInfo.ILTypeRef.FullName) else @@ -1240,7 +1240,7 @@ let rec GetXmlDocSigOfMethInfo (infoReader: InfoReader) m (minfo: MethInfo) = let fmtps = ilminfo.FormalMethodTypars let genericArity = if fmtps.Length=0 then "" else sprintf "``%d" fmtps.Length - match TryFindMetadataInfoOfExternalEntityRef infoReader m ilminfo.DeclaringTyconRef with + match TryFindMetadataInfoOfExternalEntityRef infoReader ilminfo.DeclaringTyconRef with | None -> None | Some (ccuFileName, formalTypars, formalTypeInfo) -> let filminfo = ILMethInfo(g, IlType formalTypeInfo, ilminfo.RawMetadata, fmtps) @@ -1294,23 +1294,23 @@ let GetXmlDocSigOfProp infoReader m (pinfo: PropInfo) = | None -> None | Some vref -> GetXmlDocSigOfScopedValRef g pinfo.DeclaringTyconRef vref | ILProp(ILPropInfo(_, pdef)) -> - match TryFindMetadataInfoOfExternalEntityRef infoReader m pinfo.DeclaringTyconRef with + match TryFindMetadataInfoOfExternalEntityRef infoReader pinfo.DeclaringTyconRef with | Some (ccuFileName, formalTypars, formalTypeInfo) -> let filpinfo = ILPropInfo(formalTypeInfo, pdef) Some (ccuFileName, "P:"+formalTypeInfo.ILTypeRef.FullName+"."+pdef.Name+XmlDocArgsEnc g (formalTypars, []) (filpinfo.GetParamTypes(infoReader.amap, m))) | _ -> None -let GetXmlDocSigOfEvent infoReader m (einfo: EventInfo) = +let GetXmlDocSigOfEvent infoReader (einfo: EventInfo) = match einfo with | ILEvent _ -> - match TryFindMetadataInfoOfExternalEntityRef infoReader m einfo.DeclaringTyconRef with + match TryFindMetadataInfoOfExternalEntityRef infoReader einfo.DeclaringTyconRef with | Some (ccuFileName, _, formalTypeInfo) -> Some(ccuFileName, "E:"+formalTypeInfo.ILTypeRef.FullName+"."+einfo.EventName) | _ -> None | _ -> None -let GetXmlDocSigOfILFieldInfo infoReader m (finfo: ILFieldInfo) = - match TryFindMetadataInfoOfExternalEntityRef infoReader m finfo.DeclaringTyconRef with +let GetXmlDocSigOfILFieldInfo infoReader (finfo: ILFieldInfo) = + match TryFindMetadataInfoOfExternalEntityRef infoReader finfo.DeclaringTyconRef with | Some (ccuFileName, _, formalTypeInfo) -> Some(ccuFileName, "F:"+formalTypeInfo.ILTypeRef.FullName+"."+finfo.FieldName) | _ -> None diff --git a/src/Compiler/Checking/InfoReader.fsi b/src/Compiler/Checking/InfoReader.fsi index df3fbaf0d2d..bd0a1ebb56d 100644 --- a/src/Compiler/Checking/InfoReader.fsi +++ b/src/Compiler/Checking/InfoReader.fsi @@ -344,13 +344,13 @@ val PropTypeOfEventInfo: infoReader: InfoReader -> m: range -> ad: AccessorDomai /// Try to find the name of the metadata file for this external definition val TryFindMetadataInfoOfExternalEntityRef: - infoReader: InfoReader -> m: range -> eref: EntityRef -> (string option * Typars * ILTypeInfo) option + infoReader: InfoReader -> eref: EntityRef -> (string option * Typars * ILTypeInfo) option /// Try to find the xml doc associated with the assembly name and metadata key val TryFindXmlDocByAssemblyNameAndSig: infoReader: InfoReader -> assemblyName: string -> xmlDocSig: string -> XmlDoc option -val GetXmlDocSigOfEntityRef: infoReader: InfoReader -> m: range -> eref: EntityRef -> (string option * string) option +val GetXmlDocSigOfEntityRef: infoReader: InfoReader -> eref: EntityRef -> (string option * string) option val GetXmlDocSigOfScopedValRef: TcGlobals -> tcref: TyconRef -> vref: ValRef -> (string option * string) option @@ -364,7 +364,6 @@ val GetXmlDocSigOfValRef: TcGlobals -> vref: ValRef -> (string option * string) val GetXmlDocSigOfProp: infoReader: InfoReader -> m: range -> pinfo: PropInfo -> (string option * string) option -val GetXmlDocSigOfEvent: infoReader: InfoReader -> m: range -> einfo: EventInfo -> (string option * string) option +val GetXmlDocSigOfEvent: infoReader: InfoReader -> einfo: EventInfo -> (string option * string) option -val GetXmlDocSigOfILFieldInfo: - infoReader: InfoReader -> m: range -> finfo: ILFieldInfo -> (string option * string) option +val GetXmlDocSigOfILFieldInfo: infoReader: InfoReader -> finfo: ILFieldInfo -> (string option * string) option diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 07e0e95baed..b6a436dd83c 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1868,7 +1868,7 @@ module ProvidedMethodCalls = else if isGeneric then let genericArgs = st.PApplyArray((fun st -> st.GetGenericArguments()), "GetGenericArguments", m) - let typars = headTypeAsFSharpType.Typars(m) + let typars = headTypeAsFSharpType.Typars // Drop the generic arguments that don't correspond to type arguments, i.e. are units-of-measure let genericArgs = [| for genericArg, tp in Seq.zip genericArgs typars do diff --git a/src/Compiler/Checking/MethodOverrides.fs b/src/Compiler/Checking/MethodOverrides.fs index 6da48fc0b14..125bed2fdb8 100644 --- a/src/Compiler/Checking/MethodOverrides.fs +++ b/src/Compiler/Checking/MethodOverrides.fs @@ -883,7 +883,7 @@ module DispatchSlotChecking = let overridden = if isFakeEventProperty then let slotsigs = overrideBy.MemberInfo.Value.ImplementedSlotSigs - slotsigs |> List.map (ReparentSlotSigToUseMethodTypars g overrideBy.Range overrideBy) + slotsigs |> List.map (ReparentSlotSigToUseMethodTypars g overrideBy) else [ for (reqdTy, m), SlotImplSet(_dispatchSlots, dispatchSlotsKeyed, _, _) in allImpls do let overrideByInfo = GetTypeMemberOverrideInfo g reqdTy overrideBy @@ -907,7 +907,7 @@ module DispatchSlotChecking = // The slotsig from the overridden method is in terms of the type parameters on the parent type of the overriding method, // Modify map the slotsig so it is in terms of the type parameters for the overriding method - let slotsig = ReparentSlotSigToUseMethodTypars g m overrideBy slotsig + let slotsig = ReparentSlotSigToUseMethodTypars g overrideBy slotsig // Record the slotsig via mutation yield slotsig ] diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index b9b35bad26f..593ce6c4b64 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -529,17 +529,17 @@ type ResultCollectionSettings = let NextExtensionMethodPriority() = uint64 (newStamp()) /// Checks if the type is used for C# style extension members. -let IsTyconRefUsedForCSharpStyleExtensionMembers g m (tcref: TyconRef) = +let IsTyconRefUsedForCSharpStyleExtensionMembers g (tcref: TyconRef) = // Type must be non-generic and have 'Extension' attribute match metadataOfTycon tcref.Deref with | ILTypeMetadata(TILObjectReprData(_, _, tdef)) -> tdef.CanContainExtensionMethods | _ -> true - && isNil(tcref.Typars m) && TyconRefHasWellKnownAttribute g WellKnownILAttributes.ExtensionAttribute tcref + && isNil(tcref.Typars) && TyconRefHasWellKnownAttribute g WellKnownILAttributes.ExtensionAttribute tcref /// Checks if the type is used for C# style extension members. -let IsTypeUsedForCSharpStyleExtensionMembers g m ty = +let IsTypeUsedForCSharpStyleExtensionMembers g ty = match tryTcrefOfAppTy g ty with - | ValueSome tcref -> IsTyconRefUsedForCSharpStyleExtensionMembers g m tcref + | ValueSome tcref -> IsTyconRefUsedForCSharpStyleExtensionMembers g tcref | _ -> false /// A 'plain' method is an extension method not interpreted as an extension method. @@ -591,7 +591,7 @@ let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.Impor let g = amap.g let isApplicable = - IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass || + IsTyconRefUsedForCSharpStyleExtensionMembers g tcrefOfStaticClass || g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) && tcrefOfStaticClass.IsLocalRef && @@ -1156,7 +1156,7 @@ let GetNestedTyconRefsOfType (infoReader: InfoReader) (amap: Import.ImportMap) ( /// Handle the .NET/C# business where nested generic types implicitly accumulate the type parameters /// from their enclosing types. let MakeNestedType (ncenv: NameResolver) (tinst: TType list) m (tcrefNested: TyconRef) = - let tps = match tcrefNested.Typars m with [] -> [] | l -> l[tinst.Length..] + let tps = match tcrefNested.Typars with [] -> [] | l -> l[tinst.Length..] let tinstNested = ncenv.InstantiationGenerator m tps mkWoNullAppTy tcrefNested (tinst @ tinstNested) @@ -1167,7 +1167,7 @@ let GetNestedTypesOfType (ad, ncenv: NameResolver, optFilter, staticResInfo, che |> List.map (MakeNestedType ncenv tinst m) let ChooseMethInfosForNameEnv g m ty (minfos: MethInfo list) = - let isExtTy = IsTypeUsedForCSharpStyleExtensionMembers g m ty + let isExtTy = IsTypeUsedForCSharpStyleExtensionMembers g ty minfos |> List.filter (fun minfo -> @@ -1357,11 +1357,11 @@ and private AddStaticPartsOfTyconRefToNameEnv bulkAddMode ownDefinition g amap m eIndexedExtensionMembers = eIndexedExtensionMembers eUnindexedExtensionMembers = eUnindexedExtensionMembers } -and private CanAutoOpenTyconRef (g: TcGlobals) m (tcref: TyconRef) = +and private CanAutoOpenTyconRef (g: TcGlobals) (tcref: TyconRef) = g.langVersion.SupportsFeature LanguageFeature.OpenTypeDeclaration && not tcref.IsILTycon && EntityHasWellKnownAttribute g WellKnownEntityAttributes.AutoOpenAttribute tcref.Deref && - tcref.Typars(m) |> List.isEmpty + tcref.Typars |> List.isEmpty /// Add any implied contents of a type definition to the environment. and private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g: TcGlobals) amap ad m nenv (tcref: TyconRef) = @@ -1398,7 +1398,7 @@ and private AddPartsOfTyconRefToNameEnv bulkAddMode ownDefinition (g: TcGlobals) let nenv = AddStaticPartsOfTyconRefToNameEnv bulkAddMode ownDefinition g amap m nenv None tcref let nenv = - if CanAutoOpenTyconRef g m tcref then + if CanAutoOpenTyconRef g tcref then let ty = generalizedTyconRef g tcref AddStaticContentOfTypeToNameEnv g amap ad m nenv ty else @@ -1575,14 +1575,14 @@ let AddDeclaredTyparsToNameEnv check nenv typars = /// Convert a reference to a named type into a type that includes /// a fresh set of inference type variables for the type parameters. let FreshenTycon (ncenv: NameResolver) m (tcref: TyconRef) = - let tinst = ncenv.InstantiationGenerator m (tcref.Typars m) + let tinst = ncenv.InstantiationGenerator m (tcref.Typars) let improvedTy = ncenv.g.decompileType tcref tinst ncenv.g.knownWithoutNull improvedTy /// Convert a reference to a named type into a type that includes /// a set of enclosing type instantiations and a fresh set of inference type variables for the type parameters. let FreshenTyconWithEnclosingTypeInst (ncenv: NameResolver) m (tinstEnclosing: TypeInst) (tcref: TyconRef) = - let tps = ncenv.InstantiationGenerator m (tcref.Typars m) + let tps = ncenv.InstantiationGenerator m (tcref.Typars) let tinst = List.skip tinstEnclosing.Length tps let improvedTy = ncenv.g.decompileType tcref (tinstEnclosing @ tinst) ncenv.g.knownWithoutNull improvedTy @@ -1590,12 +1590,12 @@ let FreshenTyconWithEnclosingTypeInst (ncenv: NameResolver) m (tinstEnclosing: T /// Convert a reference to a union case into a UnionCaseInfo that includes /// a fresh set of inference type variables for the type parameters of the union type. let FreshenUnionCaseRef (ncenv: NameResolver) m (ucref: UnionCaseRef) = - let tinst = ncenv.InstantiationGenerator m (ucref.TyconRef.Typars m) + let tinst = ncenv.InstantiationGenerator m (ucref.TyconRef.Typars) UnionCaseInfo(tinst, ucref) /// Generate a new reference to a record field with a fresh type instantiation let FreshenRecdFieldRef (ncenv: NameResolver) m (rfref: RecdFieldRef) = - RecdFieldInfo(ncenv.InstantiationGenerator m (rfref.Tycon.Typars m), rfref) + RecdFieldInfo(ncenv.InstantiationGenerator m (rfref.Tycon.Typars), rfref) //------------------------------------------------------------------------- // Generate type variables and record them in within the scope of the @@ -1673,7 +1673,7 @@ let FreshenTypars g m tpsorig = tpTys let FreshenMethInfo m (minfo: MethInfo) = - let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType m) minfo.DeclaringTypeInst minfo.FormalMethodTypars + let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType()) minfo.DeclaringTypeInst minfo.FormalMethodTypars tpTys /// This must be called after fetching unqualified items that may need to be freshened @@ -2518,7 +2518,7 @@ let CheckForTypeLegitimacyAndMultipleGenericTypeAmbiguities // remove later duplicates (if we've opened the same module more than once) |> List.distinctBy (fun (_, tcref) -> tcref.Stamp) // List.sortBy is a STABLE sort (the order matters!) - |> List.sortBy (fun (resInfo, tcref) -> tcref.Typars(m).Length - resInfo.EnclosingTypeInst.Length) + |> List.sortBy (fun (resInfo, tcref) -> tcref.Typars.Length - resInfo.EnclosingTypeInst.Length) let tcrefs = match tcrefs with @@ -2528,14 +2528,14 @@ let CheckForTypeLegitimacyAndMultipleGenericTypeAmbiguities // no explicit type instantiation typeNameResInfo.StaticArgsInfo.HasNoStaticArgsInfo && // some type arguments required on all types (note sorted by typar count above) - ((tcref.Typars m).Length - resInfo.EnclosingTypeInst.Length) > 0 && + ((tcref.Typars).Length - resInfo.EnclosingTypeInst.Length) > 0 && // plausible types have different arities - (tcrefs |> Seq.distinctBy (fun (_, tcref) -> tcref.Typars(m).Length) |> Seq.length > 1) -> + (tcrefs |> Seq.distinctBy (fun (_, tcref) -> tcref.Typars.Length) |> Seq.length > 1) -> [ for resInfo, tcref in tcrefs do let resInfo = resInfo.AddWarning (fun _typarChecker -> errorR(Error(FSComp.SR.nrTypeInstantiationNeededToDisambiguateTypesWithSameName(tcref.DisplayName, tcref.DisplayNameWithStaticParametersAndUnderscoreTypars), m))) yield (resInfo, tcref) ] - | [(resInfo, tcref)] when typeNameResInfo.StaticArgsInfo.HasNoStaticArgsInfo && ((tcref.Typars m).Length - resInfo.EnclosingTypeInst.Length) > 0 && typeNameResInfo.ResolutionFlag = ResolveTypeNamesToTypeRefs -> + | [(resInfo, tcref)] when typeNameResInfo.StaticArgsInfo.HasNoStaticArgsInfo && ((tcref.Typars).Length - resInfo.EnclosingTypeInst.Length) > 0 && typeNameResInfo.ResolutionFlag = ResolveTypeNamesToTypeRefs -> let resInfo = resInfo.AddWarning (fun (ResultTyparChecker typarChecker) -> if not (typarChecker()) then @@ -3220,7 +3220,7 @@ let rec ResolveExprLongIdentPrim sink (ncenv: NameResolver) first fullyQualified |> ResolveUnqualifiedTyconRefs nenv |> List.filter (fun (resInfo, tcref) -> typeNameResInfo.StaticArgsInfo.HasNoStaticArgsInfo || - typeNameResInfo.StaticArgsInfo.NumStaticArgs = tcref.Typars(m).Length - resInfo.EnclosingTypeInst.Length) + typeNameResInfo.StaticArgsInfo.NumStaticArgs = tcref.Typars.Length - resInfo.EnclosingTypeInst.Length) let search = ChooseTyconRefInExpr (ncenv, m, ad, nenv, id, typeNameResInfo, tcrefs) match AtMostOneResult m search with @@ -3284,7 +3284,7 @@ let rec ResolveExprLongIdentPrim sink (ncenv: NameResolver) first fullyQualified match tyconSearch () with | Result((resInfo, tcref) :: _) -> - let _, _, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let _, _, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars) let item = Item.Types(id.idText, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) success (resInfo, item) | _ -> @@ -3599,8 +3599,8 @@ let ResolvePatternLongIdent sink (ncenv: NameResolver) warnOnUpper newDef m ad n // // X.ListEnumerator // does not resolve // -let ResolveNestedTypeThroughAbbreviation (ncenv: NameResolver) (tcref: TyconRef) m = - if tcref.IsTypeAbbrev && tcref.Typars(m).IsEmpty then +let ResolveNestedTypeThroughAbbreviation (ncenv: NameResolver) (tcref: TyconRef) = + if tcref.IsTypeAbbrev && tcref.Typars.IsEmpty then match tryAppTy ncenv.g tcref.TypeAbbrev.Value with | ValueSome (abbrevTcref, []) -> abbrevTcref | _ -> tcref @@ -3609,7 +3609,7 @@ let ResolveNestedTypeThroughAbbreviation (ncenv: NameResolver) (tcref: TyconRef) /// Resolve a long identifier representing a type name let rec ResolveTypeLongIdentInTyconRefPrim (ncenv: NameResolver) (typeNameResInfo: TypeNameResolutionInfo) ad resInfo genOk depth m (tcref: TyconRef) (id: Ident) (rest: Ident list) = - let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref m + let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref match rest with | [] -> #if !NO_TYPEPROVIDERS @@ -3661,7 +3661,7 @@ let ResolveTypeLongIdentInTyconRef sink (ncenv: NameResolver) nenv typeNameResIn ForceRaise (ResolveTypeLongIdentInTyconRefPrim ncenv typeNameResInfo ad ResolutionInfo.Empty PermitDirectReferenceToGeneratedType.No 0 m tcref id rest) ResolutionInfo.SendEntityPathToSink(sink, ncenv, nenv, ItemOccurrence.Use, ad, resInfo, ResultTyparChecker(fun () -> true)) - let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars) let item = Item.Types(tcref.DisplayName, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) CallNameResolutionSink sink (rangeOfLid lid, nenv, item, tinst, ItemOccurrence.UseInType, ad) @@ -3824,7 +3824,7 @@ let ResolveTypeLongIdentAux sink (ncenv: NameResolver) occurrence fullyQualified | Result (resInfo, tcref) -> ResolutionInfo.SendEntityPathToSink(sink, ncenv, nenv, ItemOccurrence.UseInType, ad, resInfo, ResultTyparChecker(fun () -> true)) - let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars) let item = Item.Types(tcref.DisplayName, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) CallNameResolutionSink sink (m, nenv, item, tinst, occurrence, ad) @@ -4963,7 +4963,7 @@ let TryToResolveLongIdentAsType (ncenv: NameResolver) (nenv: NameResolutionEnv) LookupTypeNameInEnvNoArity OpenQualified id nenv |> List.tryHead |> Option.map (fun tcref -> - let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref m + let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref FreshenTycon ncenv m tcref) | _ -> None @@ -5058,7 +5058,7 @@ let rec ResolvePartialLongIdentPrim (ncenv: NameResolver) (nenv: NameResolutionE [ if not isItemVal then // type.lookup: lookup a static something in a type for tcref in LookupTypeNameInEnvNoArity OpenQualified id nenv do - let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref m + let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref let ty = FreshenTycon ncenv m tcref yield! ResolvePartialLongIdentInType ncenv nenv isApplicableMeth m ad true rest ty allowObsolete @@ -5133,7 +5133,7 @@ let getRecordFieldsInScope nenv = nenv.eFieldLabels |> Seq.collect (fun (KeyValue(_, v)) -> v) |> Seq.map (fun fref -> - let typeInsts = fref.TyconRef.TyparsNoRange |> List.map mkTyparTy + let typeInsts = fref.TyconRef.Typars |> List.map mkTyparTy Item.RecdField(RecdFieldInfo(typeInsts, fref))) |> List.ofSeq @@ -5596,7 +5596,7 @@ let rec GetCompletionForItem (ncenv: NameResolver) (nenv: NameResolutionEnv) m a | _ -> // type.lookup: lookup a static something in a type for tcref in LookupTypeNameInEnvNoArity OpenQualified id nenv do - let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref m + let tcref = ResolveNestedTypeThroughAbbreviation ncenv tcref let ty = FreshenTycon ncenv m tcref yield! ResolvePartialLongIdentInTypeForItem ncenv nenv m ad true rest item ty } diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index de8daffa7c5..d1097a7c416 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -301,14 +301,14 @@ module internal PrintUtilities = let layoutXmlDocOfEventInfo (denv: DisplayEnv) (infoReader: InfoReader) (einfo: EventInfo) restL = if denv.showDocumentation then - GetXmlDocSigOfEvent infoReader Range.range0 einfo + GetXmlDocSigOfEvent infoReader einfo |> layoutXmlDocFromSig denv infoReader true einfo.XmlDoc restL else restL let layoutXmlDocOfILFieldInfo (denv: DisplayEnv) (infoReader: InfoReader) (finfo: ILFieldInfo) restL = if denv.showDocumentation then - GetXmlDocSigOfILFieldInfo infoReader Range.range0 finfo + GetXmlDocSigOfILFieldInfo infoReader finfo |> layoutXmlDocFromSig denv infoReader true XmlDoc.Empty restL else restL @@ -329,7 +329,7 @@ module internal PrintUtilities = let layoutXmlDocOfEntity (denv: DisplayEnv) (infoReader: InfoReader) (eref: EntityRef) restL = if denv.showDocumentation then - GetXmlDocSigOfEntityRef infoReader Range.range0 eref + GetXmlDocSigOfEntityRef infoReader eref |> layoutXmlDocFromSig denv infoReader true eref.XmlDoc restL else restL @@ -1356,7 +1356,7 @@ module PrintTastMemberOrVals = let memberHasSameTyparNameAsParentTypeTypars = let parentTyparNames = - vref.DeclaringEntity.TyparsNoRange + vref.DeclaringEntity.Typars |> Seq.choose (fun tp -> if tp.typar_id.idText = unassignedTyparName then None else Some tp.typar_id.idText) |> set niceMethodTypars @@ -2081,7 +2081,7 @@ module TastDefinitionPrinting = let nameL = ConvertLogicalNameToDisplayLayout (tagger >> mkNav tycon.DefinitionRange >> wordL) tycon.DisplayNameCore let lhsL = - let tps = tycon.TyparsNoRange + let tps = tycon.Typars let tpsL = layoutTyparDecls denv nameL tycon.IsPrefixDisplay tps let tpsL = layoutAccessibility denv tycon.Accessibility tpsL typewordL ^^ tpsL diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 7924394c743..db53d382125 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -707,7 +707,7 @@ let CheckTypeAux permitByRefLike (cenv: cenv) env m ty onInnerByrefError = // with unconstrained generics (like List or Dictionary) is fine. // See: https://github.com/dotnet/fsharp/issues/19184 if tcref.CanDeref then - let typars = tcref.Typars m + let typars = tcref.Typars if typars.Length = tinst.Length then (typars, tinst) ||> List.iter2 (CheckInterfaceTypeArgForUnimplementedStaticAbstractMembers cenv m) @@ -2359,7 +2359,7 @@ let CheckEntityDefn cenv env (tycon: Entity) = let ty = generalizedTyconRef g tcref let env = { env with reflect = env.reflect || EntityHasWellKnownAttribute g WellKnownEntityAttributes.ReflectedDefinitionAttribute tycon } - let env = BindTypars g env (tycon.Typars m) + let env = BindTypars g env (tycon.Typars) CheckAttribs cenv env tycon.Attribs diff --git a/src/Compiler/Checking/QuotationTranslator.fs b/src/Compiler/Checking/QuotationTranslator.fs index f861a8ee267..82a1fe07145 100644 --- a/src/Compiler/Checking/QuotationTranslator.fs +++ b/src/Compiler/Checking/QuotationTranslator.fs @@ -616,7 +616,7 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : Exp if useGenuineField tcref.Deref fspec then mkFieldSet(parentTyconR, fldOrPropName, tyargsR, argsR) else - let envinner = BindFormalTypars env tcref.TyparsNoRange + let envinner = BindFormalTypars env tcref.Typars let propRetTypeR = ConvType cenv envinner m fspec.FormalType mkPropSet( (parentTyconR, fldOrPropName, propRetTypeR, []), tyargsR, argsR) @@ -793,7 +793,7 @@ and private ConvClassOrRecdFieldGetCore cenv env m rfref tyargs args = if useGenuineField tcref.Deref fspec then mkFieldGet(parentTyconR, fldOrPropName, tyargsR, argsR) else - let envinner = BindFormalTypars env tcref.TyparsNoRange + let envinner = BindFormalTypars env tcref.Typars let propRetTypeR = ConvType cenv envinner m fspec.FormalType mkPropGet( (parentTyconR, fldOrPropName, propRetTypeR, []), tyargsR, argsR) @@ -1284,7 +1284,7 @@ let ConvMethodBase cenv env (methName, v: Val) = let vref = mkLocalValRef v let tps, witnessInfos, argInfos, retTy, _ = GetTypeOfMemberInMemberForm cenv.g vref - let numEnclTypeArgs = vref.MemberApparentEntity.TyparsNoRange.Length + let numEnclTypeArgs = vref.MemberApparentEntity.Typars.Length let argTys = argInfos |> List.concat |> List.map fst let isNewObj = (vspr.MemberFlags.MemberKind = SynMemberKind.Constructor) diff --git a/src/Compiler/Checking/SignatureConformance.fs b/src/Compiler/Checking/SignatureConformance.fs index 0f3d5ec13fe..47d5cada40b 100644 --- a/src/Compiler/Checking/SignatureConformance.fs +++ b/src/Compiler/Checking/SignatureConformance.fs @@ -198,8 +198,8 @@ type Checker(g, amap, denv, remapInfo: SignatureRepackageInfo, checkingSig) = checkExnInfo (fun f -> FSharpExceptionNotContained(denv, infoReader, implTycon, sigTycon, f)) aenv infoReader implTycon sigTycon implTycon.ExceptionInfo sigTycon.ExceptionInfo && - let implTypars = implTycon.Typars m - let sigTypars = sigTycon.Typars m + let implTypars = implTycon.Typars + let sigTypars = sigTycon.Typars if implTypars.Length <> sigTypars.Length then errorR (Error(FSComp.SR.DefinitionsInSigAndImplNotCompatibleParameterCountsDiffer(implTycon.TypeOrMeasureKind.ToString(), implTycon.DisplayName), m)) diff --git a/src/Compiler/Checking/SignatureHash.fs b/src/Compiler/Checking/SignatureHash.fs index f81ada24082..5d639b2ddd7 100644 --- a/src/Compiler/Checking/SignatureHash.fs +++ b/src/Compiler/Checking/SignatureHash.fs @@ -78,7 +78,7 @@ module TyconDefinitionHash = let tyconHash = hashTyconRef tcref let attribHash = hashAttributeList tcref.Attribs - let typarsHash = hashTyparDecls g tycon.TyparsNoRange + let typarsHash = hashTyparDecls g tycon.Typars let topLevelDeclarationHash = tyconHash @@ attribHash @@ typarsHash // Interface implementation diff --git a/src/Compiler/Checking/import.fs b/src/Compiler/Checking/import.fs index 8979bab5e77..e13b88dd437 100644 --- a/src/Compiler/Checking/import.fs +++ b/src/Compiler/Checking/import.fs @@ -412,7 +412,7 @@ let rec ImportProvidedTypeAsILType (env: ImportMap) (m: range) (st: Tainted genericArgs.Length then error(Error(FSComp.SR.impInvalidNumberOfGenericArguments(tcref.CompiledName, tps.Length, genericArgs.Length), m)) // We're converting to an IL type, where generic arguments are erased @@ -489,7 +489,7 @@ let rec ImportProvidedType (env: ImportMap) (m: range) (* (tinst: TypeInst) *) ( else tcref - let tps = tcref.Typars m + let tps = tcref.Typars if tps.Length <> genericArgsLength then error(Error(FSComp.SR.impInvalidNumberOfGenericArguments(tcref.CompiledName, tps.Length, genericArgsLength), m)) @@ -701,9 +701,14 @@ let rec ImportILTypeDef amap m scoref (cpath: CompilationPath) enc nm (tdef: ILT Construct.NewILTycon (Some cpath) (nm, m) - // The read of the type parameters may fail to resolve types. We pick up a new range from the point where that read is forced + // The read of the type parameters may fail to resolve types. Entity.Typars forces + // entity_typars with entity_range, so the range used here is always the import-time + // range 'm' passed to NewILTycon above — never a caller's ad-hoc source range. // Make sure we reraise the original exception one occurs - see findOriginalException. - (LazyWithContext.Create((fun m -> ImportILGenericParameters amap m scoref [] nullableFallback tdef.GenericParams), findOriginalException)) + (LazyWithContext.Create( + (fun m -> ImportILGenericParameters amap m scoref [] nullableFallback tdef.GenericParams), + findOriginalException + )) (scoref, enc, tdef) (MaybeLazy.Lazy lazyModuleOrNamespaceTypeForNestedTypes) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 1a38e10f42b..d4da136b80a 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -81,10 +81,10 @@ let GetCompiledReturnTyOfProvidedMethodInfo amap m (mi: Tainted - let parentToMemberInst, _ = mkTyparToTyparRenaming (ovByMethValRef.MemberApparentEntity.Typars m) enclosingTypars + let parentToMemberInst, _ = mkTyparToTyparRenaming (ovByMethValRef.MemberApparentEntity.Typars) enclosingTypars let res = instSlotSig parentToMemberInst slotsig res | None -> @@ -1331,7 +1331,7 @@ type MethInfo = // A slot signature is w.r.t. the type variables of the type it is associated with. // So we have to rename from the member type variables to the type variables of the type. - let formalEnclosingTypars = x.ApparentEnclosingTyconRef.Typars m + let formalEnclosingTypars = x.ApparentEnclosingTyconRef.Typars let formalEnclosingTyparsFromMethod, formalMethTypars = List.splitAt formalEnclosingTypars.Length allTyparsFromMethod let methodToParentRenaming, _ = mkTyparToTyparRenaming formalEnclosingTyparsFromMethod formalEnclosingTypars let formalParams = @@ -1350,7 +1350,7 @@ type MethInfo = // then that does not correspond to a slotsig compiled as a 'void' return type. // REVIEW: should we copy down attributes to slot params? let tcref = tcrefOfAppTy g x.ApparentEnclosingAppType - let formalEnclosingTyparsOrig = tcref.Typars m + let formalEnclosingTyparsOrig = tcref.Typars let formalEnclosingTypars = copyTypars false formalEnclosingTyparsOrig let _, formalEnclosingTyparTys = FixupNewTypars m [] [] formalEnclosingTyparsOrig formalEnclosingTypars let formalMethTypars = copyTypars false x.FormalMethodTypars @@ -1451,7 +1451,7 @@ type MethInfo = /// For extension methods, no type parameters are returned, because all the /// type parameters are part of the apparent type, rather the /// declaring type, even for extension methods extending generic types. - member x.GetFormalTyparsOfDeclaringType m = + member x.GetFormalTyparsOfDeclaringType() = if x.IsExtensionMember then [] else match x with @@ -1460,7 +1460,7 @@ type MethInfo = let memberParentTypars, _, _, _ = AnalyzeTypeOfMemberVal false g (ty, vref) memberParentTypars | _ -> - x.DeclaringTyconRef.Typars m + x.DeclaringTyconRef.Typars /// Tries to get the object arg type if it's a byref type. member x.TryObjArgByrefType(amap, m, minst) = @@ -1689,7 +1689,7 @@ type UnionCaseInfo = member x.DisplayName = x.UnionCase.DisplayName /// Get the instantiation of the type parameters of the declaring type of the union case - member x.GetTyparInst m = mkTyparInst (x.TyconRef.Typars m) x.TypeInst + member x.GetTyparInst() = mkTyparInst (x.TyconRef.Typars) x.TypeInst override x.ToString() = x.TyconRef.ToString() + "::" + x.DisplayNameCore @@ -2509,7 +2509,7 @@ let CompiledSigOfMeth g amap m (minfo: MethInfo) = // of the enclosing type. This instantiations can be used to interpret those type parameters let fmtpinst = let parentTyArgs = argsOfAppTy g minfo.ApparentEnclosingAppType - let memberParentTypars = minfo.GetFormalTyparsOfDeclaringType m + let memberParentTypars = minfo.GetFormalTyparsOfDeclaringType() mkTyparInst memberParentTypars parentTyArgs CompiledSig(vargTys, vrty, formalMethTypars, fmtpinst) diff --git a/src/Compiler/Checking/infos.fsi b/src/Compiler/Checking/infos.fsi index e091834e271..0b30ea6f50c 100644 --- a/src/Compiler/Checking/infos.fsi +++ b/src/Compiler/Checking/infos.fsi @@ -43,7 +43,7 @@ val GetCompiledReturnTyOfProvidedMethodInfo: /// The slotsig returned by methInfo.GetSlotSig is in terms of the type parameters on the parent type of the overriding method. /// Reverse-map the slotsig so it is in terms of the type parameters for the overriding method -val ReparentSlotSigToUseMethodTypars: g: TcGlobals -> m: range -> ovByMethValRef: ValRef -> slotsig: SlotSig -> SlotSig +val ReparentSlotSigToUseMethodTypars: g: TcGlobals -> ovByMethValRef: ValRef -> slotsig: SlotSig -> SlotSig /// Construct the data representing a parameter in the signature of an abstract method slot val MakeSlotParam: ty: TType * argInfo: ArgReprInfo -> SlotParam @@ -514,7 +514,7 @@ type MethInfo = /// For extension methods, no type parameters are returned, because all the /// type parameters are part of the apparent type, rather the /// declaring type, even for extension methods extending generic types. - member GetFormalTyparsOfDeclaringType: m: range -> Typar list + member GetFormalTyparsOfDeclaringType: unit -> Typar list /// Get the (zero or one) 'self'/'this'/'object' arguments associated with a method. /// An instance method returns one object argument. @@ -705,7 +705,7 @@ type UnionCaseInfo = member UnionCaseRef: UnionCaseRef /// Get the instantiation of the type parameters of the declaring type of the union case - member GetTyparInst: m: range -> TyparInstantiation + member GetTyparInst: unit -> TyparInstantiation /// Describes an F# use of a property backed by Abstract IL metadata [] diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 49207b9f480..ee275dadcdf 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -558,7 +558,7 @@ type TypeReprEnv member eenv.ForTypars tps = eenv.ResetTypars().Add tps /// Get the environment for within a type definition - member eenv.ForTycon(tycon: Tycon) = eenv.ForTypars tycon.TyparsNoRange + member eenv.ForTycon(tycon: Tycon) = eenv.ForTypars tycon.Typars /// Get the environment for generating a reference to items within a type definition member eenv.ForTyconRef(tcref: TyconRef) = eenv.ForTycon tcref.Deref @@ -1460,7 +1460,7 @@ let GetMethodSpecForMemberVal cenv (memberInfo: ValMemberInfo) (vref: ValRef) = let isCtor = (memberInfo.MemberFlags.MemberKind = SynMemberKind.Constructor) let cctor = (memberInfo.MemberFlags.MemberKind = SynMemberKind.ClassConstructor) let parentTcref = vref.DeclaringEntity - let parentTypars = parentTcref.TyparsNoRange + let parentTypars = parentTcref.Typars let numParentTypars = parentTypars.Length if tps.Length < numParentTypars then @@ -4495,7 +4495,7 @@ and GenApp (cenv: cenv) cgbuf eenv (f, fty, tyargs, curriedArgs, m) sequel = // @REVIEW: refactor this let numEnclILTypeArgs = match vref.MemberInfo with - | Some _ when not vref.IsExtensionMember -> List.length (vref.MemberApparentEntity.TyparsNoRange |> DropErasedTypars) + | Some _ when not vref.IsExtensionMember -> List.length (vref.MemberApparentEntity.Typars |> DropErasedTypars) | _ -> 0 let ilEnclArgTys, ilMethArgTys = @@ -8676,11 +8676,7 @@ and GenBindingAfterDebugPoint cenv cgbuf eenv bind isStateVar startMarkOpt = CommitStartScope cgbuf startMarkOpt // The initialization code for static 'let' and 'do' bindings gets compiled into the initialization .cctor for the whole file - | _ when - vspec.IsClassConstructor - && isNil vspec.DeclaringEntity.TyparsNoRange - && not isStateVar - -> + | _ when vspec.IsClassConstructor && isNil vspec.DeclaringEntity.Typars && not isStateVar -> let tps, _, _, _, cctorBody, _ = IteratedAdjustLambdaToMatchValReprInfo g cenv.amap vspec.ValReprInfo.Value rhsExpr @@ -11214,7 +11210,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option let ilThisTy = GenType cenv m eenvinner.tyenv thisTy let tref = ilThisTy.TypeRef - let ilGenParams = GenGenericParams cenv eenvinner tycon.TyparsNoRange + let ilGenParams = GenGenericParams cenv eenvinner tycon.Typars let checkNullness = g.langFeatureNullness && g.checkNullness let ilIntfTys = @@ -11423,7 +11419,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option isEmptyStruct && cenv.options.workAroundReflectionEmitBugs - && not tycon.TyparsNoRange.IsEmpty + && not tycon.Typars.IsEmpty // Compute a bunch of useful things for each field let isCLIMutable = @@ -11821,7 +11817,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option // If this property doesn't hold then the .cctor can end up running // before the main method even starts. let typeDefTrigger = - if eenv.isFinalFile || tycon.TyparsNoRange.IsEmpty then + if eenv.isFinalFile || tycon.Typars.IsEmpty then ILTypeInit.OnAny else ILTypeInit.BeforeField @@ -11920,7 +11916,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option || // Reflection emit doesn't let us emit 'pack' and 'size' for generic structs. // In that case we generate a dummy field instead - (cenv.options.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty) + (cenv.options.workAroundReflectionEmitBugs && not tycon.Typars.IsEmpty) then ILTypeDefLayout.Sequential { Size = None; Pack = None }, ILDefaultPInvokeEncoding.Ansi else @@ -12169,7 +12165,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option // // In this case, the .cctor for this type must force the .cctor of the backing static class for the file. if - tycon.TyparsNoRange.IsEmpty + tycon.Typars.IsEmpty && not eenv.realsig && tycon.MembersOfFSharpTyconSorted |> List.exists (fun vref -> vref.Deref.IsClassConstructor) diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 4ecbfc081ef..5d3871558e9 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -170,6 +170,7 @@ type Exception with | ConstraintSolverNullnessWarningEquivWithTypes(_, _, _, _, _, m, _) | ConstraintSolverNullnessWarningWithTypes(_, _, _, _, _, m, _) | ConstraintSolverNullnessWarningWithType(_, _, _, m, _) + | ConstraintSolverNullnessWarningOnDotAccess(_, _, _, _, m, _) | ConstraintSolverNullnessWarning(_, m, _) | ConstraintSolverTypesNotInEqualityRelation(_, _, _, m, _, _) | ConstraintSolverError(_, m, _) @@ -348,6 +349,7 @@ type Exception with | ConstraintSolverNullnessWarningEquivWithTypes _ -> 3261 | ConstraintSolverNullnessWarningWithTypes _ -> 3261 | ConstraintSolverNullnessWarningWithType _ -> 3261 + | ConstraintSolverNullnessWarningOnDotAccess _ -> 3261 | ConstraintSolverNullnessWarning _ -> 3261 | InvalidAttributeTargetForLanguageElement _ -> 842 | _ -> 193 @@ -446,6 +448,11 @@ module OldStyleMessages = let ConstraintSolverNullnessWarningEquivWithTypesE () = Message("ConstraintSolverNullnessWarningEquivWithTypes", "%s") let ConstraintSolverNullnessWarningWithTypesE () = Message("ConstraintSolverNullnessWarningWithTypes", "%s%s") let ConstraintSolverNullnessWarningWithTypeE () = Message("ConstraintSolverNullnessWarningWithType", "%s") + let ConstraintSolverNullnessWarningOnDotAccessE () = Message("ConstraintSolverNullnessWarningOnDotAccess", "%s%s") + + let ConstraintSolverNullnessWarningOnDotAccessWithBindingE () = + Message("ConstraintSolverNullnessWarningOnDotAccessWithBinding", "%s%s%s") + let ConstraintSolverNullnessWarningE () = Message("ConstraintSolverNullnessWarning", "%s") let ConstraintSolverTypesNotInEqualityRelation1E () = Message("ConstraintSolverTypesNotInEqualityRelation1", "%s%s") let ConstraintSolverTypesNotInEqualityRelation2E () = Message("ConstraintSolverTypesNotInEqualityRelation2", "%s%s") @@ -731,6 +738,20 @@ type Exception with if m.StartLine <> m2.StartLine then os.Append(SeeAlsoE().Format(stringOfRange m)) |> ignore + | ConstraintSolverNullnessWarningOnDotAccess(denv, objTy, memberName, bindingName, m, m2) -> + let tyStr = NicePrint.minimalStringOfTypeWithNullness denv objTy + + match bindingName with + | Some name -> + os.Append(ConstraintSolverNullnessWarningOnDotAccessWithBindingE().Format memberName name tyStr) + |> ignore + | None -> + os.Append(ConstraintSolverNullnessWarningOnDotAccessE().Format memberName tyStr) + |> ignore + + if m.StartLine <> m2.StartLine || m.EndLine <> m2.EndLine then + os.Append(SeeAlsoE().Format(stringOfRange m2)) |> ignore + | ConstraintSolverNullnessWarning(msg, m, m2) -> os.Append(ConstraintSolverNullnessWarningE().Format(msg)) |> ignore @@ -792,6 +813,7 @@ type Exception with (match contextInfo with | ContextInfo.NoContext -> false | ContextInfo.NullnessCheckOfCapturedArg _ -> false + | ContextInfo.MemberAccessOnNullable _ -> false | _ -> true) -> e.Output(os, suggestNames) @@ -1033,7 +1055,7 @@ type Exception with os.AppendString(FSComp.SR.notAFunctionWithType (NicePrint.prettyStringOfTy denv ty)) | TyconBadArgs(_, tcref, d, _) -> - let exp = tcref.TyparsNoRange.Length + let exp = tcref.Typars.Length if exp = 0 then os.AppendString(FSComp.SR.buildUnexpectedTypeArgs (fullDisplayTextOfTyconRef tcref, d)) diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index 920cc48a52a..18482e71c9e 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -135,6 +135,12 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: The type '{0}' does not support 'null'. diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 6e9c1ced079..ce829a08f3d 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -2231,11 +2231,11 @@ type internal TypeCheckInfo |> List.sortBy (fun d -> let n = match d.Item with - | Item.Types(_, AbbrevOrAppTy(tcref, _) :: _) -> 1 + tcref.TyparsNoRange.Length + | Item.Types(_, AbbrevOrAppTy(tcref, _) :: _) -> 1 + tcref.Typars.Length // Put delegate ctors after types, sorted by #typars. RemoveDuplicateItems will remove FakeInterfaceCtor and DelegateCtor if an earlier type is also reported with this name - | Item.DelegateCtor(AbbrevOrAppTy(tcref, _)) -> 1000 + tcref.TyparsNoRange.Length + | Item.DelegateCtor(AbbrevOrAppTy(tcref, _)) -> 1000 + tcref.Typars.Length // Put type ctors after types, sorted by #typars. RemoveDuplicateItems will remove DefaultStructCtors if a type is also reported with this name - | Item.CtorGroup(_, cinfo :: _) -> 1000 + 10 * cinfo.DeclaringTyconRef.TyparsNoRange.Length + | Item.CtorGroup(_, cinfo :: _) -> 1000 + 10 * cinfo.DeclaringTyconRef.Typars.Length | _ -> 0 (d.Item.DisplayName, n)) diff --git a/src/Compiler/Service/ServiceDeclarationLists.fs b/src/Compiler/Service/ServiceDeclarationLists.fs index 98312a69306..f80d957c414 100644 --- a/src/Compiler/Service/ServiceDeclarationLists.fs +++ b/src/Compiler/Service/ServiceDeclarationLists.fs @@ -1092,12 +1092,12 @@ type DeclarationListInfo(declarations: DeclarationListItem[], isForType: bool, i items |> List.map (fun x -> match x.Item with - | Item.Types (_, TType_app(tcref, _, _) :: _) when isInterfaceTyconRef tcref -> { x with MinorPriority = 1000 + tcref.TyparsNoRange.Length } - | Item.Types (_, TType_app(tcref, _, _) :: _) -> { x with MinorPriority = 1 + tcref.TyparsNoRange.Length } + | Item.Types (_, TType_app(tcref, _, _) :: _) when isInterfaceTyconRef tcref -> { x with MinorPriority = 1000 + tcref.Typars.Length } + | Item.Types (_, TType_app(tcref, _, _) :: _) -> { x with MinorPriority = 1 + tcref.Typars.Length } // Put delegate ctors after types, sorted by #typars. RemoveDuplicateItems will remove FakeInterfaceCtor and DelegateCtor if an earlier type is also reported with this name - | Item.DelegateCtor (TType_app(tcref, _, _)) -> { x with MinorPriority = 1000 + tcref.TyparsNoRange.Length } + | Item.DelegateCtor (TType_app(tcref, _, _)) -> { x with MinorPriority = 1000 + tcref.Typars.Length } // Put type ctors after types, sorted by #typars. RemoveDuplicateItems will remove DefaultStructCtors if a type is also reported with this name - | Item.CtorGroup (_, cinfo :: _) -> { x with MinorPriority = 1000 + 10 * cinfo.DeclaringTyconRef.TyparsNoRange.Length } + | Item.CtorGroup (_, cinfo :: _) -> { x with MinorPriority = 1000 + 10 * cinfo.DeclaringTyconRef.Typars.Length } | Item.MethodGroup(_, minfo :: _, _) -> { x with IsOwnMember = tyconRefOptEq x.Type minfo.DeclaringTyconRef } | Item.Property(info = pinfo :: _) -> { x with IsOwnMember = tyconRefOptEq x.Type pinfo.DeclaringTyconRef } | Item.ILField finfo -> { x with IsOwnMember = tyconRefOptEq x.Type finfo.DeclaringTyconRef } diff --git a/src/Compiler/Symbols/Exprs.fs b/src/Compiler/Symbols/Exprs.fs index 4281393e5e8..48bca7384f9 100644 --- a/src/Compiler/Symbols/Exprs.fs +++ b/src/Compiler/Symbols/Exprs.fs @@ -1181,7 +1181,7 @@ module FSharpExprConvert = let isCtor = (ilMethRef.Name = ".ctor") let isStatic = isCtor || ilMethRef.CallingConv.IsStatic let scoref = ilMethRef.DeclaringTypeRef.Scope - let typars1 = tcref.Typars m + let typars1 = tcref.Typars let typars2 = [ 1 .. ilMethRef.GenericArity ] |> List.map (fun _ -> Construct.NewRigidTypar "T" m) let tinst1 = typars1 |> generalizeTypars let tinst2 = typars2 |> generalizeTypars diff --git a/src/Compiler/Symbols/FSharpDiagnostic.fs b/src/Compiler/Symbols/FSharpDiagnostic.fs index 0d48e550f70..06097f35ad0 100644 --- a/src/Compiler/Symbols/FSharpDiagnostic.fs +++ b/src/Compiler/Symbols/FSharpDiagnostic.fs @@ -63,6 +63,7 @@ module ExtendedData = | ContextInfo.PatternMatchGuard _ -> PatternMatchGuard | ContextInfo.SequenceExpression _ -> SequenceExpression | ContextInfo.NullnessCheckOfCapturedArg _ -> NoContext + | ContextInfo.MemberAccessOnNullable _ -> NoContext type IFSharpDiagnosticExtendedData = interface end diff --git a/src/Compiler/Symbols/SymbolHelpers.fs b/src/Compiler/Symbols/SymbolHelpers.fs index 742e7640293..8466acf1aae 100644 --- a/src/Compiler/Symbols/SymbolHelpers.fs +++ b/src/Compiler/Symbols/SymbolHelpers.fs @@ -271,7 +271,7 @@ module internal SymbolHelpers = | Item.UnqualifiedType (tcref :: _) | Item.ExnCase tcref -> - mkXmlComment (GetXmlDocSigOfEntityRef infoReader m tcref) + mkXmlComment (GetXmlDocSigOfEntityRef infoReader tcref) | Item.RecdField rfinfo -> mkXmlComment (GetXmlDocSigOfRecdFieldRef rfinfo.RecdFieldRef) @@ -279,13 +279,13 @@ module internal SymbolHelpers = | Item.NewDef _ -> FSharpXmlDoc.None | Item.ILField finfo -> - mkXmlComment (GetXmlDocSigOfILFieldInfo infoReader m finfo) + mkXmlComment (GetXmlDocSigOfILFieldInfo infoReader finfo) | Item.DelegateCtor ty | Item.Types(_, ty :: _) -> match ty with | AbbrevOrAppTy(tcref, _) -> - mkXmlComment (GetXmlDocSigOfEntityRef infoReader m tcref) + mkXmlComment (GetXmlDocSigOfEntityRef infoReader tcref) | _ -> FSharpXmlDoc.None | Item.CustomOperation (_, _, Some minfo) -> @@ -296,13 +296,13 @@ module internal SymbolHelpers = | Item.TypeVar _ -> FSharpXmlDoc.None | Item.ModuleOrNamespaces(modref :: _) -> - mkXmlComment (GetXmlDocSigOfEntityRef infoReader m modref) + mkXmlComment (GetXmlDocSigOfEntityRef infoReader modref) | Item.Property(info = pinfo :: _) -> mkXmlComment (GetXmlDocSigOfProp infoReader m pinfo) | Item.Event einfo -> - mkXmlComment (GetXmlDocSigOfEvent infoReader m einfo) + mkXmlComment (GetXmlDocSigOfEvent infoReader einfo) | Item.MethodGroup(_, minfo :: _, _) -> mkXmlComment (GetXmlDocSigOfMethInfo infoReader m minfo) @@ -313,7 +313,7 @@ module internal SymbolHelpers = | Item.OtherName(container = Some argContainer) -> match argContainer with | ArgumentContainer.Method minfo -> mkXmlComment (GetXmlDocSigOfMethInfo infoReader m minfo) - | ArgumentContainer.Type tcref -> mkXmlComment (GetXmlDocSigOfEntityRef infoReader m tcref) + | ArgumentContainer.Type tcref -> mkXmlComment (GetXmlDocSigOfEntityRef infoReader tcref) | Item.UnionCaseField (ucinfo, _) -> mkXmlComment (GetXmlDocSigOfUnionCaseRef ucinfo.UnionCaseRef) diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index 08252dd76d5..3f309c91a8e 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -198,7 +198,7 @@ module Impl = let getXmlDocSigForEntity (cenv: SymbolEnv) (ent:EntityRef)= - match GetXmlDocSigOfEntityRef cenv.infoReader ent.Range ent with + match GetXmlDocSigOfEntityRef cenv.infoReader ent with | Some (_, docsig) -> docsig | _ -> "" @@ -389,7 +389,7 @@ type FSharpEntity(cenv: SymbolEnv, entity: EntityRef, tyargs: TType list) = | Some ccu -> ccuEq ccu cenv.g.fslibCcu new(cenv: SymbolEnv, tcref: TyconRef) = - let _, _, tyargs = FreshenTypeInst cenv.g range0 (tcref.Typars range0) + let _, _, tyargs = FreshenTypeInst cenv.g range0 (tcref.Typars) FSharpEntity(cenv, tcref, tyargs) member _.Entity = entity @@ -484,7 +484,7 @@ type FSharpEntity(cenv: SymbolEnv, entity: EntityRef, tyargs: TType list) = member _.GenericParameters = checkIsResolved() - entity.TyparsNoRange |> List.map (fun tp -> FSharpGenericParameter(cenv, tp)) |> makeReadOnlyCollection + entity.Typars |> List.map (fun tp -> FSharpGenericParameter(cenv, tp)) |> makeReadOnlyCollection member _.GenericArguments = checkIsResolved() @@ -742,7 +742,7 @@ type FSharpEntity(cenv: SymbolEnv, entity: EntityRef, tyargs: TType list) = if entity.IsILEnumTycon then let (TILObjectReprData(_scoref, _enc, tdef)) = entity.ILTyconInfo - let formalTypars = entity.Typars range0 + let formalTypars = entity.Typars let formalTypeInst = generalizeTypars formalTypars let ty = TType_app(entity, formalTypeInst, cenv.g.knownWithoutNull) let formalTypeInfo = ILTypeInfo.FromType cenv.g ty @@ -971,7 +971,7 @@ type FSharpUnionCase(cenv, v: UnionCaseRef) = inherit FSharpSymbol (cenv, (fun () -> checkEntityIsResolved v.TyconRef - Item.UnionCase(UnionCaseInfo(generalizeTypars v.TyconRef.TyparsNoRange, v), false)), + Item.UnionCase(UnionCaseInfo(generalizeTypars v.TyconRef.Typars, v), false)), (fun _this thisCcu2 ad -> checkForCrossProjectAccessibility cenv.g.ilg (thisCcu2, ad) (cenv.thisCcu, v.UnionCase.Accessibility)) //&& AccessibilityLogic.IsUnionCaseAccessible cenv.amap range0 ad v) @@ -1019,7 +1019,7 @@ type FSharpUnionCase(cenv, v: UnionCaseRef) = member _.XmlDocSig = checkIsResolved() - let unionCase = UnionCaseInfo(generalizeTypars v.TyconRef.TyparsNoRange, v) + let unionCase = UnionCaseInfo(generalizeTypars v.TyconRef.Typars, v) match GetXmlDocSigOfUnionCaseRef unionCase.UnionCaseRef with | Some (_, docsig) -> docsig | _ -> "" @@ -1090,10 +1090,10 @@ type FSharpField(cenv: SymbolEnv, d: FSharpFieldData) = Item.AnonRecdField(anonInfo, tinst, n, m) | RecdOrClass v -> checkEntityIsResolved v.TyconRef - Item.RecdField(RecdFieldInfo(generalizeTypars v.TyconRef.TyparsNoRange, v)) + Item.RecdField(RecdFieldInfo(generalizeTypars v.TyconRef.Typars, v)) | Union (v, fieldIndex) -> checkEntityIsResolved v.TyconRef - Item.UnionCaseField (UnionCaseInfo (generalizeTypars v.TyconRef.TyparsNoRange, v), fieldIndex) + Item.UnionCaseField (UnionCaseInfo (generalizeTypars v.TyconRef.Typars, v), fieldIndex) | ILField f -> Item.ILField f), (fun this thisCcu2 ad -> @@ -1194,13 +1194,13 @@ type FSharpField(cenv: SymbolEnv, d: FSharpFieldData) = let xmlsig = match d with | RecdOrClass v -> - let recd = RecdFieldInfo(generalizeTypars v.TyconRef.TyparsNoRange, v) + let recd = RecdFieldInfo(generalizeTypars v.TyconRef.Typars, v) GetXmlDocSigOfRecdFieldRef recd.RecdFieldRef | Union (v, _) -> - let unionCase = UnionCaseInfo(generalizeTypars v.TyconRef.TyparsNoRange, v) + let unionCase = UnionCaseInfo(generalizeTypars v.TyconRef.Typars, v) GetXmlDocSigOfUnionCaseRef unionCase.UnionCaseRef | ILField f -> - GetXmlDocSigOfILFieldInfo cenv.infoReader range0 f + GetXmlDocSigOfILFieldInfo cenv.infoReader f | AnonField _ -> None match xmlsig with | Some (_, docsig) -> docsig @@ -2083,8 +2083,7 @@ type FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) = match d with | E e -> - let range = defaultArg sym.DeclarationLocationOpt range0 - match GetXmlDocSigOfEvent cenv.infoReader range e with + match GetXmlDocSigOfEvent cenv.infoReader e with | Some (_, docsig) -> docsig | _ -> "" | P p -> diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 733b269b588..6334697ef91 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -761,7 +761,7 @@ type Entity = #endif else ignore withStaticParameters - match x.TyparsNoRange with + match x.Typars with | [] -> nm | tps -> let nm = DemangleGenericTypeName nm @@ -893,12 +893,9 @@ type Entity = CompilationPath.DemangleEntityName x.LogicalName x.ModuleOrNamespaceType.ModuleOrNamespaceKind /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - /// - /// Lazy because it may read metadata, must provide a context "range" in case error occurs reading metadata. - member x.Typars m = x.entity_typars.Force m - - /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - member x.TyparsNoRange: Typars = x.Typars x.Range + /// + /// Lazy because it may read metadata. Uses the entity's own range for error context. + member x.Typars: Typars = x.entity_typars.Force x.Range /// Get the type abbreviated by this type definition, if it is an F# type abbreviation definition member x.TypeAbbrev = @@ -1331,7 +1328,7 @@ type Entity = | _ -> ilTypeRefForCompilationPath x.CompilationPath x.CompiledName // Pre-allocate a ILType for monomorphic types, to reduce memory usage from Abstract IL nodes let ilTypeOpt = - match x.TyparsNoRange with + match x.Typars with | [] -> Some (mkILTy boxity (mkILTySpec (ilTypeRef, []))) | _ -> None CompiledTypeRepr.ILAsmNamed (ilTypeRef, boxity, ilTypeOpt)) @@ -3792,12 +3789,9 @@ type EntityRef = member x.IsFSharpException = x.Deref.IsFSharpException /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - /// - /// Lazy because it may read metadata, must provide a context "range" in case error occurs reading metadata. - member x.Typars m = x.Deref.Typars m - - /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - member x.TyparsNoRange = x.Deref.TyparsNoRange + /// + /// Lazy because it may read metadata. Uses the entity's own range for error context. + member x.Typars = x.Deref.Typars /// Indicates if this entity is an F# type abbreviation definition member x.TypeAbbrev = x.Deref.TypeAbbrev diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index 7fbe446641a..be249ece112 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -509,8 +509,8 @@ type Entity = /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. /// - /// Lazy because it may read metadata, must provide a context "range" in case error occurs reading metadata. - member Typars: m: range -> Typars + /// Lazy because it may read metadata. Uses the entity's own range for error context. + member Typars: Typars /// Get the value representing the accessibility of an F# type definition or module. member Accessibility: Accessibility @@ -782,9 +782,6 @@ type Entity = /// These two bits represents the on-demand analysis about whether the entity has the IsReadOnly attribute member TryIsReadOnly: bool voption - /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - member TyparsNoRange: Typars - /// Get the type abbreviated by this type definition, if it is an F# type abbreviation definition member TypeAbbrev: TType option @@ -2460,8 +2457,8 @@ type EntityRef = /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. /// - /// Lazy because it may read metadata, must provide a context "range" in case error occurs reading metadata. - member Typars: m: range -> Typars + /// Lazy because it may read metadata. Uses the entity's own range for error context. + member Typars: Typars /// Get the value representing the accessibility of an F# type definition or module. member Accessibility: Accessibility @@ -2731,9 +2728,6 @@ type EntityRef = /// The on-demand analysis about whether the entity has the IsReadOnly attribute member TryIsReadOnly: bool voption - /// Get the type parameters for an entity that is a type declaration, otherwise return the empty list. - member TyparsNoRange: Typars - /// Indicates if this entity is an F# type abbreviation definition member TypeAbbrev: TType option diff --git a/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs b/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs index a57c6e23804..21c180bd330 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.Attributes.fs @@ -2318,7 +2318,7 @@ module internal DebugPrint = ) ) ^^ wordL (tagText tycon.DisplayName) - ^^ layoutTyparDecls tycon.TyparsNoRange + ^^ layoutTyparDecls tycon.Typars let lhsL = lhsL --- layoutAttribs tycon.Attribs diff --git a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs index 054df3371fd..ffabfdab59c 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.FreeVars.fs @@ -661,7 +661,7 @@ module internal MemberRepresentation = | Some _ -> if v.IsExtensionMember then 0 elif not v.IsMember then 0 - else v.MemberApparentEntity.TyparsNoRange.Length + else v.MemberApparentEntity.Typars.Length let GetValReprTypeInCompiledForm g valReprInfo numEnclosingTypars ty m = let tps, paramArgInfos, retTy, retInfo = @@ -729,7 +729,7 @@ module internal MemberRepresentation = | Some arities -> let fullTypars, _ = destTopForallTy g arities v.Type let parent = v.MemberApparentEntity - let parentTypars = parent.TyparsNoRange + let parentTypars = parent.Typars let nparentTypars = parentTypars.Length if nparentTypars <= fullTypars.Length then @@ -816,7 +816,7 @@ module internal MemberRepresentation = // Generalize type constructors to types //--------------------------------------------------------------------------- - let generalTyconRefInst (tcref: TyconRef) = generalizeTypars tcref.TyparsNoRange + let generalTyconRefInst (tcref: TyconRef) = generalizeTypars tcref.Typars let generalizeTyconRef (g: TcGlobals) tcref = let tinst = generalTyconRefInst tcref diff --git a/src/Compiler/TypedTree/TypedTreeOps.Remap.fs b/src/Compiler/TypedTree/TypedTreeOps.Remap.fs index 605b189ce17..76830e1b377 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.Remap.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.Remap.fs @@ -515,7 +515,7 @@ module internal TypeRemapping = let tinst = generalizeTypars tps mkTyparInst tpsorig tinst, tinst - let mkTyconInst (tycon: Tycon) tinst = mkTyparInst tycon.TyparsNoRange tinst + let mkTyconInst (tycon: Tycon) tinst = mkTyparInst tycon.Typars tinst let mkTyconRefInst (tcref: TyconRef) tinst = mkTyconInst tcref.Deref tinst [] diff --git a/src/Compiler/TypedTree/TypedTreeOps.Remapping.fs b/src/Compiler/TypedTree/TypedTreeOps.Remapping.fs index de28bc34138..cf73a881aa9 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.Remapping.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.Remapping.fs @@ -2233,7 +2233,7 @@ module internal ExprRemapping = let lookupTycon tycon = lookupTycon tycon let tpsR, tmenvinner2 = - tmenvCopyRemapAndBindTypars (remapAttribs ctxt tmenvinner) tmenvinner (tcd.entity_typars.Force(tcd.entity_range)) + tmenvCopyRemapAndBindTypars (remapAttribs ctxt tmenvinner) tmenvinner tcd.Typars tcdR.entity_typars <- LazyWithContext.NotLazy tpsR tcdR.entity_attribs <- WellKnownEntityAttribs.Create(tcd.entity_attribs.AsList() |> remapAttribs ctxt tmenvinner2) diff --git a/src/Compiler/TypedTree/TypedTreeOps.Transforms.fs b/src/Compiler/TypedTree/TypedTreeOps.Transforms.fs index d9503800020..d2735bc6e5d 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.Transforms.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.Transforms.fs @@ -673,7 +673,7 @@ module internal TypeTestsAndPatterns = let GetMemberCallInfo g (vref: ValRef, vFlags) = match vref.MemberInfo with | Some membInfo when not vref.IsExtensionMember -> - let numEnclTypeArgs = vref.MemberApparentEntity.TyparsNoRange.Length + let numEnclTypeArgs = vref.MemberApparentEntity.Typars.Length let virtualCall = (membInfo.MemberFlags.IsOverrideOrExplicitImpl @@ -978,7 +978,7 @@ module internal Rewriting = let rec remapEntityDataToNonLocal ctxt tmenv (d: Entity) = let tpsR, tmenvinner = - tmenvCopyRemapAndBindTypars (remapAttribs ctxt tmenv) tmenv (d.entity_typars.Force(d.entity_range)) + tmenvCopyRemapAndBindTypars (remapAttribs ctxt tmenv) tmenv d.Typars let typarsR = LazyWithContext.NotLazy tpsR let attribsR = d.entity_attribs.AsList() |> remapAttribs ctxt tmenvinner diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs index 93e277c05b4..4fe8eaf121f 100644 --- a/src/Compiler/TypedTree/TypedTreePickle.fs +++ b/src/Compiler/TypedTree/TypedTreePickle.fs @@ -2792,7 +2792,7 @@ and p_rfield_table x st = p_array p_recdfield_spec x.FieldsByIndex st and p_entity_spec_data (x: Entity) st = - p_tyar_specs (x.entity_typars.Force(x.entity_range)) st + p_tyar_specs x.Typars st p_string x.entity_logical_name st p_option p_string x.EntityCompiledName st p_range x.entity_range st diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index a28784716d6..d8e813bb38c 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Neshoda typů Očekává se řazená kolekce členů o délce {0} typu\n {1} \nale odevzdala se řazená kolekce členů o délce {2} typu\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index 73299495a4b..2a6c43b4e6e 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Typenkonflikt. Es wurde ein Tupel der Länge {0} des Typs\n {1} \nerwartet, aber ein Tupel der Länge {2} des Typs\n {3}{4}\n angegeben. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index e73ce8e4291..09958694ca7 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Error de coincidencia de tipos. Se espera una tupla de longitud {0} de tipo\n {1} \nperero se ha proporcionado una tupla de longitud {2} de tipo\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index cb784fdab67..ba65366cece 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Incompatibilité de type. Tuple de longueur attendu {0} de type\n {1} \nmais tuple de longueur {2} de type\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index de6c619667a..e78c11f3f21 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Tipo non corrispondente. È prevista una tupla di lunghezza {0} di tipo\n {1} \n, ma è stata specificata una tupla di lunghezza {2} di tipo\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index 23154e99892..4907e12557b 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n 型が一致しません。型の長さ {0} のタプルが必要です\n {1} \nただし、型の長さ {2} のタプルが指定された場合\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 8b2e15d5d5f..a08987198bf 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n 유형 불일치. 형식이 \n {1}이고 길이가 {0}인 튜플이 필요합니다. \n그러나 형식이 \n {3}이고 길이가 {2}인 튜플이 제공되었습니다.{4}\n diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index 7ab2fe2d494..160e6f04980 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Niezgodność. Oczekiwano krotki o długości {0} typu\n {1} \nale otrzymano krotkę o długości {2} typu\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index f5e8bc53ca4..b0f043eecfd 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Tipo incompatível. Esperando uma tupla de comprimento {0} do tipo\n {1} \nmas recebeu uma tupla de comprimento {2} do tipo\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 117c522a187..91f4886ef2d 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Несоответствие типов. Ожидается кортеж длиной {0} типа\n {1}, \nно предоставлен кортеж длиной {2} типа\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index 6483eba2da0..5a22beb2131 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n Tür uyuşmazlığı. {0} uzunluğunda türü\n {1} \nolan bir demet bekleniyordu ancak {2} uzunluğunda türü\n {3}{4}\nolan bir demet verildi diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index be48009ccde..d620699ec07 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n 类型不匹配。应为长度为 {0} 的类型的元组\n {1} \n但提供了长度为 {2} 的类型的元组\n {3}{4}\n diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 45cae27f445..272ec1802ba 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -32,6 +32,16 @@ Nullness warning: The types '{0}' and '{1}' do not have compatible nullability. + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on a nullable expression of type '{1}'. + + + + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + Nullness warning: Possible dereference of a null value when accessing member '{0}' on the nullable value '{1}' of type '{2}'. + + Type mismatch. Expecting a tuple of length {0} of type\n {1} \nbut given a tuple of length {2} of type\n {3} {4}\n 類型不符。必須是類型為\n {1} \n 的元組長度 {0},但提供的是類型為\n {3}{4}\n 的元組長度 {2} diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs index d969afc538f..0284263d714 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableCsharpImportTests.fs @@ -123,7 +123,7 @@ let s : string = d.Name // should warn here!! |> asLibrary |> typeCheckWithStrictNullness |> shouldFail - |> withDiagnostics [Error 3261, Line 6, Col 18, Line 6, Col 24, "Nullness warning: The types 'DirectoryInfo' and 'DirectoryInfo | null' do not have compatible nullability."] + |> withDiagnostics [Error 3261, Line 6, Col 18, Line 6, Col 19, "Nullness warning: Possible dereference of a null value when accessing member 'Name' on the nullable value 'd' of type 'DirectoryInfo | null'."] [] let ``Consumption of netstandard2 BCL api which is not annotated`` () = @@ -258,6 +258,6 @@ let theOtherOne = NullableClass.nullableImmArrayOfNotNullStrings |> compile |> shouldFail |> withDiagnostics - [Error 3261, Line 7, Col 18, Line 7, Col 36, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability."] + [Error 3261, Line 7, Col 18, Line 7, Col 29, "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 'firstString' of type 'string | null'."] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs index c36c51b3a15..18e503d32cd 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/NullableReferenceTypesTests.fs @@ -1,6 +1,7 @@ module Language.NullableReferenceTypes open Xunit +open FSharp.Test open FSharp.Test.Compiler let withNullnessOptions cu = @@ -295,7 +296,7 @@ let getLength (x: string | null) = x.Length |> asLibrary |> typeCheckWithStrictNullness |> shouldFail - |> withDiagnostics [Error 3261, Line 3, Col 36, Line 3, Col 44, "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability."] + |> withDiagnostics [Error 3261, Line 3, Col 36, Line 3, Col 37, "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 'x' of type 'string | null'."] [] let ``Does report warning on obj to static member`` () = @@ -2373,3 +2374,221 @@ let main _ = 0 |> compile |> run |> verifyOutputContains [|"-1"|] + +[] +// (source, line, col1, col2, memberName, bindingName, typeName) +[] +[] +[] +[] +[ | null) = xs.Contains(1)", + 2, 59, 61, "Contains", "xs", "System.Collections.Generic.List | null")>] +[ | null) = xs.GetEnumerator()", + 2, 66, 68, "GetEnumerator", "xs", "System.Collections.Generic.IEnumerable | null")>] +[] +let ``Issue 19658 - dot-access on nullable receiver names the binding and member`` + (source: string, line: int, col1: int, col2: int, + memberName: string, bindingName: string, typeName: string) = + FSharp source + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line line, Col col1, Line line, Col col2, + $"Nullness warning: Possible dereference of a null value when accessing member '{memberName}' on the nullable value '{bindingName}' of type '{typeName}'." + ] + +// LINQ extension methods: on net472, BCL lacks NullableAttribute so the +// extension-method parameter is ambivalent and no FS3261 fires. +[] +let ``Issue 19658 - LINQ extension method dot-access on nullable receiver`` () = + FSharp """module MyLib +open System.Linq +let f (xs: System.Collections.Generic.List | null) = xs.First()""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 59, Line 3, Col 61, + "Nullness warning: Possible dereference of a null value when accessing member 'First' on the nullable value 'xs' of type 'int seq | null'." + ] + +[] +let ``Issue 19658 - nullness warning on complex receiver omits binding name`` () = + FSharp """module MyLib +let getStr () : string | null = "" +let f () = (getStr()).Length""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 13, Line 3, Col 21, + "Nullness warning: Possible dereference of a null value when accessing member 'Length' on a nullable expression of type 'string | null'." + ] + +[] +let ``Issue 19658 - mutable receiver shows binding name`` () = + FSharp """module MyLib +let f () = + let mutable s: string | null = null + s.Length""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 4, Col 5, Line 4, Col 6, + "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 's' of type 'string | null'." + ] + +[] +let ``Issue 19658 - nested nullable generic receiver does not produce misleading inner-type-arg message`` () = + FSharp """module MyLib +let f (xs: System.Collections.Generic.List | null) = + xs.Count""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 5, Line 3, Col 7, + "Nullness warning: Possible dereference of a null value when accessing member 'Count' on the nullable value 'xs' of type 'System.Collections.Generic.List | null'." + ] + +[] +let ``Issue 19658 - static call still uses generic nullness warning`` () = + FSharp """module MyLib +type C() = + static member Do(x: string) = () +let x: string | null = "" +C.Do(x)""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 5, Col 6, Line 5, Col 7, + "Nullness warning: A non-nullable 'string' was expected but this expression is nullable. Consider either changing the target to also be nullable, or use pattern matching to safely handle the null case of this expression." + ] + +[] +let ``Issue 19658 - no FS3261 when nullness checking is off`` () = + // Without strict nullness, x.PadLeft compiles clean - the new context + // must not introduce diagnostics when --checknulls is not enabled. + FSharp """module MyLib +let f (x: string) = x.PadLeft(1)""" + |> asLibrary + |> compile + |> shouldSucceed + +[] +let ``Issue 19658 - multi-line receiver emits SeeAlso pointing at member call site`` () = + FSharp """module MyLib +let f (x: string | null) = + x + .Length""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 5, Line 3, Col 6, + "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 'x' of type 'string | null'.. See also test.fs(3,4)-(4,15)." + ] + +[] +let ``Issue 19658 - implicit 'this' receiver does not leak name`` () = + // 'this.Get()' is an Expr.App, not an Expr.Val, so tryGetBindingName + // returns None and the "expression" form fires - documents the contract + // that complex expressions get the "expression" wording. + FSharp """module MyLib +type C() = + member _.Get () : string | null = null + member this.Use () = this.Get().Length""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 4, Col 26, Line 4, Col 36, + "Nullness warning: Possible dereference of a null value when accessing member 'Length' on a nullable expression of type 'string | null'." + ] + +// -------- Coverage tests (positive: new dot-access message is used) -------- + +[] +let ``Issue 19658 - piped lambda receiver uses new message`` () = + FSharp """module MyLib +let f () = + let x: string | null = "" + x |> fun s -> s.Length""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 4, Col 19, Line 4, Col 20, + "Nullness warning: Possible dereference of a null value when accessing member 'Length' on the nullable value 's' of type 'string | null'." + ] + +// -------- Out-of-scope-path tests (positive: old generic message still used) -------- +// These pin the current behavior of paths intentionally NOT routed through +// TcMethodApplication. Widening coverage to these paths is tracked separately +// under #17409. If a future change starts emitting the new dot-access message +// for any of these, that change must update these tests deliberately. + +[] +let ``Issue 19658 - indexer access falls back to generic nullness warning`` () = + FSharp """module MyLib +let f (x: string | null) = x.[0]""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 2, Col 28, Line 2, Col 33, + "Nullness warning: A non-nullable 'string' was expected but this expression is nullable. Consider either changing the target to also be nullable, or use pattern matching to safely handle the null case of this expression." + ] + +[] +let ``Issue 19658 - F# record field access falls back to generic nullness warning`` () = + FSharp """module MyLib +type R = { Field: int } +let f (r: R | null) = r.Field""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 23, Line 3, Col 30, + "Nullness warning: The types 'R' and 'R | null' do not have compatible nullability." + ] + +[] +let ``Issue 19658 - anonymous record type cannot be marked nullable`` () = + // Anonymous record types do not support a `| null` qualification at all, + // so the dot-access nullness path cannot fire on them. This pins the + // current behavior: instead of FS3261, the language rejects the type. + FSharp """module MyLib +let f (r: {| Field: int |} | null) = r.Field""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3260, Line 2, Col 11, Line 2, Col 34, + "The type '{| Field: int |}' does not support a nullness qualification." + ] + +[] +let ``Issue 19658 - SRTP member call uses generic nullness warning`` () = + // SRTP-constrained members do not go through TcMethodApplication's + // overload resolution path; objArgInfo is None. The generic FS3261 + // message fires. If/when SRTP gets routed through the same path, this + // test should be updated. + FSharp """module MyLib +let inline f (x: ^T when ^T: (member Length: int)) : int = x.Length +let g (s: string | null) = f s""" + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics [ + Error 3261, Line 3, Col 30, Line 3, Col 31, + "Nullness warning: The types 'string' and 'string | null' do not have compatible nullability." + ] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/using-nullness-syntax-positive.fs.checknulls_on.err.bsl b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/using-nullness-syntax-positive.fs.checknulls_on.err.bsl index aa8325df86b..7332a64cf1d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/Nullness/using-nullness-syntax-positive.fs.checknulls_on.err.bsl +++ b/tests/FSharp.Compiler.ComponentTests/Language/Nullness/using-nullness-syntax-positive.fs.checknulls_on.err.bsl @@ -4,25 +4,25 @@ using-nullness-syntax-positive.fs (13,18)-(13,24) typecheck error Nullness warni using-nullness-syntax-positive.fs (17,15)-(17,19) typecheck error Nullness warning: The type 'obj' does not support 'null'. using-nullness-syntax-positive.fs (18,15)-(18,19) typecheck error Nullness warning: The type 'String | null' supports 'null' but a non-null type is expected. using-nullness-syntax-positive.fs (19,15)-(19,21) typecheck error Nullness warning: The type 'int option' uses 'null' as a representation value but a non-null type is expected. -using-nullness-syntax-positive.fs (27,14)-(27,17) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (27,14)-(27,17) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (28,14)-(28,19) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (28,14)-(28,19) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (29,14)-(29,17) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (29,14)-(29,17) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. +using-nullness-syntax-positive.fs (27,14)-(27,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'P' on the nullable value 'c' of type 'C | null'. +using-nullness-syntax-positive.fs (27,14)-(27,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'P' on the nullable value 'c' of type 'C | null'. +using-nullness-syntax-positive.fs (28,14)-(28,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'M' on the nullable value 'c' of type 'C | null'. +using-nullness-syntax-positive.fs (28,14)-(28,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'M' on the nullable value 'c' of type 'C | null'. +using-nullness-syntax-positive.fs (29,14)-(29,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'M' on the nullable value 'c' of type 'C | null'. +using-nullness-syntax-positive.fs (29,14)-(29,15) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'M' on the nullable value 'c' of type 'C | null'. using-nullness-syntax-positive.fs (43,26)-(43,30) typecheck error Nullness warning: The type 'String' does not support 'null'. -using-nullness-syntax-positive.fs (85,63)-(85,70) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (85,63)-(85,70) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (86,81)-(86,90) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (86,81)-(86,90) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (86,92)-(86,102) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (86,92)-(86,102) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (91,53)-(91,60) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (91,53)-(91,60) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (92,72)-(92,81) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (92,72)-(92,81) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (92,83)-(92,93) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. -using-nullness-syntax-positive.fs (92,83)-(92,93) typecheck error Nullness warning: The types 'C' and 'C | null' do not have compatible nullability. +using-nullness-syntax-positive.fs (85,63)-(85,64) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 's' of type 'C | null'. +using-nullness-syntax-positive.fs (85,63)-(85,64) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 's' of type 'C | null'. +using-nullness-syntax-positive.fs (86,81)-(86,84) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'fmt' of type 'C | null'. +using-nullness-syntax-positive.fs (86,81)-(86,84) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'fmt' of type 'C | null'. +using-nullness-syntax-positive.fs (86,92)-(86,96) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'arg1' of type 'C | null'. +using-nullness-syntax-positive.fs (86,92)-(86,96) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'arg1' of type 'C | null'. +using-nullness-syntax-positive.fs (91,53)-(91,54) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 's' of type 'C | null'. +using-nullness-syntax-positive.fs (91,53)-(91,54) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 's' of type 'C | null'. +using-nullness-syntax-positive.fs (92,72)-(92,75) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'fmt' of type 'C | null'. +using-nullness-syntax-positive.fs (92,72)-(92,75) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'fmt' of type 'C | null'. +using-nullness-syntax-positive.fs (92,83)-(92,87) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'arg1' of type 'C | null'. +using-nullness-syntax-positive.fs (92,83)-(92,87) typecheck error Nullness warning: Possible dereference of a null value when accessing member 'Value' on the nullable value 'arg1' of type 'C | null'. using-nullness-syntax-positive.fs (120,32)-(120,36) typecheck error Nullness warning: The type 'obj array' does not support 'null'. using-nullness-syntax-positive.fs (129,4)-(129,34) typecheck error Nullness warning: The type 'String' does not support 'null'. using-nullness-syntax-positive.fs (134,5)-(134,44) typecheck error Nullness warning: The type 'String' does not support 'null'.