Skip to content

Commit

Permalink
fix(kernel): Improve tagged type of wire values
Browse files Browse the repository at this point in the history
When passing references across the JSII language boundary, the static
return type of a method is used instead of the runtime type of the
object if they are not the same, even if they are compatible. This
causes issues that make it impossible to up-cast from methods such as
`IConstruct.findChild` that return a super-class that is expected to be
up-casted to it's known dynamic type.

Fixes #345
  • Loading branch information
RomainMuller committed Jan 11, 2019
1 parent 0301e30 commit 94ac569
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion packages/jsii-kernel/lib/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ export class Kernel {
// have an object id, so we need to allocate one for it.
this._debug('creating objref for', v);
const fqn = this._fqnForObject(v);
if (!targetType || !spec.isNamedTypeReference(targetType) || fqn === targetType.fqn) {
if (!targetType || !spec.isNamedTypeReference(targetType) || this._isAssignable(fqn, targetType)) {
return this._createObjref(v, fqn);
}
}
Expand Down Expand Up @@ -1029,6 +1029,31 @@ export class Kernel {
return v;
}

/**
* Tests whether a given type (by it's FQN) can be assigned to a named type reference.
*
* @param actualTypeFqn the FQN of the type that is being tested.
* @param requiredType the required reference type.
*
* @returns true if ``requiredType`` is a super-type (base class or implemented interface) of the type designated by
* ``actualTypeFqn``.
*/
private _isAssignable(actualTypeFqn: string, requiredType: spec.NamedTypeReference): boolean {
if (requiredType.fqn === actualTypeFqn) {
return true;
}
const actualType = this._typeInfoForFqn(actualTypeFqn);
if (spec.isClassType(actualType) && actualType.base) {
if (this._isAssignable(actualType.base.fqn, requiredType)) {
return true;
}
}
if (spec.isClassOrInterfaceType(actualType) && actualType.interfaces) {
return actualType.interfaces.find(iface => this._isAssignable(iface.fqn, requiredType)) != null;
}
return false;
}

private _toSandboxValues(args: any[]) {
return args.map(v => this._toSandbox(v));
}
Expand Down

0 comments on commit 94ac569

Please sign in to comment.