Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1544,7 +1544,21 @@ && sameUpToStates(c.parameterizedType(), target)) {
// Optional.ofNullable(element) into an Optional<T>: Kotlin's Optional bounds its T non-null, so the call
// is an Optional<T & Any>, which the invariant Optional<T> is not. Erased, the cast checks nothing
KotlinContext.message(KotlinPrintCode.UNCHECKED_CAST, e, KotlinContext.describe(e));
return new OutputBuilderImpl().add(SymbolEnum.LEFT_PARENTHESIS).add(print(e, q)).add(SpaceEnum.ONE)
OutputBuilder call = print(e, q);
String owner = KotlinTypeName.staticOwner(mc.methodInfo().typeInfo(), q);
if ("empty".equals(mc.methodInfo().name()) && mc.typeArguments().isEmpty()) {
// the cast gives Kotlin nothing to infer empty's T from: Optional<T>'s own
call = text(owner + ".empty<" + KotlinTypeName.of(target.parameters().getFirst(), q) + ">()");
} else if ("of".equals(mc.methodInfo().name()) && mc.parameterExpressions().size() == 1
&& unwrap(mc.parameterExpressions().getFirst()).parameterizedType().typeParameter() != null) {
// Optional.of(value) with a value of type T: Kotlin's of takes a T & Any; Java's throws on null too
Expression value = mc.parameterExpressions().getFirst();
KotlinContext.message(KotlinPrintCode.ASSERT_AT_DEREFERENCE, value, KotlinContext.describe(value));
call = new OutputBuilderImpl().add(new TextImpl(owner)).add(SymbolEnum.DOT).add(new TextImpl("of"))
.add(SymbolEnum.LEFT_PARENTHESIS).add(receiver(value, q)).add(KotlinNullability.NOT_NULL)
.add(SymbolEnum.RIGHT_PARENTHESIS);
}
return new OutputBuilderImpl().add(SymbolEnum.LEFT_PARENTHESIS).add(call).add(SpaceEnum.ONE)
.add(KotlinKeyword.AS).add(SpaceEnum.ONE)
.add(new TextImpl(KotlinTypeName.of(target.withNullable(io.codelaser.maddi.cst.api.type.NullableState.NONNULL), q)))
.add(SymbolEnum.RIGHT_PARENTHESIS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,28 @@ class Box<T> {
compiles(kotlin);
}

/**
* Optional.empty() and Optional.of(value) into an Optional<T>, beside ofNullable above: the cast to Optional<T>
* gives Kotlin nothing to infer the call's own T from.
*/
@Test
public void optionalEmptyAndOfIntoTypeVariable() {
String kotlin = kotlin("""
package a;
import java.util.Optional;
class Opt<T> {
private final T value;
Opt(T value) { this.value = value; }
Optional<T> none() { return Optional.empty(); }
Optional<T> some() { return Optional.of(value); }
}
""");
// empty's T from Optional<T>; of's value asserted, as Kotlin's of takes a T & Any (Java's of throws on null too)
contains(kotlin, "(Optional.empty<T>() as Optional<T>)");
contains(kotlin, "(Optional.of(value!!) as Optional<T>)");
compiles(kotlin);
}

/** guava's CaseFormat: constants override a non-abstract method of their enum, which Kotlin wants open. */
@Test
public void enumConstantOverridesOpenMethod() {
Expand Down
Loading