diff --git a/eng/test-determinism.cmd b/eng/test-determinism.cmd index 863e8bd5ca3..972f85371e6 100644 --- a/eng/test-determinism.cmd +++ b/eng/test-determinism.cmd @@ -1,2 +1,2 @@ @echo off -powershell -noprofile -executionPolicy RemoteSigned -file "%~dp0\test-determinism.ps1" %* \ No newline at end of file +powershell -noprofile -executionPolicy RemoteSigned -file "%~dp0\test-determinism.ps1" %* diff --git a/src/fsharp/CompilerConfig.fs b/src/fsharp/CompilerConfig.fs index d2bfa520d4d..55f91bad380 100644 --- a/src/fsharp/CompilerConfig.fs +++ b/src/fsharp/CompilerConfig.fs @@ -328,6 +328,12 @@ type PackageManagerLine = static member StripDependencyManagerKey (packageKey: string) (line: string): string = line.Substring(packageKey.Length + 1).Trim() +[] +type MetadataAssemblyGeneration = + | None + | ReferenceOut of outputPath: string + | ReferenceOnly + [] type TcConfigBuilder = { @@ -441,6 +447,7 @@ type TcConfigBuilder = mutable emitTailcalls: bool mutable deterministic: bool mutable concurrentBuild: bool + mutable emitMetadataAssembly: MetadataAssemblyGeneration mutable preferredUiLang: string option mutable lcid: int option mutable productNameForBannerText: string @@ -654,6 +661,7 @@ type TcConfigBuilder = emitTailcalls = true deterministic = false concurrentBuild = true + emitMetadataAssembly = MetadataAssemblyGeneration.None preferredUiLang = None lcid = None productNameForBannerText = FSharpProductName @@ -1121,6 +1129,7 @@ type TcConfig private (data: TcConfigBuilder, validate: bool) = member x.emitTailcalls = data.emitTailcalls member x.deterministic = data.deterministic member x.concurrentBuild = data.concurrentBuild + member x.emitMetadataAssembly = data.emitMetadataAssembly member x.pathMap = data.pathMap member x.langVersion = data.langVersion member x.preferredUiLang = data.preferredUiLang diff --git a/src/fsharp/CompilerConfig.fsi b/src/fsharp/CompilerConfig.fsi index 1ba7344053b..7189312bad1 100644 --- a/src/fsharp/CompilerConfig.fsi +++ b/src/fsharp/CompilerConfig.fsi @@ -143,6 +143,16 @@ type PackageManagerLine = static member SetLinesAsProcessed: string -> Map -> Map static member StripDependencyManagerKey: string -> string -> string +[] +type MetadataAssemblyGeneration = + | None + /// Includes F# signature and optimization metadata as resources in the emitting assembly. + /// Implementation assembly will still be emitted normally, but will emit the reference assembly with the specified output path. + | ReferenceOut of outputPath: string + /// Includes F# signature and optimization metadata as resources in the emitting assembly. + /// Only emits the assembly as a reference assembly. + | ReferenceOnly + [] type TcConfigBuilder = { mutable primaryAssembly: PrimaryAssembly @@ -256,6 +266,7 @@ type TcConfigBuilder = mutable emitTailcalls: bool mutable deterministic: bool mutable concurrentBuild: bool + mutable emitMetadataAssembly: MetadataAssemblyGeneration mutable preferredUiLang: string option mutable lcid : int option mutable productNameForBannerText: string @@ -452,6 +463,7 @@ type TcConfig = member emitTailcalls: bool member deterministic: bool member concurrentBuild: bool + member emitMetadataAssembly: MetadataAssemblyGeneration member pathMap: PathMap member preferredUiLang: string option member optsOn : bool diff --git a/src/fsharp/CompilerOptions.fs b/src/fsharp/CompilerOptions.fs index 9367b12c216..cb153b2a25b 100644 --- a/src/fsharp/CompilerOptions.fs +++ b/src/fsharp/CompilerOptions.fs @@ -406,6 +406,23 @@ let SetTailcallSwitch (tcConfigB: TcConfigBuilder) switch = let SetDeterministicSwitch (tcConfigB: TcConfigBuilder) switch = tcConfigB.deterministic <- (switch = OptionSwitch.On) +let SetReferenceAssemblyOnlySwitch (tcConfigB: TcConfigBuilder) switch = + match tcConfigB.emitMetadataAssembly with + | MetadataAssemblyGeneration.None -> + tcConfigB.emitMetadataAssembly <- if (switch = OptionSwitch.On) then MetadataAssemblyGeneration.ReferenceOnly else MetadataAssemblyGeneration.None + | _ -> + error(Error(FSComp.SR.optsInvalidRefAssembly(), rangeCmdArgs)) + +let SetReferenceAssemblyOutSwitch (tcConfigB: TcConfigBuilder) outputPath = + match tcConfigB.emitMetadataAssembly with + | MetadataAssemblyGeneration.None -> + if FileSystem.IsInvalidPathShim outputPath then + error(Error(FSComp.SR.optsInvalidRefOut(), rangeCmdArgs)) + else + tcConfigB.emitMetadataAssembly <- MetadataAssemblyGeneration.ReferenceOut outputPath + | _ -> + error(Error(FSComp.SR.optsInvalidRefAssembly(), rangeCmdArgs)) + let AddPathMapping (tcConfigB: TcConfigBuilder) (pathPair: string) = match pathPair.Split([|'='|], 2) with | [| oldPrefix; newPrefix |] -> @@ -723,6 +740,16 @@ let outputFileFlagsFsc (tcConfigB: TcConfigBuilder) = ("nocopyfsharpcore", tagNone, OptionUnit (fun () -> tcConfigB.copyFSharpCore <- CopyFSharpCoreFlag.No), None, Some (FSComp.SR.optsNoCopyFsharpCore())) + + CompilerOption + ("refonly", tagNone, + OptionSwitch (SetReferenceAssemblyOnlySwitch tcConfigB), None, + Some (FSComp.SR.optsRefOnly())) + + CompilerOption + ("refout", tagFile, + OptionString (SetReferenceAssemblyOutSwitch tcConfigB), None, + Some (FSComp.SR.optsRefOut())) ] diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index c8fb201700c..d2fa66b0284 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -874,6 +874,8 @@ optsDebug,"Specify debugging type: full, portable, embedded, pdbonly. ('%s' is t optsOptimize,"Enable optimizations (Short form: -O)" optsTailcalls,"Enable or disable tailcalls" optsDeterministic,"Produce a deterministic assembly (including module version GUID and timestamp)" +optsRefOnly,"Produce a reference assembly, instead of a full assembly, as the primary output" +optsRefOut,"Produce a reference assembly with the specified file path." optsPathMap,"Maps physical paths to source path names output by the compiler" optsCrossoptimize,"Enable or disable cross-module optimizations" optsWarnaserrorPM,"Report all warnings as errors" @@ -1168,6 +1170,8 @@ fscTooManyErrors,"Exiting - too many errors" 2026,fscDeterministicDebugRequiresPortablePdb,"Deterministic builds only support portable PDBs (--debug:portable or --debug:embedded)" 2027,fscPathMapDebugRequiresPortablePdb,"--pathmap can only be used with portable PDBs (--debug:portable or --debug:embedded)" 2028,optsInvalidPathMapFormat,"Invalid path map. Mappings must be comma separated and of the format 'path=sourcePath'" +2029,optsInvalidRefOut,"Invalid reference assembly path'" +2030,optsInvalidRefAssembly,"Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together." 3000,etIllegalCharactersInNamespaceName,"Character '%s' is not allowed in provided namespace name '%s'" 3001,etNullOrEmptyMemberName,"The provided type '%s' returned a member with a null or empty member name" 3002,etNullMember,"The provided type '%s' returned a null member" diff --git a/src/fsharp/IlxGen.fs b/src/fsharp/IlxGen.fs index 876836a2adf..26977f2dbc2 100644 --- a/src/fsharp/IlxGen.fs +++ b/src/fsharp/IlxGen.fs @@ -4875,8 +4875,8 @@ and GenStructStateMachine cenv cgbuf eenvouter (res: LoweredStateMachine) sequel ILFieldDef(name = templateFld.LogicalName, fieldType = fty, attributes = enum 0, data = None, literalValue = None, offset = None, marshal = None, customAttrs = mkILCustomAttrs []) .WithAccess(access) .WithStatic(false) - yield fdef - + yield fdef + // Fields for captured variables for ilCloFreeVar in ilCloFreeVars do let access = ComputeMemberAccess false @@ -4901,6 +4901,7 @@ and GenStructStateMachine cenv cgbuf eenvouter (res: LoweredStateMachine) sequel nestedTypes = emptyILTypeDefs, implements = ilInterfaceTys, extends = Some super, + isKnownToBeAttribute = false, securityDecls = emptyILSecurityDecls) .WithSealed(true) .WithSpecialName(true) @@ -5137,6 +5138,7 @@ and GenClosureTypeDefs cenv (tref: ILTypeRef, ilGenParams, attrs, ilCloAllFreeVa nestedTypes=emptyILTypeDefs, implements = ilIntfTys, extends= Some ext, + isKnownToBeAttribute=false, securityDecls= emptyILSecurityDecls) .WithSealed(true) .WithSerializable(true) @@ -8298,6 +8300,8 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) = else ILTypeInit.BeforeField + let isKnownToBeAttribute = ExistsSameHeadTypeInHierarchy g cenv.amap m super g.mk_Attribute_ty + let tdef = mkILGenericClass (ilTypeName, access, ilGenParams, ilBaseTy, ilIntfTys, mkILMethods ilMethods, ilFields, emptyILTypeDefs, ilProperties, ilEvents, mkILCustomAttrs ilAttrs, typeDefTrigger) @@ -8310,7 +8314,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) = .WithSerializable(isSerializable) .WithAbstract(isAbstract) .WithImport(isComInteropTy g thisTy) - .With(methodImpls=mkILMethodImpls methodImpls) + .With(methodImpls=mkILMethodImpls methodImpls, isKnownToBeAttribute=isKnownToBeAttribute) let tdLayout, tdEncoding = match TryFindFSharpAttribute g g.attrib_StructLayoutAttribute tycon.Attribs with @@ -8423,6 +8427,7 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) = nestedTypes=emptyILTypeDefs, implements = ilIntfTys, extends= Some (if tycon.IsStructOrEnumTycon then g.iltyp_ValueType else g.ilg.typ_Object), + isKnownToBeAttribute=false, securityDecls= emptyILSecurityDecls) .WithLayout(layout) .WithSerializable(isSerializable) @@ -8847,4 +8852,4 @@ type IlxAssemblyGenerator(amap: ImportMap, tcGlobals: TcGlobals, tcVal: Constrai member _.ForceSetGeneratedValue (ctxt, v, value: obj) = SetGeneratedValue ctxt tcGlobals ilxGenEnv true v value /// Invert the compilation of the given value and return its current dynamic value and its compiled System.Type - member _.LookupGeneratedValue (ctxt, v) = LookupGeneratedValue amap ctxt ilxGenEnv v + member _.LookupGeneratedValue (ctxt, v) = LookupGeneratedValue amap ctxt ilxGenEnv v \ No newline at end of file diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs index 398d9b25287..fb8ad552268 100644 --- a/src/fsharp/ParseAndCheckInputs.fs +++ b/src/fsharp/ParseAndCheckInputs.fs @@ -36,6 +36,7 @@ open FSharp.Compiler.Text.Range open FSharp.Compiler.Xml open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps +open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TcGlobals let CanonicalizeFilename filename = @@ -827,6 +828,11 @@ let GetInitialTcState(m, ccuName, tcConfig: TcConfig, tcGlobals, tcImports: TcIm tcsImplicitOpenDeclarations = openDecls0 } +/// Dummy typed impl file that contains no definitions and is not used for emitting any kind of assembly. +let CreateEmptyDummyTypedImplFile qualNameOfFile sigTy = + let dummyExpr = ModuleOrNamespaceExprWithSig.ModuleOrNamespaceExprWithSig(sigTy, ModuleOrNamespaceExpr.TMDefs [], range.Zero) + TypedImplFile.TImplFile(qualNameOfFile, [], dummyExpr, false, false, StampMap [], Map.empty) + /// Typecheck a single file (or interactive entry into F# Interactive) let CheckOneInput ( @@ -906,10 +912,7 @@ let CheckOneInput // Typecheck the implementation file let typeCheckOne = if skipImplIfSigExists && hadSig then - let dummyExpr = ModuleOrNamespaceExprWithSig.ModuleOrNamespaceExprWithSig(rootSigOpt.Value, ModuleOrNamespaceExpr.TMDefs [], range.Zero) - let dummyImplFile = TypedImplFile.TImplFile(qualNameOfFile, [], dummyExpr, false, false, StampMap [], Map.empty) - - (EmptyTopAttrs, dummyImplFile, Unchecked.defaultof<_>, tcImplEnv, false) + (EmptyTopAttrs, CreateEmptyDummyTypedImplFile qualNameOfFile rootSigOpt.Value, Unchecked.defaultof<_>, tcImplEnv, false) |> Cancellable.ret else CheckOneImplFile (tcGlobals, tcState.tcsNiceNameGen, amap, tcState.tcsCcu, tcState.tcsImplicitOpenDeclarations, checkForErrors, conditionalDefines, tcSink, tcConfig.internalTestSpanStackReferring, tcImplEnv, rootSigOpt, file) diff --git a/src/fsharp/StaticLinking.fs b/src/fsharp/StaticLinking.fs index 1cab0afa206..6f4a2f7de53 100644 --- a/src/fsharp/StaticLinking.fs +++ b/src/fsharp/StaticLinking.fs @@ -357,6 +357,11 @@ let StaticLink (ctok, tcConfig: TcConfig, tcImports: TcImports, ilGlobals: ILGlo id else (fun ilxMainModule -> + match tcConfig.emitMetadataAssembly with + | MetadataAssemblyGeneration.None -> () + | _ -> + error(Error(FSComp.SR.optsInvalidRefAssembly(), rangeCmdArgs)) + ReportTime tcConfig "Find assembly references" let dependentILModules = FindDependentILModulesForStaticLinking (ctok, tcConfig, tcImports, ilGlobals, ilxMainModule) diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index aeaaa204c3f..94ee4b006f3 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -170,6 +170,8 @@ let tname_RuntimeFieldHandle = "System.RuntimeFieldHandle" [] let tname_CompilerGeneratedAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute" [] +let tname_ReferenceAssemblyAttribute = "System.Runtime.CompilerServices.ReferenceAssemblyAttribute" +[] let tname_DebuggableAttribute = "System.Diagnostics.DebuggableAttribute" [] let tname_AsyncCallback = "System.AsyncCallback" @@ -1197,7 +1199,8 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member val system_Nullable_tcref = v_nullable_tcr member val system_GenericIComparable_tcref = findSysTyconRef sys "IComparable`1" member val system_GenericIEquatable_tcref = findSysTyconRef sys "IEquatable`1" - member val mk_IComparable_ty = mkSysNonGenericTy sys "IComparable" + member val mk_IComparable_ty = mkSysNonGenericTy sys "IComparable" + member val mk_Attribute_ty = mkSysNonGenericTy sys "Attribute" member val system_LinqExpression_tcref = v_linqExpression_tcr member val mk_IStructuralComparable_ty = mkSysNonGenericTy sysCollections "IStructuralComparable" @@ -1245,7 +1248,8 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member val iltyp_ValueType = findSysILTypeRef tname_ValueType |> mkILNonGenericBoxedTy member val iltyp_RuntimeFieldHandle = findSysILTypeRef tname_RuntimeFieldHandle |> mkILNonGenericValueTy member val iltyp_RuntimeMethodHandle = findSysILTypeRef tname_RuntimeMethodHandle |> mkILNonGenericValueTy - member val iltyp_RuntimeTypeHandle = findSysILTypeRef tname_RuntimeTypeHandle |> mkILNonGenericValueTy + member val iltyp_RuntimeTypeHandle = findSysILTypeRef tname_RuntimeTypeHandle |> mkILNonGenericValueTy + member val iltyp_ReferenceAssemblyAttributeOpt = tryFindSysILTypeRef tname_ReferenceAssemblyAttribute |> Option.map mkILNonGenericBoxedTy member val attrib_AttributeUsageAttribute = findSysAttrib "System.AttributeUsageAttribute" @@ -1284,7 +1288,8 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member val attrib_CallerLineNumberAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerLineNumberAttribute" member val attrib_CallerFilePathAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerFilePathAttribute" member val attrib_CallerMemberNameAttribute = findSysAttrib "System.Runtime.CompilerServices.CallerMemberNameAttribute" - member val attrib_SkipLocalsInitAttribute = findSysAttrib "System.Runtime.CompilerServices.SkipLocalsInitAttribute" + member val attrib_ReferenceAssemblyAttribute = findSysAttrib "System.Runtime.CompilerServices.ReferenceAssemblyAttribute" + member val attrib_SkipLocalsInitAttribute = findSysAttrib "System.Runtime.CompilerServices.SkipLocalsInitAttribute" member val attribs_Unsupported = v_attribs_Unsupported member val attrib_ProjectionParameterAttribute = mk_MFCore_attrib "ProjectionParameterAttribute" diff --git a/src/fsharp/TypedTreeOps.fs b/src/fsharp/TypedTreeOps.fs index f56027587a5..20e6e201cbf 100644 --- a/src/fsharp/TypedTreeOps.fs +++ b/src/fsharp/TypedTreeOps.fs @@ -1555,7 +1555,7 @@ let tryRescopeEntity viewedCcu (entity: Entity) : ValueOption = | None -> ValueNone /// Try to create a ValRef suitable for accessing the given Val from another assembly -let tryRescopeVal viewedCcu (entityRemap: Remap) (vspec: Val) : ValueOption = +let tryRescopeVal viewedCcu (entityRemap: Remap) (vspec: Val) : ValueOption = match vspec.PublicPath with | Some (ValPubPath(p, fullLinkageKey)) -> // The type information in the val linkage doesn't need to keep any information to trait solutions. @@ -2047,7 +2047,7 @@ let emptyFreeTyvars = { FreeTycons = emptyFreeTycons // The summary of values used as trait solutions FreeTraitSolutions = emptyFreeLocals - FreeTypars = emptyFreeTypars} + FreeTypars = emptyFreeTypars } let isEmptyFreeTyvars ftyvs = Zset.isEmpty ftyvs.FreeTypars && diff --git a/src/fsharp/TypedTreeOps.fsi b/src/fsharp/TypedTreeOps.fsi index cfcf6366ef0..c505e865c83 100755 --- a/src/fsharp/TypedTreeOps.fsi +++ b/src/fsharp/TypedTreeOps.fsi @@ -766,7 +766,7 @@ val emptyFreeLocals: FreeLocals val unionFreeLocals: FreeLocals -> FreeLocals -> FreeLocals -type FreeVarOptions +type FreeVarOptions val CollectLocalsNoCaching: FreeVarOptions diff --git a/src/fsharp/absil/il.fs b/src/fsharp/absil/il.fs index a5609d64bee..625728146bc 100644 --- a/src/fsharp/absil/il.fs +++ b/src/fsharp/absil/il.fs @@ -2112,12 +2112,12 @@ let convertInitSemantics (init: ILTypeInit) = [] type ILTypeDef(name: string, attributes: TypeAttributes, layout: ILTypeDefLayout, implements: ILTypes, genericParams: ILGenericParameterDefs, extends: ILType option, methods: ILMethodDefs, nestedTypes: ILTypeDefs, fields: ILFieldDefs, methodImpls: ILMethodImplDefs, - events: ILEventDefs, properties: ILPropertyDefs, securityDeclsStored: ILSecurityDeclsStored, customAttrsStored: ILAttributesStored, metadataIndex: int32) = + events: ILEventDefs, properties: ILPropertyDefs, isKnownToBeAttribute: bool, securityDeclsStored: ILSecurityDeclsStored, customAttrsStored: ILAttributesStored, metadataIndex: int32) = let mutable customAttrsStored = customAttrsStored - new (name, attributes, layout, implements, genericParams, extends, methods, nestedTypes, fields, methodImpls, events, properties, securityDecls, customAttrs) = - ILTypeDef (name, attributes, layout, implements, genericParams, extends, methods, nestedTypes, fields, methodImpls, events, properties, storeILSecurityDecls securityDecls, storeILCustomAttrs customAttrs, NoMetadataIdx) + new (name, attributes, layout, implements, genericParams, extends, methods, nestedTypes, fields, methodImpls, events, properties, isKnownToBeAttribute, securityDecls, customAttrs) = + ILTypeDef (name, attributes, layout, implements, genericParams, extends, methods, nestedTypes, fields, methodImpls, events, properties, isKnownToBeAttribute, storeILSecurityDecls securityDecls, storeILCustomAttrs customAttrs, NoMetadataIdx) member _.Name = name member _.Attributes = attributes @@ -2132,10 +2132,11 @@ type ILTypeDef(name: string, attributes: TypeAttributes, layout: ILTypeDefLayout member _.MethodImpls = methodImpls member _.Events = events member _.Properties = properties + member _.IsKnownToBeAttribute = isKnownToBeAttribute member _.CustomAttrsStored = customAttrsStored member _.MetadataIndex = metadataIndex - member x.With(?name, ?attributes, ?layout, ?implements, ?genericParams, ?extends, ?methods, ?nestedTypes, ?fields, ?methodImpls, ?events, ?properties, ?customAttrs, ?securityDecls) = + member x.With(?name, ?attributes, ?layout, ?implements, ?genericParams, ?extends, ?methods, ?nestedTypes, ?fields, ?methodImpls, ?events, ?properties, ?isKnownToBeAttribute, ?customAttrs, ?securityDecls) = ILTypeDef(name=defaultArg name x.Name, attributes=defaultArg attributes x.Attributes, layout=defaultArg layout x.Layout, @@ -2149,6 +2150,7 @@ type ILTypeDef(name: string, attributes: TypeAttributes, layout: ILTypeDefLayout methodImpls = defaultArg methodImpls x.MethodImpls, events = defaultArg events x.Events, properties = defaultArg properties x.Properties, + isKnownToBeAttribute = defaultArg isKnownToBeAttribute x.IsKnownToBeAttribute, customAttrs = defaultArg customAttrs x.CustomAttrs) member x.CustomAttrs = @@ -3355,6 +3357,7 @@ let mkILGenericClass (nm, access, genparams, extends, impl, methods, fields, nes methodImpls=emptyILMethodImpls, properties=props, events=events, + isKnownToBeAttribute=false, securityDecls=emptyILSecurityDecls) let mkRawDataValueTypeDef (iltyp_ValueType: ILType) (nm, size, pack) = @@ -3372,6 +3375,7 @@ let mkRawDataValueTypeDef (iltyp_ValueType: ILType) (nm, size, pack) = methodImpls=emptyILMethodImpls, properties=emptyILProperties, events=emptyILEvents, + isKnownToBeAttribute=false, securityDecls=emptyILSecurityDecls) diff --git a/src/fsharp/absil/il.fsi b/src/fsharp/absil/il.fsi index 71dd91fb38e..f1b516f7cde 100644 --- a/src/fsharp/absil/il.fsi +++ b/src/fsharp/absil/il.fsi @@ -792,10 +792,14 @@ type internal ILMethodBody = /// Member Access [] type ILMemberAccess = + /// Assembly - Indicates that the method is accessible to any class of this assembly. (internal) | Assembly | CompilerControlled + /// FamilyAndAssembly - Indicates that the method is accessible to members of this type and its derived types that are in _this assembly only_. (private protected) | FamilyAndAssembly + /// FamilyOrAssembly - Indicates that the method is accessible to derived classes anywhere, as well as to any class _in the assembly_. (protected internal) | FamilyOrAssembly + /// Family - Indicates that the method is accessible only to members of this class and its derived classes. (protected) | Family | Private | Public @@ -1315,12 +1319,12 @@ type ILTypeDef = internal new: name: string * attributes: TypeAttributes * layout: ILTypeDefLayout * implements: ILTypes * genericParams: ILGenericParameterDefs * extends: ILType option * methods: ILMethodDefs * nestedTypes: ILTypeDefs * fields: ILFieldDefs * methodImpls: ILMethodImplDefs * - events: ILEventDefs * properties: ILPropertyDefs * securityDeclsStored: ILSecurityDeclsStored * customAttrsStored: ILAttributesStored * metadataIndex: int32 -> ILTypeDef + events: ILEventDefs * properties: ILPropertyDefs * isKnownToBeAttribute: bool * securityDeclsStored: ILSecurityDeclsStored * customAttrsStored: ILAttributesStored * metadataIndex: int32 -> ILTypeDef /// Functional creation of a value, immediate new: name: string * attributes: TypeAttributes * layout: ILTypeDefLayout * implements: ILTypes * genericParams: ILGenericParameterDefs * extends: ILType option * methods: ILMethodDefs * nestedTypes: ILTypeDefs * fields: ILFieldDefs * methodImpls: ILMethodImplDefs * - events: ILEventDefs * properties: ILPropertyDefs * securityDecls: ILSecurityDecls * customAttrs: ILAttributes -> ILTypeDef + events: ILEventDefs * properties: ILPropertyDefs * isKnownToBeAttribute: bool * securityDecls: ILSecurityDecls * customAttrs: ILAttributes -> ILTypeDef member Name: string member Attributes: TypeAttributes @@ -1353,6 +1357,7 @@ type ILTypeDef = /// e.g. if they use SuppressUnmanagedCodeSecurityAttribute member HasSecurity: bool member Encoding: ILDefaultPInvokeEncoding + member IsKnownToBeAttribute: bool member internal WithAccess: ILTypeDefAccess -> ILTypeDef member internal WithNestedAccess: ILMemberAccess -> ILTypeDef @@ -1371,7 +1376,7 @@ type ILTypeDef = member With: ?name: string * ?attributes: TypeAttributes * ?layout: ILTypeDefLayout * ?implements: ILTypes * ?genericParams:ILGenericParameterDefs * ?extends:ILType option * ?methods:ILMethodDefs * ?nestedTypes:ILTypeDefs * ?fields: ILFieldDefs * ?methodImpls:ILMethodImplDefs * ?events:ILEventDefs * - ?properties:ILPropertyDefs * ?customAttrs:ILAttributes * ?securityDecls: ILSecurityDecls -> ILTypeDef + ?properties:ILPropertyDefs * ?isKnownToBeAttribute:bool * ?customAttrs:ILAttributes * ?securityDecls: ILSecurityDecls -> ILTypeDef /// Represents a prefix of information for ILTypeDef. /// diff --git a/src/fsharp/absil/ilread.fs b/src/fsharp/absil/ilread.fs index 156c0f90bec..8260f6de073 100644 --- a/src/fsharp/absil/ilread.fs +++ b/src/fsharp/absil/ilread.fs @@ -1741,6 +1741,7 @@ and typeDefReader ctxtH: ILTypeDefStored = methodImpls=mimpls, events= events, properties=props, + isKnownToBeAttribute=false, customAttrsStored=ctxt.customAttrsReader_TypeDef, metadataIndex=idx) ) diff --git a/src/fsharp/absil/ilwrite.fs b/src/fsharp/absil/ilwrite.fs index 69e8faf18f4..17d4dc7a5b1 100644 --- a/src/fsharp/absil/ilwrite.fs +++ b/src/fsharp/absil/ilwrite.fs @@ -564,6 +564,12 @@ type cenv = normalizeAssemblyRefs: ILAssemblyRef -> ILAssemblyRef + /// Indicates that the writing assembly will have an assembly-level attribute, System.Runtime.CompilerServices.InternalsVisibleToAttribute. + hasInternalsVisibleToAttrib: bool + + /// Indicates that the writing assembly will be a reference assembly. Method bodies will be replaced with a `throw null` if there are any. + referenceAssemblyOnly: bool + pdbImports: Dictionary } member cenv.GetTable (tab: TableName) = cenv.tables[tab.Index] @@ -1079,6 +1085,113 @@ let GetTypeAccessFlags access = | ILTypeDefAccess.Nested ILMemberAccess.FamilyOrAssembly -> 0x00000007 | ILTypeDefAccess.Nested ILMemberAccess.Assembly -> 0x00000005 +exception MethodDefNotFound +let FindMethodDefIdx cenv mdkey = + try cenv.methodDefIdxsByKey.GetTableEntry mdkey + with :? KeyNotFoundException -> + let typeNameOfIdx i = + match + (cenv.typeDefs.dict + |> Seq.fold (fun sofar kvp -> + let tkey2 = kvp.Key + let tidx2 = kvp.Value + if i = tidx2 then + if sofar = None then + Some tkey2 + else failwith "multiple type names map to index" + else sofar) None) with + | Some x -> x + | None -> raise MethodDefNotFound + let (TdKey (tenc, tname)) = typeNameOfIdx mdkey.TypeIdx + dprintn ("The local method '"+(String.concat "." (tenc@[tname]))+"'::'"+mdkey.Name+"' was referenced but not declared") + dprintn ("generic arity: "+string mdkey.GenericArity) + cenv.methodDefIdxsByKey.dict |> Seq.iter (fun (KeyValue(mdkey2, _)) -> + if mdkey2.TypeIdx = mdkey.TypeIdx && mdkey.Name = mdkey2.Name then + let (TdKey (tenc2, tname2)) = typeNameOfIdx mdkey2.TypeIdx + dprintn ("A method in '"+(String.concat "." (tenc2@[tname2]))+"' had the right name but the wrong signature:") + dprintn ("generic arity: "+string mdkey2.GenericArity) + dprintn (sprintf "mdkey2: %+A" mdkey2)) + raise MethodDefNotFound + +// -------------------------------------------------------------------- +// ILMethodRef --> ILMethodDef. +// +// Only successfully converts ILMethodRef's referring to +// methods in the module being emitted. +// -------------------------------------------------------------------- +let TryGetMethodRefAsMethodDefIdx cenv (mref: ILMethodRef) = + let tref = mref.DeclaringTypeRef + try + if not (isTypeRefLocal tref) then + Result.Error $"method referred to by method impl, event or property is not in a type defined in this module, method ref is %A{mref}" + else + let tidx = GetIdxForTypeDef cenv (TdKey(tref.Enclosing, tref.Name)) + let mdkey = MethodDefKey (cenv.ilg, tidx, mref.GenericArity, mref.Name, mref.ReturnType, mref.ArgTypes, mref.CallingConv.IsStatic) + let idx = FindMethodDefIdx cenv mdkey + Ok idx + with e -> + Result.Error $"Error in GetMethodRefAsMethodDefIdx for mref = %A{(mref.Name, tref.Name)}, error: %s{e.Message}" + +let canGenMethodDef (td: ILTypeDef) cenv (md: ILMethodDef) = + if not cenv.referenceAssemblyOnly then + true + // If the method is part of attribute type, generate get_* and set_* methods for it, consider the following case: + // [] + // type PublicWithInternalSetterPropertyAttribute() = + // inherit Attribute() + // member val internal Prop1 : int = 0 with get, set + // [] + // type ClassPublicWithAttributes() = class end + else if td.IsKnownToBeAttribute && md.IsSpecialName && (not md.IsConstructor) && (not md.IsClassInitializer) then + true + else + match md.Access with + | ILMemberAccess.Public -> true + // When emitting a reference assembly, do not emit methods that are private/protected/internal unless they are virtual/abstract or provide an explicit interface implementation. + | ILMemberAccess.Private | ILMemberAccess.Family | ILMemberAccess.Assembly | ILMemberAccess.FamilyOrAssembly + when md.IsVirtual || md.IsAbstract || md.IsNewSlot || md.IsFinal -> true + // When emitting a reference assembly, only generate internal methods if the assembly contains a System.Runtime.CompilerServices.InternalsVisibleToAttribute. + | ILMemberAccess.FamilyOrAssembly | ILMemberAccess.Assembly + when cenv.hasInternalsVisibleToAttrib -> true + | _ -> false + +let canGenFieldDef (td: ILTypeDef) cenv (fd: ILFieldDef) = + if not cenv.referenceAssemblyOnly then + true + // We want to explicitly generate fields for struct types and attributes, since they can be part of `unmanaged constraint`. + else if td.IsStruct || td.IsKnownToBeAttribute then + true + else + match fd.Access with + | ILMemberAccess.Public -> true + // When emitting a reference assembly, we only generate internal fields if the assembly contains a System.Runtime.CompilerServices.InternalsVisibleToAttribute. + | ILMemberAccess.FamilyOrAssembly | ILMemberAccess.Assembly + when cenv.hasInternalsVisibleToAttrib -> true + | _ -> false + +let canGenEventDef cenv (ev: ILEventDef) = + if not cenv.referenceAssemblyOnly then + true + else + // If we have GetMethod or SetMethod set (i.e. not None), try and see if we have MethodDefs for them. + // NOTE: They can be not-None and missing MethodDefs if we skip generating them for reference assembly in the earlier pass. + // Only generate property if we have at least getter or setter, otherwise, we skip. + [| ev.AddMethod; ev.RemoveMethod |] + |> Array.map (TryGetMethodRefAsMethodDefIdx cenv) + |> Array.exists (function | Ok _ -> true | _ -> false) + +let canGenPropertyDef cenv (prop: ILPropertyDef) = + if not cenv.referenceAssemblyOnly then + true + else + // If we have GetMethod or SetMethod set (i.e. not None), try and see if we have MethodDefs for them. + // NOTE: They can be not-None and missing MethodDefs if we skip generating them for reference assembly in the earlier pass. + // Only generate property if we have at least getter or setter, otherwise, we skip. + [| prop.GetMethod; prop.SetMethod |] + |> Array.choose id + |> Array.map (TryGetMethodRefAsMethodDefIdx cenv) + |> Array.exists (function | Ok _ -> true | _ -> false) + let rec GetTypeDefAsRow cenv env _enc (td: ILTypeDef) = let nselem, nelem = GetTypeNameAsElemPair cenv td.Name let flags = @@ -1113,32 +1226,35 @@ and GetTypeDefAsEventMapRow cenv tidx = and GetKeyForFieldDef tidx (fd: ILFieldDef) = FieldDefKey (tidx, fd.Name, fd.FieldType) -and GenFieldDefPass2 cenv tidx fd = - ignore (cenv.fieldDefs.AddUniqueEntry "field" (fun (fdkey: FieldDefKey) -> fdkey.Name) (GetKeyForFieldDef tidx fd)) +and GenFieldDefPass2 td cenv tidx fd = + if canGenFieldDef td cenv fd then + ignore (cenv.fieldDefs.AddUniqueEntry "field" (fun (fdkey: FieldDefKey) -> fdkey.Name) (GetKeyForFieldDef tidx fd)) and GetKeyForMethodDef cenv tidx (md: ILMethodDef) = MethodDefKey (cenv.ilg, tidx, md.GenericParams.Length, md.Name, md.Return.Type, md.ParameterTypes, md.CallingConv.IsStatic) -and GenMethodDefPass2 cenv tidx md = - let idx = - cenv.methodDefIdxsByKey.AddUniqueEntry - "method" - (fun (key: MethodDefKey) -> - dprintn "Duplicate in method table is:" - dprintn (" Type index: "+string key.TypeIdx) - dprintn (" Method name: "+key.Name) - dprintn (" Method arity (num generic params): "+string key.GenericArity) - key.Name - ) - (GetKeyForMethodDef cenv tidx md) - - cenv.methodDefIdxs[md] <- idx +and GenMethodDefPass2 td cenv tidx md = + if canGenMethodDef td cenv md then + let idx = + cenv.methodDefIdxsByKey.AddUniqueEntry + "method" + (fun (key: MethodDefKey) -> + dprintn "Duplicate in method table is:" + dprintn (" Type index: "+string key.TypeIdx) + dprintn (" Method name: "+key.Name) + dprintn (" Method arity (num generic params): "+string key.GenericArity) + key.Name + ) + (GetKeyForMethodDef cenv tidx md) + + cenv.methodDefIdxs[md] <- idx and GetKeyForPropertyDef tidx (x: ILPropertyDef) = PropKey (tidx, x.Name, x.PropertyType, x.Args) and GenPropertyDefPass2 cenv tidx x = - ignore (cenv.propertyDefs.AddUniqueEntry "property" (fun (PropKey (_, n, _, _)) -> n) (GetKeyForPropertyDef tidx x)) + if canGenPropertyDef cenv x then + ignore (cenv.propertyDefs.AddUniqueEntry "property" (fun (PropKey (_, n, _, _)) -> n) (GetKeyForPropertyDef tidx x)) and GetTypeAsImplementsRow cenv env tidx ty = let tdorTag, tdorRow = GetTypeAsTypeDefOrRef cenv env ty @@ -1153,38 +1269,42 @@ and GetKeyForEvent tidx (x: ILEventDef) = EventKey (tidx, x.Name) and GenEventDefPass2 cenv tidx x = - ignore (cenv.eventDefs.AddUniqueEntry "event" (fun (EventKey(_, b)) -> b) (GetKeyForEvent tidx x)) + if canGenEventDef cenv x then + ignore (cenv.eventDefs.AddUniqueEntry "event" (fun (EventKey(_, b)) -> b) (GetKeyForEvent tidx x)) and GenTypeDefPass2 pidx enc cenv (td: ILTypeDef) = try - let env = envForTypeDef td - let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) - let tidx2 = AddUnsharedRow cenv TableNames.TypeDef (GetTypeDefAsRow cenv env enc td) - if tidx <> tidx2 then failwith "index of typedef on second pass does not match index on first pass" - - // Add entries to auxiliary mapping tables, e.g. Nested, PropertyMap etc. - // Note Nested is organised differently to the others... - if not (isNil enc) then - AddUnsharedRow cenv TableNames.Nested - (UnsharedRow - [| SimpleIndex (TableNames.TypeDef, tidx) - SimpleIndex (TableNames.TypeDef, pidx) |]) |> ignore - let props = td.Properties.AsList() - if not (isNil props) then - AddUnsharedRow cenv TableNames.PropertyMap (GetTypeDefAsPropertyMapRow cenv tidx) |> ignore - let events = td.Events.AsList() - if not (isNil events) then - AddUnsharedRow cenv TableNames.EventMap (GetTypeDefAsEventMapRow cenv tidx) |> ignore - - // Now generate or assign index numbers for tables referenced by the maps. - // Don't yet generate contents of these tables - leave that to pass3, as - // code may need to embed these entries. - td.Implements |> List.iter (GenImplementsPass2 cenv env tidx) - props |> List.iter (GenPropertyDefPass2 cenv tidx) - events |> List.iter (GenEventDefPass2 cenv tidx) - td.Fields.AsList() |> List.iter (GenFieldDefPass2 cenv tidx) - td.Methods |> Seq.iter (GenMethodDefPass2 cenv tidx) - td.NestedTypes.AsList() |> GenTypeDefsPass2 tidx (enc@[td.Name]) cenv + let env = envForTypeDef td + let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) + let tidx2 = AddUnsharedRow cenv TableNames.TypeDef (GetTypeDefAsRow cenv env enc td) + if tidx <> tidx2 then failwith "index of typedef on second pass does not match index on first pass" + + // Add entries to auxiliary mapping tables, e.g. Nested, PropertyMap etc. + // Note Nested is organised differently to the others... + if not (isNil enc) then + AddUnsharedRow cenv TableNames.Nested + (UnsharedRow + [| SimpleIndex (TableNames.TypeDef, tidx) + SimpleIndex (TableNames.TypeDef, pidx) |]) |> ignore + + let props = td.Properties.AsList() + + if not (isNil props) then + AddUnsharedRow cenv TableNames.PropertyMap (GetTypeDefAsPropertyMapRow cenv tidx) |> ignore + + let events = td.Events.AsList() + if not (isNil events) then + AddUnsharedRow cenv TableNames.EventMap (GetTypeDefAsEventMapRow cenv tidx) |> ignore + + // Now generate or assign index numbers for tables referenced by the maps. + // Don't yet generate contents of these tables - leave that to pass3, as + // code may need to embed these entries. + td.Implements |> List.iter (GenImplementsPass2 cenv env tidx) + props |> List.iter (GenPropertyDefPass2 cenv tidx) + events |> List.iter (GenEventDefPass2 cenv tidx) + td.Fields.AsList() |> List.iter (GenFieldDefPass2 td cenv tidx) + td.Methods |> Seq.iter (GenMethodDefPass2 td cenv tidx) + td.NestedTypes.AsList() |> GenTypeDefsPass2 tidx (enc@[td.Name]) cenv with e -> failwith ("Error in pass2 for type "+td.Name+", error: "+e.Message) @@ -1194,36 +1314,6 @@ and GenTypeDefsPass2 pidx enc cenv tds = //===================================================================== // Pass 3 - write details of methods, fields, IL code, custom attrs etc. //===================================================================== - -exception MethodDefNotFound -let FindMethodDefIdx cenv mdkey = - try cenv.methodDefIdxsByKey.GetTableEntry mdkey - with :? KeyNotFoundException -> - let typeNameOfIdx i = - match - (cenv.typeDefs.dict - |> Seq.fold (fun sofar kvp -> - let tkey2 = kvp.Key - let tidx2 = kvp.Value - if i = tidx2 then - if sofar = None then - Some tkey2 - else failwith "multiple type names map to index" - else sofar) None) with - | Some x -> x - | None -> raise MethodDefNotFound - let (TdKey (tenc, tname)) = typeNameOfIdx mdkey.TypeIdx - dprintn ("The local method '"+(String.concat "." (tenc@[tname]))+"'::'"+mdkey.Name+"' was referenced but not declared") - dprintn ("generic arity: "+string mdkey.GenericArity) - cenv.methodDefIdxsByKey.dict |> Seq.iter (fun (KeyValue(mdkey2, _)) -> - if mdkey2.TypeIdx = mdkey.TypeIdx && mdkey.Name = mdkey2.Name then - let (TdKey (tenc2, tname2)) = typeNameOfIdx mdkey2.TypeIdx - dprintn ("A method in '"+(String.concat "." (tenc2@[tname2]))+"' had the right name but the wrong signature:") - dprintn ("generic arity: "+string mdkey2.GenericArity) - dprintn (sprintf "mdkey2: %+A" mdkey2)) - raise MethodDefNotFound - - let rec GetMethodDefIdx cenv md = cenv.methodDefIdxs[md] @@ -1236,23 +1326,12 @@ and FindFieldDefIdx cenv fdkey = and GetFieldDefAsFieldDefIdx cenv tidx fd = FindFieldDefIdx cenv (GetKeyForFieldDef tidx fd) -// -------------------------------------------------------------------- -// ILMethodRef --> ILMethodDef. -// -// Only successfully converts ILMethodRef's referring to -// methods in the module being emitted. -// -------------------------------------------------------------------- + let GetMethodRefAsMethodDefIdx cenv (mref: ILMethodRef) = - let tref = mref.DeclaringTypeRef - try - if not (isTypeRefLocal tref) then - failwithf "method referred to by method impl, event or property is not in a type defined in this module, method ref is %A" mref - let tidx = GetIdxForTypeDef cenv (TdKey(tref.Enclosing, tref.Name)) - let mdkey = MethodDefKey (cenv.ilg, tidx, mref.GenericArity, mref.Name, mref.ReturnType, mref.ArgTypes, mref.CallingConv.IsStatic) - FindMethodDefIdx cenv mdkey - with e -> - failwithf "Error in GetMethodRefAsMethodDefIdx for mref = %A, error: %s" (mref.Name, tref.Name) e.Message + match TryGetMethodRefAsMethodDefIdx cenv mref with + | Result.Error msg -> failwith msg + | Ok idx -> idx let rec MethodRefInfoAsMemberRefRow cenv env fenv (nm, ty, callconv, args, ret, varargs, genarity) = MemberRefRow(GetTypeAsMemberRefParent cenv env ty, @@ -2357,39 +2436,40 @@ let rec GetFieldDefAsFieldDefRow cenv env (fd: ILFieldDef) = and GetFieldDefSigAsBlobIdx cenv env fd = GetFieldDefTypeAsBlobIdx cenv env fd.FieldType -and GenFieldDefPass3 cenv env fd = - let fidx = AddUnsharedRow cenv TableNames.Field (GetFieldDefAsFieldDefRow cenv env fd) - GenCustomAttrsPass3Or4 cenv (hca_FieldDef, fidx) fd.CustomAttrs - // Write FieldRVA table - fixups into data section done later - match fd.Data with - | None -> () - | Some b -> - let offs = cenv.data.Position - cenv.data.EmitBytes b - AddUnsharedRow cenv TableNames.FieldRVA - (UnsharedRow [| Data (offs, false); SimpleIndex (TableNames.Field, fidx) |]) |> ignore - // Write FieldMarshal table - match fd.Marshal with - | None -> () - | Some ntyp -> - AddUnsharedRow cenv TableNames.FieldMarshal - (UnsharedRow [| HasFieldMarshal (hfm_FieldDef, fidx) - Blob (GetNativeTypeAsBlobIdx cenv ntyp) |]) |> ignore - // Write Content table - match fd.LiteralValue with - | None -> () - | Some i -> - AddUnsharedRow cenv TableNames.Constant - (UnsharedRow - [| GetFieldInitFlags i - HasConstant (hc_FieldDef, fidx) - Blob (GetFieldInitAsBlobIdx cenv i) |]) |> ignore - // Write FieldLayout table - match fd.Offset with - | None -> () - | Some offset -> - AddUnsharedRow cenv TableNames.FieldLayout - (UnsharedRow [| ULong offset; SimpleIndex (TableNames.Field, fidx) |]) |> ignore +and GenFieldDefPass3 td cenv env fd = + if canGenFieldDef td cenv fd then + let fidx = AddUnsharedRow cenv TableNames.Field (GetFieldDefAsFieldDefRow cenv env fd) + GenCustomAttrsPass3Or4 cenv (hca_FieldDef, fidx) fd.CustomAttrs + // Write FieldRVA table - fixups into data section done later + match fd.Data with + | None -> () + | Some b -> + let offs = cenv.data.Position + cenv.data.EmitBytes b + AddUnsharedRow cenv TableNames.FieldRVA + (UnsharedRow [| Data (offs, false); SimpleIndex (TableNames.Field, fidx) |]) |> ignore + // Write FieldMarshal table + match fd.Marshal with + | None -> () + | Some ntyp -> + AddUnsharedRow cenv TableNames.FieldMarshal + (UnsharedRow [| HasFieldMarshal (hfm_FieldDef, fidx) + Blob (GetNativeTypeAsBlobIdx cenv ntyp) |]) |> ignore + // Write Content table + match fd.LiteralValue with + | None -> () + | Some i -> + AddUnsharedRow cenv TableNames.Constant + (UnsharedRow + [| GetFieldInitFlags i + HasConstant (hc_FieldDef, fidx) + Blob (GetFieldInitAsBlobIdx cenv i) |]) |> ignore + // Write FieldLayout table + match fd.Offset with + | None -> () + | Some offset -> + AddUnsharedRow cenv TableNames.FieldLayout + (UnsharedRow [| ULong offset; SimpleIndex (TableNames.Field, fidx) |]) |> ignore // -------------------------------------------------------------------- @@ -2515,6 +2595,10 @@ let GetMethodDefSigAsBytes cenv env (mdef: ILMethodDef) = let GenMethodDefSigAsBlobIdx cenv env mdef = GetBytesAsBlobIdx cenv (GetMethodDefSigAsBytes cenv env mdef) +let ilMethodBodyThrowNull = + let ilCode = IL.buildILCode "" (Dictionary()) [|ILInstr.AI_ldnull; ILInstr.I_throw|] [] [] + mkILMethodBody(false, ILLocals.Empty, 0, ilCode, None, None) + let GenMethodDefAsRow cenv env midx (md: ILMethodDef) = let flags = md.Attributes @@ -2526,7 +2610,11 @@ let GenMethodDefAsRow cenv env midx (md: ILMethodDef) = let codeAddr = (match md.Body with | MethodBody.IL ilmbodyLazy -> - let ilmbody = ilmbodyLazy.Value + let ilmbody = + if cenv.referenceAssemblyOnly then + ilMethodBodyThrowNull + else + ilmbodyLazy.Value let addr = cenv.nextCodeAddr let localToken, code, seqpoints, rootScope = GenILMethodBody md.Name cenv env ilmbody @@ -2588,65 +2676,68 @@ let GenMethodImplPass3 cenv env _tgparams tidx mimpl = MethodDefOrRef (midxTag, midxRow) MethodDefOrRef (midx2Tag, midx2Row) |]) |> ignore -let GenMethodDefPass3 cenv env (md: ILMethodDef) = - let midx = GetMethodDefIdx cenv md - let idx2 = AddUnsharedRow cenv TableNames.Method (GenMethodDefAsRow cenv env midx md) - if midx <> idx2 then failwith "index of method def on pass 3 does not match index on pass 2" - GenReturnPass3 cenv md.Return - md.Parameters |> List.iteri (fun n param -> GenParamPass3 cenv env (n+1) param) - md.CustomAttrs |> GenCustomAttrsPass3Or4 cenv (hca_MethodDef, midx) - md.SecurityDecls.AsList() |> GenSecurityDeclsPass3 cenv (hds_MethodDef, midx) - md.GenericParams |> List.iteri (fun n gp -> GenGenericParamPass3 cenv env n (tomd_MethodDef, midx) gp) - match md.Body with - | MethodBody.PInvoke attrLazy -> - let attr = attrLazy.Value - let flags = - begin match attr.CallingConv with - | PInvokeCallingConvention.None -> 0x0000 - | PInvokeCallingConvention.Cdecl -> 0x0200 - | PInvokeCallingConvention.Stdcall -> 0x0300 - | PInvokeCallingConvention.Thiscall -> 0x0400 - | PInvokeCallingConvention.Fastcall -> 0x0500 - | PInvokeCallingConvention.WinApi -> 0x0100 - end ||| - begin match attr.CharEncoding with - | PInvokeCharEncoding.None -> 0x0000 - | PInvokeCharEncoding.Ansi -> 0x0002 - | PInvokeCharEncoding.Unicode -> 0x0004 - | PInvokeCharEncoding.Auto -> 0x0006 - end ||| - begin match attr.CharBestFit with - | PInvokeCharBestFit.UseAssembly -> 0x0000 - | PInvokeCharBestFit.Enabled -> 0x0010 - | PInvokeCharBestFit.Disabled -> 0x0020 - end ||| - begin match attr.ThrowOnUnmappableChar with - | PInvokeThrowOnUnmappableChar.UseAssembly -> 0x0000 - | PInvokeThrowOnUnmappableChar.Enabled -> 0x1000 - | PInvokeThrowOnUnmappableChar.Disabled -> 0x2000 - end ||| - (if attr.NoMangle then 0x0001 else 0x0000) ||| - (if attr.LastError then 0x0040 else 0x0000) - AddUnsharedRow cenv TableNames.ImplMap - (UnsharedRow - [| UShort (uint16 flags) - MemberForwarded (mf_MethodDef, midx) - StringE (GetStringHeapIdx cenv attr.Name) - SimpleIndex (TableNames.ModuleRef, GetModuleRefAsIdx cenv attr.Where) |]) |> ignore - | _ -> () +let GenMethodDefPass3 td cenv env (md: ILMethodDef) = + if canGenMethodDef td cenv md then + let midx = GetMethodDefIdx cenv md + let idx2 = AddUnsharedRow cenv TableNames.Method (GenMethodDefAsRow cenv env midx md) + if midx <> idx2 then failwith "index of method def on pass 3 does not match index on pass 2" + GenReturnPass3 cenv md.Return + md.Parameters |> List.iteri (fun n param -> GenParamPass3 cenv env (n+1) param) + md.CustomAttrs |> GenCustomAttrsPass3Or4 cenv (hca_MethodDef, midx) + md.SecurityDecls.AsList() |> GenSecurityDeclsPass3 cenv (hds_MethodDef, midx) + md.GenericParams |> List.iteri (fun n gp -> GenGenericParamPass3 cenv env n (tomd_MethodDef, midx) gp) + match md.Body with + | MethodBody.PInvoke attrLazy -> + let attr = attrLazy.Value + let flags = + begin match attr.CallingConv with + | PInvokeCallingConvention.None -> 0x0000 + | PInvokeCallingConvention.Cdecl -> 0x0200 + | PInvokeCallingConvention.Stdcall -> 0x0300 + | PInvokeCallingConvention.Thiscall -> 0x0400 + | PInvokeCallingConvention.Fastcall -> 0x0500 + | PInvokeCallingConvention.WinApi -> 0x0100 + end ||| + begin match attr.CharEncoding with + | PInvokeCharEncoding.None -> 0x0000 + | PInvokeCharEncoding.Ansi -> 0x0002 + | PInvokeCharEncoding.Unicode -> 0x0004 + | PInvokeCharEncoding.Auto -> 0x0006 + end ||| + begin match attr.CharBestFit with + | PInvokeCharBestFit.UseAssembly -> 0x0000 + | PInvokeCharBestFit.Enabled -> 0x0010 + | PInvokeCharBestFit.Disabled -> 0x0020 + end ||| + begin match attr.ThrowOnUnmappableChar with + | PInvokeThrowOnUnmappableChar.UseAssembly -> 0x0000 + | PInvokeThrowOnUnmappableChar.Enabled -> 0x1000 + | PInvokeThrowOnUnmappableChar.Disabled -> 0x2000 + end ||| + (if attr.NoMangle then 0x0001 else 0x0000) ||| + (if attr.LastError then 0x0040 else 0x0000) + AddUnsharedRow cenv TableNames.ImplMap + (UnsharedRow + [| UShort (uint16 flags) + MemberForwarded (mf_MethodDef, midx) + StringE (GetStringHeapIdx cenv attr.Name) + SimpleIndex (TableNames.ModuleRef, GetModuleRefAsIdx cenv attr.Where) |]) |> ignore + | _ -> () -let GenMethodDefPass4 cenv env md = - let midx = GetMethodDefIdx cenv md - List.iteri (fun n gp -> GenGenericParamPass4 cenv env n (tomd_MethodDef, midx) gp) md.GenericParams +let GenMethodDefPass4 td cenv env md = + if canGenMethodDef td cenv md then + let midx = GetMethodDefIdx cenv md + List.iteri (fun n gp -> GenGenericParamPass4 cenv env n (tomd_MethodDef, midx) gp) md.GenericParams let GenPropertyMethodSemanticsPass3 cenv pidx kind mref = - // REVIEW: why are we catching exceptions here? - let midx = try GetMethodRefAsMethodDefIdx cenv mref with MethodDefNotFound -> 1 - AddUnsharedRow cenv TableNames.MethodSemantics - (UnsharedRow - [| UShort (uint16 kind) - SimpleIndex (TableNames.Method, midx) - HasSemantics (hs_Property, pidx) |]) |> ignore + match TryGetMethodRefAsMethodDefIdx cenv mref with + | Ok midx -> + AddUnsharedRow cenv TableNames.MethodSemantics + (UnsharedRow + [| UShort (uint16 kind) + SimpleIndex (TableNames.Method, midx) + HasSemantics (hs_Property, pidx) |]) |> ignore + | _ -> () let rec GetPropertySigAsBlobIdx cenv env prop = GetBytesAsBlobIdx cenv (GetPropertySigAsBytes cenv env prop) @@ -2667,20 +2758,22 @@ and GetPropertyAsPropertyRow cenv env (prop: ILPropertyDef) = Blob (GetPropertySigAsBlobIdx cenv env prop) |] /// ILPropertyDef --> Property Row + MethodSemantics entries -and GenPropertyPass3 cenv env prop = - let pidx = AddUnsharedRow cenv TableNames.Property (GetPropertyAsPropertyRow cenv env prop) - prop.SetMethod |> Option.iter (GenPropertyMethodSemanticsPass3 cenv pidx 0x0001) - prop.GetMethod |> Option.iter (GenPropertyMethodSemanticsPass3 cenv pidx 0x0002) - // Write Constant table - match prop.Init with - | None -> () - | Some i -> - AddUnsharedRow cenv TableNames.Constant - (UnsharedRow - [| GetFieldInitFlags i - HasConstant (hc_Property, pidx) - Blob (GetFieldInitAsBlobIdx cenv i) |]) |> ignore - GenCustomAttrsPass3Or4 cenv (hca_Property, pidx) prop.CustomAttrs +and GenPropertyPass3 cenv env (prop: ILPropertyDef) = + if canGenPropertyDef cenv prop then + // REVIEW: We do double check here (via canGenerateProperty and GenPropertyMethodSemanticsPass3). + let pidx = AddUnsharedRow cenv TableNames.Property (GetPropertyAsPropertyRow cenv env prop) + prop.SetMethod |> Option.iter (GenPropertyMethodSemanticsPass3 cenv pidx 0x0001) + prop.GetMethod |> Option.iter (GenPropertyMethodSemanticsPass3 cenv pidx 0x0002) + // Write Constant table + match prop.Init with + | None -> () + | Some i -> + AddUnsharedRow cenv TableNames.Constant + (UnsharedRow + [| GetFieldInitFlags i + HasConstant (hc_Property, pidx) + Blob (GetFieldInitAsBlobIdx cenv i) |]) |> ignore + GenCustomAttrsPass3Or4 cenv (hca_Property, pidx) prop.CustomAttrs let rec GenEventMethodSemanticsPass3 cenv eidx kind mref = let addIdx = try GetMethodRefAsMethodDefIdx cenv mref with MethodDefNotFound -> 1 @@ -2700,12 +2793,13 @@ and GenEventAsEventRow cenv env (md: ILEventDef) = TypeDefOrRefOrSpec (tdorTag, tdorRow) |] and GenEventPass3 cenv env (md: ILEventDef) = - let eidx = AddUnsharedRow cenv TableNames.Event (GenEventAsEventRow cenv env md) - md.AddMethod |> GenEventMethodSemanticsPass3 cenv eidx 0x0008 - md.RemoveMethod |> GenEventMethodSemanticsPass3 cenv eidx 0x0010 - Option.iter (GenEventMethodSemanticsPass3 cenv eidx 0x0020) md.FireMethod - List.iter (GenEventMethodSemanticsPass3 cenv eidx 0x0004) md.OtherMethods - GenCustomAttrsPass3Or4 cenv (hca_Event, eidx) md.CustomAttrs + if canGenEventDef cenv md then + let eidx = AddUnsharedRow cenv TableNames.Event (GenEventAsEventRow cenv env md) + md.AddMethod |> GenEventMethodSemanticsPass3 cenv eidx 0x0008 + md.RemoveMethod |> GenEventMethodSemanticsPass3 cenv eidx 0x0010 + Option.iter (GenEventMethodSemanticsPass3 cenv eidx 0x0020) md.FireMethod + List.iter (GenEventMethodSemanticsPass3 cenv eidx 0x0004) md.OtherMethods + GenCustomAttrsPass3Or4 cenv (hca_Event, eidx) md.CustomAttrs // -------------------------------------------------------------------- @@ -2747,28 +2841,28 @@ and GenResourcePass3 cenv r = let rec GenTypeDefPass3 enc cenv (td: ILTypeDef) = try - let env = envForTypeDef td - let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) - td.Properties.AsList() |> List.iter (GenPropertyPass3 cenv env) - td.Events.AsList() |> List.iter (GenEventPass3 cenv env) - td.Fields.AsList() |> List.iter (GenFieldDefPass3 cenv env) - td.Methods |> Seq.iter (GenMethodDefPass3 cenv env) - td.MethodImpls.AsList() |> List.iter (GenMethodImplPass3 cenv env td.GenericParams.Length tidx) - // ClassLayout entry if needed - match td.Layout with - | ILTypeDefLayout.Auto -> () - | ILTypeDefLayout.Sequential layout | ILTypeDefLayout.Explicit layout -> - if Option.isSome layout.Pack || Option.isSome layout.Size then - AddUnsharedRow cenv TableNames.ClassLayout - (UnsharedRow - [| UShort (defaultArg layout.Pack (uint16 0x0)) - ULong (defaultArg layout.Size 0x0) - SimpleIndex (TableNames.TypeDef, tidx) |]) |> ignore - - td.SecurityDecls.AsList() |> GenSecurityDeclsPass3 cenv (hds_TypeDef, tidx) - td.CustomAttrs |> GenCustomAttrsPass3Or4 cenv (hca_TypeDef, tidx) - td.GenericParams |> List.iteri (fun n gp -> GenGenericParamPass3 cenv env n (tomd_TypeDef, tidx) gp) - td.NestedTypes.AsList() |> GenTypeDefsPass3 (enc@[td.Name]) cenv + let env = envForTypeDef td + let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) + td.Properties.AsList() |> List.iter (GenPropertyPass3 cenv env) + td.Events.AsList() |> List.iter (GenEventPass3 cenv env) + td.Fields.AsList() |> List.iter (GenFieldDefPass3 td cenv env) + td.Methods |> Seq.iter (GenMethodDefPass3 td cenv env) + td.MethodImpls.AsList() |> List.iter (GenMethodImplPass3 cenv env td.GenericParams.Length tidx) + // ClassLayout entry if needed + match td.Layout with + | ILTypeDefLayout.Auto -> () + | ILTypeDefLayout.Sequential layout | ILTypeDefLayout.Explicit layout -> + if Option.isSome layout.Pack || Option.isSome layout.Size then + AddUnsharedRow cenv TableNames.ClassLayout + (UnsharedRow + [| UShort (defaultArg layout.Pack (uint16 0x0)) + ULong (defaultArg layout.Size 0x0) + SimpleIndex (TableNames.TypeDef, tidx) |]) |> ignore + + td.SecurityDecls.AsList() |> GenSecurityDeclsPass3 cenv (hds_TypeDef, tidx) + td.CustomAttrs |> GenCustomAttrsPass3Or4 cenv (hca_TypeDef, tidx) + td.GenericParams |> List.iteri (fun n gp -> GenGenericParamPass3 cenv env n (tomd_TypeDef, tidx) gp) + td.NestedTypes.AsList() |> GenTypeDefsPass3 (enc@[td.Name]) cenv with e -> failwith ("Error in pass3 for type "+td.Name+", error: "+e.Message) reraise() @@ -2782,11 +2876,11 @@ and GenTypeDefsPass3 enc cenv tds = let rec GenTypeDefPass4 enc cenv (td: ILTypeDef) = try - let env = envForTypeDef td - let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) - td.Methods |> Seq.iter (GenMethodDefPass4 cenv env) - List.iteri (fun n gp -> GenGenericParamPass4 cenv env n (tomd_TypeDef, tidx) gp) td.GenericParams - GenTypeDefsPass4 (enc@[td.Name]) cenv (td.NestedTypes.AsList()) + let env = envForTypeDef td + let tidx = GetIdxForTypeDef cenv (TdKey(enc, td.Name)) + td.Methods |> Seq.iter (GenMethodDefPass4 td cenv env) + List.iteri (fun n gp -> GenGenericParamPass4 cenv env n (tomd_TypeDef, tidx) gp) td.GenericParams + GenTypeDefsPass4 (enc@[td.Name]) cenv (td.NestedTypes.AsList()) with e -> failwith ("Error in pass4 for type "+td.Name+", error: "+e.Message) reraise() @@ -2947,9 +3041,24 @@ let DataCapacity = 200 [] let ResourceCapacity = 200 -let generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg : ILGlobals, emitTailcalls, deterministic, showTimes) (m : ILModuleDef) cilStartAddress normalizeAssemblyRefs = +let generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg : ILGlobals, emitTailcalls, deterministic, showTimes, referenceAssemblyOnly, referenceAssemblyAttribOpt: ILAttribute option) (m : ILModuleDef) cilStartAddress normalizeAssemblyRefs = let isDll = m.IsDLL + let hasInternalsVisibleToAttrib = + (match m.Manifest with Some manifest -> manifest.CustomAttrs | None -> m.CustomAttrs).AsArray() + |> Array.exists (fun x -> x.Method.DeclaringType.TypeSpec.Name = "System.Runtime.CompilerServices.InternalsVisibleToAttribute") + + let m = + // Emit System.Runtime.CompilerServices.ReferenceAssemblyAttribute as an assembly-level attribute when generating a reference assembly. + // Useful for the runtime to know that the assembly is a reference assembly. + match referenceAssemblyAttribOpt with + | Some referenceAssemblyAttrib when referenceAssemblyOnly -> + { m with + CustomAttrsStored = + mkILCustomAttrsReader (fun _ -> Array.append [|referenceAssemblyAttrib|] (m.CustomAttrs.AsArray())) } + | _ -> + m + let tables = Array.init 64 (fun i -> if (i = TableNames.AssemblyRef.Index || @@ -2996,7 +3105,9 @@ let generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg : IL blobs= MetadataTable<_>.New("blobs", HashIdentity.Structural) strings= MetadataTable<_>.New("strings", EqualityComparer.Default) userStrings= MetadataTable<_>.New("user strings", EqualityComparer.Default) - normalizeAssemblyRefs = normalizeAssemblyRefs + normalizeAssemblyRefs = normalizeAssemblyRefs + hasInternalsVisibleToAttrib = hasInternalsVisibleToAttrib + referenceAssemblyOnly = referenceAssemblyOnly pdbImports = Dictionary<_, _>(HashIdentity.Reference) } // Now the main compilation step @@ -3098,8 +3209,7 @@ let TableCapacity = 20000 [] let MetadataCapacity = 500000 -let writeILMetadataAndCode (generatePdb, desiredMetadataVersion, ilg, emitTailcalls, deterministic, showTimes) modul cilStartAddress normalizeAssemblyRefs = - +let writeILMetadataAndCode (generatePdb, desiredMetadataVersion, ilg, emitTailcalls, deterministic, showTimes, referenceAssemblyOnly, referenceAssemblyAttribOpt) modul cilStartAddress normalizeAssemblyRefs = // When we know the real RVAs of the data section we fixup the references for the FieldRVA table. // These references are stored as offsets into the metadata we return from this function let requiredDataFixups = ref [] @@ -3107,7 +3217,7 @@ let writeILMetadataAndCode (generatePdb, desiredMetadataVersion, ilg, emitTailca let next = cilStartAddress let strings, userStrings, blobs, guids, tables, entryPointToken, code, requiredStringFixups, data, resources, pdbData, mappings = - generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg, emitTailcalls, deterministic, showTimes) modul cilStartAddress normalizeAssemblyRefs + generateIL requiredDataFixups (desiredMetadataVersion, generatePdb, ilg, emitTailcalls, deterministic, showTimes, referenceAssemblyOnly, referenceAssemblyAttribOpt) modul cilStartAddress normalizeAssemblyRefs reportTime showTimes "Generated Tables and Code" let tableSize (tab: TableName) = tables[tab.Index].Count @@ -3668,6 +3778,8 @@ let writeBinaryAux ( emitTailcalls, deterministic, showTimes, + referenceAssemblyOnly, + referenceAssemblyAttribOpt, pathMap, modul, normalizeAssemblyRefs) = @@ -3778,7 +3890,7 @@ let writeBinaryAux ( | None -> failwith "Expected mscorlib to have a version number" let entryPointToken, code, codePadding, metadata, data, resources, requiredDataFixups, pdbData, mappings, guidStart = - writeILMetadataAndCode ((pdbfile <> None), desiredMetadataVersion, ilg, emitTailcalls, deterministic, showTimes) modul next normalizeAssemblyRefs + writeILMetadataAndCode ((pdbfile <> None), desiredMetadataVersion, ilg, emitTailcalls, deterministic, showTimes, referenceAssemblyOnly, referenceAssemblyAttribOpt) modul next normalizeAssemblyRefs reportTime showTimes "Generated IL and metadata" let _codeChunk, next = chunk code.Length next @@ -4349,6 +4461,8 @@ let writeBinaryFiles (outfile, deterministic, showTimes, dumpDebugInfo, + referenceAssemblyOnly, + referenceAssemblyAttribOpt, pathMap, modul, normalizeAssemblyRefs) = @@ -4363,12 +4477,15 @@ let writeBinaryFiles (outfile, let pdbData, pdbInfoOpt, debugDirectoryChunk, debugDataChunk, debugChecksumPdbChunk, debugEmbeddedPdbChunk, debugDeterministicPdbChunk, textV2P, mappings = try - try + try writeBinaryAux( stream, ilg, pdbfile, signer, portablePDB, embeddedPDB, embedAllSource, embedSourceList, sourceLink, - checksumAlgorithm, emitTailcalls, deterministic, showTimes, pathMap, + checksumAlgorithm, emitTailcalls, deterministic, showTimes, + referenceAssemblyOnly, + referenceAssemblyAttribOpt, + pathMap, modul, normalizeAssemblyRefs) finally stream.Close() @@ -4385,7 +4502,7 @@ let writeBinaryFiles (outfile, let reopenOutput () = FileSystem.OpenFileForWriteShim(outfile, FileMode.Open, FileAccess.Write, FileShare.Read) - writePdb (dumpDebugInfo, + writePdb (dumpDebugInfo, showTimes, portablePDB, embeddedPDB, pdbfile, outfile, reopenOutput, false, signer, deterministic, pathMap, @@ -4420,7 +4537,7 @@ let writeBinaryInMemory ( portablePDB, embeddedPDB, embedAllSource, embedSourceList, sourceLink, checksumAlgorithm, emitTailcalls, - deterministic, showTimes, pathMap, modul, normalizeAssemblyRefs) + deterministic, showTimes, false, None, pathMap, modul, normalizeAssemblyRefs) let reopenOutput () = stream @@ -4434,7 +4551,7 @@ let writeBinaryInMemory ( debugDeterministicPdbChunk, textV2P) stream.Close() - + stream.ToArray(), pdbBytes @@ -4453,6 +4570,8 @@ type options = deterministic: bool showTimes: bool dumpDebugInfo: bool + referenceAssemblyOnly: bool + referenceAssemblyAttribOpt: ILAttribute option pathMap: PathMap } let WriteILBinaryFile (options: options, inputModule, normalizeAssemblyRefs) = @@ -4461,7 +4580,10 @@ let WriteILBinaryFile (options: options, inputModule, normalizeAssemblyRefs) = options.portablePDB, options.embeddedPDB,options.embedAllSource, options.embedSourceList, options.sourceLink, options.checksumAlgorithm, options.emitTailcalls, options.deterministic, options.showTimes, - options.dumpDebugInfo, options.pathMap, + options.dumpDebugInfo, + options.referenceAssemblyOnly, + options.referenceAssemblyAttribOpt, + options.pathMap, inputModule, normalizeAssemblyRefs) |> ignore diff --git a/src/fsharp/absil/ilwrite.fsi b/src/fsharp/absil/ilwrite.fsi index 2c1cab018b1..cb717d21cb4 100644 --- a/src/fsharp/absil/ilwrite.fsi +++ b/src/fsharp/absil/ilwrite.fsi @@ -23,6 +23,8 @@ type options = deterministic: bool showTimes: bool dumpDebugInfo: bool + referenceAssemblyOnly: bool + referenceAssemblyAttribOpt: ILAttribute option pathMap: PathMap } /// Write a binary to the file system. diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 0a635bf959b..449dd2eefb0 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -782,13 +782,6 @@ let main3(Args (ctok, tcConfig, tcImports, frameworkTcImports: TcImports, tcGlob errorRecoveryNoRange e exiter.Exit 1 - // Perform optimization - use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Optimize - - let optEnv0 = GetInitialOptimizationEnv (tcImports, tcGlobals) - - let importMap = tcImports.GetImportMap() - let metadataVersion = match tcConfig.metadataVersion with | Some v -> v @@ -797,17 +790,25 @@ let main3(Args (ctok, tcConfig, tcImports, frameworkTcImports: TcImports, tcGlob | Some ib -> ib.RawMetadata.TryGetILModuleDef().Value.MetadataVersion | _ -> "" - let optimizedImpls, optimizationData, _ = - ApplyAllOptimizations - (tcConfig, tcGlobals, LightweightTcValForUsingInBuildMethodCall tcGlobals, outfile, - importMap, false, optEnv0, generatedCcu, typedImplFiles) + let optimizedImpls, optDataResources = + // Perform optimization + use unwindBuildPhase = PushThreadBuildPhaseUntilUnwind BuildPhase.Optimize - AbortOnError(errorLogger, exiter) + let optEnv0 = GetInitialOptimizationEnv (tcImports, tcGlobals) + + let importMap = tcImports.GetImportMap() - // Encode the optimization data - ReportTime tcConfig "Encoding OptData" + let optimizedImpls, optimizationData, _ = + ApplyAllOptimizations + (tcConfig, tcGlobals, (LightweightTcValForUsingInBuildMethodCall tcGlobals), outfile, + importMap, false, optEnv0, generatedCcu, typedImplFiles) - let optDataResources = EncodeOptimizationData(tcGlobals, tcConfig, outfile, exportRemapping, (generatedCcu, optimizationData), false) + AbortOnError(errorLogger, exiter) + + // Encode the optimization data + ReportTime tcConfig ("Encoding OptData") + + optimizedImpls, EncodeOptimizationData(tcGlobals, tcConfig, outfile, exportRemapping, (generatedCcu, optimizationData), false) // Pass on only the minimum information required for the next phase Args (ctok, tcConfig, tcImports, tcGlobals, errorLogger, @@ -908,28 +909,71 @@ let main6 dynamicAssemblyCreator (Args (ctok, tcConfig, tcImports: TcImports, t match dynamicAssemblyCreator with | None -> try - try - ILBinaryWriter.WriteILBinaryFile - ({ ilg = tcGlobals.ilg - outfile = outfile - pdbfile = pdbfile - emitTailcalls = tcConfig.emitTailcalls - deterministic = tcConfig.deterministic - showTimes = tcConfig.showTimes - portablePDB = tcConfig.portablePDB - embeddedPDB = tcConfig.embeddedPDB - embedAllSource = tcConfig.embedAllSource - embedSourceList = tcConfig.embedSourceList - sourceLink = tcConfig.sourceLink - checksumAlgorithm = tcConfig.checksumAlgorithm - signer = GetStrongNameSigner signingInfo - dumpDebugInfo = tcConfig.dumpDebugInfo - pathMap = tcConfig.pathMap }, - ilxMainModule, - normalizeAssemblyRefs - ) - with Failure msg -> - error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs)) + match tcConfig.emitMetadataAssembly with + | MetadataAssemblyGeneration.None -> () + | _ -> + let outfile = + match tcConfig.emitMetadataAssembly with + | MetadataAssemblyGeneration.ReferenceOut outputPath -> outputPath + | _ -> outfile + let referenceAssemblyAttribOpt = + tcGlobals.iltyp_ReferenceAssemblyAttributeOpt + |> Option.map (fun ilTy -> + mkILCustomAttribute (ilTy.TypeRef, [], [], []) + ) + try + // We want to write no PDB info. + ILBinaryWriter.WriteILBinaryFile + ({ ilg = tcGlobals.ilg + outfile = outfile + pdbfile = None + emitTailcalls = tcConfig.emitTailcalls + deterministic = tcConfig.deterministic + showTimes = tcConfig.showTimes + portablePDB = false + embeddedPDB = false + embedAllSource = tcConfig.embedAllSource + embedSourceList = tcConfig.embedSourceList + sourceLink = tcConfig.sourceLink + checksumAlgorithm = tcConfig.checksumAlgorithm + signer = GetStrongNameSigner signingInfo + dumpDebugInfo = tcConfig.dumpDebugInfo + referenceAssemblyOnly = true + referenceAssemblyAttribOpt = referenceAssemblyAttribOpt + pathMap = tcConfig.pathMap }, + ilxMainModule, + normalizeAssemblyRefs + ) + with Failure msg -> + error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs)) + + match tcConfig.emitMetadataAssembly with + | MetadataAssemblyGeneration.ReferenceOnly -> () + | _ -> + try + ILBinaryWriter.WriteILBinaryFile + ({ ilg = tcGlobals.ilg + outfile = outfile + pdbfile = pdbfile + emitTailcalls = tcConfig.emitTailcalls + deterministic = tcConfig.deterministic + showTimes = tcConfig.showTimes + portablePDB = tcConfig.portablePDB + embeddedPDB = tcConfig.embeddedPDB + embedAllSource = tcConfig.embedAllSource + embedSourceList = tcConfig.embedSourceList + sourceLink = tcConfig.sourceLink + checksumAlgorithm = tcConfig.checksumAlgorithm + signer = GetStrongNameSigner signingInfo + dumpDebugInfo = tcConfig.dumpDebugInfo + referenceAssemblyOnly = false + referenceAssemblyAttribOpt = None + pathMap = tcConfig.pathMap }, + ilxMainModule, + normalizeAssemblyRefs + ) + with Failure msg -> + error(Error(FSComp.SR.fscProblemWritingBinary(outfile, msg), rangeCmdArgs)) with e -> errorRecoveryNoRange e exiter.Exit 1 diff --git a/src/fsharp/fsi/fsi.fs b/src/fsharp/fsi/fsi.fs index 2f330d55ec0..d2f4ceb0890 100644 --- a/src/fsharp/fsi/fsi.fs +++ b/src/fsharp/fsi/fsi.fs @@ -1424,6 +1424,8 @@ type internal FsiDynamicCompiler checksumAlgorithm = tcConfig.checksumAlgorithm signer = None dumpDebugInfo = tcConfig.dumpDebugInfo + referenceAssemblyOnly = false + referenceAssemblyAttribOpt = None pathMap = tcConfig.pathMap } let normalizeAssemblyRefs = id diff --git a/src/fsharp/ilx/EraseClosures.fs b/src/fsharp/ilx/EraseClosures.fs index 133c3d7c1b9..d89474e5b92 100644 --- a/src/fsharp/ilx/EraseClosures.fs +++ b/src/fsharp/ilx/EraseClosures.fs @@ -502,6 +502,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = methodImpls=emptyILMethodImpls, properties=emptyILProperties, events=emptyILEvents, + isKnownToBeAttribute=false, securityDecls=emptyILSecurityDecls) .WithSpecialName(false) .WithImport(false) @@ -598,6 +599,7 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo = methodImpls=emptyILMethodImpls, properties=emptyILProperties, events=emptyILEvents, + isKnownToBeAttribute=false, securityDecls=emptyILSecurityDecls) .WithHasSecurity(false) .WithSpecialName(false) diff --git a/src/fsharp/ilx/EraseUnions.fs b/src/fsharp/ilx/EraseUnions.fs index e215accc152..16fb91227a0 100644 --- a/src/fsharp/ilx/EraseUnions.fs +++ b/src/fsharp/ilx/EraseUnions.fs @@ -1088,6 +1088,7 @@ let mkClassUnionDef (addMethodGeneratedAttrs, addPropertyGeneratedAttrs, addProp methodImpls=emptyILMethodImpls, events=emptyILEvents, properties=emptyILProperties, + isKnownToBeAttribute=false, customAttrs= emptyILCustomAttrs) .WithNestedAccess(cud.UnionCasesAccessibility) .WithAbstract(true) diff --git a/src/fsharp/service/FSharpCheckerResults.fs b/src/fsharp/service/FSharpCheckerResults.fs index c097064a672..c48e15b94b2 100644 --- a/src/fsharp/service/FSharpCheckerResults.fs +++ b/src/fsharp/service/FSharpCheckerResults.fs @@ -15,6 +15,7 @@ open Internal.Utilities.Library open Internal.Utilities.Library.Extras open FSharp.Core.Printf open FSharp.Compiler +open FSharp.Compiler.Syntax open FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.AccessibilityLogic open FSharp.Compiler.CheckExpressions @@ -46,6 +47,10 @@ open FSharp.Compiler.Text.Position open FSharp.Compiler.Text.Range open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps +open FSharp.Compiler.AbstractIL +open System.Reflection.PortableExecutable +open FSharp.Compiler.CreateILModule +open FSharp.Compiler.IlxGen open FSharp.Compiler.BuildGraph open Internal.Utilities @@ -2228,7 +2233,7 @@ type FSharpCheckProjectResults keepAssemblyContents: bool, diagnostics: FSharpDiagnostic[], details:(TcGlobals * TcImports * CcuThunk * ModuleOrNamespaceType * Choice * - TopAttribs option * ILAssemblyRef * + TopAttribs option * (unit -> IRawFSharpAssemblyData option) * ILAssemblyRef * AccessorDomain * TypedImplFile list option * string[] * FSharpProjectOptions) option) = let getDetails() = @@ -2246,12 +2251,12 @@ type FSharpCheckProjectResults member _.HasCriticalErrors = details.IsNone member _.AssemblySignature = - let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, topAttribs, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() FSharpAssemblySignature(tcGlobals, thisCcu, ccuSig, tcImports, topAttribs, ccuSig) member _.TypedImplementationFiles = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let tcGlobals, tcImports, thisCcu, _ccuSig, _builderOrSymbolUses, _topAttribs, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, _ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2260,7 +2265,7 @@ type FSharpCheckProjectResults member info.AssemblyContents = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2269,7 +2274,7 @@ type FSharpCheckProjectResults member _.GetOptimizedAssemblyContents() = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" - let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, ccuSig, _builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() let mimpls = match tcAssemblyExpr with | None -> [] @@ -2289,7 +2294,7 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetUsesOfSymbol(symbol:FSharpSymbol, ?cancellationToken: CancellationToken) = - let _, _tcImports, _thisCcu, _ccuSig, builderOrSymbolUses, _topAttribs, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let _, _tcImports, _thisCcu, _ccuSig, builderOrSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() let results = match builderOrSymbolUses with @@ -2320,7 +2325,7 @@ type FSharpCheckProjectResults // Not, this does not have to be a SyncOp, it can be called from any thread member _.GetAllUsesOfAllSymbols(?cancellationToken: CancellationToken) = - let tcGlobals, tcImports, thisCcu, ccuSig, builderOrSymbolUses, _topAttribs, _ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, ccuSig, builderOrSymbolUses, _topAttribs, _ilAssemRef, _tcAssemblyData, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() let cenv = SymbolEnv(tcGlobals, thisCcu, Some ccuSig, tcImports) let tcSymbolUses = @@ -2351,18 +2356,18 @@ type FSharpCheckProjectResults yield FSharpSymbolUse(symbolUse.DisplayEnv, symbol, symbolUse.ItemWithInst.TyparInst, symbolUse.ItemOccurence, symbolUse.Range) |] member _.ProjectContext = - let tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _ilAssemRef, ad, _tcAssemblyExpr, _dependencyFiles, projectOptions = getDetails() + let tcGlobals, tcImports, thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, ad, _tcAssemblyExpr, _dependencyFiles, projectOptions = getDetails() let assemblies = tcImports.GetImportedAssemblies() |> List.map (fun x -> FSharpAssembly(tcGlobals, tcImports, x.FSharpViewOfMetadata)) FSharpProjectContext(thisCcu, assemblies, ad, projectOptions) member _.DependencyFiles = - let _tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _ilAssemRef, _ad, _tcAssemblyExpr, dependencyFiles, _projectOptions = getDetails() + let _tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, _ilAssemRef, _ad, _tcAssemblyExpr, dependencyFiles, _projectOptions = getDetails() dependencyFiles member _.AssemblyFullName = - let _tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() + let _tcGlobals, _tcImports, _thisCcu, _ccuSig, _tcSymbolUses, _topAttribs, _tcAssemblyData, ilAssemRef, _ad, _tcAssemblyExpr, _dependencyFiles, _projectOptions = getDetails() ilAssemRef.QualifiedName override _.ToString() = "FSharpCheckProjectResults(" + projectFileName + ")" @@ -2432,7 +2437,7 @@ type FsiInteractiveChecker(legacyReferenceResolver, FSharpCheckProjectResults (filename, Some tcConfig, keepAssemblyContents, errors, Some(tcGlobals, tcImports, tcFileInfo.ThisCcu, tcFileInfo.CcuSigForFile, - (Choice2Of2 tcFileInfo.ScopeSymbolUses), None, mkSimpleAssemblyRef "stdin", + (Choice2Of2 tcFileInfo.ScopeSymbolUses), None, (fun () -> None), mkSimpleAssemblyRef "stdin", tcState.TcEnvFromImpls.AccessRights, None, dependencyFiles, projectOptions)) diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi index 5e3ec0fea69..ecd7a6d5752 100644 --- a/src/fsharp/service/FSharpCheckerResults.fsi +++ b/src/fsharp/service/FSharpCheckerResults.fsi @@ -476,6 +476,7 @@ type public FSharpCheckProjectResults = ModuleOrNamespaceType * Choice * TopAttribs option * + (unit -> IRawFSharpAssemblyData option) * ILAssemblyRef * AccessorDomain * TypedImplFile list option * diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index c8f432eecea..ddaed5d4257 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -814,7 +814,7 @@ type BackgroundCompiler( | None -> return FSharpCheckProjectResults (options.ProjectFileName, None, keepAssemblyContents, creationDiags, None) | Some builder -> - let! tcProj, ilAssemRef, _, tcAssemblyExprOpt = builder.GetFullCheckResultsAndImplementationsForProject() + let! tcProj, ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt = builder.GetFullCheckResultsAndImplementationsForProject() let errorOptions = tcProj.TcConfig.errorSeverityOptions let fileName = DummyFileNameForRangesWithoutASpecificLocation @@ -829,6 +829,12 @@ type BackgroundCompiler( let diagnostics = [| yield! creationDiags; yield! DiagnosticHelpers.CreateDiagnostics (errorOptions, true, fileName, tcErrors, suggestNamesForErrors) |] + + let getAssemblyData() = + match tcAssemblyDataOpt with + | ProjectAssemblyDataResult.Available data -> Some data + | _ -> None + let results = FSharpCheckProjectResults (options.ProjectFileName, @@ -836,7 +842,7 @@ type BackgroundCompiler( keepAssemblyContents, diagnostics, Some(tcProj.TcGlobals, tcProj.TcImports, tcState.Ccu, tcState.CcuSig, - (Choice1Of2 builder), topAttribs, ilAssemRef, + (Choice1Of2 builder), topAttribs, getAssemblyData, ilAssemRef, tcEnvAtEnd.AccessRights, tcAssemblyExprOpt, Array.ofList tcDependencyFiles, options)) diff --git a/src/fsharp/symbols/Symbols.fs b/src/fsharp/symbols/Symbols.fs index 6ade8fd9dbd..dc65ad11541 100644 --- a/src/fsharp/symbols/Symbols.fs +++ b/src/fsharp/symbols/Symbols.fs @@ -33,18 +33,18 @@ type FSharpAccessibility(a:Accessibility, ?isProtected) = match x with | CompPath(ILScopeRef.Local, []) -> true | _ -> false - + let (|Public|Internal|Private|) (TAccess p) = match p with | [] -> Public - | _ when List.forall isInternalCompPath p -> Internal + | _ when List.forall isInternalCompPath p -> Internal | _ -> Private - member _.IsPublic = not isProtected && match a with TAccess [] -> true | _ -> false + member _.IsPublic = not isProtected && (match a with TAccess [] -> true | _ -> false) - member _.IsPrivate = not isProtected && match a with Private -> true | _ -> false + member _.IsPrivate = not isProtected && (match a with Private -> true | _ -> false) - member _.IsInternal = not isProtected && match a with Internal -> true | _ -> false + member _.IsInternal = not isProtected && (match a with Internal -> true | _ -> false) member _.IsProtected = isProtected diff --git a/src/fsharp/xlf/FSComp.txt.cs.xlf b/src/fsharp/xlf/FSComp.txt.cs.xlf index 603662589f4..da3cfd9c6ed 100644 --- a/src/fsharp/xlf/FSComp.txt.cs.xlf +++ b/src/fsharp/xlf/FSComp.txt.cs.xlf @@ -422,11 +422,31 @@ Vytiskněte odvozená rozhraní všech kompilovaných souborů do přidružených souborů podpisu. + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Zobrazte si povolené hodnoty verze jazyka a pak zadejte požadovanou verzi, například latest nebo preview. + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Podporované jazykové verze: diff --git a/src/fsharp/xlf/FSComp.txt.de.xlf b/src/fsharp/xlf/FSComp.txt.de.xlf index 38700d023c0..9481f35d0f6 100644 --- a/src/fsharp/xlf/FSComp.txt.de.xlf +++ b/src/fsharp/xlf/FSComp.txt.de.xlf @@ -422,11 +422,31 @@ Drucken der abgeleiteten Schnittstellen aller Dateien an zugehörige Signaturdateien + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Zeigen Sie die zulässigen Werte für die Sprachversion an. Geben Sie die Sprachversion als "latest" oder "preview" an. + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Unterstützte Sprachversionen: diff --git a/src/fsharp/xlf/FSComp.txt.es.xlf b/src/fsharp/xlf/FSComp.txt.es.xlf index f6cff0722b0..8d0c11b60e2 100644 --- a/src/fsharp/xlf/FSComp.txt.es.xlf +++ b/src/fsharp/xlf/FSComp.txt.es.xlf @@ -422,11 +422,31 @@ Imprimir las interfaces deducidas de todos los archivos de compilación en los archivos de signatura asociados + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Mostrar los valores permitidos para la versión de idioma, especificar la versión de idioma como "latest" "preview" + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Versiones de lenguaje admitidas: diff --git a/src/fsharp/xlf/FSComp.txt.fr.xlf b/src/fsharp/xlf/FSComp.txt.fr.xlf index 4fc68f7b7cd..98becf46792 100644 --- a/src/fsharp/xlf/FSComp.txt.fr.xlf +++ b/src/fsharp/xlf/FSComp.txt.fr.xlf @@ -422,11 +422,31 @@ Imprimer les interfaces inférées de tous les fichiers de compilation sur les fichiers de signature associés + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Afficher les valeurs autorisées pour la version du langage, spécifier la version du langage comme 'dernière' ou 'préversion' + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Versions linguistiques prises en charge : diff --git a/src/fsharp/xlf/FSComp.txt.it.xlf b/src/fsharp/xlf/FSComp.txt.it.xlf index 40d14d8b227..e1b23d948cb 100644 --- a/src/fsharp/xlf/FSComp.txt.it.xlf +++ b/src/fsharp/xlf/FSComp.txt.it.xlf @@ -422,11 +422,31 @@ Stampare le interfacce derivate di tutti i file di compilazione nei file di firma associati + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Visualizza i valori consentiti per la versione del linguaggio. Specificare la versione del linguaggio, ad esempio 'latest' o 'preview' + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Versioni del linguaggio supportate: diff --git a/src/fsharp/xlf/FSComp.txt.ja.xlf b/src/fsharp/xlf/FSComp.txt.ja.xlf index 66bbfcdb229..cd768f9b8ed 100644 --- a/src/fsharp/xlf/FSComp.txt.ja.xlf +++ b/src/fsharp/xlf/FSComp.txt.ja.xlf @@ -422,11 +422,31 @@ すべてのコンパイル ファイルの推定されたインターフェイスを関連する署名ファイルに印刷します + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' 言語バージョンで許可された値を表示し、'最新' や 'プレビュー' などの言語バージョンを指定する + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: サポートされる言語バージョン: diff --git a/src/fsharp/xlf/FSComp.txt.ko.xlf b/src/fsharp/xlf/FSComp.txt.ko.xlf index add2ab5f909..5a02f9882f2 100644 --- a/src/fsharp/xlf/FSComp.txt.ko.xlf +++ b/src/fsharp/xlf/FSComp.txt.ko.xlf @@ -422,11 +422,31 @@ 모든 컴파일 파일의 유추된 인터페이스를 관련 서명 파일로 인쇄합니다. + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' 언어 버전의 허용된 값을 표시하고 '최신' 또는 '미리 보기'와 같은 언어 버전을 지정합니다. + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: 지원되는 언어 버전: diff --git a/src/fsharp/xlf/FSComp.txt.pl.xlf b/src/fsharp/xlf/FSComp.txt.pl.xlf index 1242de81b70..a315280e795 100644 --- a/src/fsharp/xlf/FSComp.txt.pl.xlf +++ b/src/fsharp/xlf/FSComp.txt.pl.xlf @@ -422,11 +422,31 @@ Drukowanie wywnioskowanych interfejsów wszystkich plików kompilacji do skojarzonych plików sygnatur + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Wyświetl dozwolone wartości dla wersji językowej; określ wersję językową, np. „latest” lub „preview” + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Obsługiwane wersje językowe: diff --git a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf index c17ab8cea14..862eca3de10 100644 --- a/src/fsharp/xlf/FSComp.txt.pt-BR.xlf +++ b/src/fsharp/xlf/FSComp.txt.pt-BR.xlf @@ -422,11 +422,31 @@ Imprimir as interfaces inferidas de todos os arquivos de compilação para os arquivos de assinatura associados + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Exibe os valores permitidos para a versão do idioma, especifica a versão do idioma, como 'mais recente ' ou 'prévia' + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Versões de linguagens com suporte: diff --git a/src/fsharp/xlf/FSComp.txt.ru.xlf b/src/fsharp/xlf/FSComp.txt.ru.xlf index 6c0111bf3c1..3c7b2bda6f8 100644 --- a/src/fsharp/xlf/FSComp.txt.ru.xlf +++ b/src/fsharp/xlf/FSComp.txt.ru.xlf @@ -422,11 +422,31 @@ Печать определяемых интерфейсов всех файлов компиляции в связанные файлы подписей + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Отображение допустимых значений для версии языка. Укажите версию языка, например, "latest" или "preview". + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Поддерживаемые языковые версии: diff --git a/src/fsharp/xlf/FSComp.txt.tr.xlf b/src/fsharp/xlf/FSComp.txt.tr.xlf index 82e15d70092..f925a90e053 100644 --- a/src/fsharp/xlf/FSComp.txt.tr.xlf +++ b/src/fsharp/xlf/FSComp.txt.tr.xlf @@ -422,11 +422,31 @@ Tüm derleme dosyalarının çıkarsanan arabirimlerini ilişkili imza dosyalarına yazdır + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' Dil sürümü için izin verilen değerleri görüntüleyin, dil sürümünü 'en son' veya 'önizleme' örneklerindeki gibi belirtin + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: Desteklenen dil sürümleri: diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf index 5ffe569f28e..236e49f0ce7 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hans.xlf @@ -422,11 +422,31 @@ 将所有编译文件的推断接口打印到关联的签名文件 + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' 显示语言版本的允许值,指定语言版本,如“最新”或“预览” + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: 支持的语言版本: diff --git a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf index d6bcfaa2ed7..baa454a28eb 100644 --- a/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/fsharp/xlf/FSComp.txt.zh-Hant.xlf @@ -422,11 +422,31 @@ 將所有編譯檔案的推斷介面列印至相關聯的簽章檔案 + + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together. + + + + Invalid reference assembly path' + Invalid reference assembly path' + + Display the allowed values for language version, specify language version such as 'latest' or 'preview' 顯示語言版本允許的值,指定 'latest' 或 'preview' 等語言版本 + + Produce a reference assembly, instead of a full assembly, as the primary output + Produce a reference assembly, instead of a full assembly, as the primary output + + + + Produce a reference assembly with the specified file path. + Produce a reference assembly with the specified file path. + + Supported language versions: 支援的語言版本: diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index dc9699557a6..51359493963 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -1455,6 +1455,7 @@ FSharp.Compiler.AbstractIL.IL+ILType: System.String get_BasicQualifiedName() FSharp.Compiler.AbstractIL.IL+ILType: System.String get_QualifiedName() FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean HasSecurity FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsAbstract +FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsKnownToBeAttribute FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsClass FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsComInterop FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsDelegate @@ -1467,6 +1468,7 @@ FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsStruct FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean IsStructOrEnum FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_HasSecurity() FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_IsAbstract() +FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_IsKnownToBeAttribute() FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_IsClass() FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_IsComInterop() FSharp.Compiler.AbstractIL.IL+ILTypeDef: Boolean get_IsDelegate() @@ -1493,7 +1495,7 @@ FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILPropertyDefs Properties FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILPropertyDefs get_Properties() FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILSecurityDecls SecurityDecls FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILSecurityDecls get_SecurityDecls() -FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILTypeDef With(Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Reflection.TypeAttributes], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType]], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef]], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILType]], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILTypeDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILFieldDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodImplDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILEventDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILAttributes], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILSecurityDecls]) +FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILTypeDef With(Microsoft.FSharp.Core.FSharpOption`1[System.String], Microsoft.FSharp.Core.FSharpOption`1[System.Reflection.TypeAttributes], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType]], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef]], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILType]], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILTypeDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILFieldDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodImplDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILEventDefs], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILPropertyDefs], Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILAttributes], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILSecurityDecls]) FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILTypeDefAccess Access FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILTypeDefAccess get_Access() FSharp.Compiler.AbstractIL.IL+ILTypeDef: ILTypeDefLayout Layout @@ -1510,7 +1512,7 @@ FSharp.Compiler.AbstractIL.IL+ILTypeDef: System.Reflection.TypeAttributes Attrib FSharp.Compiler.AbstractIL.IL+ILTypeDef: System.Reflection.TypeAttributes get_Attributes() FSharp.Compiler.AbstractIL.IL+ILTypeDef: System.String Name FSharp.Compiler.AbstractIL.IL+ILTypeDef: System.String get_Name() -FSharp.Compiler.AbstractIL.IL+ILTypeDef: Void .ctor(System.String, System.Reflection.TypeAttributes, ILTypeDefLayout, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILType], ILMethodDefs, ILTypeDefs, ILFieldDefs, ILMethodImplDefs, ILEventDefs, ILPropertyDefs, ILSecurityDecls, ILAttributes) +FSharp.Compiler.AbstractIL.IL+ILTypeDef: Void .ctor(System.String, System.Reflection.TypeAttributes, ILTypeDefLayout, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILType], Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILGenericParameterDef], Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILType], ILMethodDefs, ILTypeDefs, ILFieldDefs, ILMethodImplDefs, ILEventDefs, ILPropertyDefs, Boolean, ILSecurityDecls, ILAttributes) FSharp.Compiler.AbstractIL.IL+ILTypeDefAccess+Nested: ILMemberAccess Item FSharp.Compiler.AbstractIL.IL+ILTypeDefAccess+Nested: ILMemberAccess get_Item() FSharp.Compiler.AbstractIL.IL+ILTypeDefAccess+Tags: Int32 Nested diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index bd6f1c580d1..5b146e6d2c4 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -17,6 +17,10 @@ open System.Collections.Immutable open System.IO open System.Text open System.Text.RegularExpressions +open System.Reflection +open System.Reflection.Metadata +open System.Reflection.PortableExecutable + open FSharp.Test.CompilerAssertHelpers open TestFramework open System.Reflection.Metadata @@ -94,15 +98,15 @@ module rec Compiler = type ErrorType = Error of int | Warning of int | Information of int | Hidden of int - type SymbolType = - | MemberOrFunctionOrValue of string - | Entity of string - | GenericParameter of string - | Parameter of string - | StaticParameter of string + type SymbolType = + | MemberOrFunctionOrValue of string + | Entity of string + | GenericParameter of string + | Parameter of string + | StaticParameter of string | ActivePatternCase of string - | UnionCase of string - | Field of string + | UnionCase of string + | Field of string member this.FullName () = match this with @@ -269,6 +273,21 @@ module rec Compiler = |> FS |> withName (Path.GetFileNameWithoutExtension(path)) + let FSharpWithInputAndOutputPath (src: string) (inputFilePath: string) (outputFilePath: string) : CompilationUnit = + let compileDirectory = Path.GetDirectoryName(outputFilePath) + let name = Path.GetFileName(outputFilePath) + { + Source = SourceCodeFileKind.Create(inputFilePath, src) + AdditionalSources = [] + Baseline = None + Options = defaultOptions + OutputType = Library + OutputDirectory = Some(DirectoryInfo(compileDirectory)) + Name = Some name + IgnoreWarnings = false + References = [] + } |> FS + let CSharp (source: string) : CompilationUnit = csFromString (SourceCodeFileKind.Fs({FileName="test.cs"; SourceText=Some source })) |> CS @@ -543,6 +562,26 @@ module rec Compiler = | CS cs -> compileCSharp cs | _ -> failwith "TODO" + let private getAssemblyInBytes (result: CompilationResult) = + match result with + | CompilationResult.Success output -> + match output.OutputPath with + | Some filePath -> File.ReadAllBytes(filePath) + | _ -> failwith "Output path not found." + | _ -> + failwith "Compilation has errors." + + let compileGuid (cUnit: CompilationUnit) : Guid = + let bytes = + compile cUnit + |> shouldSucceed + |> getAssemblyInBytes + + use reader1 = new PEReader(bytes.ToImmutableArray()) + let reader1 = reader1.GetMetadataReader() + + reader1.GetModuleDefinition().Mvid |> reader1.GetGuid + let private parseFSharp (fsSource: FSharpCompilationSource) : CompilationResult = let source = fsSource.Source.GetSourceText |> Option.defaultValue "" let fileName = fsSource.Source.ChangeExtension.GetSourceFileName @@ -756,6 +795,8 @@ module rec Compiler = | Some p -> ILChecker.checkIL p il | CompilationResult.Failure _ -> failwith "Result should be \"Success\" in order to get IL." + let verifyILBinary (il: string list) (dll: string)= ILChecker.checkIL dll il + let private verifyFSILBaseline (baseline: Baseline option) (result: CompilationOutput) : unit = match baseline with | None -> failwith "Baseline was not provided." @@ -916,7 +957,7 @@ module rec Compiler = let private assertErrorMessages (source: ErrorInfo list) (expected: string list) : unit = for exp in expected do if not (List.exists (fun (el: ErrorInfo) -> - let msg = el.Message + let msg = el.Message msg = exp) source) then failwith (sprintf "Mismatch in error message, expected '%A' was not found during compilation.\nAll errors:\n%A" exp (List.map getErrorInfo source)) assertErrorsLength source expected diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 0a53f27d177..e03a46cbd3c 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -621,6 +621,12 @@ Updated automatically, please check diffs in your pull request, changes must be static member DefaultProjectOptions = defaultProjectOptions + static member GenerateFsInputPath() = + Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), ".fs")) + + static member GenerateDllOutputPath() = + Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), ".dll")) + static member CompileWithErrors(cmpl: Compilation, expectedErrors, ?ignoreWarnings) = let ignoreWarnings = defaultArg ignoreWarnings false compileCompilation ignoreWarnings cmpl (fun ((errors, _), _) -> @@ -964,7 +970,7 @@ Updated automatically, please check diffs in your pull request, changes must be LangVersionText = langVersion } checker.ParseFile(sourceFileName, SourceText.ofString source, parsingOptions) |> Async.RunImmediate - static member ParseWithErrors (source: string, ?langVersion: string) = fun expectedParseErrors -> + static member ParseWithErrors (source: string, ?langVersion: string) = fun expectedParseErrors -> let parseResults = CompilerAssert.Parse (source, ?langVersion=langVersion) Assert.True(parseResults.ParseHadErrors) diff --git a/tests/fsharp/Compiler/CodeGen/EmittedIL/DeterministicTests.fs b/tests/fsharp/Compiler/CodeGen/EmittedIL/DeterministicTests.fs new file mode 100644 index 00000000000..1d714c38c59 --- /dev/null +++ b/tests/fsharp/Compiler/CodeGen/EmittedIL/DeterministicTests.fs @@ -0,0 +1,570 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests.CodeGen.EmittedIL + +open System.IO +open FSharp.Test +open FSharp.Test.Compiler +open NUnit.Framework + +[] +module DeterministicTests = + + [] + let ``Simple assembly should be deterministic``() = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module Assembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + let mvid1 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--deterministic"] + |> compileGuid + let mvid2 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--deterministic"] + |> compileGuid + + // Two identical compilations should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Simple assembly with different platform should not be deterministic``() = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module Assembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + let mvid1 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--deterministic"] + |> compileGuid + let mvid2 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--deterministic";"--platform:Itanium"] + |> compileGuid + + // No two platforms should produce the same MVID + Assert.AreNotEqual(mvid1, mvid2) + + [] + let ``Simple reference assembly should be deterministic``() = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest() + Console.WriteLine("Hello World!") + """ + + let mvid1 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + let mvid2 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two identical compilations should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Simple reference assembly with different platform should not be deterministic``() = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest() + Console.WriteLine("Hello World!") + """ + + let mvid1 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + let mvid2 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic";"--platform:Itanium"] + |> compileGuid + + // No two platforms should produce the same MVID + Assert.AreNotEqual(mvid1, mvid2) + + + [] + let ``False-positive reference assemblies test, different aseemblies' mvid should not match`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + let mvid1 = + FSharpWithInputAndOutputPath src inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let test2() = + Console.WriteLine("Hello World!") + """ + + let mvid2 = + FSharpWithInputAndOutputPath src2 inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two different compilations should _not_ produce the same MVID + Assert.AreNotEqual(mvid1, mvid2) +(* + [] + let ``Reference assemblies should be deterministic when only private function name is different with the same function name length`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest1() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest2() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest2() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + + [] + let ``Reference assemblies should be deterministic when only private function name is different with the different function name length`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest1() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest11() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest11() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Reference assemblies should be deterministic when only private function body is different`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest1() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest1() = + Console.Write("Private Hello World!") + +let test() = + privTest1() + Console.WriteLine("Hello World!") + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Reference assemblies should be deterministic when only private function return type is different`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1() : string = "Private Hello World!" + +let test() = + privTest1() |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest1() : int = 0 + +let test() = + privTest1() |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Reference assemblies should be deterministic when only private function parameter count is different`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1 () : string = "Private Hello World!" + +let test() = + privTest1 () |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest1 () () : string = "Private Hello World!" + +let test() = + privTest1 () () |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + + [] + let ``Reference assemblies should be deterministic when only private function parameter count is different and private function is unused`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1 () : string = "Private Hello World!" + +let test() = + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest1 () () : string = "Private Hello World!" + +let test() = + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Reference assemblies should be deterministic when only private function parameter types are different`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1 () = "Private Hello World!" + +let test() = + privTest1() |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let private privTest1 (_: string) = "Private Hello World!" + +let test() = + privTest1 "" |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + [] + let ``Reference assemblies should be deterministic when private function is missing in one of them`` () = + let inputFilePath = CompilerAssert.GenerateFsInputPath() + let outputFilePath = CompilerAssert.GenerateDllOutputPath() + let src = + """ +module ReferenceAssembly + +open System + +let private privTest1 () = "Private Hello World!" + +let test() = + privTest1() |> ignore + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath, src) + + let mvid1 = + FSharpWithInputAndOutputPath inputFilePath outputFilePath + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + + let inputFilePath2 = CompilerAssert.GenerateFsInputPath() + let outputFilePath2 = CompilerAssert.GenerateDllOutputPath() + let src2 = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine() + """ + + File.WriteAllText(inputFilePath2, src2) + + let mvid2 = + FSharpWithInputAndOutputPath inputFilePath2 outputFilePath2 + |> withOptions ["--refonly";"--deterministic"] + |> compileGuid + + // Two compilations with changes only to private code should produce the same MVID + Assert.AreEqual(mvid1, mvid2) + + // TODO: Add tests for Internal types (+IVT), (private, internal, public) fields, properties, events. +*) \ No newline at end of file diff --git a/tests/fsharp/Compiler/CodeGen/EmittedIL/ReferenceAssemblyTests.fs b/tests/fsharp/Compiler/CodeGen/EmittedIL/ReferenceAssemblyTests.fs new file mode 100644 index 00000000000..890209b8f9f --- /dev/null +++ b/tests/fsharp/Compiler/CodeGen/EmittedIL/ReferenceAssemblyTests.fs @@ -0,0 +1,726 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.UnitTests.CodeGen.EmittedIL + +open FSharp.Test.Compiler +open NUnit.Framework +open FSharp.Compiler.IO + +[] +module ReferenceAssemblyTests = + + let referenceAssemblyAttributeExpectedIL = + """.custom instance void [runtime]System.Runtime.CompilerServices.ReferenceAssemblyAttribute::.ctor() = ( 01 00 00 00 )""" + + [] + let ``Simple reference assembly should have expected IL``() = + let src = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class public abstract auto ansi sealed ReferenceAssembly + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static void test() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + }""" + ] + |> ignore + + [] + let ``Simple reference assembly should have expected IL without a private function``() = + let src = + """ +module ReferenceAssembly + +open System + +let private privTest() = + Console.WriteLine("Private Hello World!") + +let test() = + privTest() + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class public abstract auto ansi sealed ReferenceAssembly + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static void test() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + }""" + ] + |> ignore + + [] + let ``Simple reference assembly should have expected IL with anonymous record``() = + let src = + """ +module ReferenceAssembly + +open System + +let test(_x: {| a: int32 |}) = + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + }""" + ] + |> ignore + + [] + let ``Simple reference assembly with nested module should have expected IL``() = + let src = + """ +module ReferenceAssembly + +open System + +module Nested = + + let test() = + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class public abstract auto ansi sealed ReferenceAssembly + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class abstract auto ansi sealed nested public Nested + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static void test() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } + + }""" + ] + |> ignore + + [] + let ``Simple reference assembly with nested module with type should have expected IL``() = + let src = + """ +module ReferenceAssembly + +open System + +module Nested = + + type Test = { x: int } + + let private foo () = () + + let test(_x: Test) = + foo () + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class abstract auto ansi sealed nested public Nested + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .class auto ansi serializable sealed nested public Test + extends [runtime]System.Object + implements class [runtime]System.IEquatable`1, + [runtime]System.Collections.IStructuralEquatable, + class [runtime]System.IComparable`1, + [runtime]System.IComparable, + [runtime]System.Collections.IStructuralComparable + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 02 00 00 00 00 00 ) + .method public hidebysig specialname + instance int32 get_x() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public specialname rtspecialname + instance void .ctor(int32 x) cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public strict virtual instance string + ToString() cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance int32 CompareTo(class ReferenceAssembly/Nested/Test obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance int32 CompareTo(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance int32 CompareTo(object obj, + class [runtime]System.Collections.IComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance int32 GetHashCode(class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance int32 GetHashCode() cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance bool Equals(object obj, + class [runtime]System.Collections.IEqualityComparer comp) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance bool Equals(class ReferenceAssembly/Nested/Test obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig virtual final + instance bool Equals(object obj) cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .property instance int32 x() + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags, + int32) = ( 01 00 04 00 00 00 00 00 00 00 00 00 ) + .get instance int32 ReferenceAssembly/Nested/Test::get_x() + } + } + + .method public static void test(class ReferenceAssembly/Nested/Test _x) cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } """ + ] + |> ignore + + [] + let ``--refout should produce both normal and reference assemblies``() = + // TODO: We probably want a built-in test framework functionality which will be taking care of comparing/verifying refout. + let refoutDllPath = FileSystem.GetTempPathShim() + "Test.ref.dll" + let src = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + // This will produce normal assembly as well as ref in {refoutPath} + let result = + FSharp src + |> withOptions [$"--refout:{refoutDllPath}"] + |> compile + + // Should build successfully. + result |> shouldSucceed + // Verify that normal assembly has been produced. + |> verifyIL [""".class public abstract auto ansi sealed ReferenceAssembly + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static void test() cil managed + { + + .maxstack 8 + IL_0000: ldstr "Hello World!" + IL_0005: call void [runtime]System.Console::WriteLine(string) + IL_000a: ret + } + + }""" + ] + |> ignore + + // Verify that ref assembly in custom path was produced. + if not (FileSystem.FileExistsShim refoutDllPath) then + failwith $"Can't find reference assembly {refoutDllPath}" + + refoutDllPath + |> verifyILBinary [ + referenceAssemblyAttributeExpectedIL + """.class public abstract auto ansi sealed ReferenceAssembly + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 ) + .method public static void test() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + }""" + ] + + [] + let ``Can't use both --refonly and --staticlink``() = + let src = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--staticlink:foo"; "--refonly"] + |> compile + |> shouldFail + |> withSingleDiagnostic (Error 2030, Line 0, Col 1, Line 0, Col 1, "Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together.") + |> ignore + + [] + let ``Can't use both --refoout and --staticlink``() = + let src = + """ +module ReferenceAssembly + +open System + +let test() = + Console.WriteLine("Hello World!") + """ + + FSharp src + |> withOptions ["--staticlink:foo"; "--refout:foo"] + |> compile + |> shouldFail + |> withSingleDiagnostic (Error 2030, Line 0, Col 1, Line 0, Col 1, "Invalid use of emitting a reference assembly, do not use '--staticlink', or '--refonly' and '--refout' together.") + |> ignore + + [] + let ``Internal DU type doesn't generate any properties/methods without IVT`` () = + FSharp """ +module ReferenceAssembly +[] +type internal RingState<'item> = | Writable of 'item + """ + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """ +.class auto autochar serializable sealed nested assembly beforefieldinit RingState`1 +extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoComparisonAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoEqualityAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [runtime]System.Diagnostics.DebuggerDisplayAttribute::.ctor(string) = ( 01 00 15 7B 5F 5F 44 65 62 75 67 44 69 73 70 6C + 61 79 28 29 2C 6E 71 7D 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 21 00 00 00 00 00 ) + .method public strict virtual instance string + ToString() cil managed + { + .custom instance void [runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } """] + + [] + let ``Types with internal-only properties and methods don't generate anything without IVT`` () = + FSharp """ +module ReferenceAssembly +[] +type MyType() = + let mutable myInternalValue = 1 + member internal this.MyReadOnlyProperty = myInternalValue + // A write-only property. + member internal this.MyWriteOnlyProperty with set (value) = myInternalValue <- value + // A read-write property. + member internal this.MyReadWriteProperty + with get () = myInternalValue + and set (value) = myInternalValue <- value""" + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """ +.class auto ansi serializable nested public MyType +extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoComparisonAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoEqualityAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + }"""] + + [] + let ``Properties, getters, setters are emitted for internal properties`` () = + FSharp """ +module ReferenceAssembly + +[] +type MyAttribute() = + inherit System.Attribute() + member val internal Prop1 : int = 0 with get, set + +[] +type MySecondaryAttribute() = + inherit MyAttribute() + member val internal Prop1 : int = 0 with get, set + """ + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class auto ansi serializable nested public MyAttribute + extends [runtime]System.Attribute + { + .custom instance void [runtime]System.AttributeUsageAttribute::.ctor(valuetype [runtime]System.AttributeTargets) = ( 01 00 FF 7F 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .field assembly int32 Prop1@ + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method assembly hidebysig specialname + instance int32 get_Prop1() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method assembly hidebysig specialname + instance void set_Prop1(int32 v) cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } + + .class auto ansi serializable nested public MySecondaryAttribute + extends ReferenceAssembly/MyAttribute + { + .custom instance void [runtime]System.AttributeUsageAttribute::.ctor(valuetype [runtime]System.AttributeTargets) = ( 01 00 FF 7F 00 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .field assembly int32 Prop1@ + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method assembly hidebysig specialname + instance int32 get_Prop1() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method assembly hidebysig specialname + instance void set_Prop1(int32 v) cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .property instance int32 Prop1() + { + .set instance void ReferenceAssembly/MyAttribute::set_Prop1(int32) + .get instance int32 ReferenceAssembly/MyAttribute::get_Prop1() + } + .property instance int32 Prop1() + { + .set instance void ReferenceAssembly/MySecondaryAttribute::set_Prop1(int32) + .get instance int32 ReferenceAssembly/MySecondaryAttribute::get_Prop1() + } + } """ + ] + + [] + let ``Internal and private fields are emitted for structs`` () = + FSharp """ +module ReferenceAssembly + +[] +type AStruct = + struct + [] val mutable internal myInt : int + [] val mutable private myInt2 : int + end + """ + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class sequential ansi serializable sealed nested public AStruct + extends [runtime]System.ValueType + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoEqualityAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.NoComparisonAttribute::.ctor() = ( 01 00 00 00 ) + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .field assembly int32 myInt + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.DefaultValueAttribute::.ctor() = ( 01 00 00 00 ) + .field assembly int32 myInt2 + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.DefaultValueAttribute::.ctor() = ( 01 00 00 00 ) + }""" + ] + [] + let ``Only public properties are emitted on non-IVT assemblies`` () = + FSharp """ +module ReferenceAssembly + +type NotAnAttribute() = + member val internal Prop1 : int = 0 with get, set + +type MType() = + member val public PubProp1 : int = 0 with get, set + member val internal IntProp1 : int = 0 with get, set + member val private PrivProp1 : int = 0 with get, set + """ + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class auto ansi serializable nested public NotAnAttribute + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } + + .class auto ansi serializable nested public MType + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig specialname + instance int32 get_PubProp1() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .method public hidebysig specialname + instance void set_PubProp1(int32 v) cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + .property instance int32 PubProp1() + { + .set instance void ReferenceAssembly/MType::set_PubProp1(int32) + .get instance int32 ReferenceAssembly/MType::get_PubProp1() + } + } """ + ] + [] + let ``Only public events are emitted for non-IVT assembly`` () = + FSharp """ +module ReferenceAssembly + +type MType() = + let event1 = new Event<_>() + + [] + member private _.Event1 = event1.Publish + """ + |> withOptions ["--refonly"] + |> compile + |> shouldSucceed + |> verifyIL [ + referenceAssemblyAttributeExpectedIL + """.class auto ansi serializable nested public MType + extends [runtime]System.Object + { + .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 03 00 00 00 00 00 ) + .method public specialname rtspecialname + instance void .ctor() cil managed + { + + .maxstack 8 + IL_0000: ldnull + IL_0001: throw + } + + } """ + ] + // TODO: Add tests for internal functions, types, interfaces, abstract types (with and without IVTs), (private, internal, public) fields, properties (+ different visibility for getters and setters), events. \ No newline at end of file diff --git a/tests/fsharp/FSharpSuite.Tests.fsproj b/tests/fsharp/FSharpSuite.Tests.fsproj index cefe9978c75..750099a655f 100644 --- a/tests/fsharp/FSharpSuite.Tests.fsproj +++ b/tests/fsharp/FSharpSuite.Tests.fsproj @@ -27,6 +27,7 @@ + @@ -36,6 +37,7 @@ + diff --git a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl index 853541eca4d..7e7c4a13a99 100644 --- a/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl +++ b/tests/fsharpqa/Source/CompilerOptions/fsc/help/help40.437.1033.bsl @@ -1,4 +1,4 @@ -Microsoft (R) F# Compiler version 10.6.0.0 for F# 4.7 +Microsoft (R) F# Compiler version 12.0.0.0 for F# 6.0 Copyright (c) Microsoft Corporation. All Rights Reserved. @@ -39,6 +39,11 @@ Copyright (c) Microsoft Corporation. All Rights Reserved. signature files --nocopyfsharpcore Don't copy FSharp.Core.dll along the produced binaries +--refonly[+|-] Produce a reference assembly, + instead of a full assembly, as the + primary output +--refout: Produce a reference assembly with + the specified file path. - INPUT FILES -