Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate source for .resx files on build. #3607

Merged
merged 16 commits into from
Sep 22, 2017
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions src/FSharpSource.targets
Original file line number Diff line number Diff line change
Expand Up @@ -360,22 +360,36 @@
<UsingTask TaskName="FSharpEmbedResourceText"
AssemblyFile="$(FSharpSourcesRoot)\..\Proto\net40\bin\FSharp.Build-proto.dll"
Condition="'$(Configuration)' != 'Proto'" />
<UsingTask TaskName="FSharpEmbedResXSource"
AssemblyFile="$(FSharpSourcesRoot)\..\Proto\net40\bin\FSharp.Build-proto.dll"
Condition="'$(Configuration)' != 'Proto'" />

<Target Name="GenerateFSharpTextResources"
BeforeTargets="CoreResGen;PrepareForBuild"
Condition="'$(Configuration)' != 'Proto'">

<MakeDir Directories="$(IntermediateOutputPath)" />

<!-- Generate source for all resx files. -->
<FSharpEmbedResXSource EmbeddedResource="@(EmbeddedResource)" IntermediateOutputPath="$(IntermediateOutputPath)" TargetFramework="$(TargetFramework)">
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedResXSource" />
</FSharpEmbedResXSource>

<ItemGroup>
<CompileBefore Include="@(_FsGeneratedResXSource)" />
<FileWrites Include="@(_FsGeneratedResXSource)" />
</ItemGroup>

<!-- Generate resx and source for all txt files. -->
<FSharpEmbedResourceText EmbeddedText="@(EmbeddedText)" IntermediateOutputPath="$(IntermediateOutputPath)">
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedSource" />
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedTxtSource" />
<Output TaskParameter="GeneratedResx" ItemName="_FsGeneratedResx" />
</FSharpEmbedResourceText>

<ItemGroup>
<CompileBefore Include="@(_FsGeneratedSource)" />
<CompileBefore Include="@(_FsGeneratedTxtSource)" />
<EmbeddedResource Include="@(_FsGeneratedResx)" />
<FileWrites Include="@(_FsGeneratedSource)" />
<FileWrites Include="@(_FsGeneratedTxtSource)" />
<FileWrites Include="@(_FsGeneratedResx)" />
</ItemGroup>

Expand Down
4 changes: 4 additions & 0 deletions src/fsharp/FSharp.Build-proto/FSharp.Build-proto.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
<Compile Include="..\FSharp.Build\FSharpEmbedResourceText.fs">
<Link>FSharpEmbedResourceText.fs</Link>
</Compile>
<Compile Include="..\FSharp.Build\FSharpEmbedResXSource.fs">
<Link>FSharpEmbedResXSource.fs</Link>
</Compile>
<CopyAndSubstituteText Include="..\FSharp.Build\Microsoft.FSharp.Targets">
<Link>Microsoft.FSharp-proto.targets</Link>
<TargetFilename>Microsoft.FSharp-proto.targets</TargetFilename>
Expand Down Expand Up @@ -67,6 +70,7 @@
<Reference Include="System" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetDotnetProfile)' != 'coreclr' AND '$(MonoPackaging)' != 'true' ">
<Reference Include="Microsoft.Build.Framework, Version=$(VisualStudioVersion).0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<Compile Include="Fsc.fsi" />
<Compile Include="Fsc.fs" />
<Compile Include="FSharpEmbedResourceText.fs" />
<Compile Include="FSharpEmbedResXSource.fs" />
<Compile Include="CreateFSharpManifestResourceName.fsi" />
<Compile Include="CreateFSharpManifestResourceName.fs" />
<CopyAndSubstituteText Include="Microsoft.FSharp.Targets">
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/FSharp.Build/FSharp.Build.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<Compile Include="Fsc.fsi" />
<Compile Include="Fsc.fs" />
<Compile Include="FSharpEmbedResourceText.fs" />
<Compile Include="FSharpEmbedResXSource.fs" />
<Compile Include="CreateFSharpManifestResourceName.fsi" />
<Compile Include="CreateFSharpManifestResourceName.fs" />
<CopyAndSubstituteText Include="Microsoft.FSharp.Targets">
Expand Down Expand Up @@ -59,6 +60,7 @@
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetDotnetProfile)' != 'coreclr' AND '$(MonoPackaging)' != 'true' ">
<Reference Include="Microsoft.Build.Framework, Version=$(VisualStudioVersion).0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
Expand Down
144 changes: 144 additions & 0 deletions src/fsharp/FSharp.Build/FSharpEmbedResXSource.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.

namespace Microsoft.FSharp.Build

open System
open System.Collections
open System.Globalization
open System.IO
open System.Linq
open System.Text
open System.Xml.Linq
open Microsoft.Build.Framework
open Microsoft.Build.Utilities

type FSharpEmbedResXSource() =
let mutable _buildEngine : IBuildEngine = null
let mutable _hostObject : ITaskHost = null
let mutable _embeddedText : ITaskItem[] = [||]
let mutable _generatedSource : ITaskItem[] = [||]
let mutable _outputPath : string = ""
let mutable _targetFramework : string = ""

let boilerplate = @"// <auto-generated>

namespace {0}

open System.Reflection

module internal {1} =
type private C (_dummy:System.Object) = class end
let mutable Culture = System.Globalization.CultureInfo.CurrentUICulture
let ResourceManager = new System.Resources.ResourceManager(""{2}"", C(null).GetType().GetTypeInfo().Assembly)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be replaced with Assembly.GetCallingAssembly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the current executing assembly that is interesting not the calling assembly. This irritating code is the magic formulation because GetExecutingAssembly() didn\t make it into coreclr until V2.0, and the buildtask is compiled for both the desktop and coreclr.

Copy link
Contributor

@saul saul Sep 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case can we make the C class simpler:

type private Dummy = interface end
...
let ResourceManager = new System.Resources.ResourceManager(""{2}"", typeof<Dummy>.Assembly)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saul sure.

Copy link
Member Author

@brettfo brettfo Sep 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't use typeof<> because this generator is used by FSharp.Core and at the point that we need these strings is before the typeof<> operator can be defined (i.e., in prim-types.fs/fsi). I could do a custom switch on FSharp.Core, but that seemed like a nasty hack given that the hack already there will always work.

Edit: and the .GetType().GetTypeInfo() method works in both desktop and CoreCLR scenarios and I'd rather have one method that always works than switching on platform for something that doesn't matter to the end user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brettfo thanks for clearing that up, I couldn't for the life of me remember why we did it this way.

let GetString(name:System.String) : System.String = ResourceManager.GetString(name, Culture)"

let boilerplateGetObject = " let GetObject(name:System.String) : System.Object = ResourceManager.GetObject(name, Culture)"

let generateSource (resx:string) (fullModuleName:string) (generateLegacy:bool) (generateLiteral:bool) =
try
let printMessage = printfn "FSharpEmbedResXSource: %s"
let justFileName = Path.GetFileNameWithoutExtension(resx)
let namespaceName, moduleName =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check https://github.com/Microsoft/visualfsharp/pull/3614/files#diff-f583ab0cc0cd86307b6b05f78682f65a for the hack I put in to make sure this doesn't repeatedly re-generate content, causing unexpected rebuilds on a simple repeated build like build net40. If there's a better, more declarative MSBuild way to do it without the file check comparison in the code then please let's do that.

Please also manually check that repeated build net40 doesn't rebuild.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Extra commits coming soon.

let parts = fullModuleName.Split('.')
if parts.Length = 1 then ("global", parts.[0])
else (String.Join(".", parts, 0, parts.Length - 1), parts.[parts.Length - 1])
let generateGetObject =
match _targetFramework with
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

netcoreapp1.* as well

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated commits coming.

| "netstandard1.0"
| "netstandard1.1"
| "netstandard1.2"
| "netstandard1.3"
| "netstandard1.4"
| "netstandard1.5"
| "netstandard1.6" -> false // these targets don't support the `ResourceManager.GetObject()` method
| _ -> true // other supported runtimes, do
let sb = StringBuilder().AppendLine(String.Format(boilerplate, namespaceName, moduleName, justFileName))
if generateGetObject then sb.AppendLine(boilerplateGetObject) |> ignore
let sourcePath = Path.Combine(_outputPath, justFileName + ".fs")
printMessage <| sprintf "Generating: %s" sourcePath
let body =
let xname = XName.op_Implicit
XDocument.Load(resx).Descendants(xname "data")
|> Seq.fold (fun (sb:StringBuilder) (node:XElement) ->
let name =
match node.Attribute(xname "name") with
| null -> failwith "Missing resource name"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we provide a more helpful message here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Updated commits coming soon.

| attr -> attr.Value
let docComment =
match node.Elements(xname "value").FirstOrDefault() with
| null -> failwith <| sprintf "Missing resource value for '%s'" name
| element -> element.Value.Trim()
let identifier = if Char.IsLetter(name.[0]) || name.[0] = '_' then name else "_" + name
let commentBody =
XElement(xname "summary", docComment).ToString().Split([|"\r\n"; "\r"; "\n"|], StringSplitOptions.None)
|> Array.fold (fun (sb:StringBuilder) line -> sb.AppendLine(" /// " + line)) (StringBuilder())
// add the resource
let accessorBody =
match (generateLegacy, generateLiteral) with
| (true, true) -> sprintf " [<Literal>]\n let %s = \"%s\"" identifier name
| (true, false) -> sprintf " let %s = \"%s\"" identifier name // the [<Literal>] attribute can't be used for FSharp.Core
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not automatically detect if we're generating for FSharp.Core?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not directly. This generator only has access to whatever is in the project file, and while we could detect FSharp.Core.fsproj by either $(ProjectName) or the existence of the FSHARP_CORE constant, these are merely conventions that could change and it seems wrong to assume every project named FSharp.Core or every project with a defined constant FSHARP_CORE is our FSharp.Core.

| (false, _) ->
let isStringResource = match node.Attribute(xname "type") with
| null -> true
| _ -> false
match (isStringResource, generateGetObject) with
| (true, _) -> sprintf " let %s() = GetString(\"%s\")" identifier name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought, but could we replace @"\n" with "\n" at this point? Also it would be really neat if we could detect {0},{1} etc. in the string and then make a function take them as parameters. Such as:

let MyString (parameter1 : string) = String.Format(GetString("MyString"), parameter1)

It means string formatting identifiers in the resx will fail the build if they aren't expanded.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the @"\n" -> "\n" replacement, I'd rather not do it here because I would like this to be as close to the C#/VB implementation as possible and that only outputs ResourceManager.GetString(). Also, it seems wrong to do any resource manipulation without the call site explicitly knowing about it, especially since each fetch of a string resource now contains an extra function call and potentially more string allocations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the SR modules that you removed did this already - although am I right in saying that this code is for all FSharp projects, not just VFT projects?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for detecting {0},{1}, that's a surprisingly hard problem. In the past a Roslyn team member tried to write a C#/VB analyzer to detect mismatches between the value to String.Format() and the replacement values. That ended up being abandoned because to make it correct the entire string parsing had to be re-implemented and it gets very nasty very fast.

| (false, true) -> sprintf " let %s() = GetObject(\"%s\")" identifier name
| (false, false) -> "" // the target runtime doesn't support non-string resources
// TODO: When calling the `GetObject` version, parse the `type` attribute to discover the proper return type
sb.AppendLine().Append(commentBody).AppendLine(accessorBody)
) sb
File.WriteAllText(sourcePath, body.ToString())
printMessage <| sprintf "Done: %s" sourcePath
Some(sourcePath)
with e ->
printf "An exception occurred when processing '%s'\n%s" resx (e.ToString())
None

[<Required>]
member this.EmbeddedResource
with get() = _embeddedText
and set(value) = _embeddedText <- value

[<Required>]
member this.IntermediateOutputPath
with get() = _outputPath
and set(value) = _outputPath <- value

member this.TargetFramework
with get() = _targetFramework
and set(value) = _targetFramework <- value

[<Output>]
member this.GeneratedSource
with get() = _generatedSource

interface ITask with
member this.BuildEngine
with get() = _buildEngine
and set(value) = _buildEngine <- value
member this.HostObject
with get() = _hostObject
and set(value) = _hostObject <- value
member this.Execute() =
let getBooleanMetadata (metadataName:string) (defaultValue:bool) (item:ITaskItem) =
match item.GetMetadata(metadataName) with
| value when String.IsNullOrWhiteSpace(value) -> defaultValue
| value -> String.Compare(value, "true", StringComparison.OrdinalIgnoreCase) = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throw if the result isn't false? e.g. someone could write "tru e" and it would be interpreted as false.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Updated commits coming soon.

let generatedFiles, generatedResult =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the latest code in https://github.com/Microsoft/visualfsharp/pull/3614/files#diff-f583ab0cc0cd86307b6b05f78682f65a for a cleaner way to write this. A general rule is not to use fold unless you have a truly generative process where the results from one step depend on the results from the previous step

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Extra commits coming soon.

this.EmbeddedResource
|> Array.filter (getBooleanMetadata "GenerateSource" false)
|> Array.fold (fun (resultList, aggregateResult) item ->
let moduleName =
match item.GetMetadata("GeneratedModuleName") with
| null -> Path.GetFileNameWithoutExtension(item.ItemSpec)
| value -> value
let generateLegacy = getBooleanMetadata "GenerateLegacyCode" false item
let generateLiteral = getBooleanMetadata "GenerateLiterals" true item
match generateSource item.ItemSpec moduleName generateLegacy generateLiteral with
| Some (source) -> ((source :: resultList), aggregateResult)
| None -> (resultList, false)
) ([], true)
let generatedSources = generatedFiles |> List.map (fun item -> TaskItem(item) :> ITaskItem)
_generatedSource <- generatedSources |> List.rev |> List.toArray
generatedResult
18 changes: 15 additions & 3 deletions src/fsharp/FSharp.Build/Microsoft.FSharp.Targets
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ this file.

<UsingTask TaskName="Fsc" AssemblyFile="FSharp.Build{BuildSuffix}.dll"/>
<UsingTask TaskName="FSharpEmbedResourceText" AssemblyFile="FSharp.Build{BuildSuffix}.dll"/>
<UsingTask TaskName="FSharpEmbedResXSource" AssemblyFile="FSharp.Build{BuildSuffix}.dll"/>
<UsingTask TaskName="CreateFSharpManifestResourceName" AssemblyFile="FSharp.Build{BuildSuffix}.dll"/>

<PropertyGroup>
Expand Down Expand Up @@ -175,15 +176,26 @@ this file.

<MakeDir Directories="$(IntermediateOutputPath)" />

<!-- Generate source for all resx files. -->
<FSharpEmbedResXSource EmbeddedResource="@(EmbeddedResource)" IntermediateOutputPath="$(IntermediateOutputPath)" TargetFramework="$(TargetFramework)">
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedResXSource" />
</FSharpEmbedResXSource>

<ItemGroup>
<CompileBefore Include="@(_FsGeneratedResXSource)" />
<FileWrites Include="@(_FsGeneratedResXSource)" />
</ItemGroup>

<!-- Generate resx and source for all txt files. -->
<FSharpEmbedResourceText EmbeddedText="@(EmbeddedText)" IntermediateOutputPath="$(IntermediateOutputPath)">
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedSource" />
<Output TaskParameter="GeneratedSource" ItemName="_FsGeneratedTxtSource" />
<Output TaskParameter="GeneratedResx" ItemName="_FsGeneratedResx" />
</FSharpEmbedResourceText>

<ItemGroup>
<CompileBefore Include="@(_FsGeneratedSource)" />
<CompileBefore Include="@(_FsGeneratedTxtSource)" />
<EmbeddedResource Include="@(_FsGeneratedResx)" />
<FileWrites Include="@(_FsGeneratedSource)" />
<FileWrites Include="@(_FsGeneratedTxtSource)" />
<FileWrites Include="@(_FsGeneratedResx)" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/FSharp.Core/FSCore.resx
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@
<data name="QtypeArgumentOutOfRange" xml:space="preserve">
<value>type argument out of range</value>
</data>
<data name="ThisValueCannotBeMutated" xml:space="preserve">
<data name="thisValueCannotBeMutated" xml:space="preserve">
<value>This value cannot be mutated</value>
</data>
<data name="optionValueWasNone" xml:space="preserve">
Expand Down
18 changes: 11 additions & 7 deletions src/fsharp/FSharp.Core/FSharp.Core.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,20 @@
</ItemGroup>

<ItemGroup>
<CompileBefore Include="prim-types-prelude.fsi">
<Link>Primitives/prim-types-prelude.fsi</Link>
</CompileBefore>
<CompileBefore Include="prim-types-prelude.fs">
<Link>Primitives/prim-types-prelude.fs</Link>
</CompileBefore>
<EmbeddedResource Include="FSCore.resx">
<GenerateSource>true</GenerateSource>
<GenerateLegacyCode>true</GenerateLegacyCode>
<GenerateLiterals>false</GenerateLiterals>
<GeneratedModuleName>Microsoft.FSharp.Core.SR</GeneratedModuleName>
<Link>FSCore.resx</Link>
</EmbeddedResource>
<Compile Include="prim-types-prelude.fsi">
<Link>Primitives/prim-types-prelude.fsi</Link>
</Compile>
<Compile Include="prim-types-prelude.fs">
<Link>Primitives/prim-types-prelude.fs</Link>
</Compile>
<Compile Include="SR.fs">
<Compile Include="SR.fs" Condition="'$(Configuration)' == 'Proto'">
<Link>Primitives/SR.fs</Link>
</Compile>
<Compile Include="prim-types.fsi">
Expand Down
24 changes: 12 additions & 12 deletions src/fsharp/FSharp.Core/Query.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1418,41 +1418,41 @@ module Query =
TransInnerResult.Source(expr), NoConv

| Call (_, meth, _) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryCall,meth.ToString())))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryCall),meth.ToString())))

| PropertyGet (_, pinfo, _) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryProperty,pinfo.ToString())))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryProperty),pinfo.ToString())))

| NewObject(ty,_) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstructKind,"new " + ty.ToString())))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstructKind),"new " + ty.ToString())))

| NewArray(ty,_) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstructKind,"NewArray(" + ty.Name + ",...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstructKind),"NewArray(" + ty.Name + ",...)")))

| NewTuple _ when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstructKind,"NewTuple(...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstructKind),"NewTuple(...)")))

| FieldGet (_,field) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstructKind,"FieldGet(" + field.Name + ",...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstructKind),"FieldGet(" + field.Name + ",...)")))

| LetRecursive _ when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,"LetRecursive(...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),"LetRecursive(...)")))

| NewRecord _ when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,"NewRecord(...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),"NewRecord(...)")))

| NewDelegate _ when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,"NewDelegate(...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),"NewDelegate(...)")))

| NewTuple _ when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,"NewTuple(...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),"NewTuple(...)")))

| NewUnionCase (ucase,_) when check ->
raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,"NewUnionCase(" + ucase.Name + "...)")))
raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),"NewUnionCase(" + ucase.Name + "...)")))

// Error cases
| e ->
if check then raise (NotSupportedException (SR.GetString1(SR.unsupportedQueryConstruct,immutQuery.ToString())))
if check then raise (NotSupportedException (String.Format(SR.GetString(SR.unsupportedQueryConstruct),immutQuery.ToString())))
else TransInnerResult.Source(e),NoConv


Expand Down
7 changes: 0 additions & 7 deletions src/fsharp/FSharp.Core/SR.fs
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,3 @@ module internal SR =

let GetString(name:System.String) : System.String =
resources.GetString(name, System.Globalization.CultureInfo.CurrentUICulture)
let GetString1(name:System.String, arg1:System.String) : System.String =
System.String.Format(resources.GetString(name, System.Globalization.CultureInfo.CurrentUICulture), arg1)
let GetString2(name:System.String, arg1:System.String, arg2:System.String) : System.String =
System.String.Format(resources.GetString(name, System.Globalization.CultureInfo.CurrentUICulture), arg1, arg2)
let GetString3(name:System.String, arg1:System.String, arg2:System.String, arg3:System.String) : System.String =
System.String.Format(resources.GetString(name, System.Globalization.CultureInfo.CurrentUICulture), arg1, arg2, arg3)

2 changes: 1 addition & 1 deletion src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ namespace Microsoft.FSharp.Core
//-------------------------------------------------------------------------

let FailGenericComparison (obj: obj) =
raise (new System.ArgumentException(SR.GetString1(SR.genericCompareFail1, obj.GetType().ToString())))
raise (new System.ArgumentException(String.Format(SR.GetString(SR.genericCompareFail1), obj.GetType().ToString())))


/// This type has two instances - fsComparerER and fsComparerThrow.
Expand Down
Loading