Skip to content

Commit ec69f12

Browse files
authored
[swift2objc] Typealias support (#2468)
1 parent e820406 commit ec69f12

File tree

12 files changed

+205
-36
lines changed

12 files changed

+205
-36
lines changed

pkgs/swift2objc/lib/src/ast/_core/shared/referred_type.dart

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import '../../ast_node.dart';
6+
import '../../declarations/typealias_declaration.dart';
67
import '../interfaces/declaration.dart';
78
import '../interfaces/nestable_declaration.dart';
89
import '../interfaces/objc_annotatable.dart';
@@ -15,14 +16,20 @@ sealed class ReferredType extends AstNode {
1516

1617
abstract final String swiftType;
1718

18-
bool sameAs(ReferredType other);
19+
bool _sameAs(ReferredType other);
1920

2021
const ReferredType();
2122

23+
ReferredType get aliasedType;
24+
2225
@override
2326
void visit(Visitation visitation) => visitation.visitReferredType(this);
2427
}
2528

29+
extension ReferredTypeExt on ReferredType {
30+
bool sameAs(ReferredType other) => aliasedType._sameAs(other.aliasedType);
31+
}
32+
2633
/// Describes a reference of a declared type (user-defined or built-in).
2734
class DeclaredType<T extends Declaration> extends AstNode
2835
implements ReferredType {
@@ -39,15 +46,23 @@ class DeclaredType<T extends Declaration> extends AstNode
3946
final List<ReferredType> typeParams;
4047

4148
@override
42-
bool get isObjCRepresentable =>
43-
declaration is ObjCAnnotatable &&
44-
(declaration as ObjCAnnotatable).hasObjCAnnotation;
49+
bool get isObjCRepresentable => switch (declaration) {
50+
TypealiasDeclaration decl => decl.target.isObjCRepresentable,
51+
ObjCAnnotatable decl => decl.hasObjCAnnotation,
52+
_ => false,
53+
};
4554

4655
@override
4756
String get swiftType => name;
4857

4958
@override
50-
bool sameAs(ReferredType other) => other is DeclaredType && other.id == id;
59+
bool _sameAs(ReferredType other) => other is DeclaredType && other.id == id;
60+
61+
@override
62+
ReferredType get aliasedType => switch (declaration) {
63+
TypealiasDeclaration decl => decl.target.aliasedType,
64+
_ => this,
65+
};
5166

5267
const DeclaredType({
5368
required this.id,
@@ -83,7 +98,10 @@ class GenericType extends AstNode implements ReferredType {
8398
String get swiftType => name;
8499

85100
@override
86-
bool sameAs(ReferredType other) => other is GenericType && other.id == id;
101+
bool _sameAs(ReferredType other) => other is GenericType && other.id == id;
102+
103+
@override
104+
ReferredType get aliasedType => this;
87105

88106
const GenericType({
89107
required this.id,
@@ -108,9 +126,12 @@ class OptionalType extends AstNode implements ReferredType {
108126
String get swiftType => '$child?';
109127

110128
@override
111-
bool sameAs(ReferredType other) =>
129+
bool _sameAs(ReferredType other) =>
112130
other is OptionalType && child.sameAs(other.child);
113131

132+
@override
133+
ReferredType get aliasedType => OptionalType(child.aliasedType);
134+
114135
OptionalType(this.child);
115136

116137
@override
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../_core/interfaces/nestable_declaration.dart';
6+
import '../_core/shared/referred_type.dart';
7+
import '../ast_node.dart';
8+
9+
/// Describes the declaration of a Swift class.
10+
class TypealiasDeclaration extends AstNode implements InnerNestableDeclaration {
11+
@override
12+
final String id;
13+
14+
@override
15+
final String name;
16+
17+
final ReferredType target;
18+
19+
@override
20+
OuterNestableDeclaration? nestingParent;
21+
22+
TypealiasDeclaration(
23+
{required this.id, required this.name, required this.target});
24+
25+
@override
26+
void visit(Visitation visitation) =>
27+
visitation.visitTypealiasDeclaration(this);
28+
29+
@override
30+
void visitChildren(Visitor visitor) {
31+
super.visitChildren(visitor);
32+
visitor.visit(target);
33+
}
34+
}

pkgs/swift2objc/lib/src/ast/visitor.dart

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@
44

55
import 'package:logging/logging.dart';
66

7-
import '../ast/_core/interfaces/compound_declaration.dart';
8-
import '../ast/_core/interfaces/declaration.dart';
9-
import '../ast/_core/interfaces/enum_declaration.dart';
10-
import '../ast/_core/interfaces/function_declaration.dart';
11-
import '../ast/_core/interfaces/variable_declaration.dart';
12-
import '../ast/_core/shared/referred_type.dart';
13-
import '../ast/ast_node.dart';
14-
import '../ast/declarations/built_in/built_in_declaration.dart';
15-
import '../ast/declarations/compounds/class_declaration.dart';
16-
import '../ast/declarations/compounds/members/initializer_declaration.dart';
17-
import '../ast/declarations/compounds/members/method_declaration.dart';
18-
import '../ast/declarations/compounds/members/property_declaration.dart';
19-
import '../ast/declarations/compounds/protocol_declaration.dart';
20-
import '../ast/declarations/compounds/struct_declaration.dart';
21-
import '../ast/declarations/enums/associated_value_enum_declaration.dart';
22-
import '../ast/declarations/enums/normal_enum_declaration.dart';
23-
import '../ast/declarations/enums/raw_value_enum_declaration.dart';
24-
import '../ast/declarations/globals/globals.dart';
7+
import '_core/interfaces/compound_declaration.dart';
8+
import '_core/interfaces/declaration.dart';
9+
import '_core/interfaces/enum_declaration.dart';
10+
import '_core/interfaces/function_declaration.dart';
11+
import '_core/interfaces/variable_declaration.dart';
12+
import '_core/shared/referred_type.dart';
13+
import 'ast_node.dart';
14+
import 'declarations/built_in/built_in_declaration.dart';
15+
import 'declarations/compounds/class_declaration.dart';
16+
import 'declarations/compounds/members/initializer_declaration.dart';
17+
import 'declarations/compounds/members/method_declaration.dart';
18+
import 'declarations/compounds/members/property_declaration.dart';
19+
import 'declarations/compounds/protocol_declaration.dart';
20+
import 'declarations/compounds/struct_declaration.dart';
21+
import 'declarations/enums/associated_value_enum_declaration.dart';
22+
import 'declarations/enums/normal_enum_declaration.dart';
23+
import 'declarations/enums/raw_value_enum_declaration.dart';
24+
import 'declarations/globals/globals.dart';
25+
import 'declarations/typealias_declaration.dart';
2526

2627
final _logger = Logger('swift2objc.visitor');
2728

@@ -114,6 +115,8 @@ abstract class Visitation {
114115
visitEnumDeclaration(node);
115116
void visitRawValueEnumDeclaration<T>(RawValueEnumDeclaration<T> node) =>
116117
visitEnumDeclaration(node);
118+
void visitTypealiasDeclaration(TypealiasDeclaration node) =>
119+
visitDeclaration(node);
117120

118121
/// Default behavior for all visit methods.
119122
void visitAstNode(AstNode node) => node.visitChildren(visitor);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../../../ast/declarations/typealias_declaration.dart';
6+
import '../../_core/json.dart';
7+
import '../../_core/parsed_symbolgraph.dart';
8+
import '../../_core/token_list.dart';
9+
import '../../_core/utils.dart';
10+
import '../parse_type.dart';
11+
12+
TypealiasDeclaration? parseTypealiasDeclaration(
13+
Json typealiasSymbolJson, ParsedSymbolgraph symbolgraph) {
14+
final id = parseSymbolId(typealiasSymbolJson);
15+
final name = parseSymbolName(typealiasSymbolJson);
16+
final declarationFragments = typealiasSymbolJson['declarationFragments'];
17+
18+
final malformedException = Exception(
19+
'Malformed typealias at ${declarationFragments.path}: '
20+
'$declarationFragments',
21+
);
22+
23+
final tokens = TokenList(declarationFragments);
24+
final equals = tokens.indexWhere((tok) => matchFragment(tok, 'text', '='));
25+
if (equals == -1) throw malformedException;
26+
27+
final (target, remaining) = parseType(symbolgraph, tokens.slice(equals + 1));
28+
if (remaining.isNotEmpty) throw malformedException;
29+
30+
return TypealiasDeclaration(id: id, name: name, target: target);
31+
}

pkgs/swift2objc/lib/src/parser/parsers/parse_declarations.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import '../_core/utils.dart';
1010
import 'declaration_parsers/parse_compound_declaration.dart';
1111
import 'declaration_parsers/parse_function_declaration.dart';
1212
import 'declaration_parsers/parse_initializer_declaration.dart';
13+
import 'declaration_parsers/parse_typealias_declaration.dart';
1314
import 'declaration_parsers/parse_variable_declaration.dart';
1415

1516
List<Declaration> parseDeclarations(ParsedSymbolgraph symbolgraph) {
@@ -56,6 +57,7 @@ Declaration parseDeclaration(
5657
'swift.init' => parseInitializerDeclaration(symbolJson, symbolgraph),
5758
'swift.func' => parseGlobalFunctionDeclaration(symbolJson, symbolgraph),
5859
'swift.var' => parseGlobalVariableDeclaration(symbolJson, symbolgraph),
60+
'swift.typealias' => parseTypealiasDeclaration(symbolJson, symbolgraph),
5961
_ => throw Exception(
6062
'Symbol of type $symbolType is not implemented yet.',
6163
),

pkgs/swift2objc/lib/src/transformer/_core/utils.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import '../../ast/_core/shared/referred_type.dart';
88
import '../../ast/declarations/compounds/class_declaration.dart';
99
import '../../ast/declarations/compounds/members/initializer_declaration.dart';
1010
import '../../ast/declarations/compounds/members/property_declaration.dart';
11+
import '../../ast/declarations/typealias_declaration.dart';
1112
import '../../transformer/_core/primitive_wrappers.dart';
1213
import '../transform.dart';
1314
import 'unique_namer.dart';
@@ -35,8 +36,15 @@ import 'unique_namer.dart';
3536
if (type is GenericType) {
3637
throw UnimplementedError('Generic types are not implemented yet');
3738
} else if (type is DeclaredType) {
39+
final declaration = type.declaration;
40+
if (declaration is TypealiasDeclaration) {
41+
return maybeWrapValue(
42+
declaration.target, value, globalNamer, transformationMap,
43+
shouldWrapPrimitives: shouldWrapPrimitives);
44+
}
45+
3846
final transformedTypeDeclaration = transformDeclaration(
39-
type.declaration,
47+
declaration,
4048
globalNamer,
4149
transformationMap,
4250
);
@@ -72,6 +80,8 @@ import 'unique_namer.dart';
7280
if (declaration is ClassDeclaration) {
7381
final wrappedInstance = declaration.wrappedInstance!;
7482
return ('$value.${wrappedInstance.name}', wrappedInstance.type);
83+
} else if (declaration is TypealiasDeclaration) {
84+
return maybeUnwrapValue(declaration.target, value);
7585
} else {
7686
return (value, type);
7787
}

pkgs/swift2objc/lib/src/transformer/transform.dart

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@ import '../ast/declarations/built_in/built_in_declaration.dart';
99
import '../ast/declarations/compounds/class_declaration.dart';
1010
import '../ast/declarations/compounds/struct_declaration.dart';
1111
import '../ast/declarations/globals/globals.dart';
12+
import '../ast/declarations/typealias_declaration.dart';
1213
import '../ast/visitor.dart';
1314
import '_core/dependencies.dart';
1415
import '_core/unique_namer.dart';
1516
import 'transformers/transform_compound.dart';
1617
import 'transformers/transform_globals.dart';
1718

18-
typedef TransformationMap = Map<Declaration, Declaration>;
19+
typedef TransformationMap = Map<Declaration, Declaration?>;
1920

2021
Set<Declaration> generateDependencies(Iterable<Declaration> decls) =>
2122
visit(DependencyVisitation(), decls).topLevelDeclarations;
2223

2324
/// Transforms the given declarations into the desired ObjC wrapped declarations
2425
List<Declaration> transform(List<Declaration> declarations,
2526
{required bool Function(Declaration) filter}) {
26-
final transformationMap = <Declaration, Declaration>{};
27+
final transformationMap = <Declaration, Declaration?>{};
2728

2829
final declarations0 = declarations.where(filter).toSet();
2930
declarations0.addAll(generateDependencies(declarations0));
@@ -45,9 +46,11 @@ List<Declaration> transform(List<Declaration> declarations,
4546
.toList();
4647

4748
final transformedDeclarations = [
48-
...nonGlobals.map(
49-
(decl) => transformDeclaration(decl, globalNamer, transformationMap),
50-
),
49+
...nonGlobals
50+
.map(
51+
(d) => maybeTransformDeclaration(d, globalNamer, transformationMap),
52+
)
53+
.nonNulls,
5154
if (globals.functions.isNotEmpty || globals.variables.isNotEmpty)
5255
transformGlobals(globals, globalNamer, transformationMap),
5356
];
@@ -62,9 +65,19 @@ Declaration transformDeclaration(
6265
UniqueNamer parentNamer,
6366
TransformationMap transformationMap, {
6467
bool nested = false,
68+
}) =>
69+
maybeTransformDeclaration(declaration, parentNamer, transformationMap,
70+
nested: nested) ??
71+
declaration;
72+
73+
Declaration? maybeTransformDeclaration(
74+
Declaration declaration,
75+
UniqueNamer parentNamer,
76+
TransformationMap transformationMap, {
77+
bool nested = false,
6578
}) {
66-
if (transformationMap[declaration] != null) {
67-
return transformationMap[declaration]!;
79+
if (transformationMap.containsKey(declaration)) {
80+
return transformationMap[declaration];
6881
}
6982

7083
if (declaration is InnerNestableDeclaration &&
@@ -80,6 +93,7 @@ Declaration transformDeclaration(
8093
parentNamer,
8194
transformationMap,
8295
),
96+
TypealiasDeclaration() => null,
8397
_ => throw UnimplementedError(),
8498
};
8599
}
@@ -89,5 +103,6 @@ List<Declaration> _getPrimitiveWrapperClasses(
89103
return transformationMap.entries
90104
.where((entry) => entry.key is BuiltInDeclaration)
91105
.map((entry) => entry.value)
106+
.nonNulls
92107
.toList();
93108
}

pkgs/swift2objc/lib/src/transformer/transformers/transform_compound.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ ClassDeclaration transformCompound(
4444
transformationMap[originalCompound] = transformedCompound;
4545

4646
transformedCompound.nestedDeclarations = originalCompound.nestedDeclarations
47-
.map((nested) => transformDeclaration(
47+
.map((nested) => maybeTransformDeclaration(
4848
nested, compoundNamer, transformationMap, nested: true)
49-
as InnerNestableDeclaration)
49+
as InnerNestableDeclaration?)
50+
.nonNulls
5051
.toList()
5152
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));
5253
transformedCompound.nestedDeclarations

pkgs/swift2objc/lib/src/transformer/transformers/transform_referred_type.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import '../../ast/_core/interfaces/declaration.dart';
66
import '../../ast/_core/shared/referred_type.dart';
7+
import '../../ast/declarations/typealias_declaration.dart';
78
import '../_core/unique_namer.dart';
89
import '../transform.dart';
910

@@ -20,8 +21,12 @@ ReferredType transformReferredType(
2021
if (type is GenericType) {
2122
throw UnimplementedError('Generic types are not supported yet');
2223
} else if (type is DeclaredType) {
24+
final decl = type.declaration;
25+
if (decl is TypealiasDeclaration) {
26+
return transformReferredType(decl.target, globalNamer, transformationMap);
27+
}
2328
return transformDeclaration(
24-
type.declaration,
29+
decl,
2530
globalNamer,
2631
transformationMap,
2732
).asDeclaredType;

pkgs/swift2objc/lib/src/transformer/transformers/transform_variable.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import '../../ast/_core/interfaces/declaration.dart';
22
import '../../ast/_core/interfaces/variable_declaration.dart';
3+
import '../../ast/_core/shared/referred_type.dart';
34
import '../../ast/declarations/compounds/members/method_declaration.dart';
45
import '../../ast/declarations/compounds/members/property_declaration.dart';
56
import '../../ast/declarations/globals/globals.dart';

0 commit comments

Comments
 (0)