Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[swift2objc] Support properties that throw #1939

Merged
merged 2 commits into from
Jan 28, 2025
Merged
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 @@ -72,11 +72,6 @@ bool _parseVariableIsConstant(Json variableSymbolJson) {
bool _parseVariableThrows(Json json) {
final throws = json['declarationFragments']
.any((frag) => matchFragment(frag, 'keyword', 'throws'));
if (throws) {
// TODO(https://github.com/dart-lang/native/issues/1765): Support throwing
// getters.
throw Exception("Throwing getters aren't supported yet, at ${json.path}");
}
return throws;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../../ast/_core/shared/parameter.dart';
import '../../ast/declarations/built_in/built_in_declaration.dart';
import '../../ast/declarations/compounds/class_declaration.dart';
import '../../ast/declarations/compounds/members/initializer_declaration.dart';
import '../../ast/declarations/compounds/members/method_declaration.dart';
import '../../ast/declarations/compounds/members/property_declaration.dart';
import '../../parser/_core/utils.dart';
import '../_core/unique_namer.dart';
Expand Down Expand Up @@ -51,16 +52,15 @@ ClassDeclaration transformCompound(
transformedCompound.nestedDeclarations
.fillNestingParents(transformedCompound);

transformedCompound.properties = originalCompound.properties
final transformedProperties = originalCompound.properties
.map((property) => transformProperty(
property,
wrappedCompoundInstance,
parentNamer,
transformationMap,
))
.nonNulls
.toList()
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));
.toList();

transformedCompound.initializers = originalCompound.initializers
.map((initializer) => transformInitializer(
Expand All @@ -72,17 +72,25 @@ ClassDeclaration transformCompound(
.toList()
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));

transformedCompound.methods = originalCompound.methods
final transformedMethods = originalCompound.methods
.map((method) => transformMethod(
method,
wrappedCompoundInstance,
parentNamer,
transformationMap,
))
.nonNulls
.toList();

transformedCompound.properties = transformedProperties
.whereType<PropertyDeclaration>()
.toList()
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));

transformedCompound.methods = (transformedMethods +
transformedProperties.whereType<MethodDeclaration>().toList())
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));

return transformedCompound;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import '../../ast/_core/interfaces/declaration.dart';
import '../../ast/declarations/built_in/built_in_declaration.dart';
import '../../ast/declarations/compounds/class_declaration.dart';
import '../../ast/declarations/compounds/members/method_declaration.dart';
import '../../ast/declarations/compounds/members/property_declaration.dart';
import '../../ast/declarations/globals/globals.dart';
import '../../parser/_core/utils.dart';
import '../_core/unique_namer.dart';
Expand All @@ -21,23 +23,30 @@ ClassDeclaration transformGlobals(
isWrapper: true,
);

transformedGlobals.properties = globals.variables
final transformedProperties = globals.variables
.map((variable) => transformGlobalVariable(
variable,
globalNamer,
transformationMap,
))
.toList()
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));
.toList();

transformedGlobals.methods = globals.functions
final transformedMethods = globals.functions
.map((function) => transformGlobalFunction(
function,
globalNamer,
transformationMap,
))
.toList();

transformedGlobals.properties = transformedProperties
.whereType<PropertyDeclaration>()
.toList()
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));

transformedGlobals.methods = (transformedMethods +
transformedProperties.whereType<MethodDeclaration>().toList())
..sort((Declaration a, Declaration b) => a.id.compareTo(b.id));

return transformedGlobals;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import '../../ast/_core/interfaces/declaration.dart';
import '../../ast/_core/interfaces/variable_declaration.dart';
import '../../ast/declarations/compounds/members/method_declaration.dart';
import '../../ast/declarations/compounds/members/property_declaration.dart';
import '../../ast/declarations/globals/globals.dart';
import '../_core/unique_namer.dart';
Expand All @@ -13,7 +15,7 @@ import 'transform_referred_type.dart';
// through the wrapped class instance in the wrapper class. In global variable
// case, it can be referenced directly since it's not a member of any entity.

PropertyDeclaration? transformProperty(
Declaration? transformProperty(
PropertyDeclaration originalProperty,
PropertyDeclaration wrappedClassInstance,
UniqueNamer globalNamer,
Expand All @@ -36,7 +38,7 @@ PropertyDeclaration? transformProperty(
);
}

PropertyDeclaration transformGlobalVariable(
Declaration transformGlobalVariable(
GlobalVariableDeclaration globalVariable,
UniqueNamer globalNamer,
TransformationMap transformationMap,
Expand All @@ -54,7 +56,7 @@ PropertyDeclaration transformGlobalVariable(

// -------------------------- Core Implementation --------------------------

PropertyDeclaration _transformVariable(
Declaration _transformVariable(
VariableDeclaration originalVariable,
UniqueNamer globalNamer,
TransformationMap transformationMap, {
Expand All @@ -71,6 +73,25 @@ PropertyDeclaration _transformVariable(
? originalVariable.hasSetter
: !originalVariable.isConstant;

if (originalVariable.throws) {
return MethodDeclaration(
id: originalVariable.id,
name: wrapperPropertyName,
returnType: transformedType,
params: [],
hasObjCAnnotation: true,
isStatic: originalVariable is PropertyDeclaration
? originalVariable.isStatic
: true,
statements: [
'let result = try $variableReferenceExpression',
'return $transformedType(result)',
],
throws: true,
async: originalVariable.async,
);
}

final transformedProperty = PropertyDeclaration(
id: originalVariable.id,
name: wrapperPropertyName,
Expand Down
29 changes: 29 additions & 0 deletions pkgs/swift2objc/test/integration/throwing_getters_input.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation

public class MyClass {
public init(y: Int) throws {}

public var classGetter: MyClass {
get throws {
try MyClass(y: 3)
}
}
public var otherClassGetter: OtherClass {
get throws {
OtherClass()
}
}
}

public class OtherClass {}

public var globalClassGetter: MyClass {
get throws {
try MyClass(y: 4)
}
}
public var globalOtherClassGetter: OtherClass {
get throws {
OtherClass()
}
}
49 changes: 49 additions & 0 deletions pkgs/swift2objc/test/integration/throwing_getters_output.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Test preamble text

import Foundation

@objc public class GlobalsWrapper: NSObject {
@objc static public func globalClassGetterWrapper() throws -> MyClassWrapper {
let result = try globalClassGetter
return MyClassWrapper(result)
}

@objc static public func globalOtherClassGetterWrapper() throws -> OtherClassWrapper {
let result = try globalOtherClassGetter
return OtherClassWrapper(result)
}

}

@objc public class OtherClassWrapper: NSObject {
var wrappedInstance: OtherClass

init(_ wrappedInstance: OtherClass) {
self.wrappedInstance = wrappedInstance
}

}

@objc public class MyClassWrapper: NSObject {
var wrappedInstance: MyClass

init(_ wrappedInstance: MyClass) {
self.wrappedInstance = wrappedInstance
}

@objc init(y: Int) throws {
wrappedInstance = try MyClass(y: y)
}

@objc public func otherClassGetter() throws -> OtherClassWrapper {
let result = try wrappedInstance.otherClassGetter
return OtherClassWrapper(result)
}

@objc public func classGetter() throws -> MyClassWrapper {
let result = try wrappedInstance.classGetter
return MyClassWrapper(result)
}

}

Loading