Skip to content

jextract: LabeledTuple support!#670

Merged
ktoso merged 4 commits intoswiftlang:mainfrom
ktoso:wip-labelled-tuples
Apr 2, 2026
Merged

jextract: LabeledTuple support!#670
ktoso merged 4 commits intoswiftlang:mainfrom
ktoso:wip-labelled-tuples

Conversation

@ktoso
Copy link
Copy Markdown
Collaborator

@ktoso ktoso commented Apr 2, 2026

We now support passing and returing labelled tuples like (a: Int, b: Stirng) etc.

        var result = MySwiftLibrary.labeledTuple();
        // Access via named accessors
        assertEquals(10, result.x());
        assertEquals(20, result.y());
        // Positional access still works (inherited from Tuple2)
        assertEquals(10, result.$0);
        assertEquals(20, result.$1);

        // The labelled tuple is a subclass of Tuple2
        assertInstanceOf(Tuple2.class, result);
        // And the generic types match positionally as well
        @SuppressWarnings("unused")
        Tuple2<Integer, Integer> check = result;

This is important for being able to quickly port over code from swift to Java using the same libraries as we don't have to special case the labelled tuples and move them over to positional use.

These ad hoc tuple types are printed per method.

They would conflict if you use the same shape twice in a method right now... I'm not seeing much of that use so ignored it for now.

The new tuples inherit from TupleN so Java code can just use them as positional when necessary, also for passing them along to other methods.

The change is large because I also cleaned up type printing, I think printing full qualified type names is good here, better nor risk clashes.

We now support passing and returing labelled tuples like (a: Int, b:
Stirng) etc.

This is important for being able to quickly port over code from swift to
Java using the same libraries as we don't have to special case the
labelled tuples and move them over to positional use.

These ad hoc tuple types are printed per method.

They would conflict if you use the same shape twice in a method right
now... I'm not seeing much of that use so ignored it for now.

The new tuples inherit from TupleN so Java code can just use them as
positional when necessary, also for passing them along to other methods.

The change is large because I also cleaned up type printing, I think
printing full qualified type names is good here, better nor risk
clashes.
// TODO: When we support typed throws on Swift side we'll want to throw the right type here instead
if translatedSignature.isThrowing {
throwsClauses.append(JavaType.swiftJavaErrorException.simpleClassName)
throwsClauses.append(JavaType.swiftJavaErrorException.className!)
Copy link
Copy Markdown
Collaborator Author

@ktoso ktoso Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simpleClassName was crashing on misuse anyway

swiftResult: SwiftResult,
loweredResult: LoweredResult
loweredResult: LoweredResult,
methodName: String
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need the method name to form the adhoc types per method


let wrappedValueResult = try translate(
swiftResult: SwiftResult(convention: .direct, type: swiftType),
methodName: "",
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double check this one


// Element names are embedded in the class name after "LabeledTuple_<baseName>_"
// We need to extract the last `arity` underscore-separated components
let parts = rawClassName.split(separator: "_")
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: this is pretty horrible, we're getting the field names from the type name...

To make this nicer we need to intreoduce SwiftJavaType that wraps a JavaType since JavaType is just "pure" java types without additional context like this. That's quite a big refactor so we may want to do this but better to do separately...

case .array(let element):
collectLabeledTuples(from: element, into: &result)
default:
break
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potentially more uses here...

@ktoso ktoso force-pushed the wip-labelled-tuples branch from 5aa9fad to 9a4a431 Compare April 2, 2026 08:04
@ktoso ktoso force-pushed the wip-labelled-tuples branch from 9a4a431 to 0bfe36e Compare April 2, 2026 08:31
@ktoso ktoso marked this pull request as ready for review April 2, 2026 08:34
@ktoso ktoso marked this pull request as draft April 2, 2026 08:34
@ktoso ktoso marked this pull request as ready for review April 2, 2026 08:41
@ktoso ktoso merged commit ab9e0a1 into swiftlang:main Apr 2, 2026
61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant