Skip to content

Commit a336508

Browse files
edgarfgpnojaf
authored andcommitted
Add CSharp Extension Attribute Not Required as a Preview Language Feature
1 parent c0c3425 commit a336508

19 files changed

+336
-127
lines changed

src/Compiler/Checking/CheckDeclarations.fs

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -956,16 +956,18 @@ module MutRecBindingChecking =
956956
let prelimRecValues = [ for x in defnAs do match x with Phase2AMember bind -> yield bind.RecBindingInfo.Val | _ -> () ]
957957

958958
let tyconOpt =
959-
tyconOpt
960-
|> Option.map (fun tycon ->
961-
tryAddExtensionAttributeIfNotAlreadyPresent
962-
(fun tryFindExtensionAttribute ->
963-
tycon.MembersOfFSharpTyconSorted
964-
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
965-
)
966-
tycon
967-
)
968-
959+
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
960+
tyconOpt
961+
|> Option.map (fun tycon ->
962+
tryAddExtensionAttributeIfNotAlreadyPresent
963+
(fun tryFindExtensionAttribute ->
964+
tycon.MembersOfFSharpTyconSorted
965+
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
966+
)
967+
tycon
968+
)
969+
else
970+
tyconOpt
969971
let defnAs = MutRecShape.Tycon(TyconBindingsPhase2A(tyconOpt, declKind, prelimRecValues, tcref, copyOfTyconTypars, thisTy, defnAs))
970972
defnAs, (tpenv, recBindIdx, uncheckedBindsRev))
971973

@@ -4207,46 +4209,49 @@ module TcDeclarations =
42074209
// Check the members and decide on representations for types with implicit constructors.
42084210
let withBindings, envFinal = TcMutRecDefns_Phase2 cenv envInitial m scopem mutRecNSInfo envMutRecPrelimWithReprs withEnvs
42094211

4210-
// If any of the types has a member with the System.Runtime.CompilerServices.ExtensionAttribute,
4211-
// or a recursive module has a binding with the System.Runtime.CompilerServices.ExtensionAttribute,
4212-
// that type/recursive module should also received the ExtensionAttribute if it is not yet present.
4213-
// Example:
4214-
// open System.Runtime.CompilerServices
4215-
//
4216-
// type Int32Extensions =
4217-
// [<Extension>]
4218-
// static member PlusOne (a:int) : int = a + 1
4219-
//
4220-
// or
4221-
//
4222-
// module rec Foo
4223-
//
4224-
// [<System.Runtime.CompilerServices.Extension>]
4225-
// let PlusOne (a:int) = a + 1
42264212
let withBindings =
4227-
withBindings
4228-
|> List.map (function
4229-
| MutRecShape.Tycon (Some tycon, bindings) ->
4230-
let tycon =
4231-
tryAddExtensionAttributeIfNotAlreadyPresent
4232-
(fun tryFindExtensionAttribute ->
4233-
tycon.MembersOfFSharpTyconSorted
4234-
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
4235-
)
4236-
tycon
4237-
MutRecShape.Tycon (Some tycon, bindings)
4238-
| MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes) ->
4239-
let entity =
4240-
tryAddExtensionAttributeIfNotAlreadyPresent
4241-
(fun tryFindExtensionAttribute ->
4242-
moduleOrNamespaceType.Value.AllValsAndMembers
4243-
|> Seq.filter(fun v -> v.IsModuleBinding)
4244-
|> Seq.tryPick (fun v -> tryFindExtensionAttribute v.Attribs)
4245-
)
4246-
entity
4247-
4248-
MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes)
4249-
| shape -> shape)
4213+
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
4214+
// If any of the types has a member with the System.Runtime.CompilerServices.ExtensionAttribute,
4215+
// or a recursive module has a binding with the System.Runtime.CompilerServices.ExtensionAttribute,
4216+
// that type/recursive module should also received the ExtensionAttribute if it is not yet present.
4217+
// Example:
4218+
// open System.Runtime.CompilerServices
4219+
//
4220+
// type Int32Extensions =
4221+
// [<Extension>]
4222+
// static member PlusOne (a:int) : int = a + 1
4223+
//
4224+
// or
4225+
//
4226+
// module rec Foo
4227+
//
4228+
// [<System.Runtime.CompilerServices.Extension>]
4229+
// let PlusOne (a:int) = a + 1
4230+
withBindings
4231+
|> List.map (function
4232+
| MutRecShape.Tycon (Some tycon, bindings) ->
4233+
let tycon =
4234+
tryAddExtensionAttributeIfNotAlreadyPresent
4235+
(fun tryFindExtensionAttribute ->
4236+
tycon.MembersOfFSharpTyconSorted
4237+
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
4238+
)
4239+
tycon
4240+
MutRecShape.Tycon (Some tycon, bindings)
4241+
| MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes) ->
4242+
let entity =
4243+
tryAddExtensionAttributeIfNotAlreadyPresent
4244+
(fun tryFindExtensionAttribute ->
4245+
moduleOrNamespaceType.Value.AllValsAndMembers
4246+
|> Seq.filter(fun v -> v.IsModuleBinding)
4247+
|> Seq.tryPick (fun v -> tryFindExtensionAttribute v.Attribs)
4248+
)
4249+
entity
4250+
4251+
MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes)
4252+
| shape -> shape)
4253+
else
4254+
withBindings
42504255

42514256
// Generate the hash/compare/equality bindings for all tycons.
42524257
//
@@ -4785,27 +4790,30 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
47854790
// Get the inferred type of the decls and record it in the modul.
47864791
moduleEntity.entity_modul_type <- MaybeLazy.Strict moduleTyAcc.Value
47874792

4788-
// If any of the let bindings inside the module has the System.Runtime.CompilerServices.ExtensionAttribute,
4789-
// that module should also received the ExtensionAttribute if it is not yet present.
4790-
// Example:
4791-
// module Foo
4792-
//
4793-
//[<System.Runtime.CompilerServices.Extension>]
4794-
//let PlusOne (a:int) = a + 1
47954793
let moduleEntity =
4796-
tryAddExtensionAttributeIfNotAlreadyPresent
4797-
(fun tryFindExtensionAttribute ->
4798-
match moduleContents with
4799-
| ModuleOrNamespaceContents.TMDefs(defs) ->
4800-
defs
4801-
|> Seq.tryPick (function
4802-
| ModuleOrNamespaceContents.TMDefLet (Binding.TBind(var = v),_) ->
4803-
tryFindExtensionAttribute v.Attribs
4804-
| _ -> None)
4805-
| _ -> None
4806-
)
4794+
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
4795+
// If any of the let bindings inside the module has the System.Runtime.CompilerServices.ExtensionAttribute,
4796+
// that module should also received the ExtensionAttribute if it is not yet present.
4797+
// Example:
4798+
// module Foo
4799+
//
4800+
//[<System.Runtime.CompilerServices.Extension>]
4801+
//let PlusOne (a:int) = a + 1
4802+
tryAddExtensionAttributeIfNotAlreadyPresent
4803+
(fun tryFindExtensionAttribute ->
4804+
match moduleContents with
4805+
| ModuleOrNamespaceContents.TMDefs(defs) ->
4806+
defs
4807+
|> Seq.tryPick (function
4808+
| ModuleOrNamespaceContents.TMDefLet (Binding.TBind(var = v),_) ->
4809+
tryFindExtensionAttribute v.Attribs
4810+
| _ -> None)
4811+
| _ -> None
4812+
)
4813+
moduleEntity
4814+
else
48074815
moduleEntity
4808-
4816+
48094817
let moduleDef = TMDefRec(false, [], [], [ModuleOrNamespaceBinding.Module(moduleEntity, moduleContents)], m)
48104818

48114819
PublishModuleDefn cenv env moduleEntity

src/Compiler/Checking/NameResolution.fs

Lines changed: 109 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -517,65 +517,118 @@ let IsMethInfoPlainCSharpStyleExtensionMember g m isEnclExtTy (minfo: MethInfo)
517517
/// Get the info for all the .NET-style extension members listed as static members in the type.
518518
let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.ImportMap) m (tcrefOfStaticClass: TyconRef) =
519519
let g = amap.g
520-
let ty = generalizedTyconRef g tcrefOfStaticClass
520+
521+
if g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
522+
let ty = generalizedTyconRef g tcrefOfStaticClass
523+
524+
let minfos =
525+
GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty
526+
|> List.filter (IsMethInfoPlainCSharpStyleExtensionMember g m true)
521527

522-
let minfos =
523-
GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty
524-
|> List.filter (IsMethInfoPlainCSharpStyleExtensionMember g m true)
525-
526-
if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass || not minfos.IsEmpty then
527-
let pri = NextExtensionMethodPriority()
528-
529-
[ for minfo in minfos do
530-
let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri)
531-
532-
// The results are indexed by the TyconRef of the first 'this' argument, if any.
533-
// So we need to go and crack the type of the 'this' argument.
534-
//
535-
// This is convoluted because we only need the ILTypeRef of the first argument, and we don't
536-
// want to read any other metadata as it can trigger missing-assembly errors. It turns out ImportILTypeRef
537-
// is less eager in reading metadata than GetParamTypes.
538-
//
539-
// We don't use the index for the IL extension method for tuple of F# function types (e.g. if extension
540-
// methods for tuple occur in C# code)
541-
let thisTyconRef =
542-
try
543-
let rs =
544-
match metadataOfTycon tcrefOfStaticClass.Deref, minfo with
545-
| ILTypeMetadata (TILObjectReprData(scoref, _, _)), ILMeth(_, ILMethInfo(_, _, _, ilMethod, _), _) ->
546-
match ilMethod.ParameterTypes with
547-
| firstTy :: _ ->
548-
match firstTy with
549-
| ILType.Boxed tspec | ILType.Value tspec ->
550-
let tref = (tspec |> rescopeILTypeSpec scoref).TypeRef
551-
if Import.CanImportILTypeRef amap m tref then
552-
let tcref = tref |> Import.ImportILTypeRef amap m
553-
if isCompiledTupleTyconRef g tcref || tyconRefEq g tcref g.fastFunc_tcr then None
554-
else Some tcref
555-
else None
528+
if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass || not minfos.IsEmpty then
529+
let pri = NextExtensionMethodPriority()
530+
531+
[ for minfo in minfos do
532+
let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri)
533+
534+
// The results are indexed by the TyconRef of the first 'this' argument, if any.
535+
// So we need to go and crack the type of the 'this' argument.
536+
//
537+
// This is convoluted because we only need the ILTypeRef of the first argument, and we don't
538+
// want to read any other metadata as it can trigger missing-assembly errors. It turns out ImportILTypeRef
539+
// is less eager in reading metadata than GetParamTypes.
540+
//
541+
// We don't use the index for the IL extension method for tuple of F# function types (e.g. if extension
542+
// methods for tuple occur in C# code)
543+
let thisTyconRef =
544+
try
545+
let rs =
546+
match metadataOfTycon tcrefOfStaticClass.Deref, minfo with
547+
| ILTypeMetadata (TILObjectReprData(scoref, _, _)), ILMeth(_, ILMethInfo(_, _, _, ilMethod, _), _) ->
548+
match ilMethod.ParameterTypes with
549+
| firstTy :: _ ->
550+
match firstTy with
551+
| ILType.Boxed tspec | ILType.Value tspec ->
552+
let tref = (tspec |> rescopeILTypeSpec scoref).TypeRef
553+
if Import.CanImportILTypeRef amap m tref then
554+
let tcref = tref |> Import.ImportILTypeRef amap m
555+
if isCompiledTupleTyconRef g tcref || tyconRefEq g tcref g.fastFunc_tcr then None
556+
else Some tcref
557+
else None
558+
| _ -> None
559+
| _ -> None
560+
| _ ->
561+
// The results are indexed by the TyconRef of the first 'this' argument, if any.
562+
// So we need to go and crack the type of the 'this' argument.
563+
let thisTy = minfo.GetParamTypes(amap, m, generalizeTypars minfo.FormalMethodTypars).Head.Head
564+
match thisTy with
565+
| AppTy g (tcrefOfTypeExtended, _) when not (isByrefTy g thisTy) -> Some tcrefOfTypeExtended
556566
| _ -> None
557-
| _ -> None
558-
| _ ->
559-
// The results are indexed by the TyconRef of the first 'this' argument, if any.
560-
// So we need to go and crack the type of the 'this' argument.
561-
let thisTy = minfo.GetParamTypes(amap, m, generalizeTypars minfo.FormalMethodTypars).Head.Head
562-
match thisTy with
563-
| AppTy g (tcrefOfTypeExtended, _) when not (isByrefTy g thisTy) -> Some tcrefOfTypeExtended
564-
| _ -> None
565-
566-
Some rs
567-
568-
with e -> // Import of the ILType may fail, if so report the error and skip on
569-
errorRecovery e m
570-
None
571-
572-
match thisTyconRef with
573-
| None -> ()
574-
| Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem)
575-
| Some None -> yield Choice2Of2 ilExtMem ]
576-
else
577-
[]
578567

568+
Some rs
569+
570+
with e -> // Import of the ILType may fail, if so report the error and skip on
571+
errorRecovery e m
572+
None
573+
574+
match thisTyconRef with
575+
| None -> ()
576+
| Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem)
577+
| Some None -> yield Choice2Of2 ilExtMem ]
578+
else
579+
[]
580+
else
581+
if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass then
582+
let pri = NextExtensionMethodPriority()
583+
let ty = generalizedTyconRef g tcrefOfStaticClass
584+
let minfos = GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty
585+
586+
[ for minfo in minfos do
587+
if IsMethInfoPlainCSharpStyleExtensionMember g m true minfo then
588+
let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri)
589+
// The results are indexed by the TyconRef of the first 'this' argument, if any.
590+
// So we need to go and crack the type of the 'this' argument.
591+
//
592+
// This is convoluted because we only need the ILTypeRef of the first argument, and we don't
593+
// want to read any other metadata as it can trigger missing-assembly errors. It turns out ImportILTypeRef
594+
// is less eager in reading metadata than GetParamTypes.
595+
//
596+
// We don't use the index for the IL extension method for tuple of F# function types (e.g. if extension
597+
// methods for tuple occur in C# code)
598+
let thisTyconRef =
599+
try
600+
let rs =
601+
match metadataOfTycon tcrefOfStaticClass.Deref, minfo with
602+
| ILTypeMetadata (TILObjectReprData(scoref, _, _)), ILMeth(_, ILMethInfo(_, _, _, ilMethod, _), _) ->
603+
match ilMethod.ParameterTypes with
604+
| firstTy :: _ ->
605+
match firstTy with
606+
| ILType.Boxed tspec | ILType.Value tspec ->
607+
let tref = (tspec |> rescopeILTypeSpec scoref).TypeRef
608+
if Import.CanImportILTypeRef amap m tref then
609+
let tcref = tref |> Import.ImportILTypeRef amap m
610+
if isCompiledTupleTyconRef g tcref || tyconRefEq g tcref g.fastFunc_tcr then None
611+
else Some tcref
612+
else None
613+
| _ -> None
614+
| _ -> None
615+
| _ ->
616+
// The results are indexed by the TyconRef of the first 'this' argument, if any.
617+
// So we need to go and crack the type of the 'this' argument.
618+
let thisTy = minfo.GetParamTypes(amap, m, generalizeTypars minfo.FormalMethodTypars).Head.Head
619+
match thisTy with
620+
| AppTy g (tcrefOfTypeExtended, _) when not (isByrefTy g thisTy) -> Some tcrefOfTypeExtended
621+
| _ -> None
622+
Some rs
623+
with e -> // Import of the ILType may fail, if so report the error and skip on
624+
errorRecovery e m
625+
None
626+
match thisTyconRef with
627+
| None -> ()
628+
| Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem)
629+
| Some None -> yield Choice2Of2 ilExtMem ]
630+
else
631+
[]
579632

580633
/// Query the declared properties of a type (including inherited properties)
581634
let IntrinsicPropInfosOfTypeInScope (infoReader: InfoReader) optFilter ad findFlag m ty =

0 commit comments

Comments
 (0)