@@ -335,6 +335,52 @@ struct ExpoModuleMacroTests {
335335 )
336336 }
337337
338+ @Test
339+ func `Implicitly-unwrapped optional return normalizes to optional in the cast expression`() {
340+ assertExpansion (
341+ """
342+ @ExpoModule
343+ final class MyModule: Module {
344+ @JS
345+ func make(count: Int) -> MyRecord! { nil }
346+ }
347+ """ ,
348+ expandedSource: """
349+ final class MyModule: Module {
350+ @JavaScriptActor
351+ func make(count: Int) -> MyRecord! { nil }
352+
353+ private func _assertTypesConformance_make() {
354+ func make<T: AnyArgument>(_: T.Type) {
355+ }
356+ make(MyRecord.self)
357+ }
358+
359+ public static let _jsName = " MyModule "
360+
361+ public func _synthesizedDefinition() -> [AnyDefinition] {
362+ return []
363+ }
364+
365+ @JavaScriptActor
366+ public func _decorateModule(object: borrowing JavaScriptObject, in runtime: JavaScriptRuntime, appContext: AppContext) throws {
367+ object.setProperty( " make " ) { [weak appContext, self] (this: borrowing JavaScriptUnownedValue, arguments: consuming JavaScriptValuesBuffer) in
368+ guard let appContext else {
369+ throw Exceptions.AppContextLost()
370+ }
371+ guard arguments.count == 1 else {
372+ throw Exceptions.ArgumentsRangeMismatch((functionName: " make " , received: arguments.count, required: 1, maximum: 1))
373+ }
374+ let arg0 = try arguments.unownedValue(at: 0).asInt()
375+ let result = self.make(count: arg0)
376+ return try MyRecord?.getDynamicType().castToJS(result, appContext: appContext, in: runtime)
377+ }
378+ }
379+ }
380+ """
381+ )
382+ }
383+
338384 @Test
339385 func `Static func tion emits a static conformance- assertion peer`() {
340386 assertExpansion (
@@ -613,6 +659,57 @@ struct ExpoModuleMacroTests {
613659 )
614660 }
615661
662+ @Test
663+ func `Implicitly-unwrapped optional property normalizes the type to optional in the cast expressions`() {
664+ assertExpansion(
665+ """
666+ @ExpoModule
667+ final class MyModule : Module {
668+ @JS
669+ var config : MyRecord !
670+ }
671+ """ ,
672+ expandedSource: """
673+ final class MyModule : Module {
674+ @JavaScriptActor
675+ var config : MyRecord !
676+
677+ private func _assertTypesConformance_config( ) {
678+ func config< T: AnyArgument > ( _: T . Type ) {
679+ }
680+ config ( MyRecord . self)
681+ }
682+
683+ public static let _jsName = " MyModule "
684+
685+ public func _synthesizedDefinition( ) -> [ AnyDefinition ] {
686+ return [ ]
687+ }
688+
689+ @JavaScriptActor
690+ public func _decorateModule( object: borrowing JavaScriptObject , in runtime: JavaScriptRuntime , appContext: AppContext ) throws {
691+ let configDescriptor = runtime. createObject ( )
692+ configDescriptor. setProperty ( " enumerable " , value: true )
693+ configDescriptor. setProperty ( " get " ) { [ weak appContext, self ] ( this: borrowing JavaScriptUnownedValue , arguments: consuming JavaScriptValuesBuffer ) in
694+ guard let appContext else {
695+ throw Exceptions . AppContextLost ( )
696+ }
697+ return try MyRecord ? . getDynamicType ( ) . castToJS ( self . config, appContext: appContext, in: runtime)
698+ }
699+ configDescriptor. setProperty ( " set " ) { [ weak appContext, self ] ( this: borrowing JavaScriptUnownedValue , arguments: consuming JavaScriptValuesBuffer ) in
700+ guard let appContext else {
701+ throw Exceptions . AppContextLost ( )
702+ }
703+ self . config = try MyRecord ? . getDynamicType ( ) . cast ( jsValue: arguments [ 0 ] , appContext: appContext) as! MyRecord ?
704+ return . undefined
705+ }
706+ object. defineProperty ( " config " , descriptor: configDescriptor)
707+ }
708+ }
709+ """
710+ )
711+ }
712+
616713 @Test
617714 func `Mixed members: only @JS-marked ones are picked up`() {
618715 assertExpansion(
0 commit comments