Skip to content

Commit 5728b68

Browse files
authored
Improve compiler designtime probing (#4250)
1 parent e2af0fa commit 5728b68

File tree

9 files changed

+125
-56
lines changed

9 files changed

+125
-56
lines changed

src/fsharp/ExtensionTyping.fs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module internal ExtensionTyping =
3838

3939
// Specify the tooling-compatible fragments of a path such as:
4040
// typeproviders/fsharp41/net461/MyProvider.DesignTime.dll
41+
// tools/fsharp41/net461/MyProvider.DesignTime.dll
4142
// See https://github.com/Microsoft/visualfsharp/issues/3736
4243

4344
// Represents the FF#-compiler <-> type provider protocol.
@@ -55,16 +56,12 @@ module internal ExtensionTyping =
5556
System.Diagnostics.Debug.Assert(false, "Couldn't determine runtime tooling context, assuming it supports at least .NET Standard 2.0")
5657
[ "netstandard2.0"]
5758

58-
// When significant new processor types appear add a new moniker here. Note that use of this qualifier will be very rare
59-
// and we don't expect different design-time assemblies will be needed for different architectures very often. Some
60-
// exceptions may be design-time components for type providers for systems such as Python or R.
61-
let toolingCompatibleArch() = if sizeof<nativeint> = 8 then "x64" else "x86"
59+
6260
let toolingCompatiblePaths() =
6361
[ for protocol in toolingCompatibleTypeProviderProtocolMonikers() do
64-
for netRuntime in toolingCompatibleVersions() do
65-
let dir = Path.Combine("typeproviders", protocol, netRuntime)
66-
yield Path.Combine(dir, toolingCompatibleArch())
67-
yield dir
62+
for netRuntime in toolingCompatibleVersions() do
63+
yield Path.Combine("typeproviders", protocol, netRuntime)
64+
yield Path.Combine("tools", protocol, netRuntime)
6865
]
6966

7067
/// Load a the design-time part of a type-provider into the host process, and look for types

tests/FSharp.Compiler.UnitTests/ProductVersion.fs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,16 @@ module TypeProviderDesignTimeComponentLoading =
111111

112112
[<Test>]
113113
let ``check tooling paths for type provider design time component loading`` () =
114-
let arch = if sizeof<nativeint> = 8 then "x64" else "x86"
115-
let expected =
116-
[ @"typeproviders\fsharp41\net461\" + arch
117-
@"typeproviders\fsharp41\net461"
118-
@"typeproviders\fsharp41\net452\" + arch
114+
let expected =
115+
[ @"typeproviders\fsharp41\net461"
116+
@"tools\fsharp41\net461"
119117
@"typeproviders\fsharp41\net452"
120-
@"typeproviders\fsharp41\net451\" + arch
118+
@"tools\fsharp41\net452"
121119
@"typeproviders\fsharp41\net451"
122-
@"typeproviders\fsharp41\net45\" + arch
120+
@"tools\fsharp41\net451"
123121
@"typeproviders\fsharp41\net45"
124-
@"typeproviders\fsharp41\netstandard2.0\" + arch
122+
@"tools\fsharp41\net45"
125123
@"typeproviders\fsharp41\netstandard2.0"
126-
]
124+
@"tools\fsharp41\netstandard2.0" ]
127125
let actual = Microsoft.FSharp.Compiler.ExtensionTyping.toolingCompatiblePaths()
128126
Assert.areEqual expected actual

tests/fsharp/TypeProviderTests.fs

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,16 @@ let ``negative type provider tests`` (name:string) =
248248

249249
SingleTest.singleNegTest cfg name
250250

251-
[<Test>]
252-
let splitAssembly () =
251+
let splitAssembly subdir project =
253252

254-
let cfg = testConfig "typeProviders/splitAssembly"
253+
let cfg = testConfig project
255254

256255
let clean() =
257256
rm cfg "providerDesigner.dll"
258257
rmdir cfg "typeproviders"
258+
rmdir cfg "tools"
259259
rmdir cfg (".." ++ "typeproviders")
260+
rmdir cfg (".." ++ "tools")
260261

261262
clean()
262263

@@ -276,20 +277,11 @@ let splitAssembly () =
276277

277278
// check a few load locations
278279
let someLoadPaths =
279-
[ "typeproviders" ++ "fsharp41" ++ "net461" ++ "x86"
280-
"typeproviders" ++ "fsharp41" ++ "net461"
281-
"typeproviders" ++ "fsharp41" ++ "net45"
280+
[ subdir ++ "fsharp41" ++ "net461"
281+
subdir ++ "fsharp41" ++ "net45"
282282
// include up one directory
283-
".." ++ "typeproviders" ++ "fsharp41" ++ "net45"
284-
"typeproviders" ++ "fsharp41" ++ "netstandard2.0" ]
285-
286-
let someLoadPaths64 =
287-
[ "typeproviders" ++ "fsharp41" ++ "net461" ++ "x64"
288-
"typeproviders" ++ "fsharp41" ++ "net461" ]
289-
290-
let someNegativeLoadPaths64 =
291-
[ "typeproviders" ++ "fsharp41" ++ "net461" ++ "x86" ]
292-
283+
".." ++ subdir ++ "fsharp41" ++ "net45"
284+
subdir ++ "fsharp41" ++ "netstandard2.0" ]
293285

294286
for dir in someLoadPaths do
295287

@@ -311,31 +303,13 @@ let splitAssembly () =
311303

312304
SingleTest.singleTestBuildAndRunAux cfg FSI_BASIC
313305

314-
for dir in someLoadPaths64 do
315-
316-
clean()
317-
318-
// put providerDesigner.dll into a different place
319-
mkdir cfg dir
320-
fsc cfg "--out:%s/providerDesigner.dll -a" dir ["providerDesigner.fsx"]
321-
322-
SingleTest.singleTestBuildAndRunAux cfg FSIANYCPU_BASIC
323-
324-
for dir in someNegativeLoadPaths64 do
325-
326-
clean()
327-
328-
// put providerDesigner.dll into a different place
329-
mkdir cfg dir
330-
fsc cfg "--out:%s/providerDesigner.dll -a" dir ["providerDesigner.fsx"]
306+
clean()
331307

332-
// We expect a failure here - an error correctly gets printed on the console
333-
try
334-
SingleTest.singleTestBuildAndRunAux cfg FSIANYCPU_BASIC |> ignore
335-
failwith "expected an AssertionException"
336-
with :? NUnit.Framework.AssertionException -> ()
308+
[<Test>]
309+
let splitAssemblyTools () = splitAssembly "tools" "typeProviders/splitAssemblyTools"
337310

338-
clean()
311+
[<Test>]
312+
let splitAssemblyTypeProviders () = splitAssembly "typeproviders" "typeProviders/splitAssemblyTypeproviders"
339313

340314
[<Test>]
341315
let wedgeAssembly () =
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Microsoft.FSharp.Core.CompilerServices
2+
3+
type TypeProviderAssemblyAttribute(assemblyName) =
4+
inherit System.Attribute()
5+
6+
new() = TypeProviderAssemblyAttribute(null)
7+
member this.AssemblyName
8+
with get () = assemblyName
9+
10+
[<assembly:TypeProviderAssembly("providerDesigner")>]
11+
do()
12+
13+
14+
namespace My
15+
type Runtime =
16+
static member Id x = x
17+
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
namespace Provider
2+
#load @"..\helloWorld\TypeMagic.fs"
3+
open Microsoft.FSharp.Core.CompilerServices
4+
open System.Collections.Generic
5+
open System.IO
6+
open System
7+
open System.Reflection
8+
open System.Linq.Expressions
9+
open FSharp.TypeMagic
10+
11+
[<TypeProvider>]
12+
type public Provider(config : TypeProviderConfig) =
13+
let runtimeAssembly = Assembly.ReflectionOnlyLoadFrom(config.RuntimeAssembly)
14+
let modul = runtimeAssembly.GetModules().[0]
15+
16+
let ``My.Runtime`` = runtimeAssembly.GetType("My.Runtime")
17+
let rootNamespace = "FSharp.SplitAssembly"
18+
let invalidation = new Event<System.EventHandler,_>()
19+
20+
let theType =
21+
let rec members =
22+
lazy
23+
[| let p = TypeBuilder.CreateSyntheticProperty(theType,"Foo",typeof<int>,isStatic=true)
24+
yield! TypeBuilder.JoinPropertiesIntoMemberInfos [p]
25+
|]
26+
and theType =
27+
TypeBuilder.CreateSimpleType(TypeContainer.Namespace(modul,rootNamespace),"TheType", members = members)
28+
theType
29+
30+
interface IProvidedNamespace with
31+
member this.NamespaceName = rootNamespace
32+
member this.GetNestedNamespaces() = [||]
33+
member this.ResolveTypeName typeName =
34+
match typeName with
35+
| "TheType" -> theType
36+
| _ -> null
37+
member this.GetTypes() = [| theType |]
38+
39+
interface IDisposable with
40+
member __.Dispose() = ()
41+
interface ITypeProvider with
42+
member this.ApplyStaticArguments (st,_,_) = st
43+
member this.GetInvokerExpression(mb,p) =
44+
let mi = ``My.Runtime``.GetMethod("Id").MakeGenericMethod([|typeof<int>|])
45+
Quotations.Expr.Call(mi, [ Quotations.Expr.Value(42) ])
46+
member this.GetNamespaces() = [| this |]
47+
member this.GetStaticParameters st = [||]
48+
[<CLIEvent>]
49+
member this.Invalidate = invalidation.Publish
50+
member this.GetGeneratedAssemblyContents(assembly) = failwith "GetGeneratedAssemblyContents - only erased types were provided!!"
51+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#r "provider.dll"
2+
3+
let mutable failures = []
4+
let reportFailure s =
5+
stdout.WriteLine "\n................TEST FAILED...............\n"; failures <- failures @ [s]
6+
7+
let check s e r =
8+
if r = e then stdout.WriteLine (s+": YES")
9+
else (stdout.WriteLine ("\n***** "+s+": FAIL\n"); reportFailure s)
10+
11+
let test s b =
12+
if b then ( (* stdout.WriteLine ("passed: " + s) *) )
13+
else (stderr.WriteLine ("failure: " + s);
14+
reportFailure s)
15+
(*========================================================================*)
16+
17+
check "fgdjkwefg"
18+
FSharp.SplitAssembly.TheType.Foo
19+
42
20+
21+
(*---------------------------------------------------------------------------
22+
!* wrap up
23+
*--------------------------------------------------------------------------- *)
24+
25+
let _ =
26+
if not failures.IsEmpty then (printfn "Test Failed, failures = %A" failures; exit 1)
27+
28+
do (stdout.WriteLine "Test Passed";
29+
System.IO.File.WriteAllText("test.ok","ok");
30+
exit 0)
31+
32+

0 commit comments

Comments
 (0)