Skip to content

Commit 4d30755

Browse files
committed
Fix expressions for type providers
1 parent 6e86a6b commit 4d30755

File tree

12 files changed

+3618
-8
lines changed

12 files changed

+3618
-8
lines changed

FSharp.Compiler.Service.sln

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
2-
# Visual Studio 2013
3-
VisualStudioVersion = 12.0.31101.0
2+
# Visual Studio 14
3+
VisualStudioVersion = 14.0.23107.0
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{B6B68AE6-E7A4-4D43-9B34-FFA74BFE192B}"
66
ProjectSection(SolutionItems) = preProject
@@ -57,6 +57,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Fsc", "samples\FscExe\Fsc.f
5757
EndProject
5858
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharp_Analysis", "tests\service\data\CSharp_Analysis\CSharp_Analysis.csproj", "{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}"
5959
EndProject
60+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TestTP", "tests\service\TestTP\TestTP.fsproj", "{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}"
61+
EndProject
6062
Global
6163
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6264
Debug|Any CPU = Debug|Any CPU
@@ -190,6 +192,24 @@ Global
190192
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
191193
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
192194
{887630A3-4B1D-40EA-B8B3-2D842E9C40DB}.Release|x86.ActiveCfg = Release|Any CPU
195+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
196+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|Any CPU.Build.0 = Debug|Any CPU
197+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
198+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
199+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|x86.ActiveCfg = Debug|Any CPU
200+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Debug|x86.Build.0 = Debug|Any CPU
201+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|Any CPU.ActiveCfg = Release|Any CPU
202+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|Any CPU.Build.0 = Release|Any CPU
203+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|Mixed Platforms.ActiveCfg = Release|Any CPU
204+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|Mixed Platforms.Build.0 = Release|Any CPU
205+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|x86.ActiveCfg = Release|Any CPU
206+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Proto|x86.Build.0 = Release|Any CPU
207+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|Any CPU.ActiveCfg = Release|Any CPU
208+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|Any CPU.Build.0 = Release|Any CPU
209+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
210+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
211+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|x86.ActiveCfg = Release|Any CPU
212+
{FF76BD3C-5E0A-4752-B6C3-044F6E15719B}.Release|x86.Build.0 = Release|Any CPU
193213
EndGlobalSection
194214
GlobalSection(SolutionProperties) = preSolution
195215
HideSolutionNode = FALSE

src/fsharp/vs/Exprs.fs

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,80 @@ open Microsoft.FSharp.Compiler.TypeRelations
1616
open Internal.Utilities
1717

1818

19+
[<AutoOpen>]
20+
module ExprUtilsImpl =
21+
22+
// ILCall nodes arise from calls to .NET methods, and provided calls to
23+
// F# methods. This method attempts to take the information in a ILMethodRef
24+
// and bind it to a symbol. This is not fool proof when the ILCall refers to
25+
// an F# method, but is a good approximation.
26+
let bindILMethodRefToSymbol (cenv:Impl.cenv) m (ilMethRef: ILMethodRef) =
27+
let tcref = Import.ImportILTypeRef cenv.amap m ilMethRef.EnclosingTypeRef
28+
let enclosingType = generalizedTyconRef tcref
29+
// First try to resolve it to IL metadata
30+
let try1 =
31+
if tcref.IsILTycon then
32+
try
33+
let mdef = resolveILMethodRefWithRescope (rescopeILType (p13 tcref.ILTyconInfo)) tcref.ILTyconRawMetadata ilMethRef
34+
let minfo = MethInfo.CreateILMeth(cenv.amap, m, enclosingType, mdef)
35+
Some (FSharpMemberOrFunctionOrValue(cenv, minfo))
36+
with _ -> None
37+
else None
38+
39+
// Otherwise try to bind it to an F# symbol
40+
match try1 with
41+
| Some res -> res
42+
| None ->
43+
try
44+
// Try to bind the call to an F# method call
45+
let memberParentName = if tcref.IsModuleOrNamespace then None else Some tcref.LogicalName
46+
// TODO: this logical name is not correct in the presence of CompiledName
47+
let logicalName = ilMethRef.Name
48+
let isMember = memberParentName.IsSome
49+
if isMember then
50+
let isCtor = (ilMethRef.Name = ".ctor")
51+
let isStatic = isCtor || ilMethRef.CallingConv.IsStatic
52+
let scoref = ilMethRef.EnclosingTypeRef.Scope
53+
let typars1 = tcref.Typars(m)
54+
let typars2 = [ 1 .. ilMethRef.GenericArity ] |> List.map (fun _ -> NewRigidTypar "T" m)
55+
let tinst1 = typars1 |> generalizeTypars
56+
let tinst2 = typars2 |> generalizeTypars
57+
// TODO: this will not work for curried methods in F# classes.
58+
// This is difficult to solve as the information in the ILMethodRef
59+
// is not sufficient to resolve to a symbol unambiguously in these cases.
60+
let argtys = [ ilMethRef.ArgTypes |> List.map (ImportTypeFromMetadata cenv.amap m scoref tinst1 tinst2) ]
61+
let rty =
62+
match ImportReturnTypeFromMetaData cenv.amap m ilMethRef.ReturnType scoref tinst1 tinst2 with
63+
| None -> if isCtor then enclosingType else cenv.g.unit_ty
64+
| Some ty -> ty
65+
66+
let linkageType =
67+
let ty = mkIteratedFunTy (List.map (mkTupledTy cenv.g) argtys) rty
68+
let ty = if isStatic then ty else mkFunTy enclosingType ty
69+
tryMkForallTy (typars1 @ typars2) ty
70+
71+
let argCount = List.sum (List.map List.length argtys) + (if isStatic then 0 else 1)
72+
let key = ValLinkageFullKey({ MemberParentMangledName=memberParentName; MemberIsOverride=false; LogicalName=logicalName; TotalArgCount= argCount },Some linkageType)
73+
74+
let enclosingNonLocalRef = mkNonLocalEntityRef tcref.nlr.Ccu tcref.PublicPath.Value.EnclosingPath
75+
let vref = mkNonLocalValRef enclosingNonLocalRef key
76+
vref.Deref |> ignore // check we can dereference the value
77+
let minfo = MethInfo.FSMeth(cenv.g, enclosingType, vref, None)
78+
FSharpMemberOrFunctionOrValue(cenv, minfo)
79+
else
80+
let key = ValLinkageFullKey({ MemberParentMangledName=memberParentName; MemberIsOverride=false; LogicalName=logicalName; TotalArgCount= 0 },None)
81+
let vref = mkNonLocalValRef tcref.nlr key
82+
vref.Deref |> ignore // check we can dereference the value
83+
FSharpMemberOrFunctionOrValue(cenv, vref)
84+
85+
with _ ->
86+
failwith (sprintf "A call to '%s' could not be resolved" (ilMethRef.ToString()))
87+
88+
89+
1990
[<AutoOpen>]
2091
module ExprTranslationImpl =
92+
2193
type ExprTranslationEnv =
2294
{ //Map from Val to binding index
2395
vs: ValMap<unit>;
@@ -612,12 +684,7 @@ module FSharpExprConvert =
612684
| _ -> failwith "unexpected for-loop form"
613685

614686
| TOp.ILCall(_,_,_,isNewObj,_valUseFlags,_isProp,_,ilMethRef,enclTypeArgs,methTypeArgs,_tys),[],callArgs ->
615-
let tcref = Import.ImportILTypeRef cenv.amap m ilMethRef.EnclosingTypeRef
616-
let mdef =
617-
try resolveILMethodRefWithRescope (rescopeILType (p13 tcref.ILTyconInfo)) tcref.ILTyconRawMetadata ilMethRef
618-
with _ -> failwith (sprintf "A call to '%s' could not be resolved" (ilMethRef.ToString()))
619-
let minfo = MethInfo.CreateILMeth(cenv.amap, m, generalizedTyconRef tcref, mdef)
620-
let v = FSharpMemberFunctionOrValue(cenv, minfo)
687+
let v = bindILMethodRefToSymbol cenv m ilMethRef
621688
ConvObjectModelCallLinear cenv env (isNewObj, v, enclTypeArgs, methTypeArgs, callArgs) (fun e -> e)
622689

623690
| TOp.TryFinally _,[_resty],[Expr.Lambda(_,_,_,[_],e1,_,_); Expr.Lambda(_,_,_,[_],e2,_,_)] ->

tests/service/ExprTests.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,28 @@ let ``Test expressions of declarations stress big expressions`` () =
673673
printDeclarations None (List.ofSeq file1.Declarations) |> Seq.toList |> ignore
674674

675675

676+
677+
[<Test>]
678+
let ``Check use of type provider that provides calls to F# code`` () =
679+
let res =
680+
checker.GetProjectOptionsFromProjectFile (Path.Combine(__SOURCE_DIRECTORY__, @"TestProject\TestProject.fsproj"))
681+
|> checker.ParseAndCheckProject
682+
|> Async.RunSynchronously
683+
684+
res.Errors.Length |> shouldEqual 0
685+
686+
let results =
687+
[ for f in res.AssemblyContents.ImplementationFiles do
688+
for d in f.Declarations do
689+
for line in d |> printDeclaration None do
690+
yield line ]
691+
results |> shouldEqual
692+
["type TestProject"; "type AssemblyInfo"; "type TestProject"; "type T";
693+
"type Class1";
694+
"member .ctor(unitVar0) = (Object..ctor (); ()) @ (5,5--5,11)";
695+
"""member get_X(this) (unitVar1) = let this: Microsoft.FSharp.Core.obj = ("My internal state" :> Microsoft.FSharp.Core.obj) :> ErasedWithConstructor.Provided.MyType in Helper.doNothing () @ (6,20--6,35)""" ]
696+
697+
676698
#if SELF_HOST_STRESS
677699

678700
[<Test>]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
namespace TestProject.AssemblyInfo
2+
3+
open System.Reflection
4+
open System.Runtime.CompilerServices
5+
open System.Runtime.InteropServices
6+
7+
// General Information about an assembly is controlled through the following
8+
// set of attributes. Change these attribute values to modify the information
9+
// associated with an assembly.
10+
[<assembly: AssemblyTitle("TestProject")>]
11+
[<assembly: AssemblyDescription("")>]
12+
[<assembly: AssemblyConfiguration("")>]
13+
[<assembly: AssemblyCompany("")>]
14+
[<assembly: AssemblyProduct("TestProject")>]
15+
[<assembly: AssemblyCopyright("Copyright © 2015")>]
16+
[<assembly: AssemblyTrademark("")>]
17+
[<assembly: AssemblyCulture("")>]
18+
19+
// Setting ComVisible to false makes the types in this assembly not visible
20+
// to COM components. If you need to access a type in this assembly from
21+
// COM, set the ComVisible attribute to true on that type.
22+
[<assembly: ComVisible(false)>]
23+
24+
// The following GUID is for the ID of the typelib if this project is exposed to COM
25+
[<assembly: Guid("ed64425e-b549-439a-b105-6c921a81f31a")>]
26+
27+
// Version information for an assembly consists of the following four values:
28+
//
29+
// Major Version
30+
// Minor Version
31+
// Build Number
32+
// Revision
33+
//
34+
// You can specify all the values or you can default the Build and Revision Numbers
35+
// by using the '*' as shown below:
36+
// [<assembly: AssemblyVersion("1.0.*")>]
37+
[<assembly: AssemblyVersion("1.0.0.0")>]
38+
[<assembly: AssemblyFileVersion("1.0.0.0")>]
39+
40+
do
41+
()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace TestProject
2+
3+
type T = ErasedWithConstructor.Provided.MyType
4+
5+
type Class1() =
6+
member this.X = T().DoNothing()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<SchemaVersion>2.0</SchemaVersion>
8+
<ProjectGuid>ed64425e-b549-439a-b105-6c921a81f31a</ProjectGuid>
9+
<OutputType>Library</OutputType>
10+
<RootNamespace>TestProject</RootNamespace>
11+
<AssemblyName>TestProject</AssemblyName>
12+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
13+
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
14+
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
15+
<Name>TestProject</Name>
16+
</PropertyGroup>
17+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18+
<DebugSymbols>true</DebugSymbols>
19+
<DebugType>full</DebugType>
20+
<Optimize>false</Optimize>
21+
<Tailcalls>false</Tailcalls>
22+
<OutputPath>bin\Debug\</OutputPath>
23+
<DefineConstants>DEBUG;TRACE</DefineConstants>
24+
<WarningLevel>3</WarningLevel>
25+
<DocumentationFile>bin\Debug\TestProject.XML</DocumentationFile>
26+
</PropertyGroup>
27+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
28+
<DebugType>pdbonly</DebugType>
29+
<Optimize>true</Optimize>
30+
<Tailcalls>true</Tailcalls>
31+
<OutputPath>bin\Release\</OutputPath>
32+
<DefineConstants>TRACE</DefineConstants>
33+
<WarningLevel>3</WarningLevel>
34+
<DocumentationFile>bin\Release\TestProject.XML</DocumentationFile>
35+
</PropertyGroup>
36+
<ItemGroup>
37+
<Reference Include="mscorlib" />
38+
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
39+
<Private>True</Private>
40+
</Reference>
41+
<Reference Include="System" />
42+
<Reference Include="System.Core" />
43+
<Reference Include="System.Numerics" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="AssemblyInfo.fs" />
47+
<Compile Include="Library.fs" />
48+
<None Include="Script.fsx" />
49+
</ItemGroup>
50+
<ItemGroup>
51+
<ProjectReference Include="..\TestTP\TestTP.fsproj">
52+
<Name>TestTP</Name>
53+
<Project>{ff76bd3c-5e0a-4752-b6c3-044f6e15719b}</Project>
54+
<Private>True</Private>
55+
</ProjectReference>
56+
</ItemGroup>
57+
<PropertyGroup>
58+
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
59+
</PropertyGroup>
60+
<Choose>
61+
<When Condition="'$(VisualStudioVersion)' == '11.0'">
62+
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
63+
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
64+
</PropertyGroup>
65+
</When>
66+
<Otherwise>
67+
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
68+
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
69+
</PropertyGroup>
70+
</Otherwise>
71+
</Choose>
72+
<Import Project="$(FSharpTargetsPath)" />
73+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
74+
Other similar extension points exist, see Microsoft.Common.targets.
75+
<Target Name="BeforeBuild">
76+
</Target>
77+
<Target Name="AfterBuild">
78+
</Target>
79+
-->
80+
</Project>

tests/service/TestTP/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
5+
</startup>
6+
</configuration>

tests/service/TestTP/Library.fs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
namespace TestTP
2+
3+
open ProviderImplementation.ProvidedTypes
4+
open Microsoft.FSharp.Core.CompilerServices
5+
open System.Reflection
6+
7+
module Helper =
8+
let doNothing() = ()
9+
let doNothingOneArg(x:int) = ()
10+
let doNothingGeneric(x:'T) = ()
11+
type C() =
12+
static member DoNothing() = ()
13+
static member DoNothingOneArg(x:int) = ()
14+
static member DoNothingTwoArg(c:C, x:int) = ()
15+
static member DoNothingGeneric(x:'T) = ()
16+
member __.InstanceDoNothing() = ()
17+
member __.InstanceDoNothingOneArg(x:int) = ()
18+
member __.InstanceDoNothingTwoArg(c:C, x:int) = ()
19+
member __.InstanceDoNothingGeneric(x:'T) = ()
20+
21+
type G<'U>() =
22+
static member DoNothing() = ()
23+
static member DoNothingOneArg(x:int) = ()
24+
static member DoNothingTwoArg(c:C, x:int) = ()
25+
static member DoNothingGeneric(x:'T) = ()
26+
member __.InstanceDoNothing() = ()
27+
member __.InstanceDoNothingOneArg(x:int) = ()
28+
member __.InstanceDoNothingTwoArg(c:C, x:int) = ()
29+
member __.InstanceDoNothingGeneric(x:'U) = ()
30+
31+
[<TypeProvider>]
32+
type BasicProvider (config : TypeProviderConfig) as this =
33+
inherit TypeProviderForNamespaces ()
34+
35+
let ns = "ErasedWithConstructor.Provided"
36+
let asm = Assembly.GetExecutingAssembly()
37+
38+
let createTypes () =
39+
let myType = ProvidedTypeDefinition(asm, ns, "MyType", Some typeof<obj>)
40+
41+
let ctor = ProvidedConstructor([], InvokeCode = fun args -> <@@ "My internal state" :> obj @@>)
42+
myType.AddMember(ctor)
43+
44+
let ctor2 = ProvidedConstructor(
45+
[ProvidedParameter("InnerState", typeof<string>)],
46+
InvokeCode = fun args -> <@@ (%%(args.[0]):string) :> obj @@>)
47+
myType.AddMember(ctor2)
48+
49+
let innerState = ProvidedProperty("InnerState", typeof<string>,
50+
GetterCode = fun args -> <@@ (%%(args.[0]) :> obj) :?> string @@>)
51+
myType.AddMember(innerState)
52+
53+
let someMethod = ProvidedMethod("DoNothing", [], typeof<unit>,
54+
InvokeCode = fun args -> <@@ Helper.doNothing();
55+
Helper.doNothingOneArg(3)
56+
Helper.doNothingGeneric(3)
57+
Helper.C.DoNothing()
58+
Helper.C.DoNothingGeneric(3)
59+
Helper.C.DoNothingOneArg(3)
60+
Helper.C.DoNothingTwoArg(Helper.C(), 3)
61+
Helper.C().InstanceDoNothing()
62+
Helper.C().InstanceDoNothingGeneric(3)
63+
Helper.C().InstanceDoNothingOneArg(3)
64+
Helper.C().InstanceDoNothingTwoArg(Helper.C(), 3)
65+
Helper.G<int>.DoNothing()
66+
Helper.G<int>.DoNothingGeneric(3)
67+
Helper.G<int>.DoNothingOneArg(3)
68+
Helper.G<int>.DoNothingTwoArg(Helper.C(), 3)
69+
Helper.G<int>().InstanceDoNothing()
70+
Helper.G<int>().InstanceDoNothingGeneric(3)
71+
Helper.G<int>().InstanceDoNothingOneArg(3)
72+
Helper.G<int>().InstanceDoNothingTwoArg(Helper.C(), 3) @@>)
73+
74+
myType.AddMember(someMethod)
75+
76+
[myType]
77+
78+
do
79+
this.AddNamespace(ns, createTypes())
80+
81+
[<assembly:TypeProviderAssembly>]
82+
do ()

0 commit comments

Comments
 (0)