@@ -41,6 +41,24 @@ type GenerativeInterfacesProvider (config: TypeProviderConfig) as this =
4141 let contract = createInterface " IContract" members
4242 container.AddMember contract
4343
44+ // IExtended inherits from IContract and adds an extra method
45+ let extended = createInterface " IExtended" [ " GetLength" , [( " s" , typeof< string>)], typeof< int> ]
46+ extended.AddInterfaceImplementation( contract)
47+ container.AddMember extended
48+
49+ // Impl is a concrete class that implements both IMarker and IContract
50+ let impl = ProvidedTypeDefinition( " Impl" , Some typeof< obj>, isErased = false )
51+ let getString = ProvidedMethod( " GetString" , [], typeof< string>, invokeCode = fun _args -> <@@ " hello" @@>)
52+ getString.AddMethodAttrs( MethodAttributes.Virtual)
53+ let sum = ProvidedMethod( " Sum" , [ ProvidedParameter( " x" , typeof< int>); ProvidedParameter( " y" , typeof< int>)], typeof< int>,
54+ invokeCode = fun args -> <@@ (%% args.[ 1 ] : int) + (%% args.[ 2 ] : int) @@>)
55+ sum.AddMethodAttrs( MethodAttributes.Virtual)
56+ impl.AddMember getString
57+ impl.AddMember sum
58+ impl.AddInterfaceImplementation( marker)
59+ impl.AddInterfaceImplementation( contract)
60+ container.AddMember impl
61+
4462 tempAssembly.AddTypes [ container]
4563 this.AddNamespace( container.Namespace, [ container])
4664
@@ -89,3 +107,53 @@ let ``Interfaces with methods are generated correctly``() =
89107 Assert.True( contractSum.IsAbstract, " Expected Sum method to be abstract" )
90108 Assert.True( contractSum.IsVirtual, " Expected Sum method to be virtual" )
91109
110+ [<Fact>]
111+ let ``Interface inheritance : IExtended extends IContract`` () =
112+ testProvidedAssembly <| fun container ->
113+ let extended = container.GetNestedType " IExtended"
114+ Assert.NotNull( extended)
115+ Assert.True( extended.IsInterface, " Expected IExtended to be an interface" )
116+
117+ // IExtended declares its own method
118+ let getLength = extended.GetMethod( " GetLength" )
119+ Assert.NotNull( getLength)
120+ Assert.True( getLength.IsAbstract, " Expected GetLength to be abstract" )
121+
122+ // IExtended inherits IContract
123+ let ifaces = extended.GetInterfaces()
124+ let hasIContract = ifaces |> Array.exists ( fun i -> i.Name = " IContract" )
125+ Assert.True( hasIContract, " Expected IExtended to implement IContract" )
126+
127+ [<Fact>]
128+ let ``Concrete class implementing interfaces is generated correctly`` () =
129+ testProvidedAssembly <| fun container ->
130+ let impl = container.GetNestedType " Impl"
131+ Assert.NotNull( impl)
132+ Assert.False( impl.IsInterface, " Impl should not be an interface" )
133+ Assert.False( impl.IsAbstract, " Impl should not be abstract" )
134+
135+ // Impl implements both IMarker and IContract
136+ let ifaces = impl.GetInterfaces()
137+ let hasIMarker = ifaces |> Array.exists ( fun i -> i.Name = " IMarker" )
138+ let hasIContract = ifaces |> Array.exists ( fun i -> i.Name = " IContract" )
139+ Assert.True( hasIMarker, " Expected Impl to implement IMarker" )
140+ Assert.True( hasIContract, " Expected Impl to implement IContract" )
141+
142+ [<Fact>]
143+ let ``Concrete class methods satisfy interface contract`` () =
144+ testProvidedAssembly <| fun container ->
145+ let impl = container.GetNestedType " Impl"
146+ Assert.NotNull( impl)
147+
148+ let getString = impl.GetMethod( " GetString" )
149+ Assert.NotNull( getString)
150+ Assert.False( getString.IsAbstract, " GetString on Impl should not be abstract" )
151+
152+ let sum = impl.GetMethod( " Sum" )
153+ Assert.NotNull( sum)
154+ let ps = sum.GetParameters()
155+ Assert.Equal( 2 , ps.Length)
156+ Assert.Equal( typeof< int>, ps.[ 0 ]. ParameterType)
157+ Assert.Equal( typeof< int>, ps.[ 1 ]. ParameterType)
158+ Assert.Equal( typeof< int>, sum.ReturnType)
159+
0 commit comments