Skip to content

Commit 1491a8c

Browse files
[release/10.0.4xx] Source code updates from dotnet/fsharp (#6345)
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
1 parent 069f06d commit 1491a8c

19 files changed

Lines changed: 363 additions & 56 deletions

src/fsharp/.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@
3131
"FSHARPCORE_USE_PACKAGE": "false",
3232
"PATH": "${localWorkspaceFolder}/.dotnet:${containerEnv:PATH}"
3333
},
34-
"postCreateCommand": [ "bash", "-c", "eng/common/dotnet.sh && cp -r .dotnet/sdk/* /usr/share/dotnet/sdk && cp -r .dotnet/shared/Microsoft.NETCore.App/* /usr/share/dotnet/shared/Microsoft.NETCore.App" ]
34+
"postCreateCommand": [ "bash", "-c", "eng/common/dotnet.sh", "build", "FSharp.Compiler.Service.sln" ]
3535
}

src/fsharp/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Fix `YieldFromFinal`/`ReturnFromFinal` being incorrectly called in non-tail positions (`for`, `use`, `use!`, `try/with` handler). ([Issue #19402](https://github.com/dotnet/fsharp/issues/19402), [PR #19403](https://github.com/dotnet/fsharp/pull/19403))
2020
* Fixed how the source ranges of warn directives are reported (as trivia) in the parser output (by not reporting leading spaces). ([Issue #19405](https://github.com/dotnet/fsharp/issues/19405), [PR #19408]((https://github.com/dotnet/fsharp/pull/19408)))
2121
* Fix UoM value type `ToString()` returning garbage values when `--checknulls+` is enabled, caused by double address-taking in codegen. ([Issue #19435](https://github.com/dotnet/fsharp/issues/19435), [PR #19440](https://github.com/dotnet/fsharp/pull/19440))
22+
* Fix accessibility and type-matching for extension method lookups. ([Issue #19349](https://github.com/dotnet/fsharp/issues/19349), [PR #19536](https://github.com/dotnet/fsharp/pull/19536))
2223
* Fix completion inconsistently showing some obsolete members (fields and events) while hiding others (methods and properties). All obsolete members are now consistently hidden by default. ([Issue #13512](https://github.com/dotnet/fsharp/issues/13512), [PR #19506](https://github.com/dotnet/fsharp/pull/19506))
2324
* Fix O(n) `TypeStructure.GetHashCode` performance regression causing sustained high CPU in IDE mode with generative type providers. ([Issue #18925](https://github.com/dotnet/fsharp/issues/18925), [PR #19369](https://github.com/dotnet/fsharp/pull/19369))
2425
* Fix TypeLoadException when creating delegate with voidptr parameter. (Issue [#11132](https://github.com/dotnet/fsharp/issues/11132), [PR #19338](https://github.com/dotnet/fsharp/pull/19338))
@@ -35,6 +36,8 @@
3536
* Fix signature generation: `private` keyword placement for prefix-style type abbreviations. ([Issue #15560](https://github.com/dotnet/fsharp/issues/15560), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
3637
* Fix signature generation: missing `[<Class>]` attribute for types without visible constructors. ([Issue #16531](https://github.com/dotnet/fsharp/issues/16531), [PR #19586](https://github.com/dotnet/fsharp/pull/19586))
3738
* Fix methods being tagged as `Member` instead of `Method` in tooltips. ([Issue #10540](https://github.com/dotnet/fsharp/issues/10540), [PR #19507](https://github.com/dotnet/fsharp/pull/19507))
39+
* Fix Debug-mode compilation when mixing resumable and standard computation expressions. ([Issue #19625](https://github.com/dotnet/fsharp/issues/19625), [PR #19630](https://github.com/dotnet/fsharp/pull/19630))
40+
* IlxGen: fix missing CompilationMapping attribute for generic values ([PR #19643](https://github.com/dotnet/fsharp/pull/19643))
3841

3942
### Added
4043

src/fsharp/eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
<PropertyGroup>
7676
<!-- These have to be in sync with latest release branch -->
7777
<VSMajorVersion>18</VSMajorVersion>
78-
<VSMinorVersion>4</VSMinorVersion>
78+
<VSMinorVersion>7</VSMinorVersion>
7979
<VSGeneralVersion>$(VSMajorVersion).0</VSGeneralVersion>
8080
<VSAssemblyVersionPrefix>$(VSMajorVersion).$(VSMinorVersion).0</VSAssemblyVersionPrefix>
8181
<VSAssemblyVersion>$(VSAssemblyVersionPrefix).0</VSAssemblyVersion>

src/fsharp/src/Compiler/Checking/Expressions/CheckComputationExpressions.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ let inline noTailCall ceenv = { ceenv with tailCall = false }
6767

6868
let inline TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: TcEnv) m ad nm ty =
6969
AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty
70+
|> List.filter (IsExtensionMethCompatibleWithTy cenv.infoReader m ty)
7071

7172
/// Ignores an attribute
7273
let inline IgnoreAttribute _ = None

src/fsharp/src/Compiler/Checking/Expressions/CheckExpressions.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,7 @@ let BuildPossiblyConditionalMethodCall (cenv: cenv) env isMutable m isProp minfo
31263126

31273127
let TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: TcEnv) m ad nm ty =
31283128
AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty
3129+
|> List.filter (IsExtensionMethCompatibleWithTy cenv.infoReader m ty)
31293130

31303131
let TryFindFSharpSignatureInstanceGetterProperty (cenv: cenv) (env: TcEnv) m nm ty (sigTys: TType list) =
31313132
let g = cenv.g

src/fsharp/src/Compiler/Checking/NameResolution.fs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,11 @@ let SelectMethInfosFromExtMembers (infoReader: InfoReader) optFilter apparentTy
727727
]
728728

729729
/// Query the available extension methods of a type (including extension methods for inherited types)
730-
let ExtensionMethInfosOfTypeInScope (collectionSettings: ResultCollectionSettings) (infoReader: InfoReader) (nenv: NameResolutionEnv) optFilter isInstanceFilter m ty =
731-
let extMemsDangling = SelectMethInfosFromExtMembers infoReader optFilter ty m nenv.eUnindexedExtensionMembers
730+
let ExtensionMethInfosOfTypeInScope (collectionSettings: ResultCollectionSettings) (infoReader: InfoReader) (nenv: NameResolutionEnv) ad optFilter isInstanceFilter m ty =
731+
let amap = infoReader.amap
732+
733+
let extMemsDangling = SelectMethInfosFromExtMembers infoReader optFilter ty m nenv.eUnindexedExtensionMembers
734+
732735
if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil extMemsDangling) then
733736
extMemsDangling
734737
else
@@ -743,6 +746,9 @@ let ExtensionMethInfosOfTypeInScope (collectionSettings: ResultCollectionSetting
743746
| _ -> [])
744747
extMemsDangling @ extMemsFromHierarchy
745748
|> List.filter (fun minfo ->
749+
let isAccesible = IsMethInfoAccessible amap m ad minfo
750+
751+
isAccesible &&
746752
match isInstanceFilter with
747753
| LookupIsInstance.Ambivalent -> true
748754
| LookupIsInstance.Yes -> minfo.IsInstance
@@ -754,7 +760,35 @@ let AllMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad fi
754760
if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil intrinsic) then
755761
intrinsic
756762
else
757-
intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter LookupIsInstance.Ambivalent m ty
763+
intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv ad optFilter LookupIsInstance.Ambivalent m ty
764+
765+
let IsExtensionMethCompatibleWithTy (infoReader: InfoReader) m (ty: TType) (minfo: MethInfo) =
766+
let g = infoReader.g
767+
let amap = infoReader.amap
768+
769+
not minfo.IsExtensionMember ||
770+
match minfo.GetObjArgTypes(amap, m, []) with
771+
| thisTy :: _ ->
772+
let ty1 = thisTy |> stripTyEqns g
773+
let ty2 = ty |> stripTyEqns g
774+
775+
match ty1, ty2 with
776+
| TType_var (tp1, _), _ ->
777+
let coercesToConstraints =
778+
tp1.Constraints |> List.choose (function
779+
| TyparConstraint.CoercesTo(targetCTy, _) -> Some targetCTy
780+
| _ -> None)
781+
match coercesToConstraints with
782+
| [] -> true // No CoercesTo constraint means it could match anything
783+
| constraints ->
784+
constraints |> List.exists (fun targetCTy ->
785+
let cTy = targetCTy |> stripTyEqns g
786+
TypeRelations.TypeFeasiblySubsumesType 0 g amap m cTy TypeRelations.CanCoerce ty2)
787+
| _, TType_var _ -> true
788+
| _ ->
789+
TypeRelations.TypeFeasiblySubsumesType 0 g amap m ty1 TypeRelations.CanCoerce ty2
790+
| _ ->
791+
true
758792

759793
//-------------------------------------------------------------------------
760794
// Helpers to do with building environments
@@ -1184,7 +1218,7 @@ let rec AddStaticContentOfTypeToNameEnv (g:TcGlobals) (amap: Import.ImportMap) a
11841218
[|
11851219
// Extension methods
11861220
yield!
1187-
ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv None LookupIsInstance.No m ty
1221+
ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults infoReader nenv ad None LookupIsInstance.No m ty
11881222
|> ChooseMethInfosForNameEnv g m ty
11891223

11901224
// Extension properties
@@ -2827,7 +2861,7 @@ let rec ResolveLongIdentInTypePrim (ncenv: NameResolver) nenv lookupKind (resInf
28272861
| _ ->
28282862
// lookup in-scope extension methods
28292863
// to keep in sync with the same expression in `| Some(MethodItem msets) when isLookupExpr` below
2830-
match ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv optFilter isInstanceFilter m ty with
2864+
match ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv ad optFilter isInstanceFilter m ty with
28312865
| [] -> success [resInfo, x, rest]
28322866
| methods ->
28332867
let extensionMethods = Item.MakeMethGroup(nm, methods)
@@ -2841,7 +2875,7 @@ let rec ResolveLongIdentInTypePrim (ncenv: NameResolver) nenv lookupKind (resInf
28412875
let minfos = msets |> ExcludeHiddenOfMethInfos g ncenv.amap m
28422876

28432877
// fold the available extension members into the overload resolution
2844-
let extensionMethInfos = ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv optFilter isInstanceFilter m ty
2878+
let extensionMethInfos = ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv ad optFilter isInstanceFilter m ty
28452879

28462880
success [resInfo, Item.MakeMethGroup (nm, minfos@extensionMethInfos), rest]
28472881

@@ -2860,7 +2894,7 @@ let rec ResolveLongIdentInTypePrim (ncenv: NameResolver) nenv lookupKind (resInf
28602894

28612895
if not (isNil pinfos) && isLookUpExpr then OneResult(success (resInfo, Item.Property (nm, pinfos, None), rest)) else
28622896

2863-
let minfos = ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv optFilter isInstanceFilter m ty
2897+
let minfos = ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv ad optFilter isInstanceFilter m ty
28642898

28652899
if not (isNil minfos) && isLookUpExpr then
28662900
success [resInfo, Item.MakeMethGroup (nm, minfos), rest]
@@ -2898,7 +2932,7 @@ let rec ResolveLongIdentInTypePrim (ncenv: NameResolver) nenv lookupKind (resInf
28982932
for p in ExtensionPropInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv None LookupIsInstance.Ambivalent ad m ty do
28992933
addToBuffer p.PropertyName
29002934

2901-
for m in ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv None LookupIsInstance.Ambivalent m ty do
2935+
for m in ExtensionMethInfosOfTypeInScope ResultCollectionSettings.AllResults ncenv.InfoReader nenv ad None LookupIsInstance.Ambivalent m ty do
29022936
addToBuffer m.DisplayName
29032937

29042938
for p in GetIntrinsicPropInfosOfType ncenv.InfoReader None ad AllowMultiIntfInstantiations.No findFlag m ty do

src/fsharp/src/Compiler/Checking/NameResolution.fsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,9 @@ val internal AllMethInfosOfTypeInScope:
689689
ty: TType ->
690690
MethInfo list
691691

692+
/// Check whether the 'this' argument of an extension method is compatible with the target type
693+
val internal IsExtensionMethCompatibleWithTy: infoReader: InfoReader -> m: range -> ty: TType -> minfo: MethInfo -> bool
694+
692695
/// Used to report an error condition where name resolution failed due to an indeterminate type
693696
exception internal IndeterminateType of range
694697

src/fsharp/src/Compiler/CodeGen/IlxGen.fs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9863,8 +9863,14 @@ and GenMethodForBinding
98639863
| _ -> ilAttrsThatGoOnPrimaryItem
98649864
| _ -> ilAttrsThatGoOnPrimaryItem
98659865

9866+
let compilationMappingAttrs =
9867+
[
9868+
if v.MemberInfo.IsNone && curriedArgInfos.IsEmpty then
9869+
mkCompilationMappingAttr g (int SourceConstructFlags.Value)
9870+
]
9871+
98669872
let ilCustomAttrs =
9867-
mkILCustomAttrs (ilAttrs @ sourceNameAttribs @ ilAttrsCompilerGenerated)
9873+
mkILCustomAttrs (ilAttrs @ compilationMappingAttrs @ sourceNameAttribs @ ilAttrsCompilerGenerated)
98689874

98699875
let mdef = mdef.With(customAttrs = ilCustomAttrs)
98709876
mdef

src/fsharp/src/Compiler/Optimize/LowerStateMachines.fs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,13 @@ type LowerStateMachine(g: TcGlobals, outerResumableCodeDefns: ValMap<Expr>) =
338338
if sm_verbose then printfn "expanding defns and reducing %A..." expr
339339
//if sm_verbose then printfn "checking %A for possible resumable code application..." expr
340340
match expr with
341+
// Reduce helper-local 'if __useResumableCode then ... else ...' after inlining,
342+
// but preserve real nested state machines so their own lowering can still choose
343+
// the dynamic fallback if static compilation fails.
344+
| IfUseResumableStateMachinesExpr g (thenExpr, _) when Option.isNone (IsStateMachineExpr g thenExpr) ->
345+
if sm_verbose then printfn "reducing helper-local 'if __useResumableCode ...' to static branch"
346+
Some (remake thenExpr)
347+
341348
// defn --> [expand_code]
342349
| Expr.Val (defnRef, _, _) when env.ResumableCodeDefns.ContainsVal defnRef.Deref ->
343350
let defn = env.ResumableCodeDefns[defnRef.Deref]
@@ -372,22 +379,13 @@ type LowerStateMachine(g: TcGlobals, outerResumableCodeDefns: ValMap<Expr>) =
372379
// Repeated top-down rewrite
373380
let makeRewriteEnv (env: env) =
374381
{ PreIntercept = Some (fun cont e ->
375-
match e with
376-
// Don't recurse into nested state machine expressions - they will be
377-
// processed by their own LowerStateMachineExpr during codegen.
378-
// This prevents modification of the nested machine's internal
379-
// 'if __useResumableCode' patterns which select its dynamic fallback.
380-
| _ when Option.isSome (IsStateMachineExpr g e) -> Some e
381-
// Eliminate 'if __useResumableCode' - nested state machines are already
382-
// guarded above, so any remaining occurrences at this level are from
383-
// beta-reduced inline helpers and should take the static branch.
384-
| IfUseResumableStateMachinesExpr g (thenExpr, _) -> Some (cont thenExpr)
385-
| _ ->
386-
match TryReduceExpr env e [] id with Some e2 -> Some (cont e2) | None -> None)
382+
match TryReduceExpr env e [] id with
383+
| Some e2 -> Some (cont e2)
384+
| None -> None)
387385
PostTransform = (fun _ -> None)
388386
PreInterceptBinding = None
389387
RewriteQuotations=true
390-
StackGuard = StackGuard("LowerStateMachineStackGuardDepth") }
388+
StackGuard = StackGuard("LowerStateMachineStackGuard") }
391389

392390
let ConvertStateMachineLeafExpression (env: env) expr =
393391
if sm_verbose then printfn "ConvertStateMachineLeafExpression for %A..." expr
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Conformance.BasicGrammarElements.UseBindExtensionMethodCapture
2+
3+
open Xunit
4+
open FSharp.Test.Compiler
5+
6+
[<Fact>]
7+
let ``Use binding doesn't capture an extension method with generic type``() =
8+
FSharp """
9+
open System
10+
open System.Runtime.CompilerServices
11+
12+
type FooClass() = class end
13+
14+
type Disposable() =
15+
interface IDisposable with
16+
member _.Dispose() = ()
17+
18+
[<Extension>]
19+
type PublicExtensions =
20+
[<Extension>]
21+
static member inline Dispose(this: #FooClass) =
22+
this
23+
24+
let foo() =
25+
use a = new Disposable()
26+
()
27+
28+
foo()
29+
"""
30+
|> asExe
31+
|> compile
32+
|> shouldSucceed

0 commit comments

Comments
 (0)