diff --git a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md index d3e795bf8b7..1d38ddec633 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md +++ b/docs/release-notes/.FSharp.Compiler.Service/9.0.100.md @@ -24,6 +24,7 @@ * Allow object expression without overrides. ([Language suggestion #632](https://github.com/fsharp/fslang-suggestions/issues/632), [PR #17387](https://github.com/dotnet/fsharp/pull/17387)) * Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17438)), [PR](https://github.com/dotnet/fsharp/pull/17500))) * Enable LanguageFeature.EnforceAttributeTargets in F# 9.0. ([Issue #17514](https://github.com/dotnet/fsharp/issues/17558), [PR #17516](https://github.com/dotnet/fsharp/pull/17558)) +* Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597) ### Changed diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 9b8f659f647..9ed1822676b 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -1862,9 +1862,10 @@ type ILGenericParameterDef = Name: string Constraints: ILTypes Variance: ILGenericVariance - HasReferenceTypeConstraint: bool + HasReferenceTypeConstraint: bool HasNotNullableValueTypeConstraint: bool HasDefaultConstructorConstraint: bool + HasAllowsRefStruct: bool CustomAttrsStored: ILAttributesStored MetadataIndex: int32 } @@ -3283,6 +3284,7 @@ let mkILSimpleTypar nm = HasReferenceTypeConstraint = false HasNotNullableValueTypeConstraint = false HasDefaultConstructorConstraint = false + HasAllowsRefStruct = false CustomAttrsStored = storeILCustomAttrs emptyILCustomAttrs MetadataIndex = NoMetadataIdx } diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index 1e2a6ee3705..e3ec95a40d7 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -1021,6 +1021,9 @@ type ILGenericParameterDef = /// Indicates the type argument must have a public nullary constructor. HasDefaultConstructorConstraint: bool + /// Indicates the type parameter allows ref struct, i.e. an anti constraint. + HasAllowsRefStruct: bool + /// Do not use this CustomAttrsStored: ILAttributesStored diff --git a/src/Compiler/AbstractIL/ilread.fs b/src/Compiler/AbstractIL/ilread.fs index 5dcc051ab9f..94677898f6d 100644 --- a/src/Compiler/AbstractIL/ilread.fs +++ b/src/Compiler/AbstractIL/ilread.fs @@ -2291,6 +2291,7 @@ and seekReadGenericParamsUncached ctxtH (GenericParamsIdx(numTypars, a, b)) = HasReferenceTypeConstraint = (flags &&& 0x0004) <> 0 HasNotNullableValueTypeConstraint = (flags &&& 0x0008) <> 0 HasDefaultConstructorConstraint = (flags &&& 0x0010) <> 0 + HasAllowsRefStruct = (flags &&& 0x0020) <> 0 }) ) diff --git a/src/Compiler/AbstractIL/ilreflect.fs b/src/Compiler/AbstractIL/ilreflect.fs index 8c56aca9be8..9b0b7eddb9e 100644 --- a/src/Compiler/AbstractIL/ilreflect.fs +++ b/src/Compiler/AbstractIL/ilreflect.fs @@ -1714,31 +1714,34 @@ let buildGenParamsPass1b cenv emEnv (genArgs: Type array) (gps: ILGenericParamet gp.CustomAttrs |> emitCustomAttrs cenv emEnv (wrapCustomAttr gpB.SetCustomAttribute) - let flags = GenericParameterAttributes.None - let flags = match gp.Variance with - | NonVariant -> flags - | CoVariant -> flags ||| GenericParameterAttributes.Covariant - | ContraVariant -> flags ||| GenericParameterAttributes.Contravariant + | NonVariant -> GenericParameterAttributes.None + | CoVariant -> GenericParameterAttributes.Covariant + | ContraVariant -> GenericParameterAttributes.Contravariant - let flags = - if gp.HasReferenceTypeConstraint then - flags ||| GenericParameterAttributes.ReferenceTypeConstraint - else - flags + let zero = GenericParameterAttributes.None let flags = - if gp.HasNotNullableValueTypeConstraint then - flags ||| GenericParameterAttributes.NotNullableValueTypeConstraint - else - flags - - let flags = - if gp.HasDefaultConstructorConstraint then - flags ||| GenericParameterAttributes.DefaultConstructorConstraint - else - flags + flags + ||| (if gp.HasReferenceTypeConstraint then + GenericParameterAttributes.ReferenceTypeConstraint + else + zero) + ||| (if gp.HasNotNullableValueTypeConstraint then + GenericParameterAttributes.NotNullableValueTypeConstraint + else + zero) + ||| (if gp.HasDefaultConstructorConstraint then + GenericParameterAttributes.DefaultConstructorConstraint + else + zero) + ||| + // GenericParameterAttributes.AllowByRefLike from net9, not present in ns20 + (if gp.HasAllowsRefStruct then + (enum 0x0020) + else + zero) gpB.SetGenericParameterAttributes flags) //---------------------------------------------------------------------------- diff --git a/src/Compiler/AbstractIL/ilwrite.fs b/src/Compiler/AbstractIL/ilwrite.fs index f1112b334f8..832aa1c2810 100644 --- a/src/Compiler/AbstractIL/ilwrite.fs +++ b/src/Compiler/AbstractIL/ilwrite.fs @@ -2513,7 +2513,8 @@ let rec GetGenericParamAsGenericParamRow cenv _env idx owner gp = | ContraVariant -> 0x0002) ||| (if gp.HasReferenceTypeConstraint then 0x0004 else 0x0000) ||| (if gp.HasNotNullableValueTypeConstraint then 0x0008 else 0x0000) ||| - (if gp.HasDefaultConstructorConstraint then 0x0010 else 0x0000) + (if gp.HasDefaultConstructorConstraint then 0x0010 else 0x0000) ||| + (if gp.HasAllowsRefStruct then 0x0020 else 0x0000) let mdVersionMajor, _ = metadataSchemaVersionSupportedByCLRVersion cenv.desiredMetadataVersion diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 3fbe6427248..06ef1b9766a 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -28,6 +28,7 @@ open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypeHierarchy open FSharp.Compiler.TypeRelations +open Import //-------------------------------------------------------------------------- // NOTES: reraise safety checks @@ -334,7 +335,20 @@ let RecordAnonRecdInfo cenv (anonInfo: AnonRecdTypeInfo) = // approx walk of type //-------------------------------------------------------------------------- -let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, visitTraitSolutionOpt, visitTyparOpt as f) (g: TcGlobals) env isInner ty = +/// Represents the container for nester type instantions, carrying information about the parent (generic type) and data about correspinding generic typar definition. +/// For current use, IlGenericParameterDef was enough. For other future use cases, conversion into F# Typar might be needed. +type TypeInstCtx = + | NoInfo + | IlGenericInst of parent:TyconRef * genericArg:ILGenericParameterDef + | TyparInst of parent:TyconRef + | TopLevelAllowingByRef + + with member x.TyparAllowsRefStruct() = + match x with + | IlGenericInst(_,ilTypar) -> ilTypar.HasAllowsRefStruct + | _ -> false + +let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, visitTraitSolutionOpt, visitTyparOpt as f) (g: TcGlobals) env (typeInstParentOpt:TypeInstCtx) ty = // We iterate the _solved_ constraints as well, to pick up any record of trait constraint solutions // This means we walk _all_ the constraints _everywhere_ in a type, including // those attached to _solved_ type variables. This is used by PostTypeCheckSemanticChecks to detect uses of @@ -366,22 +380,30 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi match ty with | TType_forall (tps, body) -> let env = BindTypars g env tps - CheckTypeDeep cenv f g env isInner body + CheckTypeDeep cenv f g env typeInstParentOpt body tps |> List.iter (fun tp -> tp.Constraints |> List.iter (CheckTypeConstraintDeep cenv f g env)) | TType_measure _ -> () | TType_app (tcref, tinst, _) -> match visitTyconRefOpt with - | Some visitTyconRef -> visitTyconRef isInner tcref + | Some visitTyconRef -> visitTyconRef typeInstParentOpt tcref | None -> () // If it's a 'byref<'T>', don't check 'T as an inner. This allows byref>. // 'byref>' is invalid and gets checked in visitAppTy. - if isByrefTyconRef g tcref then - CheckTypesDeepNoInner cenv f g env tinst + //if isByrefTyconRef g tcref then + // CheckTypesDeepNoInner cenv f g env tinst + + if tcref.CanDeref && tcref.IsILTycon && tinst.Length = tcref.ILTyconRawMetadata.GenericParams.Length then + (tinst,tcref.ILTyconRawMetadata.GenericParams) + ||> List.iter2 (fun ty ilGenericParam -> + let typeInstParent = IlGenericInst(tcref, ilGenericParam) + CheckTypeDeep cenv f g env typeInstParent ty) else - CheckTypesDeep cenv f g env tinst + let parentRef = TyparInst(tcref) + for ty in tinst do + CheckTypeDeep cenv f g env parentRef ty match visitAppTyOpt with | Some visitAppTy -> visitAppTy (tcref, tinst) @@ -398,8 +420,8 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi CheckTypesDeep cenv f g env tys | TType_fun (s, t, _) -> - CheckTypeDeep cenv f g env true s - CheckTypeDeep cenv f g env true t + CheckTypeDeep cenv f g env NoInfo s + CheckTypeDeep cenv f g env NoInfo t | TType_var (tp, _) -> if not tp.IsSolved then @@ -410,20 +432,16 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi and CheckTypesDeep cenv f g env tys = for ty in tys do - CheckTypeDeep cenv f g env true ty - -and CheckTypesDeepNoInner cenv f g env tys = - for ty in tys do - CheckTypeDeep cenv f g env false ty + CheckTypeDeep cenv f g env NoInfo ty and CheckTypeConstraintDeep cenv f g env x = match x with - | TyparConstraint.CoercesTo(ty, _) -> CheckTypeDeep cenv f g env true ty + | TyparConstraint.CoercesTo(ty, _) -> CheckTypeDeep cenv f g env NoInfo ty | TyparConstraint.MayResolveMember(traitInfo, _) -> CheckTraitInfoDeep cenv f g env traitInfo - | TyparConstraint.DefaultsTo(_, ty, _) -> CheckTypeDeep cenv f g env true ty + | TyparConstraint.DefaultsTo(_, ty, _) -> CheckTypeDeep cenv f g env NoInfo ty | TyparConstraint.SimpleChoice(tys, _) -> CheckTypesDeep cenv f g env tys - | TyparConstraint.IsEnum(underlyingTy, _) -> CheckTypeDeep cenv f g env true underlyingTy - | TyparConstraint.IsDelegate(argTys, retTy, _) -> CheckTypeDeep cenv f g env true argTys; CheckTypeDeep cenv f g env true retTy + | TyparConstraint.IsEnum(underlyingTy, _) -> CheckTypeDeep cenv f g env NoInfo underlyingTy + | TyparConstraint.IsDelegate(argTys, retTy, _) -> CheckTypeDeep cenv f g env NoInfo argTys; CheckTypeDeep cenv f g env NoInfo retTy | TyparConstraint.SupportsComparison _ | TyparConstraint.SupportsEquality _ | TyparConstraint.SupportsNull _ @@ -436,18 +454,18 @@ and CheckTypeConstraintDeep cenv f g env x = and CheckTraitInfoDeep cenv (_, _, _, visitTraitSolutionOpt, _ as f) g env traitInfo = CheckTypesDeep cenv f g env traitInfo.SupportTypes CheckTypesDeep cenv f g env traitInfo.CompiledObjectAndArgumentTypes - Option.iter (CheckTypeDeep cenv f g env true ) traitInfo.CompiledReturnType + Option.iter (CheckTypeDeep cenv f g env NoInfo ) traitInfo.CompiledReturnType match visitTraitSolutionOpt, traitInfo.Solution with | Some visitTraitSolution, Some sln -> visitTraitSolution sln | _ -> () /// Check for byref-like types let CheckForByrefLikeType cenv env m ty check = - CheckTypeDeep cenv (ignore, Some (fun _deep tcref -> if isByrefLikeTyconRef cenv.g m tcref then check()), None, None, None) cenv.g env false ty + CheckTypeDeep cenv (ignore, Some (fun ctx tcref -> if (isByrefLikeTyconRef cenv.g m tcref && not(ctx.TyparAllowsRefStruct())) then check()), None, None, None) cenv.g env NoInfo ty /// Check for byref types let CheckForByrefType cenv env ty check = - CheckTypeDeep cenv (ignore, Some (fun _deep tcref -> if isByrefTyconRef cenv.g tcref then check()), None, None, None) cenv.g env false ty + CheckTypeDeep cenv (ignore, Some (fun _ctx tcref -> if isByrefTyconRef cenv.g tcref then check()), None, None, None) cenv.g env NoInfo ty /// check captures under lambdas /// @@ -516,7 +534,7 @@ let CheckTypeForAccess (cenv: cenv) env objName valAcc m ty = if isLessAccessible tyconAcc valAcc then errorR(Error(FSComp.SR.chkTypeLessAccessibleThanType(tcref.DisplayName, (objName())), m)) - CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env false ty + CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env NoInfo ty let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty = if cenv.reportErrors then @@ -534,7 +552,7 @@ let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty = let warningText = errorText + Environment.NewLine + FSComp.SR.tcTypeAbbreviationsCheckedAtCompileTime() warning(AttributeChecking.ObsoleteWarning(warningText, m)) - CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env false ty + CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env NoInfo ty /// Indicates whether a byref or byref-like type is permitted at a particular location [] @@ -629,16 +647,26 @@ let CheckTypeAux permitByRefLike (cenv: cenv) env m ty onInnerByrefError = else errorR (Error(FSComp.SR.checkNotSufficientlyGenericBecauseOfScope(tp.DisplayName), m)) - let visitTyconRef isInner tcref = + let visitTyconRef (ctx:TypeInstCtx) tcref = + let checkInner() = + match ctx with + | TopLevelAllowingByRef -> false + | TyparInst(parentTcRef) + | IlGenericInst(parentTcRef,_) when isByrefTyconRef cenv.g parentTcRef -> false + | _ -> true + + let isInnerByRefLike() = checkInner() && isByrefLikeTyconRef cenv.g m tcref + + let permitByRefLike = + if ctx.TyparAllowsRefStruct() then PermitByRefType.All else permitByRefLike - let isInnerByRefLike = isInner && isByrefLikeTyconRef cenv.g m tcref match permitByRefLike with | PermitByRefType.None when isByrefLikeTyconRef cenv.g m tcref -> errorR(Error(FSComp.SR.chkErrorUseOfByref(), m)) - | PermitByRefType.NoInnerByRefLike when isInnerByRefLike -> + | PermitByRefType.NoInnerByRefLike when isInnerByRefLike() -> onInnerByrefError () - | PermitByRefType.SpanLike when isByrefTyconRef cenv.g tcref || isInnerByRefLike -> + | PermitByRefType.SpanLike when isByrefTyconRef cenv.g tcref || isInnerByRefLike() -> onInnerByrefError () | _ -> () @@ -665,7 +693,13 @@ let CheckTypeAux permitByRefLike (cenv: cenv) env m ty onInnerByrefError = cenv.potentialUnboundUsesOfVals <- cenv.potentialUnboundUsesOfVals.Add(vref.Stamp, m) | _ -> () - CheckTypeDeep cenv (ignore, Some visitTyconRef, Some visitAppTy, Some visitTraitSolution, Some visitTyar) cenv.g env false ty + let initialCtx = + match permitByRefLike with + | PermitByRefType.SpanLike + | PermitByRefType.NoInnerByRefLike -> TopLevelAllowingByRef + | _ -> NoInfo + + CheckTypeDeep cenv (ignore, Some visitTyconRef, Some visitAppTy, Some visitTraitSolution, Some visitTyar) cenv.g env initialCtx ty let CheckType permitByRefLike cenv env m ty = CheckTypeAux permitByRefLike cenv env m ty (fun () -> errorR(Error(FSComp.SR.chkErrorUseOfByref(), m))) @@ -1458,9 +1492,31 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = CombineTwoLimits limit1 limit2 | TOp.ILCall (_, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), _, _ -> + CheckTypeInstNoByrefs cenv env m tyargs - CheckTypeInstNoByrefs cenv env m enclTypeInst - CheckTypeInstNoByrefs cenv env m methInst + + match enclTypeInst,methInst with + | [],[] -> () + | enclTypeInst,methInst -> + let tyconRef = ImportILTypeRef cenv.amap m ilMethRef.DeclaringTypeRef + match tyconRef.TypeReprInfo with + | TILObjectRepr(TILObjectReprData(scoref, _, tdef)) -> + (enclTypeInst,tdef.GenericParams) + ||> List.iter2 (fun typeInst typeGeneric -> + if not typeGeneric.HasAllowsRefStruct then + CheckTypeNoByrefs cenv env m typeInst) + + match methInst with + | [] -> () + | methInst -> + let methDef = resolveILMethodRefWithRescope (rescopeILType scoref) tdef ilMethRef + (methInst,methDef.GenericParams) + ||> List.iter2 (fun methInst methGeneric -> + if not methGeneric.HasAllowsRefStruct then + CheckTypeNoByrefs cenv env m methInst) + + | _ -> () + CheckTypeInstNoInnerByrefs cenv env m retTypes // permit byref returns let hasReceiver = diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index 2b1308dcddc..6758b6dcd94 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -2070,6 +2070,7 @@ type AnonTypeGenerationTable() = HasReferenceTypeConstraint = false HasNotNullableValueTypeConstraint = false HasDefaultConstructorConstraint = false + HasAllowsRefStruct = false MetadataIndex = NoMetadataIdx } ] @@ -5733,6 +5734,7 @@ and GenGenericParam cenv eenv (tp: Typar) = HasReferenceTypeConstraint = refTypeConstraint HasNotNullableValueTypeConstraint = notNullableValueTypeConstraint || emitUnmanagedInIlOutput HasDefaultConstructorConstraint = defaultConstructorConstraint + HasAllowsRefStruct = false } //-------------------------------------------------------------------------- diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/ByrefTests.fs b/tests/FSharp.Compiler.ComponentTests/Interop/ByrefTests.fs index dca7589c903..db89445122b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/ByrefTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/ByrefTests.fs @@ -53,4 +53,169 @@ module ``Byref interop verification tests`` = """ |> asExe |> compileAndRun - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``Ref structs in generics - can declare`` () = + FSharp """module Foo +open System +let x(a:Action>) = a.Invoke(ReadOnlySpan([||])) + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + [] + let ``Ref structs in generics - can return as inner`` () = + + FSharp """module Foo +open System +let x() = + let a:(Action>) = Unchecked.defaultof<_> + a + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + [] + let ``Ref structs in generics - can use in object expressions`` () = + FSharp """module Foo +open System + +let main _args = + let comparer = + { new System.IComparable> + with member x.CompareTo(o) = 42 } + comparer.CompareTo(ReadOnlySpan([||])) + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + [] + let ``Ref structs in generics - can use in foreach`` () = + FSharp """module Foo +open System + +let processSeq (input:seq>) = + for ros in input do + printfn "%i" (ros.Length) + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + [] + let ``Ref structs in generics - IL and runtime test`` () = + FSharp """module Foo +open System +open System.Collections.Generic + +let myDict = ["x",1;"xyz",2] |> dict |> Dictionary + +let checkIfPresent (input:ReadOnlySpan) = + let altLookup = myDict.GetAlternateLookup>() + let present = altLookup.ContainsKey(input) + for c in input do + printf "%c" c + printfn ": %A" present + +[] +let main _args = + checkIfPresent(ReadOnlySpan([||])) + checkIfPresent("x".AsSpan()) + checkIfPresent(ReadOnlySpan([|'x';'y';'z'|])) + 0 + """ + |> asExe + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + |> verifyOutputContains [|": false";"x: true";"xyz: true"|] + |> verifyIL + ["call valuetype [System.Collections]System.Collections.Generic.Dictionary`2/AlternateLookup`1 [System.Collections]System.Collections.Generic.CollectionExtensions::GetAlternateLookup>(class [System.Collections]System.Collections.Generic.Dictionary`2)"] + + [] + let ``Ref structs in generics - GetAlternateLookup`` () = + FSharp """module Foo +open System +open System.Collections.Generic + +let main _args = + let myDict = ["x",1;"y",2] |> dict |> Dictionary + let altLookup = myDict.GetAlternateLookup>() + altLookup.ContainsKey(ReadOnlySpan([|'x'|])) + """ + |> withLangVersionPreview + |> typecheck + |> shouldSucceed + + [] + [ Async.RunSynchronously")>] + [] + let ``Ref structs in generics - builders`` (build:string) (getter:string) = + + FSharp $$$"""module Foo +open System + +let getAction() = + {{{build}}} { + let x = new Action>(fun ros -> printfn "%i" ros.Length) + return x + } + +let getBuilderResult() = + {{{build}}} { + let! myAction = getAction() + myAction.Invoke(ReadOnlySpan([|1|])) + return myAction + } + +[] +let main _args = + let myTask = getBuilderResult(){{{getter}}} + printfn "%O" myTask + 0 + """ + |> asExe + |> withLangVersionPreview + |> compileAndRun + |> shouldSucceed + |> verifyOutputContains [|"1";"System.Action`1[System.ReadOnlySpan`1[System.Int32]]"|] + |> verifyIL + [ if build = "task" then + "valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1>>>" + else "[FSharp.Core]Microsoft.FSharp.Control.FSharpAsync`1>>>" ] + + [] + let ``Ref structs in generics - negative tests`` () = + FSharp """module Foo +open System +open System.Collections.Generic + +[] +type MyRecordFullOfWrongStuff<'T> = + { Value : Span<'T> + MyMap : list> + MyDict: Dictionary> + Nested: Span> } + +let processRecord (recd:MyRecordFullOfWrongStuff>>) = + recd.MyDict.["x"] + + """ + |> withLangVersionPreview + |> typecheck + |> shouldFail + |> withDiagnostics + [ Error 412, Line 7, Col 7, Line 7, Col 12, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 437, Line 6, Col 6, Line 6, Col 30, "A type would store a byref typed value. This is not permitted by Common IL." + Error 412, Line 8, Col 7, Line 8, Col 12, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 412, Line 9, Col 7, Line 9, Col 13, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 412, Line 10, Col 7, Line 10, Col 13, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 3300, Line 12, Col 20, Line 12, Col 24, "The parameter 'recd' has an invalid type 'MyRecordFullOfWrongStuff>>'. This is not permitted by the rules of Common IL." + Error 412, Line 13, Col 5, Line 13, Col 22, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 412, Line 13, Col 5, Line 13, Col 16, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL." + Error 412, Line 13, Col 5, Line 13, Col 9, "A type instantiation involves a byref type. This is not permitted by the rules of Common IL."] + diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index 820f94aa28a..47a8e6166fb 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -670,9 +670,11 @@ FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String Name FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String get_Name() FSharp.Compiler.AbstractIL.IL+ILFieldSpec: Void .ctor(ILFieldRef, ILType) +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasAllowsRefStruct FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasDefaultConstructorConstraint FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasNotNullableValueTypeConstraint FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasReferenceTypeConstraint +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasAllowsRefStruct() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasDefaultConstructorConstraint() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasNotNullableValueTypeConstraint() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasReferenceTypeConstraint() @@ -689,7 +691,7 @@ FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Microsoft.FSharp.Collection FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String Name FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String get_Name() -FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], ILGenericVariance, Boolean, Boolean, Boolean, ILAttributesStored, Int32) +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], ILGenericVariance, Boolean, Boolean, Boolean, Boolean, ILAttributesStored, Int32) FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 CoVariant FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 ContraVariant FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 NonVariant diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index 820f94aa28a..47a8e6166fb 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -670,9 +670,11 @@ FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String Name FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILFieldSpec: System.String get_Name() FSharp.Compiler.AbstractIL.IL+ILFieldSpec: Void .ctor(ILFieldRef, ILType) +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasAllowsRefStruct FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasDefaultConstructorConstraint FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasNotNullableValueTypeConstraint FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean HasReferenceTypeConstraint +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasAllowsRefStruct() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasDefaultConstructorConstraint() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasNotNullableValueTypeConstraint() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Boolean get_HasReferenceTypeConstraint() @@ -689,7 +691,7 @@ FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Microsoft.FSharp.Collection FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String Name FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String ToString() FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: System.String get_Name() -FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], ILGenericVariance, Boolean, Boolean, Boolean, ILAttributesStored, Int32) +FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef: Void .ctor(System.String, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], ILGenericVariance, Boolean, Boolean, Boolean, Boolean, ILAttributesStored, Int32) FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 CoVariant FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 ContraVariant FSharp.Compiler.AbstractIL.IL+ILGenericVariance+Tags: Int32 NonVariant diff --git a/tests/fsharp/Compiler/Language/SpanTests.fs b/tests/fsharp/Compiler/Language/SpanTests.fs index aef001deec2..d02cca4e8f5 100644 --- a/tests/fsharp/Compiler/Language/SpanTests.fs +++ b/tests/fsharp/Compiler/Language/SpanTests.fs @@ -175,4 +175,22 @@ type IsByRefLikeAttribute() = inherit Attribute() type T(span: Span) = struct end """ [| |] + + [] + let ``A byref struct with custom attr can be passed as typar``() = + CompilerAssert.TypeCheckWithErrors """ +namespace System.Runtime.CompilerServices + +open System + +[] +type IsByRefLikeAttribute() = inherit Attribute() + +[] +type T(span: Span) = struct end + +module WhatEver = + let processT (a: Action, ie: seq, asList: list) = () + """ + [| FSharpDiagnosticSeverity.Error, 3300, (13, 45, 13, 51), "The parameter 'asList' has an invalid type 'T list'. This is not permitted by the rules of Common IL." |] #endif \ No newline at end of file