Skip to content

Commit 35142d2

Browse files
committed
Adjust extension method checking to work with generic types with no constrains. Add test. Minor refactoring.
1 parent 0a74bdb commit 35142d2

5 files changed

Lines changed: 56 additions & 17 deletions

File tree

src/Compiler/Checking/Expressions/CheckComputationExpressions.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ 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.g cenv.amap m ty)
7170

7271
/// Ignores an attribute
7372
let inline IgnoreAttribute _ = None

src/Compiler/Checking/Expressions/CheckExpressions.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3121,7 +3121,6 @@ let BuildPossiblyConditionalMethodCall (cenv: cenv) env isMutable m isProp minfo
31213121

31223122
let TryFindIntrinsicOrExtensionMethInfo collectionSettings (cenv: cenv) (env: TcEnv) m ad nm ty =
31233123
AllMethInfosOfTypeInScope collectionSettings cenv.infoReader env.NameEnv (Some nm) ad IgnoreOverrides m ty
3124-
|> List.filter (IsExtensionMethCompatibleWithTy cenv.g cenv.amap m ty)
31253124

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

src/Compiler/Checking/NameResolution.fs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -746,23 +746,18 @@ let ExtensionMethInfosOfTypeInScope (collectionSettings: ResultCollectionSetting
746746
| _ -> [])
747747
extMemsDangling @ extMemsFromHierarchy
748748
|> List.filter (fun minfo ->
749-
let isAccesible = AccessibilityLogic.IsMethInfoAccessible amap m ad minfo
749+
let isAccesible = IsMethInfoAccessible amap m ad minfo
750750

751751
isAccesible &&
752752
match isInstanceFilter with
753753
| LookupIsInstance.Ambivalent -> true
754754
| LookupIsInstance.Yes -> minfo.IsInstance
755755
| LookupIsInstance.No -> not minfo.IsInstance)
756756

757-
/// Get all the available methods of a type (both intrinsic and extension)
758-
let AllMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty =
759-
let intrinsic = IntrinsicMethInfosOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty
760-
if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil intrinsic) then
761-
intrinsic
762-
else
763-
intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv ad optFilter LookupIsInstance.Ambivalent m ty
757+
let IsExtensionMethCompatibleWithTy (infoReader: InfoReader) m (ty: TType) (minfo: MethInfo) =
758+
let g = infoReader.g
759+
let amap = infoReader.amap
764760

765-
let IsExtensionMethCompatibleWithTy g amap m (ty: TType) (minfo: MethInfo) =
766761
not minfo.IsExtensionMember ||
767762
match minfo.GetObjArgTypes(amap, m, []) with
768763
| thisTy :: _ ->
@@ -771,17 +766,31 @@ let IsExtensionMethCompatibleWithTy g amap m (ty: TType) (minfo: MethInfo) =
771766

772767
match ty1, ty2 with
773768
| TType_var (tp1, _), _ ->
774-
tp1.Constraints |> List.exists (function
775-
| TyparConstraint.CoercesTo(targetCTy, _) ->
769+
let coercesToConstraints =
770+
tp1.Constraints |> List.choose (function
771+
| TyparConstraint.CoercesTo(targetCTy, _) -> Some targetCTy
772+
| _ -> None)
773+
match coercesToConstraints with
774+
| [] -> true // No CoercesTo constraint means it could match anything
775+
| constraints ->
776+
constraints |> List.exists (fun targetCTy ->
776777
let cTy = targetCTy |> stripTyEqns g
777-
TypeRelations.TypeFeasiblySubsumesType 0 g amap m cTy TypeRelations.CanCoerce ty2
778-
| _ -> false)
778+
TypeRelations.TypeFeasiblySubsumesType 0 g amap m cTy TypeRelations.CanCoerce ty2)
779779
| _, TType_var _ -> true
780780
| _ ->
781781
TypeRelations.TypeFeasiblySubsumesType 0 g amap m ty1 TypeRelations.CanCoerce ty2
782782
| _ ->
783783
true
784784

785+
/// Get all the available methods of a type (both intrinsic and extension)
786+
let AllMethInfosOfTypeInScope collectionSettings infoReader nenv optFilter ad findFlag m ty =
787+
let intrinsic = IntrinsicMethInfosOfType infoReader optFilter ad AllowMultiIntfInstantiations.Yes findFlag m ty
788+
if collectionSettings = ResultCollectionSettings.AtMostOneResult && not (isNil intrinsic) then
789+
intrinsic
790+
else
791+
intrinsic @ ExtensionMethInfosOfTypeInScope collectionSettings infoReader nenv ad optFilter LookupIsInstance.Ambivalent m ty
792+
|> List.filter (IsExtensionMethCompatibleWithTy infoReader m ty)
793+
785794
//-------------------------------------------------------------------------
786795
// Helpers to do with building environments
787796
//-------------------------------------------------------------------------

src/Compiler/Checking/NameResolution.fsi

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,8 +691,7 @@ val internal AllMethInfosOfTypeInScope:
691691

692692
/// Check whether the 'this' argument of an extension method is compatible with the target type
693693
val internal IsExtensionMethCompatibleWithTy:
694-
g: TcGlobals ->
695-
amap: ImportMap ->
694+
infoReader: InfoReader ->
696695
m: range ->
697696
ty: TType ->
698697
minfo: MethInfo ->

tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/CEExtensionMethodCapture.fs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,36 @@ let ``CE captures a public extension method with valid generic constrainted type
134134
|> asExe
135135
|> compile
136136
|> shouldFail
137+
138+
// Deliberately trigger an error to ensure that a method is captured
139+
[<Fact>]
140+
let ``CE captures a public extension method with generic type and procudes an error due to invalid args``() =
141+
FSharp """
142+
open System.Runtime.CompilerServices
143+
144+
type AsyncSeq<'T>(i: 'T) =
145+
class
146+
let l = [i]
147+
member this.Data = l
148+
end
149+
150+
type AsyncSeqBuilder() =
151+
member _.Yield(x: 'T) : AsyncSeq<'T> =
152+
AsyncSeq(x)
153+
154+
[<Extension>]
155+
type PublicExtensions =
156+
[<Extension>]
157+
static member Run(this: 'T, invalidArg: string) =
158+
this
159+
160+
let asyncSeq = AsyncSeqBuilder()
161+
162+
let xs : AsyncSeq<int> =
163+
asyncSeq {
164+
yield 1
165+
}
166+
"""
167+
|> asExe
168+
|> compile
169+
|> shouldFail

0 commit comments

Comments
 (0)