google / google/jsinterop-generator

Giving a class both a static and instance members with a matching union type causes invalid java to be generated

Open
#46 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
85
Forks
24
PR merge metrics
No merged PRs in 30d

Description

Given two members on a class, one static and one instance, one will be generated with a `_STATIC` suffix. That is,
```
Foo.noArgMethod = function() {};
Foo.prototype.noArgMethod = function() {};
```
will cause this to be generated:
```
@JsMethod(name = "noArgMethod")
public static native Object noArgMethod_STATIC();

public native Object noArgMethod();
```

(removed an incorrect statement, will follow up separately)

However, if both of these have a parameter which is unioned, then the generated `*UnionType` will be emitted twice, as the names are not distinct - unlike the actual member name, the union type's name is only based on the method name and argument name.

Additionally, once a native method is generated for this, two or more `@JsOverlay` methods will be generated as well, and when those are renamed to append `_STATIC` to them, a `@JsMethod`/`@JsProperty` annotation will also be decorated on them, which will cause a compiler error in J2CL.

Example js with a method:
```
/**
* @param {string|number} arg
*/
Foo.unionArgMethod = function(arg) {};
/**
* @param {string|number} arg
*/
Foo.prototype.unionArgMethod = function(arg) {};
```

Resulting java:
```
@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface UnionArgMethodArgUnionType {
@JsOverlay
static Foo.UnionArgMethodArgUnionType of(Object o) {
return Js.cast(o);
}

@JsOverlay
default double asDouble() {
return Js.asDouble(this);
}

@JsOverlay
default String asString() {
return Js.asString(this);
}

@JsOverlay
default boolean isDouble() {
return (Object) this instanceof Double;
}

@JsOverlay
default boolean isString() {
return (Object) this instanceof String;
}
}

@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface UnionArgMethodArgUnionType {
@JsOverlay
static Foo.UnionArgMethodArgUnionType of(Object o) {
return Js.cast(o);
}

@JsOverlay
default double asDouble() {
return Js.asDouble(this);
}

@JsOverlay
default String asString() {
return Js.asString(this);
}

@JsOverlay
default boolean isDouble() {
return (Object) this instanceof Double;
}

@JsOverlay
default boolean isString() {
return (Object) this instanceof String;
}
}

@JsOverlay
@JsMethod(name = "unionArgMethod")
public static final Object unionArgMethod_STATIC(String arg) {
return unionArgMethod(Js.uncheckedCast(arg));
}

@JsMethod(name = "unionArgMethod")
public static native Object unionArgMethod_STATIC(Foo.UnionArgMethodArgUnionType arg);

@JsOverlay
@JsMethod(name = "unionArgMethod")
public static final Object unionArgMethod_STATIC(double arg) {
return unionArgMethod(Js.uncheckedCast(arg));
}

@JsOverlay
public final Object unionArgMethod(String arg) {
return unionArgMethod(Js.uncheckedCast(arg));
}

public native Object unionArgMethod(Foo.UnionArgMethodArgUnionType arg);

@JsOverlay
public final Object unionArgMethod(double arg) {
return unionArgMethod(Js.uncheckedCast(arg));
}
```

Example JS with a property:
```
/**
* @type {string|number}
*/
Foo.unionProperty;
/**
* @type {string|number}
*/
Foo.prototype.unionProperty;
```
Resulting Java:
```
@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface UnionPropertyUnionType {
@JsOverlay
static Foo.UnionPropertyUnionType of(Object o) {
return Js.cast(o);
}

@JsOverlay
default double asDouble() {
return Js.asDouble(this);
}

@JsOverlay
default String asString() {
return Js.asString(this);
}

@JsOverlay
default boolean isDouble() {
return (Object) this instanceof Double;
}

@JsOverlay
default boolean isString() {
return (Object) this instanceof String;
}
}

@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface UnionPropertyUnionType {
@JsOverlay
static Foo.UnionPropertyUnionType of(Object o) {
return Js.cast(o);
}

@JsOverlay
default double asDouble() {
return Js.asDouble(this);
}

@JsOverlay
default String asString() {
return Js.asString(this);
}

@JsOverlay
default boolean isDouble() {
return (Object) this instanceof Double;
}

@JsOverlay
default boolean isString() {
return (Object) this instanceof String;
}
}

public static Foo.UnionPropertyUnionType unionProperty;
```

There is also a separate correctness issue which I'll file separately - in some cases, there is only one `unionProperty`, the static variant, as the non-static member is failed to be emitted.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.