@@ -52,6 +52,9 @@ struct MethodModifiers {
52
52
returns_retained : bool ,
53
53
returns_not_retained : bool ,
54
54
designated_initializer : bool ,
55
+ non_isolated : bool ,
56
+ sendable : Option < bool > ,
57
+ mainthreadonly : bool ,
55
58
}
56
59
57
60
impl MethodModifiers {
@@ -68,6 +71,18 @@ impl MethodModifiers {
68
71
UnexposedAttr :: ReturnsNotRetained => {
69
72
this. returns_not_retained = true ;
70
73
}
74
+ UnexposedAttr :: NonIsolated => {
75
+ this. non_isolated = true ;
76
+ }
77
+ UnexposedAttr :: Sendable => {
78
+ this. sendable = Some ( true ) ;
79
+ }
80
+ UnexposedAttr :: NonSendable => {
81
+ this. sendable = Some ( false ) ;
82
+ }
83
+ UnexposedAttr :: UIActor => {
84
+ this. mainthreadonly = true ;
85
+ }
71
86
attr => error ! ( ?attr, "unknown attribute" ) ,
72
87
}
73
88
}
@@ -214,6 +229,7 @@ impl MemoryManagement {
214
229
consumes_self : false ,
215
230
returns_retained : false ,
216
231
returns_not_retained : false ,
232
+ ..
217
233
} = modifiers
218
234
{
219
235
Self :: Normal
@@ -233,11 +249,14 @@ pub struct Method {
233
249
pub is_class : bool ,
234
250
is_optional_protocol : bool ,
235
251
memory_management : MemoryManagement ,
236
- arguments : Vec < ( String , Ty ) > ,
252
+ pub ( crate ) arguments : Vec < ( String , Ty ) > ,
237
253
pub result_type : Ty ,
238
254
safe : bool ,
239
255
mutating : bool ,
240
256
is_protocol : bool ,
257
+ // Thread-safe, even on main-thread only (@MainActor/@UIActor) classes
258
+ non_isolated : bool ,
259
+ pub ( crate ) mainthreadonly : bool ,
241
260
}
242
261
243
262
impl Method {
@@ -367,6 +386,10 @@ impl<'tu> PartialMethod<'tu> {
367
386
368
387
let modifiers = MethodModifiers :: parse ( & entity, context) ;
369
388
389
+ if modifiers. sendable . is_some ( ) {
390
+ error ! ( "sendable on method" ) ;
391
+ }
392
+
370
393
let mut arguments: Vec < _ > = entity
371
394
. get_arguments ( )
372
395
. expect ( "method arguments" )
@@ -377,6 +400,8 @@ impl<'tu> PartialMethod<'tu> {
377
400
let qualifier = entity
378
401
. get_objc_qualifiers ( )
379
402
. map ( MethodArgumentQualifier :: parse) ;
403
+ let mut sendable = None ;
404
+ let mut no_escape = false ;
380
405
381
406
immediate_children ( & entity, |entity, _span| match entity. get_kind ( ) {
382
407
EntityKind :: ObjCClassRef
@@ -390,7 +415,12 @@ impl<'tu> PartialMethod<'tu> {
390
415
}
391
416
EntityKind :: UnexposedAttr => {
392
417
if let Some ( attr) = UnexposedAttr :: parse ( & entity, context) {
393
- error ! ( ?attr, "unknown attribute" ) ;
418
+ match attr {
419
+ UnexposedAttr :: Sendable => sendable = Some ( true ) ,
420
+ UnexposedAttr :: NonSendable => sendable = Some ( false ) ,
421
+ UnexposedAttr :: NoEscape => no_escape = true ,
422
+ attr => error ! ( ?attr, "unknown attribute" ) ,
423
+ }
394
424
}
395
425
}
396
426
// For some reason we recurse into array types
@@ -399,7 +429,7 @@ impl<'tu> PartialMethod<'tu> {
399
429
} ) ;
400
430
401
431
let ty = entity. get_type ( ) . expect ( "argument type" ) ;
402
- let ty = Ty :: parse_method_argument ( ty, qualifier, context) ;
432
+ let ty = Ty :: parse_method_argument ( ty, qualifier, sendable , no_escape , context) ;
403
433
404
434
( name, ty)
405
435
} )
@@ -463,6 +493,8 @@ impl<'tu> PartialMethod<'tu> {
463
493
// immutable subclass, or as a property.
464
494
mutating : data. mutating . unwrap_or ( parent_is_mutable) ,
465
495
is_protocol,
496
+ non_isolated : modifiers. non_isolated ,
497
+ mainthreadonly : modifiers. mainthreadonly ,
466
498
} ,
467
499
) )
468
500
}
@@ -519,6 +551,7 @@ impl PartialProperty<'_> {
519
551
let ty = Ty :: parse_property_return (
520
552
entity. get_type ( ) . expect ( "property type" ) ,
521
553
is_copy,
554
+ modifiers. sendable ,
522
555
context,
523
556
) ;
524
557
@@ -538,6 +571,8 @@ impl PartialProperty<'_> {
538
571
// is, so let's default to immutable.
539
572
mutating : getter_data. mutating . unwrap_or ( false ) ,
540
573
is_protocol,
574
+ non_isolated : modifiers. non_isolated ,
575
+ mainthreadonly : modifiers. mainthreadonly ,
541
576
} )
542
577
} else {
543
578
None
@@ -546,8 +581,12 @@ impl PartialProperty<'_> {
546
581
let setter = if let Some ( setter_name) = setter_name {
547
582
let setter_data = setter_data. expect ( "setter_data must be present if setter_name was" ) ;
548
583
if !setter_data. skipped {
549
- let ty =
550
- Ty :: parse_property ( entity. get_type ( ) . expect ( "property type" ) , is_copy, context) ;
584
+ let ty = Ty :: parse_property (
585
+ entity. get_type ( ) . expect ( "property type" ) ,
586
+ is_copy,
587
+ modifiers. sendable ,
588
+ context,
589
+ ) ;
551
590
552
591
let selector = setter_name. clone ( ) + ":" ;
553
592
let memory_management =
@@ -566,6 +605,8 @@ impl PartialProperty<'_> {
566
605
// Setters are usually mutable if the class itself is.
567
606
mutating : setter_data. mutating . unwrap_or ( parent_is_mutable) ,
568
607
is_protocol,
608
+ non_isolated : modifiers. non_isolated ,
609
+ mainthreadonly : modifiers. mainthreadonly ,
569
610
} )
570
611
} else {
571
612
None
@@ -595,6 +636,11 @@ impl fmt::Display for Method {
595
636
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
596
637
let _span = debug_span ! ( "method" , self . fn_name) . entered ( ) ;
597
638
639
+ // TODO: Use this somehow?
640
+ // if self.non_isolated {
641
+ // writeln!(f, "// non_isolated")?;
642
+ // }
643
+
598
644
//
599
645
// Attributes
600
646
//
@@ -648,7 +694,11 @@ impl fmt::Display for Method {
648
694
// Arguments
649
695
for ( param, arg_ty) in & self . arguments {
650
696
let param = handle_reserved ( & crate :: to_snake_case ( param) ) ;
651
- write ! ( f, "{param}: {arg_ty}," ) ?;
697
+ write ! ( f, "{param}: {arg_ty}, " ) ?;
698
+ }
699
+ // FIXME: Skipping main thread only on protocols for now
700
+ if self . mainthreadonly && !self . is_protocol {
701
+ write ! ( f, "mtm: MainThreadMarker" ) ?;
652
702
}
653
703
write ! ( f, ")" ) ?;
654
704
0 commit comments