diff --git a/src/Compiler/Checking/AugmentWithHashCompare.fs b/src/Compiler/Checking/AugmentWithHashCompare.fs index cfaece0bfb4..ec37f2c4ee1 100644 --- a/src/Compiler/Checking/AugmentWithHashCompare.fs +++ b/src/Compiler/Checking/AugmentWithHashCompare.fs @@ -15,7 +15,7 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypeHierarchy let mkIComparableCompareToSlotSig (g: TcGlobals) = - TSlotSig("CompareTo", g.mk_IComparable_ty, [], [], [ [ TSlotParam(Some("obj"), g.obj_ty, false, false, false, []) ] ], Some g.int_ty) + TSlotSig("CompareTo", g.mk_IComparable_ty, [], [], [ [ TSlotParam(Some("obj"), g.obj_ty_withNulls, false, false, false, []) ] ], Some g.int_ty) let mkGenericIComparableCompareToSlotSig (g: TcGlobals) ty = TSlotSig( @@ -35,7 +35,7 @@ let mkIStructuralComparableCompareToSlotSig (g: TcGlobals) = [], [ [ - TSlotParam(None, (mkRefTupledTy g [ g.obj_ty; g.IComparer_ty ]), false, false, false, []) + TSlotParam(None, (mkRefTupledTy g [ g.obj_ty_withNulls; g.IComparer_ty ]), false, false, false, []) ] ], Some g.int_ty @@ -59,7 +59,7 @@ let mkIStructuralEquatableEqualsSlotSig (g: TcGlobals) = [], [ [ - TSlotParam(None, (mkRefTupledTy g [ g.obj_ty; g.IEqualityComparer_ty ]), false, false, false, []) + TSlotParam(None, (mkRefTupledTy g [ g.obj_ty_withNulls; g.IEqualityComparer_ty ]), false, false, false, []) ] ], Some g.bool_ty @@ -76,10 +76,10 @@ let mkIStructuralEquatableGetHashCodeSlotSig (g: TcGlobals) = ) let mkGetHashCodeSlotSig (g: TcGlobals) = - TSlotSig("GetHashCode", g.obj_ty, [], [], [ [] ], Some g.int_ty) + TSlotSig("GetHashCode", g.obj_ty_noNulls, [], [], [ [] ], Some g.int_ty) let mkEqualsSlotSig (g: TcGlobals) = - TSlotSig("Equals", g.obj_ty, [], [], [ [ TSlotParam(Some("obj"), g.obj_ty, false, false, false, []) ] ], Some g.bool_ty) + TSlotSig("Equals", g.obj_ty_noNulls, [], [], [ [ TSlotParam(Some("obj"), g.obj_ty_withNulls, false, false, false, []) ] ], Some g.bool_ty) //------------------------------------------------------------------------- // Helpers associated with code-generation of comparison/hash augmentations @@ -89,22 +89,22 @@ let mkThisTy g ty = if isStructTy g ty then mkByrefTy g ty else ty let mkCompareObjTy g ty = - mkFunTy g (mkThisTy g ty) (mkFunTy g g.obj_ty g.int_ty) + mkFunTy g (mkThisTy g ty) (mkFunTy g g.obj_ty_withNulls g.int_ty) let mkCompareTy g ty = mkFunTy g (mkThisTy g ty) (mkFunTy g ty g.int_ty) let mkCompareWithComparerTy g ty = - mkFunTy g (mkThisTy g ty) (mkFunTy g (mkRefTupledTy g [ g.obj_ty; g.IComparer_ty ]) g.int_ty) + mkFunTy g (mkThisTy g ty) (mkFunTy g (mkRefTupledTy g [ g.obj_ty_withNulls; g.IComparer_ty ]) g.int_ty) let mkEqualsObjTy g ty = - mkFunTy g (mkThisTy g ty) (mkFunTy g g.obj_ty g.bool_ty) + mkFunTy g (mkThisTy g ty) (mkFunTy g g.obj_ty_withNulls g.bool_ty) let mkEqualsTy g ty = mkFunTy g (mkThisTy g ty) (mkFunTy g ty g.bool_ty) let mkEqualsWithComparerTy g ty = - mkFunTy g (mkThisTy g ty) (mkFunTy g (mkRefTupledTy g [ g.obj_ty; g.IEqualityComparer_ty ]) g.bool_ty) + mkFunTy g (mkThisTy g ty) (mkFunTy g (mkRefTupledTy g [ g.obj_ty_withNulls; g.IEqualityComparer_ty ]) g.bool_ty) let mkHashTy g ty = mkFunTy g (mkThisTy g ty) (mkFunTy g g.unit_ty g.int_ty) @@ -1096,7 +1096,7 @@ let CheckAugmentationAttribs isImplementation g amap (tycon: Tycon) = hasNominalInterface g.system_GenericIComparable_tcref let hasExplicitEquals = - tycon.HasOverride g "Equals" [ g.obj_ty ] + tycon.HasOverride g "Equals" [ g.obj_ty_ambivalent ] || hasNominalInterface g.tcref_System_IStructuralEquatable let hasExplicitGenericEquals = hasNominalInterface g.system_GenericIEquatable_tcref @@ -1351,13 +1351,13 @@ let MakeBindingsForCompareAugmentation g (tycon: Tycon) = let tinst, ty = mkMinimalTy g tcref let thisv, thise = mkThisVar g m ty - let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty + let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty_ambivalent let comparee = if isUnitTy g ty then mkZero g m else - let thate = mkCoerceExpr (thatobje, ty, m, g.obj_ty) + let thate = mkCoerceExpr (thatobje, ty, m, g.obj_ty_ambivalent) mkApps g ((exprForValRef m vref2, vref2.Type), (if isNil tinst then [] else [ tinst ]), [ thise; thate ], m) @@ -1394,8 +1394,8 @@ let MakeBindingsForCompareWithComparerAugmentation g (tycon: Tycon) = let compv, compe = mkCompGenLocal m "comp" g.IComparer_ty let thisv, thise = mkThisVar g m ty - let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty - let thate = mkCoerceExpr (thatobje, ty, m, g.obj_ty) + let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty_ambivalent + let thate = mkCoerceExpr (thatobje, ty, m, g.obj_ty_ambivalent) let rhs = let comparee = comparef g tcref tycon (thisv, thise) (thatobjv, thate) compe @@ -1453,7 +1453,7 @@ let MakeBindingsForEqualityWithComparerAugmentation (g: TcGlobals) (tycon: Tycon let withcEqualsExpr = let _tinst, ty = mkMinimalTy g tcref let thisv, thise = mkThisVar g m ty - let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty + let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty_ambivalent let thatv, thate = mkCompGenLocal m "that" ty let compv, compe = mkCompGenLocal m "comp" g.IEqualityComparer_ty let equalse = equalsf g tcref tycon (thisv, thise) thatobje (thatv, thate) compe @@ -1515,7 +1515,7 @@ let MakeBindingsForEqualsAugmentation (g: TcGlobals) (tycon: Tycon) = let tinst, ty = mkMinimalTy g tcref let thisv, thise = mkThisVar g m ty - let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty + let thatobjv, thatobje = mkCompGenLocal m "obj" g.obj_ty_ambivalent let equalse = if isUnitTy g ty then diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 504a574b0cc..66d3ae49214 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -860,7 +860,7 @@ module AddAugmentationDeclarations = let m = tycon.Range // Note: tycon.HasOverride only gives correct results after we've done the type augmentation - let hasExplicitObjectEqualsOverride = tycon.HasOverride g "Equals" [g.obj_ty] + let hasExplicitObjectEqualsOverride = tycon.HasOverride g "Equals" [g.obj_ty_ambivalent] let hasExplicitGenericIEquatable = tcaugHasNominalInterface g tcaug g.system_GenericIEquatable_tcref if hasExplicitGenericIEquatable then @@ -1610,7 +1610,7 @@ module MutRecBindingChecking = if tcref.IsStructOrEnumTycon then Some (incrCtorInfo, mkUnit g tcref.Range, false), defnCs else - let inheritsExpr, _ = TcNewExpr cenv envForDecls tpenv g.obj_ty None true (SynExpr.Const (SynConst.Unit, tcref.Range)) tcref.Range + let inheritsExpr, _ = TcNewExpr cenv envForDecls tpenv g.obj_ty_noNulls None true (SynExpr.Const (SynConst.Unit, tcref.Range)) tcref.Range // If there is no 'inherits' and no simple non-static 'let' of a non-method then add a debug point at the entry to the constructor over the type name itself. let addDebugPointAtImplicitCtorArguments = @@ -3313,7 +3313,7 @@ module EstablishTypeDefinitionCores = if isTyparTy g ty then if firstPass then errorR(Error(FSComp.SR.tcCannotInheritFromVariableType(), m)) - Some g.obj_ty // a "super" that is a variable type causes grief later + Some g.obj_ty_noNulls // a "super" that is a variable type causes grief later else Some ty | _ -> diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 71901975f15..fe7fa3df3e6 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -3106,7 +3106,7 @@ let BuildDisposableCleanup (cenv: cenv) env m (v: Val) = else let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposable_ty let disposeExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] [] None - let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty, m, v.Type) + let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty_ambivalent, m, v.Type) mkIsInstConditional g m g.system_IDisposable_ty inputExpr disposeObjVar disposeExpr (mkUnit g m) /// Build call to get_OffsetToStringData as part of 'fixed' @@ -3346,7 +3346,7 @@ let AnalyzeArbitraryExprAsEnumerable (cenv: cenv) (env: TcEnv) localAlloc m expr // e.g. MatchCollection typeEquiv g g.int32_ty ty || // e.g. EnvDTE.Documents.Item - typeEquiv g g.obj_ty ty + typeEquiv g g.obj_ty_ambivalent ty | _ -> false match TryFindIntrinsicOrExtensionMethInfo ResultCollectionSettings.AllResults cenv env m ad "get_Item" tyToSearchForGetEnumeratorAndItem with @@ -4462,7 +4462,7 @@ and TcTypeOrMeasure kindOpt (cenv: cenv) newOk checkConstraints occ (iwsam: Warn match synTy with | SynType.LongIdent(SynLongIdent([], _, _)) -> // special case when type name is absent - i.e. empty inherit part in type declaration - g.obj_ty, tpenv + g.obj_ty_ambivalent, tpenv | SynType.LongIdent synLongId -> TcLongIdentType kindOpt cenv newOk checkConstraints occ iwsam env tpenv synLongId @@ -5096,7 +5096,7 @@ and TcTypeOrMeasureAndRecover kindOpt (cenv: cenv) newOk checkConstraints occ iw match kindOpt, newOk with | Some TyparKind.Measure, NoNewTypars -> TType_measure Measure.One | Some TyparKind.Measure, _ -> TType_measure (NewErrorMeasure ()) - | _, NoNewTypars -> g.obj_ty + | _, NoNewTypars -> g.obj_ty_ambivalent | _ -> NewErrorType () recoveryTy, tpenv @@ -7482,7 +7482,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) - let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m) + let argsExpr = mkArray (g.obj_ty_withNulls, fillExprsBoxed, m) let percentATysExpr = if percentATys.Length = 0 then mkNull m (mkArrayType g g.system_Type_ty) @@ -7509,7 +7509,7 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) let dotnetFormatStringExpr = mkString g m dotnetFormatString - let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m) + let argsExpr = mkArray (g.obj_ty_withNulls, fillExprsBoxed, m) // FormattableString are *always* turned into FormattableStringFactory.Create calls, boxing each argument let createExpr, _ = BuildPossiblyConditionalMethodCall cenv env NeverMutates m false createFormattableStringMethod NormalValUse [] [dotnetFormatStringExpr; argsExpr] [] None @@ -9540,7 +9540,7 @@ and TcEventItemThen (cenv: cenv) overallTy env tpenv mItem mExprAndItem objDetai (let dv, de = mkCompGenLocal mItem "eventDelegate" delTy let callExpr, _ = BuildPossiblyConditionalMethodCall cenv env PossiblyMutates mItem false einfo.RemoveMethod NormalValUse [] objVars [de] None mkLambda mItem dv (callExpr, g.unit_ty)) - (let fvty = mkFunTy g g.obj_ty (mkFunTy g argsTy g.unit_ty) + (let fvty = mkFunTy g g.obj_ty_withNulls (mkFunTy g argsTy g.unit_ty) let fv, fe = mkCompGenLocal mItem "callback" fvty let createExpr = BuildNewDelegateExpr (Some einfo, g, cenv.amap, delTy, delInvokeMeth, delArgTys, fe, fvty, mItem) mkLambda mItem fv (createExpr, delTy))) @@ -9926,7 +9926,7 @@ and TcAdhocChecksOnLibraryMethods (cenv: cenv) (env: TcEnv) isInstance (finalCal if (isInstance && finalCalledMethInfo.IsInstance && - typeEquiv g finalCalledMethInfo.ApparentEnclosingType g.obj_ty && + typeEquiv g finalCalledMethInfo.ApparentEnclosingType g.obj_ty_ambivalent && (finalCalledMethInfo.LogicalName = "GetHashCode" || finalCalledMethInfo.LogicalName = "Equals")) then for objArg in objArgs do diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index c3903d1b75c..306af7cbafe 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -1050,12 +1050,8 @@ and SolveNullnessEquiv (csenv: ConstraintSolverEnv) m2 (trace: OptionalTrace) ty // TODO NULLNESS: this is not sound in contravariant cases etc. It is assuming covariance. | NullnessInfo.WithNull, NullnessInfo.WithoutNull -> CompleteD | _ -> - // NOTE: we never give nullness warnings for the 'obj' type if csenv.g.checkNullness then - if not (isObjTy csenv.g ty1) || not (isObjTy csenv.g ty2) then - WarnD(ConstraintSolverNullnessWarningEquivWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, csenv.m, m2)) - else - CompleteD + WarnD(ConstraintSolverNullnessWarningEquivWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, csenv.m, m2)) else CompleteD @@ -1088,11 +1084,8 @@ and SolveNullnessSubsumesNullness (csenv: ConstraintSolverEnv) m2 (trace: Option | NullnessInfo.WithNull, NullnessInfo.WithoutNull -> CompleteD | NullnessInfo.WithoutNull, NullnessInfo.WithNull -> - if csenv.g.checkNullness then - if not (isObjTy csenv.g ty1) || not (isObjTy csenv.g ty2) then - WarnD(ConstraintSolverNullnessWarningWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, csenv.m, m2)) - else - CompleteD + if csenv.g.checkNullness then + WarnD(ConstraintSolverNullnessWarningWithTypes(csenv.DisplayEnv, ty1, ty2, n1, n2, csenv.m, m2)) else CompleteD @@ -2575,7 +2568,7 @@ and SolveNullnessSupportsNull (csenv: ConstraintSolverEnv) ndeep m2 (trace: Opti | NullnessInfo.AmbivalentToNull -> () | NullnessInfo.WithNull -> () | NullnessInfo.WithoutNull -> - if g.checkNullness && not (isObjTy g ty) then + if g.checkNullness then return! WarnD(ConstraintSolverNullnessWarningWithType(denv, ty, n1, m, m2)) } @@ -2590,7 +2583,7 @@ and SolveTypeUseNotSupportsNull (csenv: ConstraintSolverEnv) ndeep m2 trace ty = // code via Option.ofObj and Option.toObj do! WarnD (ConstraintSolverNullnessWarning(FSComp.SR.csTypeHasNullAsTrueValue(NicePrint.minimalStringOfType denv ty), m, m2)) elif TypeNullIsExtraValueNew g m ty then - if g.checkNullness && not (isObjTy g ty) then + if g.checkNullness then let denv = { denv with showNullnessAnnotations = Some true } do! WarnD (ConstraintSolverNullnessWarning(FSComp.SR.csTypeHasNullAsExtraValue(NicePrint.minimalStringOfType denv ty), m, m2)) else @@ -2618,7 +2611,7 @@ and SolveNullnessNotSupportsNull (csenv: ConstraintSolverEnv) ndeep m2 (trace: O | NullnessInfo.AmbivalentToNull -> () | NullnessInfo.WithoutNull -> () | NullnessInfo.WithNull -> - if g.checkNullness && TypeNullIsExtraValueNew g m ty && not (isObjTy g ty) then + if g.checkNullness && TypeNullIsExtraValueNew g m ty then let denv = { denv with showNullnessAnnotations = Some true } return! WarnD(ConstraintSolverNullnessWarning(FSComp.SR.csTypeHasNullAsExtraValue(NicePrint.minimalStringOfType denv ty), m, m2)) } diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index cbe4a770d6f..6e56d794dfa 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -1260,7 +1260,7 @@ let MethInfoChecks g amap isInstance tyargsOpt objArgs ad m (minfo: MethInfo) = /// Build a call to the System.Object constructor taking no arguments, let BuildObjCtorCall (g: TcGlobals) m = let ilMethRef = (mkILCtorMethSpecForTy(g.ilg.typ_Object, [])).MethodRef - Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty]), [], [], m) + Expr.Op (TOp.ILCall (false, false, false, false, CtorValUsedAsSuperInit, false, true, ilMethRef, [], [], [g.obj_ty_noNulls]), [], [], m) /// Implements the elaborated form of adhoc conversions from functions to delegates at member callsites let BuildNewDelegateExpr (eventInfoOpt: EventInfo option, g, amap, delegateTy, delInvokeMeth: MethInfo, delArgTys, delFuncExpr, delFuncTy, m) = @@ -1447,7 +1447,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C | Some tref -> let ty = mkILNonGenericBoxedTy tref let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty_noNulls]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) emptyPreBinder, expr | WrapperForIUnknown -> @@ -1456,7 +1456,7 @@ let rec GetDefaultExpressionForCallerSideOptionalArg tcFieldInit g (calledArg: C | Some tref -> let ty = mkILNonGenericBoxedTy tref let mref = mkILCtorMethSpecForTy(ty, [g.ilg.typ_Object]).MethodRef - let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) + let expr = Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [g.obj_ty_noNulls]), [], [mkDefault(mMethExpr, currCalledArgTy)], mMethExpr) emptyPreBinder, expr | PassByRef (ty, dfltVal2) -> diff --git a/src/Compiler/Checking/MethodOverrides.fs b/src/Compiler/Checking/MethodOverrides.fs index 5abf08578fb..c58047383e1 100644 --- a/src/Compiler/Checking/MethodOverrides.fs +++ b/src/Compiler/Checking/MethodOverrides.fs @@ -897,7 +897,7 @@ let FinalTypeDefinitionChecksAtEndOfInferenceScope (infoReader: InfoReader, nenv #endif Option.isNone tycon.GeneratedCompareToValues && tycon.HasInterface g g.mk_IComparable_ty && - not (tycon.HasOverride g "Equals" [g.obj_ty]) && + not (tycon.HasOverride g "Equals" [g.obj_ty_ambivalent]) && not tycon.IsFSharpInterfaceTycon then (* Warn when we're doing this for class types *) @@ -916,7 +916,7 @@ let FinalTypeDefinitionChecksAtEndOfInferenceScope (infoReader: InfoReader, nenv let tcaug = tycon.TypeContents let m = tycon.Range let hasExplicitObjectGetHashCode = tycon.HasOverride g "GetHashCode" [] - let hasExplicitObjectEqualsOverride = tycon.HasOverride g "Equals" [g.obj_ty] + let hasExplicitObjectEqualsOverride = tycon.HasOverride g "Equals" [g.obj_ty_ambivalent] if (Option.isSome tycon.GeneratedHashAndEqualsWithComparerValues) && (hasExplicitObjectGetHashCode || hasExplicitObjectEqualsOverride) then diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index f6ca36614a6..a751fbe8195 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -4017,7 +4017,7 @@ let ResolveNestedField sink (ncenv: NameResolver) nenv ad recdTy lid = match item with | Item.RecdField info -> info.FieldType | Item.AnonRecdField (_, tys, index, _) -> tys[index] - | _ -> g.obj_ty + | _ -> g.obj_ty_ambivalent idsBeforeField, (fieldId, item) :: (nestedFieldSearch [] fieldTy rest) diff --git a/src/Compiler/Checking/QuotationTranslator.fs b/src/Compiler/Checking/QuotationTranslator.fs index 9c814c1da97..1ee9fb9fbd3 100644 --- a/src/Compiler/Checking/QuotationTranslator.fs +++ b/src/Compiler/Checking/QuotationTranslator.fs @@ -1223,7 +1223,7 @@ and ConvILType cenv env m ty = and TryElimErasableTyconRef cenv m (tcref: TyconRef) = match tcref.TypeReprInfo with // Get the base type - | TProvidedTypeRepr info when info.IsErased -> Some (info.BaseTypeForErased (m, cenv.g.obj_ty)) + | TProvidedTypeRepr info when info.IsErased -> Some (info.BaseTypeForErased (m, cenv.g.obj_ty_withNulls)) | _ -> None #endif diff --git a/src/Compiler/Checking/TypeHierarchy.fs b/src/Compiler/Checking/TypeHierarchy.fs index ea0d9e93970..1ab418c276a 100644 --- a/src/Compiler/Checking/TypeHierarchy.fs +++ b/src/Compiler/Checking/TypeHierarchy.fs @@ -68,7 +68,7 @@ let GetSuperTypeOfType g amap m ty = elif isArrayTy g ty then Some g.system_Array_ty elif isRefTy g ty && not (isObjTy g ty) then - Some g.obj_ty + Some g.obj_ty_noNulls elif isStructTupleTy g ty then Some g.system_Value_ty elif isFSharpStructOrEnumTy g ty then @@ -79,9 +79,9 @@ let GetSuperTypeOfType g amap m ty = elif isStructAnonRecdTy g ty then Some g.system_Value_ty elif isAnonRecdTy g ty then - Some g.obj_ty + Some g.obj_ty_noNulls elif isRecdTy g ty || isUnionTy g ty then - Some g.obj_ty + Some g.obj_ty_noNulls else None @@ -267,11 +267,11 @@ let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor List.foldBack (loop (ndeep+1)) (GetImmediateInterfacesOfType skipUnref g amap m ty) - (loop ndeep g.obj_ty state) + (loop ndeep g.obj_ty_noNulls state) else match tryDestTyparTy g ty with | ValueSome tp -> - let state = loop (ndeep+1) g.obj_ty state + let state = loop (ndeep+1) g.obj_ty_noNulls state List.foldBack (fun x vacc -> match x with diff --git a/src/Compiler/Checking/TypeRelations.fs b/src/Compiler/Checking/TypeRelations.fs index b04cfe488ce..16ed5e9f9d3 100644 --- a/src/Compiler/Checking/TypeRelations.fs +++ b/src/Compiler/Checking/TypeRelations.fs @@ -31,7 +31,7 @@ let rec TypeDefinitelySubsumesTypeNoCoercion ndeep g amap m ty1 ty2 = let ty1 = stripTyEqns g ty1 let ty2 = stripTyEqns g ty2 // F# reference types are subtypes of type 'obj' - (typeEquiv g ty1 g.obj_ty && isRefTy g ty2) || + (typeEquiv g ty1 g.obj_ty_ambivalent && isRefTy g ty2) || // Follow the supertype chain (isAppTy g ty2 && isRefTy g ty2 && @@ -138,7 +138,7 @@ let ChooseTyparSolutionAndRange (g: TcGlobals) amap (tp:Typar) = let (maxTy, isRefined), m = let initialTy = match tp.Kind with - | TyparKind.Type -> g.obj_ty + | TyparKind.Type -> g.obj_ty_noNulls | TyparKind.Measure -> TType_measure Measure.One // Loop through the constraints computing the lub (((initialTy, false), m), tp.Constraints) ||> List.fold (fun ((maxTy, isRefined), _) tpc -> diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 56bb9b85ad5..71854a4ac28 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -642,7 +642,8 @@ and GenNamedTyAppAux (cenv: cenv) m (tyenv: TypeReprEnv) ptrsOK tcref tinst = #if !NO_TYPEPROVIDERS match tcref.TypeReprInfo with // Generate the base type, because that is always the representation of the erased type, unless the assembly is being injected - | TProvidedTypeRepr info when info.IsErased -> GenTypeAux cenv m tyenv VoidNotOK ptrsOK (info.BaseTypeForErased(m, g.obj_ty)) + | TProvidedTypeRepr info when info.IsErased -> + GenTypeAux cenv m tyenv VoidNotOK ptrsOK (info.BaseTypeForErased(m, g.obj_ty_withNulls)) | _ -> #endif GenTyAppAux cenv m tyenv (GenTyconRef tcref) tinst @@ -10802,7 +10803,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) : ILTypeRef option Option.isNone tycon.GeneratedCompareToValues && Option.isNone tycon.GeneratedHashAndEqualsValues && tycon.HasInterface g g.mk_IComparable_ty - && not (tycon.HasOverride g "Equals" [ g.obj_ty ]) + && not (tycon.HasOverride g "Equals" [ g.obj_ty_ambivalent ]) && not tycon.IsFSharpInterfaceTycon then [ GenEqualsOverrideCallingIComparable cenv (tcref, ilThisTy, ilThisTy) ] diff --git a/src/Compiler/Optimize/LowerComputedCollections.fs b/src/Compiler/Optimize/LowerComputedCollections.fs index 18eafb2c6de..ab6877889ff 100644 --- a/src/Compiler/Optimize/LowerComputedCollections.fs +++ b/src/Compiler/Optimize/LowerComputedCollections.fs @@ -34,7 +34,7 @@ let BuildDisposableCleanup tcVal (g: TcGlobals) infoReader m (v: Val) = else let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposable_ty let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] [] None - let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty, m, v.Type) + let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty_ambivalent, m, v.Type) mkIsInstConditional g m g.system_IDisposable_ty inputExpr disposeObjVar disposeExpr (mkUnit g m) let mkCallCollectorMethod tcVal (g: TcGlobals) infoReader m name collExpr args = diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index 5af43b07801..43431340952 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -3228,7 +3228,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = // the target takes a tupled argument, so we need to reorder the arg expressions in the // arg list, and create a tuple of y & comp // push the comparer to the end and box the argument - let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty, m, ty) ; comp]] + let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty) ; comp]] Some (DevirtualizeApplication cenv env vref ty tyargs args2 m) | _ -> None @@ -3249,7 +3249,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = match tcref.GeneratedHashAndEqualsWithComparerValues, args with | Some (_, _, withcEqualsVal), [comp; x; y] -> // push the comparer to the end and box the argument - let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty, m, ty) ; comp]] + let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty) ; comp]] Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m) | _ -> None @@ -3258,7 +3258,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) = let tcref, tyargs = StripToNominalTyconRef cenv ty match tcref.GeneratedHashAndEqualsWithComparerValues, args with | Some (_, _, withcEqualsVal), [x; y] -> - let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty, m, ty); (mkCallGetGenericPEREqualityComparer g m)]] + let args2 = [x; mkRefTupledNoTypes g m [mkCoerceExpr(y, g.obj_ty_ambivalent, m, ty); (mkCallGetGenericPEREqualityComparer g m)]] Some (DevirtualizeApplication cenv env withcEqualsVal ty tyargs args2 m) | _ -> None diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 46ea4bce4f5..6ba009889c1 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1060,7 +1060,8 @@ type internal TypeCheckInfo match r.Item with | Item.Types(_, ty :: _) when equals r.Range typeNameRange && isAppTy g ty -> let superTy = - (tcrefOfAppTy g ty).TypeContents.tcaug_super |> Option.defaultValue g.obj_ty + (tcrefOfAppTy g ty).TypeContents.tcaug_super + |> Option.defaultValue g.obj_ty_noNulls let overriddenMethods = GetImmediateIntrinsicMethInfosOfType (None, ad) g amap typeNameRange ty diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index aa6671e96d2..7044e41471c 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -442,7 +442,9 @@ type TcGlobals( let v_enum_ty = mkNonGenericTy v_int_tcr let v_bool_ty = mkNonGenericTy v_bool_tcr let v_char_ty = mkNonGenericTy v_char_tcr - let v_obj_ty = mkNonGenericTy v_obj_tcr + let v_obj_ty_without_null = mkNonGenericTyWithNullness v_obj_tcr v_knownWithoutNull + let v_obj_ty_ambivalent = mkNonGenericTyWithNullness v_obj_tcr KnownAmbivalentToNull + let v_obj_ty_with_null = mkNonGenericTyWithNullness v_obj_tcr v_knownWithNull let v_IFormattable_tcref = findSysTyconRef sys "IFormattable" let v_FormattableString_tcref = findSysTyconRef sys "FormattableString" let v_IFormattable_ty = mkNonGenericTy v_IFormattable_tcref @@ -737,11 +739,11 @@ type TcGlobals( let v_generic_hash_withc_inner_info = makeIntrinsicValRef(fslib_MFHashCompare_nleref, "GenericHashWithComparerIntrinsic" , None , None , [vara], mk_hash_withc_sig varaTy) let v_create_instance_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "CreateInstance" , None , None , [vara], ([[v_unit_ty]], varaTy)) - let v_unbox_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "UnboxGeneric" , None , None , [vara], ([[v_obj_ty]], varaTy)) + let v_unbox_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "UnboxGeneric" , None , None , [vara], ([[v_obj_ty_with_null]], varaTy)) - let v_unbox_fast_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "UnboxFast" , None , None , [vara], ([[v_obj_ty]], varaTy)) - let v_istype_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "TypeTestGeneric" , None , None , [vara], ([[v_obj_ty]], v_bool_ty)) - let v_istype_fast_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "TypeTestFast" , None , None , [vara], ([[v_obj_ty]], v_bool_ty)) + let v_unbox_fast_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "UnboxFast" , None , None , [vara], ([[v_obj_ty_with_null]], varaTy)) + let v_istype_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "TypeTestGeneric" , None , None , [vara], ([[v_obj_ty_with_null]], v_bool_ty)) + let v_istype_fast_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "TypeTestFast" , None , None , [vara], ([[v_obj_ty_with_null]], v_bool_ty)) let v_dispose_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "Dispose" , None , None , [vara], ([[varaTy]], v_unit_ty)) @@ -807,7 +809,7 @@ type TcGlobals( let v_enum_operator_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "enum" , None , Some "ToEnum", [vara], ([[varaTy]], v_enum_ty)) let v_hash_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "hash" , None , Some "Hash" , [vara], ([[varaTy]], v_int_ty)) - let v_box_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "box" , None , Some "Box" , [vara], ([[varaTy]], v_obj_ty)) + let v_box_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "box" , None , Some "Box" , [vara], ([[varaTy]], v_obj_ty_with_null)) let v_isnull_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "isNull" , None , Some "IsNull" , [vara], ([[varaTy]], v_bool_ty)) let v_raise_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "raise" , None , Some "Raise" , [vara], ([[mkSysNonGenericTy sys "Exception"]], varaTy)) let v_failwith_info = makeIntrinsicValRef(fslib_MFOperators_nleref, "failwith" , None , Some "FailWith" , [vara], ([[v_string_ty]], varaTy)) @@ -863,7 +865,7 @@ type TcGlobals( let v_seq_finally_info = makeIntrinsicValRef(fslib_MFRuntimeHelpers_nleref, "EnumerateThenFinally" , None , None , [varb], ([[mkSeqTy varbTy]; [v_unit_ty --> v_unit_ty]], mkSeqTy varbTy)) let v_seq_trywith_info = makeIntrinsicValRef(fslib_MFRuntimeHelpers_nleref, "EnumerateTryWith" , None , None , [varb], ([[mkSeqTy varbTy]; [mkNonGenericTy v_exn_tcr --> v_int32_ty]; [mkNonGenericTy v_exn_tcr --> mkSeqTy varbTy]], mkSeqTy varbTy)) let v_seq_of_functions_info = makeIntrinsicValRef(fslib_MFRuntimeHelpers_nleref, "EnumerateFromFunctions" , None , None , [vara;varb], ([[v_unit_ty --> varaTy]; [varaTy --> v_bool_ty]; [varaTy --> varbTy]], mkSeqTy varbTy)) - let v_create_event_info = makeIntrinsicValRef(fslib_MFRuntimeHelpers_nleref, "CreateEvent" , None , None , [vara;varb], ([[varaTy --> v_unit_ty]; [varaTy --> v_unit_ty]; [(v_obj_ty --> (varbTy --> v_unit_ty)) --> varaTy]], mkIEvent2Ty varaTy varbTy)) + let v_create_event_info = makeIntrinsicValRef(fslib_MFRuntimeHelpers_nleref, "CreateEvent" , None , None , [vara;varb], ([[varaTy --> v_unit_ty]; [varaTy --> v_unit_ty]; [(v_obj_ty_with_null --> (varbTy --> v_unit_ty)) --> varaTy]], mkIEvent2Ty varaTy varbTy)) let v_cgh__useResumableCode_info = makeIntrinsicValRef(fslib_MFStateMachineHelpers_nleref, "__useResumableCode" , None , None , [vara], ([[]], v_bool_ty)) let v_cgh__debugPoint_info = makeIntrinsicValRef(fslib_MFStateMachineHelpers_nleref, "__debugPoint" , None , None , [vara], ([[v_int_ty]; [varaTy]], varaTy)) let v_cgh__resumeAt_info = makeIntrinsicValRef(fslib_MFStateMachineHelpers_nleref, "__resumeAt" , None , None , [vara], ([[v_int_ty]; [varaTy]], varaTy)) @@ -1364,7 +1366,9 @@ type TcGlobals( member _.system_FormattableString_ty = v_FormattableString_ty member _.system_FormattableStringFactory_ty = v_FormattableStringFactory_ty member _.unit_ty = v_unit_ty - member _.obj_ty = v_obj_ty + member _.obj_ty_noNulls = v_obj_ty_without_null + member _.obj_ty_ambivalent = v_obj_ty_ambivalent + member _.obj_ty_withNulls = v_obj_ty_with_null member _.char_ty = v_char_ty member _.decimal_ty = v_decimal_ty diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index dcd41add400..31be53f5ca7 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -720,7 +720,7 @@ let reduceTyconMeasureableOrProvided (g: TcGlobals) (tycon: Tycon) tyargs = | TMeasureableRepr ty -> if isNil tyargs then ty else instType (mkTyconInst tycon tyargs) ty #if !NO_TYPEPROVIDERS - | TProvidedTypeRepr info when info.IsErased -> info.BaseTypeForErased (range0, g.obj_ty) + | TProvidedTypeRepr info when info.IsErased -> info.BaseTypeForErased (range0, g.obj_ty_withNulls) #endif | _ -> invalidArg "tc" "this type definition is not a refinement" @@ -3427,7 +3427,7 @@ let trimPathByDisplayEnv denv path = let superOfTycon (g: TcGlobals) (tycon: Tycon) = match tycon.TypeContents.tcaug_super with - | None -> g.obj_ty + | None -> g.obj_ty_noNulls | Some ty -> ty /// walk a TyconRef's inheritance tree, yielding any parent types as an array @@ -6172,7 +6172,7 @@ and remapTyconRepr ctxt tmenv repr = | TProvidedTypeRepr info -> TProvidedTypeRepr { info with - LazyBaseType = info.LazyBaseType.Force (range0, ctxt.g.obj_ty) |> remapType tmenv |> LazyWithContext.NotLazy + LazyBaseType = info.LazyBaseType.Force (range0, ctxt.g.obj_ty_withNulls) |> remapType tmenv |> LazyWithContext.NotLazy // The load context for the provided type contains TyconRef objects. We must remap these. // This is actually done on-demand (see the implementation of ProvidedTypeContext) ProvidedType = diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.net472.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.net472.bsl index ed1c23fb398..1ef3de3b967 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.net472.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.net472.bsl @@ -337,6 +337,8 @@ .method public hidebysig virtual final instance int32 CompareTo(object obj) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 8 IL_0000: ldarg.0 @@ -352,6 +354,8 @@ class [runtime]System.Collections.IComparer comp) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 5 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0, @@ -524,6 +528,8 @@ class [runtime]System.Collections.IEqualityComparer comp) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 5 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0, @@ -643,6 +649,8 @@ .method public hidebysig virtual final instance bool Equals(object obj) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 4 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.netcore.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.netcore.bsl index c5181276c5b..7faa78a8042 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.netcore.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/Nullness/AnonRecords.fs.il.netcore.bsl @@ -337,6 +337,8 @@ .method public hidebysig virtual final instance int32 CompareTo(object obj) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void [runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 8 IL_0000: ldarg.0 @@ -352,6 +354,8 @@ class [runtime]System.Collections.IComparer comp) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void [runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 5 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0, @@ -524,6 +528,8 @@ class [runtime]System.Collections.IEqualityComparer comp) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void [runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 5 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0, @@ -643,6 +649,8 @@ .method public hidebysig virtual final instance bool Equals(object obj) cil managed { .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + .param [1] + .custom instance void [runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 ) .maxstack 4 .locals init (class '<>f__AnonymousType2430756162`3'j__TPar',!'j__TPar',!'j__TPar'> V_0) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/NullableReferenceTypesTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/NullableReferenceTypesTests.fs index 1227fc44f47..7639c8ca208 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/NullableReferenceTypesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/NullableReferenceTypesTests.fs @@ -235,23 +235,53 @@ looseFunc(maybeDu2) |> ignore Error 3261, Line 19, Col 12, Line 19, Col 20, "Nullness warning: The type ''a | null' supports 'null' but a non-null type is expected."] [] -let ``Regression strict func`` () = +let ``Strict func handling of obj type`` () = FSharp """module MyLibrary let strictFunc(arg: 'x when 'x : not null) = printfn "%s" (arg.ToString()) -strictFunc({|Anon=5|}) |> ignore strictFunc("hi") |> ignore -strictFunc(null) |> ignore -strictFunc(null:(string|null)) |> ignore +strictFunc({|Anon=5|}) |> ignore strictFunc(null:obj) |> ignore - +strictFunc(null:(obj|null)) |> ignore +strictFunc(null:(string|null)) |> ignore """ |> asLibrary |> typeCheckWithStrictNullness |> shouldFail |> withDiagnostics - [ Error 3261, Line 7, Col 12, Line 7, Col 30, "Nullness warning: The type 'string | null' supports 'null' but a non-null type is expected." ] - + [ Error 3261, Line 6, Col 12, Line 6, Col 20, "Nullness warning: The type 'obj' supports 'null' but a non-null type is expected." + Error 3261, Line 7, Col 18, Line 7, Col 26, "Nullness warning: The type 'obj' supports 'null' but a non-null type is expected." + Error 3261, Line 7, Col 12, Line 7, Col 27, "Nullness warning: The type 'obj | null' supports 'null' but a non-null type is expected." + Error 3261, Line 8, Col 12, Line 8, Col 30, "Nullness warning: The type 'string | null' supports 'null' but a non-null type is expected."] + + + +[] +let ``Strict func null literal`` () = + FSharp """module MyLibrary +let strictFunc(arg: 'x when 'x : not null) = printfn "%s" (arg.ToString()) + +strictFunc(null) |> ignore """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics + [ Error 3261, Line 4, Col 12, Line 4, Col 16, "Nullness warning: The type 'obj | null' supports 'null' but a non-null type is expected."] + +[] +let ``Strict func null literal2`` () = + FSharp """module MyLibrary +let strictFunc(arg: 'x when 'x : not null) = printfn "%s" (arg.ToString()) + +strictFunc(null) |> ignore +strictFunc({|Anon=5|}) |> ignore +strictFunc("hi") |> ignore """ + |> asLibrary + |> typeCheckWithStrictNullness + |> shouldFail + |> withDiagnostics + [ Error 3261, Line 4, Col 12, Line 4, Col 16, "Nullness warning: The type 'obj | null' supports 'null' but a non-null type is expected."] + [] let ``Nullnesss support for F# types`` () = @@ -297,8 +327,6 @@ type Maybe<'T> = 'T | null let maybeTuple2 : Maybe = null strictFunc(maybeTuple2) |> ignore looseFunc(maybeTuple2) |> ignore - - """ |> asLibrary |> typeCheckWithStrictNullness