未验证 提交 df393d08 编写于 作者: F Florian Verdonck 提交者: GitHub

Allow extension methods without type attribute. (#13839)

* Allow extension methods without type attribute.
* Add Extension attribute to type if any member has the attribute.
* Handle C# extensions as let bindings in a module.
* Add test for recursive types.
* Add tests for types in recursive modules.
* Only add attribute to module when module declaration has attribute.
* Add additional test.
* Add CSharp Extension Attribute Not Required as a Preview Language Feature
* Passing propper Fsharp.Core version to executed tests in legacy FsharpSuite
* Fix for tests that use NetFramework types (like winforms brushes etc.)
Co-authored-by: NEdgar Gonzalez <edgar.gonzalez@fundourselves.com>
Co-authored-by: NTomas Grosup <tomasgrosup@microsoft.com>
Co-authored-by: NVlad Zarytovskii <vzaritovsky@hotmail.com>
上级 4ffb1ccb
...@@ -969,6 +969,20 @@ module MutRecBindingChecking = ...@@ -969,6 +969,20 @@ module MutRecBindingChecking =
| rest -> rest | rest -> rest
let prelimRecValues = [ for x in defnAs do match x with Phase2AMember bind -> yield bind.RecBindingInfo.Val | _ -> () ] let prelimRecValues = [ for x in defnAs do match x with Phase2AMember bind -> yield bind.RecBindingInfo.Val | _ -> () ]
let tyconOpt =
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
tyconOpt
|> Option.map (fun tycon ->
tryAddExtensionAttributeIfNotAlreadyPresent
(fun tryFindExtensionAttribute ->
tycon.MembersOfFSharpTyconSorted
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
)
tycon
)
else
tyconOpt
let defnAs = MutRecShape.Tycon(TyconBindingsPhase2A(tyconOpt, declKind, prelimRecValues, tcref, copyOfTyconTypars, thisTy, defnAs)) let defnAs = MutRecShape.Tycon(TyconBindingsPhase2A(tyconOpt, declKind, prelimRecValues, tcref, copyOfTyconTypars, thisTy, defnAs))
defnAs, (tpenv, recBindIdx, uncheckedBindsRev)) defnAs, (tpenv, recBindIdx, uncheckedBindsRev))
...@@ -4228,6 +4242,50 @@ module TcDeclarations = ...@@ -4228,6 +4242,50 @@ module TcDeclarations =
// Check the members and decide on representations for types with implicit constructors. // Check the members and decide on representations for types with implicit constructors.
let withBindings, envFinal = TcMutRecDefns_Phase2 cenv envInitial m scopem mutRecNSInfo envMutRecPrelimWithReprs withEnvs isMutRec let withBindings, envFinal = TcMutRecDefns_Phase2 cenv envInitial m scopem mutRecNSInfo envMutRecPrelimWithReprs withEnvs isMutRec
let withBindings =
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
// If any of the types has a member with the System.Runtime.CompilerServices.ExtensionAttribute,
// or a recursive module has a binding with the System.Runtime.CompilerServices.ExtensionAttribute,
// that type/recursive module should also received the ExtensionAttribute if it is not yet present.
// Example:
// open System.Runtime.CompilerServices
//
// type Int32Extensions =
// [<Extension>]
// static member PlusOne (a:int) : int = a + 1
//
// or
//
// module rec Foo
//
// [<System.Runtime.CompilerServices.Extension>]
// let PlusOne (a:int) = a + 1
withBindings
|> List.map (function
| MutRecShape.Tycon (Some tycon, bindings) ->
let tycon =
tryAddExtensionAttributeIfNotAlreadyPresent
(fun tryFindExtensionAttribute ->
tycon.MembersOfFSharpTyconSorted
|> Seq.tryPick (fun m -> tryFindExtensionAttribute m.Attribs)
)
tycon
MutRecShape.Tycon (Some tycon, bindings)
| MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes) ->
let entity =
tryAddExtensionAttributeIfNotAlreadyPresent
(fun tryFindExtensionAttribute ->
moduleOrNamespaceType.Value.AllValsAndMembers
|> Seq.filter(fun v -> v.IsModuleBinding)
|> Seq.tryPick (fun v -> tryFindExtensionAttribute v.Attribs)
)
entity
MutRecShape.Module ((MutRecDefnsPhase2DataForModule(moduleOrNamespaceType, entity), env), shapes)
| shape -> shape)
else
withBindings
// Generate the hash/compare/equality bindings for all tycons. // Generate the hash/compare/equality bindings for all tycons.
// //
// Note: generating these bindings must come after generating the members, since some in the case of structs some fields // Note: generating these bindings must come after generating the members, since some in the case of structs some fields
...@@ -4766,6 +4824,31 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem ...@@ -4766,6 +4824,31 @@ let rec TcModuleOrNamespaceElementNonMutRec (cenv: cenv) parent typeNames scopem
// Get the inferred type of the decls and record it in the modul. // Get the inferred type of the decls and record it in the modul.
moduleEntity.entity_modul_type <- MaybeLazy.Strict moduleTyAcc.Value moduleEntity.entity_modul_type <- MaybeLazy.Strict moduleTyAcc.Value
let moduleEntity =
if cenv.g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
// If any of the let bindings inside the module has the System.Runtime.CompilerServices.ExtensionAttribute,
// that module should also received the ExtensionAttribute if it is not yet present.
// Example:
// module Foo
//
//[<System.Runtime.CompilerServices.Extension>]
//let PlusOne (a:int) = a + 1
tryAddExtensionAttributeIfNotAlreadyPresent
(fun tryFindExtensionAttribute ->
match moduleContents with
| ModuleOrNamespaceContents.TMDefs(defs) ->
defs
|> Seq.tryPick (function
| ModuleOrNamespaceContents.TMDefLet (Binding.TBind(var = v),_) ->
tryFindExtensionAttribute v.Attribs
| _ -> None)
| _ -> None
)
moduleEntity
else
moduleEntity
let moduleDef = TMDefRec(false, [], [], [ModuleOrNamespaceBinding.Module(moduleEntity, moduleContents)], m) let moduleDef = TMDefRec(false, [], [], [ModuleOrNamespaceBinding.Module(moduleEntity, moduleContents)], m)
PublishModuleDefn cenv env moduleEntity PublishModuleDefn cenv env moduleEntity
......
...@@ -530,14 +530,18 @@ let IsMethInfoPlainCSharpStyleExtensionMember g m isEnclExtTy (minfo: MethInfo) ...@@ -530,14 +530,18 @@ let IsMethInfoPlainCSharpStyleExtensionMember g m isEnclExtTy (minfo: MethInfo)
/// Get the info for all the .NET-style extension members listed as static members in the type. /// Get the info for all the .NET-style extension members listed as static members in the type.
let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.ImportMap) m (tcrefOfStaticClass: TyconRef) = let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.ImportMap) m (tcrefOfStaticClass: TyconRef) =
let g = amap.g let g = amap.g
if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass then if g.langVersion.SupportsFeature(LanguageFeature.CSharpExtensionAttributeNotRequired) then
let pri = NextExtensionMethodPriority()
let ty = generalizedTyconRef g tcrefOfStaticClass let ty = generalizedTyconRef g tcrefOfStaticClass
let minfos =
GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty
|> List.filter (IsMethInfoPlainCSharpStyleExtensionMember g m true)
let minfos = GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass || not minfos.IsEmpty then
[ for minfo in minfos do let pri = NextExtensionMethodPriority()
if IsMethInfoPlainCSharpStyleExtensionMember g m true minfo then
[ for minfo in minfos do
let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri) let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri)
// The results are indexed by the TyconRef of the first 'this' argument, if any. // The results are indexed by the TyconRef of the first 'this' argument, if any.
...@@ -584,9 +588,60 @@ let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.Impor ...@@ -584,9 +588,60 @@ let private GetCSharpStyleIndexedExtensionMembersForTyconRef (amap: Import.Impor
| None -> () | None -> ()
| Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem) | Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem)
| Some None -> yield Choice2Of2 ilExtMem ] | Some None -> yield Choice2Of2 ilExtMem ]
else
[]
else else
[] if IsTyconRefUsedForCSharpStyleExtensionMembers g m tcrefOfStaticClass then
let pri = NextExtensionMethodPriority()
let ty = generalizedTyconRef g tcrefOfStaticClass
let minfos = GetImmediateIntrinsicMethInfosOfType (None, AccessorDomain.AccessibleFromSomeFSharpCode) g amap m ty
[ for minfo in minfos do
if IsMethInfoPlainCSharpStyleExtensionMember g m true minfo then
let ilExtMem = ILExtMem (tcrefOfStaticClass, minfo, pri)
// The results are indexed by the TyconRef of the first 'this' argument, if any.
// So we need to go and crack the type of the 'this' argument.
//
// This is convoluted because we only need the ILTypeRef of the first argument, and we don't
// want to read any other metadata as it can trigger missing-assembly errors. It turns out ImportILTypeRef
// is less eager in reading metadata than GetParamTypes.
//
// We don't use the index for the IL extension method for tuple of F# function types (e.g. if extension
// methods for tuple occur in C# code)
let thisTyconRef =
try
let rs =
match metadataOfTycon tcrefOfStaticClass.Deref, minfo with
| ILTypeMetadata (TILObjectReprData(scoref, _, _)), ILMeth(_, ILMethInfo(_, _, _, ilMethod, _), _) ->
match ilMethod.ParameterTypes with
| firstTy :: _ ->
match firstTy with
| ILType.Boxed tspec | ILType.Value tspec ->
let tref = (tspec |> rescopeILTypeSpec scoref).TypeRef
if Import.CanImportILTypeRef amap m tref then
let tcref = tref |> Import.ImportILTypeRef amap m
if isCompiledTupleTyconRef g tcref || tyconRefEq g tcref g.fastFunc_tcr then None
else Some tcref
else None
| _ -> None
| _ -> None
| _ ->
// The results are indexed by the TyconRef of the first 'this' argument, if any.
// So we need to go and crack the type of the 'this' argument.
let thisTy = minfo.GetParamTypes(amap, m, generalizeTypars minfo.FormalMethodTypars).Head.Head
match thisTy with
| AppTy g (tcrefOfTypeExtended, _) when not (isByrefTy g thisTy) -> Some tcrefOfTypeExtended
| _ -> None
Some rs
with e -> // Import of the ILType may fail, if so report the error and skip on
errorRecovery e m
None
match thisTyconRef with
| None -> ()
| Some (Some tcref) -> yield Choice1Of2(tcref, ilExtMem)
| Some None -> yield Choice2Of2 ilExtMem ]
else
[]
/// Query the declared properties of a type (including inherited properties) /// Query the declared properties of a type (including inherited properties)
let IntrinsicPropInfosOfTypeInScope (infoReader: InfoReader) optFilter ad findFlag m ty = let IntrinsicPropInfosOfTypeInScope (infoReader: InfoReader) optFilter ad findFlag m ty =
......
...@@ -1560,6 +1560,7 @@ featureRequiredProperties,"support for required properties" ...@@ -1560,6 +1560,7 @@ featureRequiredProperties,"support for required properties"
featureInitProperties,"support for consuming init properties" featureInitProperties,"support for consuming init properties"
featureLowercaseDUWhenRequireQualifiedAccess,"Allow lowercase DU when RequireQualifiedAccess attribute" featureLowercaseDUWhenRequireQualifiedAccess,"Allow lowercase DU when RequireQualifiedAccess attribute"
featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allowed for union case that takes no data." featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allowed for union case that takes no data."
featureCSharpExtensionAttributeNotRequired,"Allow implicit Extension attribute on declaring types, modules"
3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'"
3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." 3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." 3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation."
......
...@@ -55,6 +55,7 @@ type LanguageFeature = ...@@ -55,6 +55,7 @@ type LanguageFeature =
| InterfacesWithAbstractStaticMembers | InterfacesWithAbstractStaticMembers
| SelfTypeConstraints | SelfTypeConstraints
| MatchNotAllowedForUnionCaseWithNoData | MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
/// LanguageVersion management /// LanguageVersion management
type LanguageVersion(versionText) = type LanguageVersion(versionText) =
...@@ -126,6 +127,8 @@ type LanguageVersion(versionText) = ...@@ -126,6 +127,8 @@ type LanguageVersion(versionText) =
// F# preview // F# preview
LanguageFeature.FromEndSlicing, previewVersion LanguageFeature.FromEndSlicing, previewVersion
LanguageFeature.MatchNotAllowedForUnionCaseWithNoData, previewVersion LanguageFeature.MatchNotAllowedForUnionCaseWithNoData, previewVersion
LanguageFeature.CSharpExtensionAttributeNotRequired, previewVersion
] ]
static let defaultLanguageVersion = LanguageVersion("default") static let defaultLanguageVersion = LanguageVersion("default")
...@@ -233,6 +236,7 @@ type LanguageVersion(versionText) = ...@@ -233,6 +236,7 @@ type LanguageVersion(versionText) =
| LanguageFeature.InterfacesWithAbstractStaticMembers -> FSComp.SR.featureInterfacesWithAbstractStaticMembers () | LanguageFeature.InterfacesWithAbstractStaticMembers -> FSComp.SR.featureInterfacesWithAbstractStaticMembers ()
| LanguageFeature.SelfTypeConstraints -> FSComp.SR.featureSelfTypeConstraints () | LanguageFeature.SelfTypeConstraints -> FSComp.SR.featureSelfTypeConstraints ()
| LanguageFeature.MatchNotAllowedForUnionCaseWithNoData -> FSComp.SR.featureMatchNotAllowedForUnionCaseWithNoData () | LanguageFeature.MatchNotAllowedForUnionCaseWithNoData -> FSComp.SR.featureMatchNotAllowedForUnionCaseWithNoData ()
| LanguageFeature.CSharpExtensionAttributeNotRequired -> FSComp.SR.featureCSharpExtensionAttributeNotRequired ()
/// Get a version string associated with the given feature. /// Get a version string associated with the given feature.
static member GetFeatureVersionString feature = static member GetFeatureVersionString feature =
......
...@@ -45,6 +45,7 @@ type LanguageFeature = ...@@ -45,6 +45,7 @@ type LanguageFeature =
| InterfacesWithAbstractStaticMembers | InterfacesWithAbstractStaticMembers
| SelfTypeConstraints | SelfTypeConstraints
| MatchNotAllowedForUnionCaseWithNoData | MatchNotAllowedForUnionCaseWithNoData
| CSharpExtensionAttributeNotRequired
/// LanguageVersion management /// LanguageVersion management
type LanguageVersion = type LanguageVersion =
......
...@@ -10410,4 +10410,22 @@ let (|EmptyModuleOrNamespaces|_|) (moduleOrNamespaceContents: ModuleOrNamespaceC ...@@ -10410,4 +10410,22 @@ let (|EmptyModuleOrNamespaces|_|) (moduleOrNamespaceContents: ModuleOrNamespaceC
Some emptyModuleOrNamespaces Some emptyModuleOrNamespaces
else else
None None
| _ -> None | _ -> None
\ No newline at end of file
let tryAddExtensionAttributeIfNotAlreadyPresent
(tryFindExtensionAttributeIn: (Attrib list -> Attrib option) -> Attrib option)
(entity: Entity)
: Entity
=
let tryFindExtensionAttribute (attribs: Attrib list): Attrib option =
List.tryFind
(fun (a: Attrib) ->
a.TyconRef.CompiledRepresentationForNamedType.BasicQualifiedName = "System.Runtime.CompilerServices.ExtensionAttribute")
attribs
if Option.isSome (tryFindExtensionAttribute entity.Attribs) then
entity
else
match tryFindExtensionAttributeIn tryFindExtensionAttribute with
| None -> entity
| Some extensionAttrib -> { entity with entity_attribs = extensionAttrib :: entity.Attribs }
...@@ -2687,3 +2687,7 @@ type TraitConstraintInfo with ...@@ -2687,3 +2687,7 @@ type TraitConstraintInfo with
/// This will match anything that does not have any types or bindings. /// This will match anything that does not have any types or bindings.
val (|EmptyModuleOrNamespaces|_|): val (|EmptyModuleOrNamespaces|_|):
moduleOrNamespaceContents: ModuleOrNamespaceContents -> (ModuleOrNamespace list) option moduleOrNamespaceContents: ModuleOrNamespaceContents -> (ModuleOrNamespace list) option
/// Add an System.Runtime.CompilerServices.ExtensionAttribute to the Entity if found via predicate and not already present.
val tryAddExtensionAttributeIfNotAlreadyPresent:
tryFindExtensionAttributeIn: ((Attrib list -> Attrib option) -> Attrib option) -> entity: Entity -> Entity
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">automatické generování vlastnosti Message pro deklarace exception</target> <target state="translated">automatické generování vlastnosti Message pro deklarace exception</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">využití člena výchozího rozhraní</target> <target state="translated">využití člena výchozího rozhraní</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">Automatische Generierung der Eigenschaft „Message“ für „exception“-Deklarationen</target> <target state="translated">Automatische Generierung der Eigenschaft „Message“ für „exception“-Deklarationen</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">standardmäßige Schnittstellenmembernutzung</target> <target state="translated">standardmäßige Schnittstellenmembernutzung</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">generación automática de la propiedad 'Message' para declaraciones 'exception'</target> <target state="translated">generación automática de la propiedad 'Message' para declaraciones 'exception'</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">consumo de miembros de interfaz predeterminados</target> <target state="translated">consumo de miembros de interfaz predeterminados</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">génération automatique de la propriété « Message » pour les déclarations « exception »</target> <target state="translated">génération automatique de la propriété « Message » pour les déclarations « exception »</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">consommation par défaut des membres d'interface</target> <target state="translated">consommation par défaut des membres d'interface</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">generazione automatica della proprietà 'Messaggio' per le dichiarazioni 'eccezione'</target> <target state="translated">generazione automatica della proprietà 'Messaggio' per le dichiarazioni 'eccezione'</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">utilizzo predefinito dei membri di interfaccia</target> <target state="translated">utilizzo predefinito dei membri di interfaccia</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">`exception` 宣言の `Message` プロパティの自動生成</target> <target state="translated">`exception` 宣言の `Message` プロパティの自動生成</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">既定のインターフェイス メンバーの消費</target> <target state="translated">既定のインターフェイス メンバーの消費</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">'exception' 선언에 대한 'Message' 속성 자동 생성</target> <target state="translated">'exception' 선언에 대한 'Message' 속성 자동 생성</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">기본 인터페이스 멤버 사용</target> <target state="translated">기본 인터페이스 멤버 사용</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">Automatyczne generowanie właściwości „Wiadomość“ dla deklaracji „Wyjątek“</target> <target state="translated">Automatyczne generowanie właściwości „Wiadomość“ dla deklaracji „Wyjątek“</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">domyślne użycie składowej interfejsu</target> <target state="translated">domyślne użycie składowej interfejsu</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">geração automática da propriedade 'Message' para declarações de 'exception'</target> <target state="translated">geração automática da propriedade 'Message' para declarações de 'exception'</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">consumo de membro da interface padrão</target> <target state="translated">consumo de membro da interface padrão</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">автоматическое создание свойства “Message” для объявлений “exception”</target> <target state="translated">автоматическое создание свойства “Message” для объявлений “exception”</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">использование элемента интерфейса по умолчанию</target> <target state="translated">использование элемента интерфейса по умолчанию</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">'exception' bildirimleri için 'Message' özelliğinin otomatik olarak oluşturulması</target> <target state="translated">'exception' bildirimleri için 'Message' özelliğinin otomatik olarak oluşturulması</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">varsayılan arabirim üyesi tüketimi</target> <target state="translated">varsayılan arabirim üyesi tüketimi</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">自动生成“异常”声明的“消息”属性</target> <target state="translated">自动生成“异常”声明的“消息”属性</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">默认接口成员消耗</target> <target state="translated">默认接口成员消耗</target>
......
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<target state="translated">自動產生 'exception' 宣告的 'Message' 屬性</target> <target state="translated">自動產生 'exception' 宣告的 'Message' 屬性</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="featureCSharpExtensionAttributeNotRequired">
<source>Allow implicit Extension attribute on declaring types, modules</source>
<target state="new">Allow implicit Extension attribute on declaring types, modules</target>
<note />
</trans-unit>
<trans-unit id="featureDefaultInterfaceMemberConsumption"> <trans-unit id="featureDefaultInterfaceMemberConsumption">
<source>default interface member consumption</source> <source>default interface member consumption</source>
<target state="translated">預設介面成員使用</target> <target state="translated">預設介面成員使用</target>
......
...@@ -174,6 +174,7 @@ ...@@ -174,6 +174,7 @@
<Compile Include="Language\ComputationExpressionTests.fs" /> <Compile Include="Language\ComputationExpressionTests.fs" />
<Compile Include="Language\CastingTests.fs" /> <Compile Include="Language\CastingTests.fs" />
<Compile Include="Language\NameofTests.fs" /> <Compile Include="Language\NameofTests.fs" />
<Compile Include="Language\ExtensionMethodTests.fs" />
<Compile Include="ConstraintSolver\PrimitiveConstraints.fs" /> <Compile Include="ConstraintSolver\PrimitiveConstraints.fs" />
<Compile Include="ConstraintSolver\MemberConstraints.fs" /> <Compile Include="ConstraintSolver\MemberConstraints.fs" />
<None Include="**\*.cs;**\*.fs;**\*.fsx;**\*.fsi" Exclude="@(Compile)"> <None Include="**\*.cs;**\*.fs;**\*.fsx;**\*.fsi" Exclude="@(Compile)">
......
namespace FSharp.Compiler.ComponentTests.Language
open FSharp.Test
open Xunit
open FSharp.Test.Compiler
module ExtensionMethodTests =
[<Fact>]
let ``Extension method with toplevel attribute on type`` () =
Fsx
"""
open System.Runtime.CompilerServices
[<Extension>]
type Foo =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
let f (b:int) = b.PlusOne()
"""
|> withLangVersionPreview
|> compile
|> shouldSucceed
[<Fact>]
let ``Extension method without toplevel attribute on type`` () =
Fsx
"""
open System.Runtime.CompilerServices
type Foo =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
let f (b:int) = b.PlusOne()
"""
|> withLangVersionPreview
|> compile
|> shouldSucceed
[<Fact>]
let ``Extension method without toplevel attribute on type lang version 7`` () =
Fsx
"""
open System.Runtime.CompilerServices
type Foo =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
let f (b:int) = b.PlusOne()
"""
|> withLangVersion70
|> compile
|> shouldFail
|> withDiagnostics [
(Error 39, Line 8, Col 19, Line 8, Col 26, "The type 'Int32' does not define the field, constructor or member 'PlusOne'.")
]
[<Fact>]
let ``Extension method without toplevel attribute on recursive type`` () =
Fsx
"""
open System.Runtime.CompilerServices
type Foo =
class
end
and Bar =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
let f (b:int) = b.PlusOne()
"""
|> withLangVersionPreview
|> compile
|> shouldSucceed
[<Fact>]
let ``F# CSharpStyleExtensionMethod consumed in C#`` () =
let fsharp =
FSharp
"""
module Hello
open System.Runtime.CompilerServices
type Foo =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp
"""
namespace Consumer
{
using static Hello.Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``F# lang version 7 CSharpStyleExtensionMethod consumed in C#`` () =
let fsharp =
FSharp
"""
module Hello
open System.Runtime.CompilerServices
type Foo =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
"""
|> withLangVersion70
|> withName "FSLib"
let csharp =
CSharp
"""
namespace Consumer
{
using static Hello.Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp
|> compile
|> shouldFail
|> withDiagnostics [
(Error 1061, Line 9, Col 25, Line 9, Col 32, "'int' does not contain a definition for 'PlusOne' and no accessible extension method 'PlusOne' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?)")
]
[<Fact>]
let ``F# CSharpStyleExtensionMethod in recursive type consumed in C#`` () =
let fsharp =
FSharp
"""
module Hello
open System.Runtime.CompilerServices
type Foo =
class
end
and Bar =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp
"""
namespace Consumer
{
using static Hello.Bar;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``F# CSharpStyleExtensionMethod defined in top level module with attribute consumed in C#`` () =
let fsharp =
FSharp
"""
namespace Hello
open System.Runtime.CompilerServices
[<Extension>]
module Foo =
[<Extension>]
let PlusOne (a:int) : int = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp
"""
namespace Consumer
{
using static Hello.Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``F# CSharpStyleExtensionMethod defined in top level module without attribute consumed in C#`` () =
let fsharp =
FSharp
"""
namespace Hello
open System.Runtime.CompilerServices
module Foo =
[<Extension>]
let PlusOne (a:int) : int = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp
"""
namespace Consumer
{
using static Hello.Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Toplevel named module with Extension attribute and top level let binding with Extension attribute`` () =
let fsharp =
FSharp """
[<System.Runtime.CompilerServices.Extension>]
module Foo
[<System.Runtime.CompilerServices.Extension>]
let PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Toplevel named module without Extension attribute and top level let binding with Extension attribute`` () =
let fsharp =
FSharp """
module Foo
[<System.Runtime.CompilerServices.Extension>]
let PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Recursive toplevel named module with Extension attribute and top level let binding with Extension attribute`` () =
let fsharp =
FSharp """
[<System.Runtime.CompilerServices.Extension>]
module rec Foo
[<System.Runtime.CompilerServices.Extension>]
let PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Recursive toplevel named module without Extension attribute and top level let binding with Extension attribute`` () =
let fsharp =
FSharp """
module rec Foo
[<System.Runtime.CompilerServices.Extension>]
let PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Foobar `` () =
let fsharp =
FSharp """
module rec Foo
[<System.Runtime.CompilerServices.Extension>]
type Bar =
[<System.Runtime.CompilerServices.Extension>]
static member PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo.Bar;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Recursive named module with type with CSharp style extension can be consumed in CSharp`` () =
let fsharp =
FSharp """
module rec Foo
type Bar =
[<System.Runtime.CompilerServices.Extension>]
static member PlusOne (a:int) = a + 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo.Bar;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``CSharp style extension method in F# type backed by a signature`` () =
let implementation =
SourceCodeFileKind.Create(
"Source.fs",
"""
module Foo
open System.Runtime.CompilerServices
type Bar =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
"""
)
let fsharp =
Fsi """
module Foo
open System.Runtime.CompilerServices
[<Class>]
type Bar =
[<Extension>]
static member PlusOne: a: int -> int
"""
|> withLangVersionPreview
|> withAdditionalSourceFile implementation
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo.Bar;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``CSharp style extension method in F# type backed by a signature in a recursive module`` () =
let implementation =
SourceCodeFileKind.Create(
"Source.fs",
"""
module rec Foo
open System.Runtime.CompilerServices
type Bar =
[<Extension>]
static member PlusOne (a:int) : int = a + 1
"""
)
let fsharp =
Fsi """
module rec Foo
open System.Runtime.CompilerServices
[<Class>]
type Bar =
[<Extension>]
static member PlusOne: a: int -> int
"""
|> withLangVersionPreview
|> withAdditionalSourceFile implementation
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo.Bar;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
[<Fact>]
let ``Multiple top level let binding with Extension attribute`` () =
let fsharp =
FSharp """
module Foo
[<System.Runtime.CompilerServices.Extension>]
let PlusOne (a:int) = a + 1
[<System.Runtime.CompilerServices.Extension>]
let MinusOne (a:int) = a - 1
"""
|> withLangVersionPreview
|> withName "FSLib"
let csharp =
CSharp """
namespace Consumer
{
using static Foo;
public class Class1
{
public Class1()
{
var meh = 1.PlusOne().MinusOne();
}
}
}
"""
|> withName "CSLib"
|> withReferences [ fsharp ]
csharp |> compile |> shouldSucceed
...@@ -392,7 +392,7 @@ let singleVersionedNegTest (cfg: TestConfig) version testname = ...@@ -392,7 +392,7 @@ let singleVersionedNegTest (cfg: TestConfig) version testname =
let cfg = { let cfg = {
cfg with cfg with
fsc_flags = sprintf "%s %s --preferreduilang:en-US --define:NEGATIVE" cfg.fsc_flags options fsc_flags = sprintf """%s %s --preferreduilang:en-US --define:NEGATIVE --simpleresolution /r:"%s" """ cfg.fsc_flags options cfg.FSCOREDLLPATH
fsi_flags = sprintf "%s --preferreduilang:en-US %s" cfg.fsi_flags options fsi_flags = sprintf "%s --preferreduilang:en-US %s" cfg.fsi_flags options
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册