@@ -698,7 +698,13 @@ impl Stmt {
698698
699699 verify_objc_decl ( entity, context) ;
700700 let generics = parse_class_generics ( entity, context) ;
701- let protocols = parse_direct_protocols ( entity, context) ;
701+ let mut protocols = parse_direct_protocols ( entity, context) ;
702+
703+ let skipped_protocols = data
704+ . map ( |data| data. skipped_protocols . clone ( ) )
705+ . unwrap_or_default ( ) ;
706+ protocols. retain ( |protocol| !skipped_protocols. contains ( & protocol. name ) ) ;
707+
702708 let ( methods, designated_initializers) = parse_methods (
703709 entity,
704710 |name| ClassData :: get_method_data ( data, name) ,
@@ -825,7 +831,7 @@ impl Stmt {
825831 context,
826832 ) ;
827833
828- let ( sendable, mainthreadonly) = parse_attributes ( entity, context) ;
834+ let ( sendable, mut mainthreadonly) = parse_attributes ( entity, context) ;
829835
830836 if !designated_initializers. is_empty ( ) {
831837 warn ! (
@@ -834,6 +840,43 @@ impl Stmt {
834840 )
835841 }
836842
843+ // Set the protocol as main thread only if all methods are
844+ // main thread only.
845+ //
846+ // This is done to make the UI nicer when the user tries to
847+ // implement such traits.
848+ //
849+ // Note: This is a deviation from the headers, but I don't
850+ // see a way for this to be unsound? As an example, let's say
851+ // there is some Objective-C code that assumes it can create
852+ // an object which is not `MainThreadOnly`, and then sets it
853+ // as the application delegate.
854+ //
855+ // Rust code that later retrieves the delegate would assume
856+ // that the object is `MainThreadOnly`, and could use this
857+ // information to create `MainThreadMarker`; but they can
858+ // _already_ do that, since the only way to retrieve the
859+ // delegate in the first place would be through
860+ // `NSApplication`!
861+ if !methods. is_empty ( ) && methods. iter ( ) . all ( |method| method. mainthreadonly ) {
862+ mainthreadonly = true ;
863+ }
864+
865+ // Overwrite with config preference
866+ if let Some ( data) = data
867+ . map ( |data| data. requires_mainthreadonly )
868+ . unwrap_or_default ( )
869+ {
870+ if mainthreadonly == data {
871+ warn ! (
872+ mainthreadonly,
873+ data,
874+ "set requires-mainthreadonly to the same value that it already has"
875+ ) ;
876+ }
877+ mainthreadonly = data;
878+ }
879+
837880 vec ! [ Self :: ProtocolDecl {
838881 id,
839882 actual_name,
@@ -1630,7 +1673,7 @@ impl fmt::Display for Stmt {
16301673 protocols,
16311674 methods,
16321675 required_sendable : _,
1633- required_mainthreadonly : _ ,
1676+ required_mainthreadonly,
16341677 } => {
16351678 writeln ! ( f, "extern_protocol!(" ) ?;
16361679 write ! ( f, "{availability}" ) ?;
@@ -1661,6 +1704,14 @@ impl fmt::Display for Stmt {
16611704 // }
16621705 // write!(f, "Send + Sync")?;
16631706 // }
1707+ if * required_mainthreadonly {
1708+ if protocols. is_empty ( ) {
1709+ write ! ( f, ": " ) ?;
1710+ } else {
1711+ write ! ( f, "+ " ) ?;
1712+ }
1713+ write ! ( f, "IsMainThreadOnly" ) ?;
1714+ }
16641715 writeln ! ( f, " {{" ) ?;
16651716
16661717 for method in methods {
0 commit comments