Skip to content

Commit

Permalink
fix(jsii): deduplicate interfaces
Browse files Browse the repository at this point in the history
When processing interfaces from multiple declaration sites (e.g.
when a base class is erased), we need to make sure that only
include every interface once.

Fixes #496
  • Loading branch information
Elad Ben-Israel committed May 6, 2019
1 parent 46bc9b0 commit afed905
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 7 deletions.
8 changes: 8 additions & 0 deletions packages/jsii-calc/lib/erasures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@ export interface IJsii487External { }
export interface IJsii487External2 { }
class Jsii487Internal implements IJsii487External { }
export class Jsii487Derived extends Jsii487Internal implements IJsii487External2 { }

//
// Deduplicate interfaces that come from different declaration sites
// https://github.com/awslabs/jsii/issues/496
//
export interface IJsii496 { }
class Jsii496Base implements IJsii496 { }
export class Jsii496Derived extends Jsii496Base implements IJsii496 { }
26 changes: 25 additions & 1 deletion packages/jsii-calc/test/assembly.jsii
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,16 @@
},
"name": "IJsii487External2"
},
"jsii-calc.IJsii496": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.IJsii496",
"kind": "interface",
"locationInModule": {
"filename": "lib/erasures.ts",
"line": 56
},
"name": "IJsii496"
},
"jsii-calc.IMutableObjectLiteral": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.IMutableObjectLiteral",
Expand Down Expand Up @@ -4073,6 +4083,20 @@
},
"name": "Jsii487Derived"
},
"jsii-calc.Jsii496Derived": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.Jsii496Derived",
"initializer": {},
"interfaces": [
"jsii-calc.IJsii496"
],
"kind": "class",
"locationInModule": {
"filename": "lib/erasures.ts",
"line": 58
},
"name": "Jsii496Derived"
},
"jsii-calc.JsiiAgent": {
"assembly": "jsii-calc",
"docs": {
Expand Down Expand Up @@ -6779,5 +6803,5 @@
}
},
"version": "0.10.5",
"fingerprint": "yLgYMXLhffrmN5U4ftTmlWijmxvKaKHA4QXx9+adYe0="
"fingerprint": "Zn881YRFrX198/TaBpApis646FTCp/XbGmU7cWaw/cs="
}
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,16 @@
},
"name": "IJsii487External2"
},
"jsii-calc.IJsii496": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.IJsii496",
"kind": "interface",
"locationInModule": {
"filename": "lib/erasures.ts",
"line": 56
},
"name": "IJsii496"
},
"jsii-calc.IMutableObjectLiteral": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.IMutableObjectLiteral",
Expand Down Expand Up @@ -4073,6 +4083,20 @@
},
"name": "Jsii487Derived"
},
"jsii-calc.Jsii496Derived": {
"assembly": "jsii-calc",
"fqn": "jsii-calc.Jsii496Derived",
"initializer": {},
"interfaces": [
"jsii-calc.IJsii496"
],
"kind": "class",
"locationInModule": {
"filename": "lib/erasures.ts",
"line": 58
},
"name": "Jsii496Derived"
},
"jsii-calc.JsiiAgent": {
"assembly": "jsii-calc",
"docs": {
Expand Down Expand Up @@ -6779,5 +6803,5 @@
}
},
"version": "0.10.5",
"fingerprint": "yLgYMXLhffrmN5U4ftTmlWijmxvKaKHA4QXx9+adYe0="
"fingerprint": "Zn881YRFrX198/TaBpApis646FTCp/XbGmU7cWaw/cs="
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Amazon.JSII.Runtime.Deputy;

namespace Amazon.JSII.Tests.CalculatorNamespace
{
[JsiiInterface(nativeType: typeof(IIJsii496), fullyQualifiedName: "jsii-calc.IJsii496")]
public interface IIJsii496
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Amazon.JSII.Runtime.Deputy;

namespace Amazon.JSII.Tests.CalculatorNamespace
{
[JsiiTypeProxy(nativeType: typeof(IIJsii496), fullyQualifiedName: "jsii-calc.IJsii496")]
internal sealed class IJsii496Proxy : DeputyBase, IIJsii496
{
private IJsii496Proxy(ByRefValue reference): base(reference)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Amazon.JSII.Runtime.Deputy;

namespace Amazon.JSII.Tests.CalculatorNamespace
{
[JsiiClass(nativeType: typeof(Jsii496Derived), fullyQualifiedName: "jsii-calc.Jsii496Derived")]
public class Jsii496Derived : DeputyBase, IIJsii496
{
public Jsii496Derived(): base(new DeputyProps(new object[]{}))
{
}

protected Jsii496Derived(ByRefValue reference): base(reference)
{
}

protected Jsii496Derived(DeputyProps props): base(props)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ protected Class<?> resolveClass(final String fqn) throws ClassNotFoundException
case "jsii-calc.IJSII417PublicBaseOfBase": return software.amazon.jsii.tests.calculator.IJSII417PublicBaseOfBase.class;
case "jsii-calc.IJsii487External": return software.amazon.jsii.tests.calculator.IJsii487External.class;
case "jsii-calc.IJsii487External2": return software.amazon.jsii.tests.calculator.IJsii487External2.class;
case "jsii-calc.IJsii496": return software.amazon.jsii.tests.calculator.IJsii496.class;
case "jsii-calc.IMutableObjectLiteral": return software.amazon.jsii.tests.calculator.IMutableObjectLiteral.class;
case "jsii-calc.INonInternalInterface": return software.amazon.jsii.tests.calculator.INonInternalInterface.class;
case "jsii-calc.IPrivatelyImplemented": return software.amazon.jsii.tests.calculator.IPrivatelyImplemented.class;
Expand All @@ -92,6 +93,7 @@ protected Class<?> resolveClass(final String fqn) throws ClassNotFoundException
case "jsii-calc.JSObjectLiteralToNativeClass": return software.amazon.jsii.tests.calculator.JSObjectLiteralToNativeClass.class;
case "jsii-calc.JavaReservedWords": return software.amazon.jsii.tests.calculator.JavaReservedWords.class;
case "jsii-calc.Jsii487Derived": return software.amazon.jsii.tests.calculator.Jsii487Derived.class;
case "jsii-calc.Jsii496Derived": return software.amazon.jsii.tests.calculator.Jsii496Derived.class;
case "jsii-calc.JsiiAgent": return software.amazon.jsii.tests.calculator.JsiiAgent.class;
case "jsii-calc.LoadBalancedFargateServiceProps": return software.amazon.jsii.tests.calculator.LoadBalancedFargateServiceProps.class;
case "jsii-calc.Multiply": return software.amazon.jsii.tests.calculator.Multiply.class;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package software.amazon.jsii.tests.calculator;

@javax.annotation.Generated(value = "jsii-pacmak")
public interface IJsii496 extends software.amazon.jsii.JsiiSerializable {

/**
* A proxy class which represents a concrete javascript instance of this type.
*/
final static class Jsii$Proxy extends software.amazon.jsii.JsiiObject implements software.amazon.jsii.tests.calculator.IJsii496 {
protected Jsii$Proxy(final software.amazon.jsii.JsiiObject.InitializationMode mode) {
super(mode);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package software.amazon.jsii.tests.calculator;

@javax.annotation.Generated(value = "jsii-pacmak")
@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.Jsii496Derived")
public class Jsii496Derived extends software.amazon.jsii.JsiiObject implements software.amazon.jsii.tests.calculator.IJsii496 {
protected Jsii496Derived(final software.amazon.jsii.JsiiObject.InitializationMode mode) {
super(mode);
}
public Jsii496Derived() {
super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii);
software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,18 @@ class _IJsii487External2Proxy():
__jsii_type__ = "jsii-calc.IJsii487External2"
pass

@jsii.interface(jsii_type="jsii-calc.IJsii496")
class IJsii496(jsii.compat.Protocol):
@staticmethod
def __jsii_proxy_class__():
return _IJsii496Proxy

pass

class _IJsii496Proxy():
__jsii_type__ = "jsii-calc.IJsii496"
pass

@jsii.interface(jsii_type="jsii-calc.IMutableObjectLiteral")
class IMutableObjectLiteral(jsii.compat.Protocol):
@staticmethod
Expand Down Expand Up @@ -1985,6 +1997,12 @@ def __init__(self) -> None:
jsii.create(Jsii487Derived, self, [])


@jsii.implements(IJsii496)
class Jsii496Derived(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.Jsii496Derived"):
def __init__(self) -> None:
jsii.create(Jsii496Derived, self, [])


class JsiiAgent(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.JsiiAgent"):
"""Host runtime version should be set via JSII_AGENT."""
def __init__(self) -> None:
Expand Down Expand Up @@ -3302,6 +3320,6 @@ def parts(self, value: typing.List[scope.jsii_calc_lib.Value]):
return jsii.set(self, "parts", value)


__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithDocs", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IJsii487External", "IJsii487External2", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "Jsii487Derived", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "StaticContext", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "VoidCallback", "__jsii_assembly__", "composition"]
__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithDocs", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IExtendsPrivateInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IJSII417Derived", "IJSII417PublicBaseOfBase", "IJsii487External", "IJsii487External2", "IJsii496", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "Jsii487Derived", "Jsii496Derived", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "StaticContext", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "VoidCallback", "__jsii_assembly__", "composition"]

publication.publish()
58 changes: 58 additions & 0 deletions packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2877,6 +2877,35 @@ IJsii487External2 (interface)



IJsii496 (interface)
^^^^^^^^^^^^^^^^^^^^

.. py:class:: IJsii496
**Language-specific names:**

.. tabs::

.. code-tab:: c#

using Amazon.JSII.Tests.CalculatorNamespace;

.. code-tab:: java

import software.amazon.jsii.tests.calculator.IJsii496;

.. code-tab:: javascript

// IJsii496 is an interface

.. code-tab:: typescript

import { IJsii496 } from 'jsii-calc';





IMutableObjectLiteral (interface)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -3972,6 +4001,35 @@ Jsii487Derived
:implements: :py:class:`~jsii-calc.IJsii487External2`\
:implements: :py:class:`~jsii-calc.IJsii487External`\
Jsii496Derived
^^^^^^^^^^^^^^
.. py:class:: Jsii496Derived()
**Language-specific names:**
.. tabs::
.. code-tab:: c#
using Amazon.JSII.Tests.CalculatorNamespace;
.. code-tab:: java
import software.amazon.jsii.tests.calculator.Jsii496Derived;
.. code-tab:: javascript
const { Jsii496Derived } = require('jsii-calc');
.. code-tab:: typescript
import { Jsii496Derived } from 'jsii-calc';
:implements: :py:class:`~jsii-calc.IJsii496`\
JsiiAgent
^^^^^^^^^
Expand Down
10 changes: 6 additions & 4 deletions packages/jsii/lib/assembler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,12 @@ export class Assembler implements Emitter {
}

// process all "implements" clauses
jsiiType.interfaces = jsiiType.interfaces || [];
const allInterfaces = new Set<string>();
for (const clause of implementsClauses) {
const { interfaces } = await this._processBaseInterfaces(fqn, clause.types.map(t => this._typeChecker.getTypeFromTypeNode(t)));
jsiiType.interfaces.push(...(interfaces || []).map(i => i.fqn));
for (const ifc of (interfaces || [])) {
allInterfaces.add(ifc.fqn);
}
if (interfaces) {
this._deferUntilTypesAvailable(jsiiType.fqn, interfaces, type.symbol.valueDeclaration, (...ifaces) => {
for (const iface of ifaces) {
Expand All @@ -522,8 +524,8 @@ export class Assembler implements Emitter {
}
}

if (jsiiType.interfaces.length === 0) {
delete jsiiType.interfaces;
if (allInterfaces.size > 0) {
jsiiType.interfaces = Array.from(allInterfaces);
}

if (!type.isClass()) {
Expand Down

0 comments on commit afed905

Please sign in to comment.