Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit780b634

Browse files
dsymeKevinRansom
authored andcommitted
Type provider design time component loading suitable for .NET Core tooling (#3864)
* type provider design time component loading* fix build* fix build* tests* add tests
1 parent0e5f772 commit780b634

File tree

8 files changed

+233
-38
lines changed

8 files changed

+233
-38
lines changed

‎src/FSharpSource.Profiles.targets‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
<DefineConstants>$(DefineConstants);FX_LCIDFROMCODEPAGE</DefineConstants>
1010
</PropertyGroup>
1111

12+
<!-- Note: The TargetDotnetProfile value 'coreclr' currently covers all of netstandard1.6, netstandard2.0 and netcoreapp2.0 in a confused way-->
13+
<!-- These should be distinguished in the future-->
14+
1215
<PropertyGroupCondition="'$(TargetDotnetProfile)'=='coreclr'">
1316
<DefineConstants>$(DefineConstants);FX_PORTABLE_OR_NETSTANDARD</DefineConstants>
1417
<DefineConstants>$(DefineConstants);NETSTANDARD1_6</DefineConstants>

‎src/fsharp/CompileOps.fs‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4281,14 +4281,16 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti
42814281

42824282
// Find assembly level TypeProviderAssemblyAttributes. These will point to the assemblies that
42834283
// have class which implement ITypeProvider and which have TypeProviderAttribute on them.
4284-
letproviderAssemblies=
4284+
letdesignTimeAssemblyNames=
42854285
runtimeAssemblyAttributes
42864286
|> List.choose(TryDecodeTypeProviderAssemblyAttr(defaultArg ilGlobalsOpt EcmaMscorlibILGlobals))
42874287
// If no design-time assembly is specified, use the runtime assembly
4288-
|> List.map(functionnull-> Path.GetFileNameWithoutExtension fileNameOfRuntimeAssembly| s-> s)
4289-
|> Set.ofList
4288+
|> List.map(functionnull-> fileNameOfRuntimeAssembly| s-> s)
4289+
// For each simple name of a design-time assembly, we take the first matching one in the order they are
4290+
// specified in the attributes
4291+
|> List.distinctBy(fun s->try Path.GetFileNameWithoutExtension(s)with_-> s)
42904292

4291-
ifproviderAssemblies.Count>0then
4293+
ifdesignTimeAssemblyNames.Length>0then
42924294

42934295
// Find the SystemRuntimeAssemblyVersion value to report in the TypeProviderConfig.
42944296
letprimaryAssemblyVersion=
@@ -4316,10 +4318,9 @@ type TcImports(tcConfigP:TcConfigProvider, initialResolutions:TcAssemblyResoluti
43164318
fun arg-> systemRuntimeContainsTypeRef.Value arg
43174319

43184320
letproviders=
4319-
[for assemblyNamein providerAssembliesdo
4320-
yield ExtensionTyping.GetTypeProvidersOfAssembly(fileNameOfRuntimeAssembly, ilScopeRefOfRuntimeAssembly, assemblyName, typeProviderEnvironment,
4321-
tcConfig.isInvalidationSupported, tcConfig.isInteractive, systemRuntimeContainsType, primaryAssemblyVersion, m)]
4322-
letproviders= providers|> List.concat
4321+
[for designTimeAssemblyNamein designTimeAssemblyNamesdo
4322+
yield! ExtensionTyping.GetTypeProvidersOfAssembly(fileNameOfRuntimeAssembly, ilScopeRefOfRuntimeAssembly, designTimeAssemblyName, typeProviderEnvironment,
4323+
tcConfig.isInvalidationSupported, tcConfig.isInteractive, systemRuntimeContainsType, primaryAssemblyVersion, m)]
43234324

43244325
// Note, type providers are disposable objects. The TcImports owns the provider objects - when/if it is disposed, the providers are disposed.
43254326
// We ignore all exceptions from provider disposal.

‎src/fsharp/ExtensionTyping.fs‎

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,37 @@ module internal ExtensionTyping =
3636
temporaryFolder:string}
3737

3838

39+
// Specify the tooling-compatible fragments of a path such as:
40+
// typeproviders/fsharp41/net461/MyProvider.DesignTime.dll
41+
// See https://github.com/Microsoft/visualfsharp/issues/3736
42+
43+
// Represents the FF#-compiler <-> type provider protocol.
44+
// When the API or protocol updates, add a new version moniker to the front of the list here.
45+
lettoolingCompatibleTypeProviderProtocolMonikers()=
46+
["fsharp41"]
47+
48+
// Detect the host tooling context
49+
lettoolingCompatibleVersions()=
50+
if typeof<obj>.Assembly.GetName().Name="mscorlib"then
51+
["net461";"net452";"net451";"net45";"netstandard2.0"]
52+
elif typeof<obj>.Assembly.GetName().Name="System.Private.CoreLib"then
53+
["netcoreapp2.0";"netstandard2.0"]
54+
else
55+
System.Diagnostics.Debug.Assert(false,"Couldn't determine runtime tooling context, assuming it supports at least .NET Standard 2.0")
56+
["netstandard2.0"]
57+
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+
lettoolingCompatibleArch()=if sizeof<nativeint>=8then"x64"else"x86"
62+
lettoolingCompatiblePaths()=
63+
[for protocolin toolingCompatibleTypeProviderProtocolMonikers()do
64+
for netRuntimein toolingCompatibleVersions()do
65+
letdir= Path.Combine("typeproviders", protocol, netRuntime)
66+
yield Path.Combine(dir, toolingCompatibleArch())
67+
yield dir
68+
]
69+
3970
/// Load a the design-time part of a type-provider into the host process, and look for types
4071
/// marked with the TypeProviderAttribute attribute.
4172
letGetTypeProviderImplementationTypes(runTimeAssemblyFileName,designTimeAssemblyNameString,m:range)=
@@ -46,32 +77,58 @@ module internal ExtensionTyping =
4677

4778
// Find and load the designer assembly for the type provider component.
4879
//
49-
// If the assembly name ends with .dll, or is just a simple name, we look in the directory next to runtime assembly.
50-
// Else we only look in the GAC.
51-
letdesignTimeAssemblyOpt=
52-
letloadFromDir fileName=
80+
// We look in the directories stepping up from the location of the runtime assembly.
81+
82+
letloadFromLocation designTimeAssemblyPath=
83+
try
84+
Some(FileSystem.AssemblyLoadFrom designTimeAssemblyPath)
85+
with e->
86+
raiseError e
87+
88+
let recsearchParentDirChain dir designTimeAssemblyName=
89+
seq{
90+
for subdirin toolingCompatiblePaths()do
91+
letdesignTimeAssemblyPath= Path.Combine(dir, subdir, designTimeAssemblyName)
92+
if FileSystem.SafeExists designTimeAssemblyPaththen
93+
yield loadFromLocation designTimeAssemblyPath
94+
match Path.GetDirectoryName(dir)with
95+
| swhen s=""|| s=null|| Path.GetFileName(dir)="packages"|| s= dir->()
96+
| parentDir->yield! searchParentDirChain parentDir designTimeAssemblyName
97+
}
98+
99+
letloadFromParentDirRelativeToRuntimeAssemblyLocation designTimeAssemblyName=
100+
letrunTimeAssemblyPath= Path.GetDirectoryName runTimeAssemblyFileName
101+
searchParentDirChain runTimeAssemblyPath designTimeAssemblyName
102+
|> Seq.tryHead
103+
|>function
104+
| Some res-> res
105+
| None->
106+
// The search failed, just load from the first location and report an error
53107
letrunTimeAssemblyPath= Path.GetDirectoryName runTimeAssemblyFileName
54-
letdesignTimeAssemblyPath= Path.Combine(runTimeAssemblyPath, fileName)
55-
try
56-
Some(FileSystem.AssemblyLoadFrom designTimeAssemblyPath)
57-
with e->
58-
raiseError e
59-
letloadFromGac()=
60-
try
61-
letasmName= System.Reflection.AssemblyName designTimeAssemblyNameString
62-
Some(FileSystem.AssemblyLoad(asmName))
63-
with e->
64-
raiseError e
108+
loadFromLocation(Path.Combine(runTimeAssemblyPath, designTimeAssemblyName))
109+
110+
letdesignTimeAssemblyOpt=
65111

66112
if designTimeAssemblyNameString.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)then
67-
loadFromDir designTimeAssemblyNameString
113+
loadFromParentDirRelativeToRuntimeAssemblyLocation designTimeAssemblyNameString
68114
else
69-
letname= System.Reflection.AssemblyName designTimeAssemblyNameString
115+
// Cover the case where the ".dll" extension has been left off and no version etc. has been used in the assembly
116+
// string specification. The Name=FullName comparison is particularly strange, and was there to support
117+
// design-time DLLs specified using "x.DesignTIme, Version= ..." long assembly names and GAC loads.
118+
// These kind of design-time assembly specifications are no longer used to our knowledge so that comparison is basically legacy
119+
// and will always succeed.
120+
letname= System.Reflection.AssemblyName(Path.GetFileNameWithoutExtension designTimeAssemblyNameString)
70121
if name.Name.Equals(name.FullName, StringComparison.OrdinalIgnoreCase)then
71-
letfileName= designTimeAssemblyNameString+".dll"
72-
loadFromDir fileName
122+
letdesignTimeAssemblyName= designTimeAssemblyNameString+".dll"
123+
loadFromParentDirRelativeToRuntimeAssemblyLocation designTimeAssemblyName
73124
else
74-
loadFromGac()
125+
// Load from the GAC using Assembly.Load. This is legacy since type provider design-time components are
126+
// never in the GAC these days and "x.DesignTIme, Version= ..." specifications are never used.
127+
try
128+
letasmName= System.Reflection.AssemblyName designTimeAssemblyNameString
129+
Some(FileSystem.AssemblyLoad(asmName))
130+
with e->
131+
raiseError e
75132

76133
// If we've find a design-time assembly, look for the public types with TypeProviderAttribute
77134
match designTimeAssemblyOptwith
@@ -152,12 +209,17 @@ module internal ExtensionTyping =
152209
try
153210
letdesignTimeAssemblyName=
154211
try
155-
Some(System.Reflection.AssemblyName designTimeAssemblyNameString)
212+
if designTimeAssemblyNameString.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)then
213+
Some(System.Reflection.AssemblyName(Path.GetFileNameWithoutExtension designTimeAssemblyNameString))
214+
else
215+
Some(System.Reflection.AssemblyName designTimeAssemblyNameString)
156216
with:? ArgumentException->
157217
errorR(Error(FSComp.SR.etInvalidTypeProviderAssemblyName(runTimeAssemblyFileName, designTimeAssemblyNameString), m))
158218
None
159219

160220
[match designTimeAssemblyName, resolutionEnvironment.outputFilewith
221+
// Check if the attribute is pointing to the file being compiled, in which case ignore it
222+
// This checks seems like legacy but is included for compat.
161223
| Some designTimeAssemblyName, Some pathwhen String.Compare(designTimeAssemblyName.Name, Path.GetFileNameWithoutExtension path, StringComparison.OrdinalIgnoreCase)=0->
162224
()
163225
| Some_,_->

‎src/fsharp/ExtensionTyping.fsi‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ module internal ExtensionTyping =
2424
/// Raised when an type provider has thrown an exception.
2525
exception ProvidedTypeResolutionNoRangeofexn
2626

27+
/// Get the list of relative paths searched for type provider design-time components
28+
valtoolingCompatiblePaths:unit->string list
29+
2730
/// Carries information about the type provider resolution environment.
2831
typeResolutionEnvironment=
2932
{

‎src/fsharp/FSharp.Compiler.Unittests/ProductVersion.fs‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,11 @@ module ProductVersionTest =
8282
"0.0.0.0",(0us,0us,0us,0us)
8383
"3213.57843.32382.59493",(3213us,57843us,32382us,59493us)
8484
(sprintf"%d.%d.%d.%d" max max max max),(max,max,max,max)]
85-
|> List.map(fun(s,e)-> TestCaseData(s, e))
8685

87-
[<TestCaseSource("validValues")>]
88-
let``should use values if valid major.minor.revision.build version format``(v,expected)=
89-
v|> productVersionToILVersionInfo|> Assert.areEqual expected
86+
[<Test>]
87+
let``should use values if valid major.minor.revision.build version format``()=
88+
for(v, expected)in validValues()do
89+
v|> productVersionToILVersionInfo|> Assert.areEqual expected
9090

9191
letinvalidValues()=
9292
["1.2.3.4",(1us,2us,3us,4us)
@@ -100,8 +100,29 @@ module ProductVersionTest =
100100
"",(0us,0us,0us,0us)
101101
"70000.80000.90000.100000",(0us,0us,0us,0us)
102102
(sprintf"%d.70000.80000.90000" System.UInt16.MaxValue),(System.UInt16.MaxValue,0us,0us,0us)]
103-
|> List.map(fun(s,e)-> TestCaseData(s, e))
104103

105-
[<TestCaseSource("invalidValues")>]
106-
let``should zero starting from first invalid version part``(v,expected)=
107-
v|> productVersionToILVersionInfo|> Assert.areEqual expected
104+
[<Test>]
105+
let``should zero starting from first invalid version part``()=
106+
for(v, expected)in invalidValues()do
107+
v|> productVersionToILVersionInfo|> Assert.areEqual expected
108+
109+
moduleTypeProviderDesignTimeComponentLoading=
110+
111+
112+
[<Test>]
113+
let``check tooling paths for type provider design time component loading``()=
114+
letarch=if sizeof<nativeint>=8then"x64"else"x86"
115+
letexpected=
116+
[@"typeproviders\fsharp41\net461\"+ arch
117+
@"typeproviders\fsharp41\net461"
118+
@"typeproviders\fsharp41\net452\"+ arch
119+
@"typeproviders\fsharp41\net452"
120+
@"typeproviders\fsharp41\net451\"+ arch
121+
@"typeproviders\fsharp41\net451"
122+
@"typeproviders\fsharp41\net45\"+ arch
123+
@"typeproviders\fsharp41\net45"
124+
@"typeproviders\fsharp41\netstandard2.0\"+ arch
125+
@"typeproviders\fsharp41\netstandard2.0"
126+
]
127+
letactual= Microsoft.FSharp.Compiler.ExtensionTyping.toolingCompatiblePaths()
128+
Assert.areEqual expected actual

‎tests/fsharp/TypeProviderTests.fs‎

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ open SingleTest
2323
// Use these lines if you want to test CoreCLR
2424
letFSC_BASIC= FSC_CORECLR
2525
letFSI_BASIC= FSI_CORECLR
26+
letFSIANYCPU_BASIC= FSI_CORECLR
2627
#else
2728
letFSC_BASIC= FSC_OPT_PLUS_DEBUG
2829
letFSI_BASIC= FSI_FILE
30+
letFSIANYCPU_BASIC= FSIANYCPU_FILE
2931
#endif
3032

3133
[<Test>]
@@ -248,14 +250,93 @@ let ``negative type provider tests`` (name:string) =
248250

249251
[<Test>]
250252
letsplitAssembly()=
253+
251254
letcfg= testConfig"typeProviders/splitAssembly"
252255

256+
letclean()=
257+
rm cfg"providerDesigner.dll"
258+
rmdir cfg"typeproviders"
259+
rmdir cfg(".."++"typeproviders")
260+
261+
clean()
262+
253263
fsc cfg"--out:provider.dll -a"["provider.fs"]
254264

255265
fsc cfg"--out:providerDesigner.dll -a"["providerDesigner.fsx"]
256266

257267
SingleTest.singleTestBuildAndRunAux cfg FSC_BASIC
258-
268+
269+
SingleTest.singleTestBuildAndRunAux cfg FSI_BASIC
270+
271+
SingleTest.singleTestBuildAndRunAux cfg FSIANYCPU_BASIC
272+
273+
// Do the same thing with different load locations for the type provider design-time component
274+
275+
clean()
276+
277+
// check a few load locations
278+
letsomeLoadPaths=
279+
["typeproviders"++"fsharp41"++"net461"++"x86"
280+
"typeproviders"++"fsharp41"++"net461"
281+
"typeproviders"++"fsharp41"++"net45"
282+
// include up one directory
283+
".."++"typeproviders"++"fsharp41"++"net45"
284+
"typeproviders"++"fsharp41"++"netstandard2.0"]
285+
286+
letsomeLoadPaths64=
287+
["typeproviders"++"fsharp41"++"net461"++"x64"
288+
"typeproviders"++"fsharp41"++"net461"]
289+
290+
letsomeNegativeLoadPaths64=
291+
["typeproviders"++"fsharp41"++"net461"++"x86"]
292+
293+
294+
for dirin someLoadPathsdo
295+
296+
clean()
297+
298+
// put providerDesigner.dll into a different place
299+
mkdir cfg dir
300+
fsc cfg"--out:%s/providerDesigner.dll -a" dir["providerDesigner.fsx"]
301+
302+
SingleTest.singleTestBuildAndRunAux cfg FSC_BASIC
303+
304+
for dirin someLoadPathsdo
305+
306+
clean()
307+
308+
// put providerDesigner.dll into a different place
309+
mkdir cfg dir
310+
fsc cfg"--out:%s/providerDesigner.dll -a" dir["providerDesigner.fsx"]
311+
312+
SingleTest.singleTestBuildAndRunAux cfg FSI_BASIC
313+
314+
for dirin someLoadPaths64do
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 dirin someNegativeLoadPaths64do
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"]
331+
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->()
337+
338+
clean()
339+
259340
[<Test>]
260341
letwedgeAssembly()=
261342
letcfg= testConfig"typeProviders/wedgeAssembly"

‎tests/fsharp/single-test.fs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Permutation =
1212
| FSI_CORECLR
1313
#if!FSHARP_SUITE_DRIVES_CORECLR_TESTS
1414
| FSI_FILE
15+
| FSIANYCPU_FILE
1516
| FSI_STDIN
1617
| GENERATED_SIGNATURE
1718
| FSC_OPT_MINUS_DEBUG
@@ -94,6 +95,14 @@ let singleTestBuildAndRunCore cfg (copyFiles:string) p =
9495

9596
testOkFile.CheckExists()
9697

98+
| FSIANYCPU_FILE->
99+
use cleanup=(cleanUpFSharpCore cfg)
100+
use testOkFile=new FileGuard(getfullpath cfg"test.ok")
101+
102+
fsiAnyCpu cfg"%s" cfg.fsi_flags sources
103+
104+
testOkFile.CheckExists()
105+
97106
| FSI_STDIN->
98107
use cleanup=(cleanUpFSharpCore cfg)
99108
use testOkFile=new FileGuard(getfullpath cfg"test.ok")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp