Skip to content

Commit 19610c0

Browse files
committed
Rendering AllowsRefStruct for type parameters (#17706)
1 parent d470fe8 commit 19610c0

File tree

15 files changed

+113
-26
lines changed

15 files changed

+113
-26
lines changed

docs/release-notes/.FSharp.Compiler.Service/9.0.100.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,11 @@
3636
* Enable FSharp 9.0 Language Version ([Issue #17497](https://github.com/dotnet/fsharp/issues/17438)), [PR](https://github.com/dotnet/fsharp/pull/17500)))
3737
* 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))
3838
* Parser: better recovery for unfinished patterns ([PR #17231](https://github.com/dotnet/fsharp/pull/17231), [PR #17232](https://github.com/dotnet/fsharp/pull/17232)))
39-
* Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597)
39+
* Enable consuming generic arguments defined as `allows ref struct` in C# ([Issue #17597](https://github.com/dotnet/fsharp/issues/17597), display them in tooltips [PR #17706](https://github.com/dotnet/fsharp/pull/17706))
4040
* Trivia for SynTypeConstraint.WhereTyparNotSupportsNull. ([Issue #17721](https://github.com/dotnet/fsharp/issues/17721), [PR #17745](https://github.com/dotnet/fsharp/pull/17745))
4141
* Trivia for SynType.WithNull. ([Issue #17720](https://github.com/dotnet/fsharp/issues/17720), [PR #17745](https://github.com/dotnet/fsharp/pull/17745))
4242

43+
4344
### Changed
4445

4546
* Change compiler default setting realsig+ when building assemblies ([Issue #17384](https://github.com/dotnet/fsharp/issues/17384), [PR #17378](https://github.com/dotnet/fsharp/pull/17385))

src/Compiler/Checking/ConstraintSolver.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,7 @@ and SolveTypMeetsTyparConstraints (csenv: ConstraintSolverEnv) ndeep m2 trace ty
10241024
| TyparConstraint.IsDelegate(aty, bty, m2) -> SolveTypeIsDelegate csenv ndeep m2 trace ty aty bty
10251025
| TyparConstraint.IsNonNullableStruct m2 -> SolveTypeIsNonNullableValueType csenv ndeep m2 trace ty
10261026
| TyparConstraint.IsUnmanaged m2 -> SolveTypeIsUnmanaged csenv ndeep m2 trace ty
1027+
| TyparConstraint.AllowsRefStruct _ -> CompleteD
10271028
| TyparConstraint.IsReferenceType m2 -> SolveTypeIsReferenceType csenv ndeep m2 trace ty
10281029
| TyparConstraint.RequiresDefaultConstructor m2 -> SolveTypeRequiresDefaultConstructor csenv ndeep m2 trace ty
10291030
| TyparConstraint.SimpleChoice(tys, m2) -> SolveTypeChoice csenv ndeep m2 trace ty tys
@@ -2465,6 +2466,7 @@ and CheckConstraintImplication (csenv: ConstraintSolverEnv) tpc1 tpc2 =
24652466
| TyparConstraint.NotSupportsNull _, TyparConstraint.NotSupportsNull _
24662467
| TyparConstraint.IsNonNullableStruct _, TyparConstraint.IsNonNullableStruct _
24672468
| TyparConstraint.IsUnmanaged _, TyparConstraint.IsUnmanaged _
2469+
| TyparConstraint.AllowsRefStruct _, TyparConstraint.AllowsRefStruct _
24682470
| TyparConstraint.IsReferenceType _, TyparConstraint.IsReferenceType _
24692471
| TyparConstraint.RequiresDefaultConstructor _, TyparConstraint.RequiresDefaultConstructor _ -> true
24702472
| TyparConstraint.SimpleChoice (tys1, _), TyparConstraint.SimpleChoice (tys2, _) -> ListSet.isSubsetOf (typeEquiv g) tys1 tys2

src/Compiler/Checking/Expressions/CheckExpressions.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5163,6 +5163,7 @@ and TcPatLongIdentActivePatternCase warnOnUpper (cenv: cenv) (env: TcEnv) vFlags
51635163
| TyparConstraint.SupportsComparison _
51645164
| TyparConstraint.SupportsEquality _
51655165
| TyparConstraint.DefaultsTo (ty = Unit)
5166+
| TyparConstraint.AllowsRefStruct _
51665167
| TyparConstraint.MayResolveMember _ -> true
51675168

51685169
// Any other kind of constraint is incompatible with unit.

src/Compiler/Checking/NicePrint.fs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,13 @@ module PrintTypes =
773773
| _ ->
774774
if denv.abbreviateAdditionalConstraints then
775775
wordL (tagKeyword "when") ^^ wordL(tagText "<constraints>")
776-
elif denv.shortConstraints then
777-
LeftL.leftParen ^^ wordL (tagKeyword "requires") ^^ sepListL (wordL (tagKeyword "and")) cxsL ^^ RightL.rightParen
776+
elif denv.shortConstraints then
777+
match cxs with
778+
| (_,TyparConstraint.AllowsRefStruct _) :: _ ->
779+
// If the first constraint is 'allows ref struct', we do not want to prefix it with 'requires', because that just reads wrong.
780+
LeftL.leftParen ^^ sepListL (wordL (tagKeyword "and")) cxsL ^^ RightL.rightParen
781+
| _ ->
782+
LeftL.leftParen ^^ wordL (tagKeyword "requires") ^^ sepListL (wordL (tagKeyword "and")) cxsL ^^ RightL.rightParen
778783
else
779784
wordL (tagKeyword "when") ^^ sepListL (wordL (tagKeyword "and")) cxsL
780785

@@ -834,6 +839,12 @@ module PrintTypes =
834839
[wordL (tagKeyword "unmanaged")]
835840
else
836841
[wordL (tagKeyword "unmanaged") |> longConstraintPrefix]
842+
843+
| TyparConstraint.AllowsRefStruct _ ->
844+
if denv.shortConstraints then
845+
[wordL (tagKeyword "allows ref struct")]
846+
else
847+
[wordL (tagKeyword "allows ref struct") |> longConstraintPrefix]
837848

838849
| TyparConstraint.IsReferenceType _ ->
839850
if denv.shortConstraints then

src/Compiler/Checking/PostInferenceChecks.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ and CheckTypeConstraintDeep cenv f g env x =
448448
| TyparConstraint.NotSupportsNull _
449449
| TyparConstraint.IsNonNullableStruct _
450450
| TyparConstraint.IsUnmanaged _
451+
| TyparConstraint.AllowsRefStruct _
451452
| TyparConstraint.IsReferenceType _
452453
| TyparConstraint.RequiresDefaultConstructor _ -> ()
453454

src/Compiler/Checking/SignatureHash.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ module rec HashTypes =
165165
| TyparConstraint.SimpleChoice(tys, _) -> tpHash @@ 12 @@ (tys |> hashListOrderIndependent (hashTType g))
166166
| TyparConstraint.RequiresDefaultConstructor _ -> tpHash @@ 13
167167
| TyparConstraint.NotSupportsNull(_) -> tpHash @@ 14
168+
| TyparConstraint.AllowsRefStruct _ -> tpHash @@ 15
168169

169170
/// Hash type parameter constraints
170171
let private hashConstraints (g: TcGlobals) cxs =

src/Compiler/Checking/TypeHierarchy.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor
285285
| TyparConstraint.NotSupportsNull _
286286
| TyparConstraint.IsNonNullableStruct _
287287
| TyparConstraint.IsUnmanaged _
288+
| TyparConstraint.AllowsRefStruct _
288289
| TyparConstraint.IsReferenceType _
289290
| TyparConstraint.SimpleChoice _
290291
| TyparConstraint.RequiresDefaultConstructor _ -> vacc
@@ -412,7 +413,9 @@ let ImportReturnTypeFromMetadata amap m nullnessSource ilTy scoref tinst minst =
412413
413414
let CopyTyparConstraints m tprefInst (tporig: Typar) =
414415
tporig.Constraints
415-
|> List.map (fun tpc ->
416+
// F# does not have escape analysis for authoring 'allows ref struct' generic code. Therefore, typar is not copied, can only come from C# authored code
417+
|> List.filter (fun tp -> match tp with | TyparConstraint.AllowsRefStruct _ -> false | _ -> true)
418+
|> List.map (fun tpc ->
416419
match tpc with
417420
| TyparConstraint.CoercesTo(ty, _) ->
418421
TyparConstraint.CoercesTo (instType tprefInst ty, m)
@@ -434,6 +437,7 @@ let CopyTyparConstraints m tprefInst (tporig: Typar) =
434437
TyparConstraint.IsNonNullableStruct m
435438
| TyparConstraint.IsUnmanaged _ ->
436439
TyparConstraint.IsUnmanaged m
440+
| TyparConstraint.AllowsRefStruct _ -> failwith "impossible, filtered above"
437441
| TyparConstraint.IsReferenceType _ ->
438442
TyparConstraint.IsReferenceType m
439443
| TyparConstraint.SimpleChoice (tys, _) ->

src/Compiler/Checking/TypeRelations.fs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,19 +151,13 @@ let ChooseTyparSolutionAndRange (g: TcGlobals) amap (tp:Typar) =
151151
match tpc with
152152
| TyparConstraint.CoercesTo(x, m) ->
153153
join m x, m
154-
| TyparConstraint.MayResolveMember(_traitInfo, m) ->
155-
(maxTy, isRefined), m
156154
| TyparConstraint.SimpleChoice(_, m) ->
157155
errorR(Error(FSComp.SR.typrelCannotResolveAmbiguityInPrintf(), m))
158156
(maxTy, isRefined), m
159157
| TyparConstraint.SupportsNull m ->
160158
((addNullnessToTy KnownWithNull maxTy), isRefined), m
161-
| TyparConstraint.NotSupportsNull m ->
162-
(maxTy, isRefined), m // NOTE: this doesn't "force" non-nullness, since it is the default choice in 'obj' or 'int'
163159
| TyparConstraint.SupportsComparison m ->
164160
join m g.mk_IComparable_ty, m
165-
| TyparConstraint.SupportsEquality m ->
166-
(maxTy, isRefined), m
167161
| TyparConstraint.IsEnum(_, m) ->
168162
errorR(Error(FSComp.SR.typrelCannotResolveAmbiguityInEnum(), m))
169163
(maxTy, isRefined), m
@@ -175,12 +169,15 @@ let ChooseTyparSolutionAndRange (g: TcGlobals) amap (tp:Typar) =
175169
| TyparConstraint.IsUnmanaged m ->
176170
errorR(Error(FSComp.SR.typrelCannotResolveAmbiguityInUnmanaged(), m))
177171
(maxTy, isRefined), m
178-
| TyparConstraint.RequiresDefaultConstructor m ->
179-
(maxTy, isRefined), m
180-
| TyparConstraint.IsReferenceType m ->
172+
| TyparConstraint.NotSupportsNull m // NOTE: this doesn't "force" non-nullness, since it is the default choice in 'obj' or 'int'
173+
| TyparConstraint.SupportsEquality m
174+
| TyparConstraint.AllowsRefStruct m
175+
| TyparConstraint.RequiresDefaultConstructor m
176+
| TyparConstraint.IsReferenceType m
177+
| TyparConstraint.MayResolveMember(_, m)
178+
| TyparConstraint.DefaultsTo(_,_, m) ->
181179
(maxTy, isRefined), m
182-
| TyparConstraint.DefaultsTo(_priority, _ty, m) ->
183-
(maxTy, isRefined), m)
180+
)
184181

185182
if g.langVersion.SupportsFeature LanguageFeature.DiagnosticForObjInference then
186183
match tp.Kind with

src/Compiler/Checking/import.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ let ImportILGenericParameters amap m scoref tinst (nullableFallback:Nullness.Nul
653653
TyparConstraint.IsNonNullableStruct(m)
654654
if gp.HasReferenceTypeConstraint then
655655
TyparConstraint.IsReferenceType(m)
656+
if gp.HasAllowsRefStruct then
657+
TyparConstraint.AllowsRefStruct(m)
656658
for ilTy in gp.Constraints do
657659
TyparConstraint.CoercesTo(ImportILType amap m importInst (rescopeILType scoref ilTy), m) ]
658660

src/Compiler/TypedTree/TypedTree.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,9 @@ type TyparConstraint =
25312531

25322532
/// A constraint that a type is .NET unmanaged type
25332533
| IsUnmanaged of range: range
2534+
2535+
/// An anti-constraint indicating that ref structs (e.g. Span<>) are allowed here
2536+
| AllowsRefStruct of range:range
25342537

25352538
// %+A formatting is used, so this is not needed
25362539
//[<DebuggerBrowsable(DebuggerBrowsableState.Never)>]

0 commit comments

Comments
 (0)