@@ -440,7 +440,11 @@ class cpp_function : public function {
440440 std::string signature;
441441 size_t type_index = 0 , arg_index = 0 ;
442442 bool is_starred = false ;
443+ // `is_return_value` is true if we are currently inside the return type of the signature.
444+ // The same is true for `use_return_value`, except for forced usage of arg/return type
445+ // using @^/@$.
443446 bool is_return_value = false ;
447+ bool use_return_value = false ;
444448 for (const auto *pc = text; *pc != ' \0 ' ; ++pc) {
445449 const auto c = *pc;
446450
@@ -495,11 +499,21 @@ class cpp_function : public function {
495499 signature += detail::quote_cpp_type_name (detail::clean_type_id (t->name ()));
496500 }
497501 } else if (c == ' @' ) {
502+ // `@^ ... @^` and `@$ ... @$` are used to force arg/return value type (see
503+ // typing::Callable/detail::arg_descr/detail::return_descr)
504+ if ((*(pc + 1 ) == ' ^' && is_return_value)
505+ || (*(pc + 1 ) == ' $' && !is_return_value)) {
506+ use_return_value = !use_return_value;
507+ }
508+ if (*(pc + 1 ) == ' ^' || *(pc + 1 ) == ' $' ) {
509+ ++pc;
510+ continue ;
511+ }
498512 // Handle types that differ depending on whether they appear
499- // in an argument or a return value position
500- // For named arguments (py::arg()) with noconvert set, use return value type
513+ // in an argument or a return value position (see io_name<text1, text2>).
514+ // For named arguments (py::arg()) with noconvert set, return value type is used.
501515 ++pc;
502- if (!is_return_value
516+ if (!use_return_value
503517 && !(arg_index < rec->args .size () && !rec->args [arg_index].convert )) {
504518 while (*pc && *pc != ' @' )
505519 signature += *pc++;
@@ -518,6 +532,7 @@ class cpp_function : public function {
518532 } else {
519533 if (c == ' -' && *(pc + 1 ) == ' >' ) {
520534 is_return_value = true ;
535+ use_return_value = true ;
521536 }
522537 signature += c;
523538 }
0 commit comments