prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  `ak.fill_none` doesn't support option-in-record
  ### Version of Awkward Array
  
  main
  
  ### Description and code to reproduce
  
  The following example is left unchanged by `ak.fill_none`:
  ```python
  import awkward as ak
  
  record = ak.zip({
      'x': [1, None],
      'y': [2, 3]
  })
  
  result = ak.fill_none(record, 0, axis=-1)
  result.show()
  ```
  
  I'm fairly sure that this is a bug, because `ak.is_none` walks successfully through records. My understanding of records is that it's only reducers that cannot peer through them. 
  
  Of course, this example would imply
  ```python
  record = ak.zip({
      "x": [1, 4], 
  	"y": [2, 3]
  }).mask[[True, False]]
  assert ak.fill_none(record, 0, axis=-1).to_list() == [
      {"x": 1, "y": 2},
      0
  ]
  ```
  
  I think this is reasonable; again, `is_none` behaves identically to this. Maybe we _do_ want a parameter in future, e.g. `visit_records` or some such.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/awkward/operations/ak_fill_none.py`
  Content:
  ```
  1 # BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
  2 
  3 import numbers
  4 
  5 import awkward as ak
  6 
  7 np = ak._nplikes.NumpyMetadata.instance()
  8 cpu = ak._backends.NumpyBackend.instance()
  9 
  10 
  11 def fill_none(array, value, axis=-1, *, highlevel=True, behavior=None):
  12     """
  13     Args:
  14         array: Array-like data (anything #ak.to_layout recognizes).
  15         value: Data with which to replace None.
  16         axis (None or int): If None, replace all None values in the array
  17             with the given value; if an int, The dimension at which this
  18             operation is applied. The outermost dimension is `0`, followed
  19             by `1`, etc., and negative values count backward from the
  20             innermost: `-1` is the innermost  dimension, `-2` is the next
  21             level up, etc.
  22         highlevel (bool): If True, return an #ak.Array; otherwise, return
  23             a low-level #ak.contents.Content subclass.
  24         behavior (None or dict): Custom #ak.behavior for the output array, if
  25             high-level.
  26 
  27     Replaces missing values (None) with a given `value`.
  28 
  29     For example, in the following
  30 
  31         >>> array = ak.Array([[1.1, None, 2.2], [], [None, 3.3, 4.4]])
  32 
  33     The None values could be replaced with `0` by
  34 
  35         >>> ak.fill_none(array, 0)
  36         <Array [[1.1, 0, 2.2], [], [0, 3.3, 4.4]] type='3 * var * float64'>
  37 
  38     The replacement value doesn't strictly need the same type as the
  39     surrounding data. For example, the None values could also be replaced
  40     by a string.
  41 
  42         >>> ak.fill_none(array, "hi")
  43         <Array [[1.1, 'hi', 2.2], [], ['hi', ...]] type='3 * var * union[float64, s...'>
  44 
  45     The list content now has a union type:
  46 
  47         >>> ak.fill_none(array, "hi").type.show()
  48         3 * var * union[
  49             float64,
  50             string
  51         ]
  52 
  53     The values could be floating-point numbers or strings.
  54     """
  55     with ak._errors.OperationErrorContext(
  56         "ak.fill_none",
  57         dict(
  58             array=array, value=value, axis=axis, highlevel=highlevel, behavior=behavior
  59         ),
  60     ):
  61         return _impl(array, value, axis, highlevel, behavior)
  62 
  63 
  64 def _impl(array, value, axis, highlevel, behavior):
  65     arraylayout = ak.operations.to_layout(array, allow_record=True, allow_other=False)
  66     behavior = ak._util.behavior_of(array, behavior=behavior)
  67     backend = ak._backends.backend_of(arraylayout, default=cpu)
  68 
  69     # Convert value type to appropriate layout
  70     if (
  71         isinstance(value, np.ndarray)
  72         and issubclass(value.dtype.type, (np.bool_, np.number))
  73         and len(value.shape) != 0
  74     ):
  75         valuelayout = ak.operations.to_layout(
  76             backend.nplike.asarray(value)[np.newaxis],
  77             allow_record=False,
  78             allow_other=False,
  79         )
  80     elif isinstance(value, (bool, numbers.Number, np.bool_, np.number)) or (
  81         isinstance(value, np.ndarray)
  82         and issubclass(value.dtype.type, (np.bool_, np.number))
  83     ):
  84         valuelayout = ak.operations.to_layout(
  85             backend.nplike.asarray(value), allow_record=False, allow_other=False
  86         )
  87     elif (
  88         ak._util.is_sized_iterable(value)
  89         and not (isinstance(value, (str, bytes)))
  90         or isinstance(value, (ak.highlevel.Record, ak.record.Record))
  91     ):
  92         valuelayout = ak.operations.to_layout(
  93             value, allow_record=True, allow_other=False
  94         )
  95         if isinstance(valuelayout, ak.record.Record):
  96             valuelayout = valuelayout.array[valuelayout.at : valuelayout.at + 1]
  97         elif len(valuelayout) == 0:
  98             offsets = ak.index.Index64(
  99                 backend.index_nplike.array([0, 0], dtype=np.int64)
  100             )
  101             valuelayout = ak.contents.ListOffsetArray(offsets, valuelayout)
  102         else:
  103             valuelayout = ak.contents.RegularArray(valuelayout, len(valuelayout), 1)
  104     else:
  105         valuelayout = ak.operations.to_layout(
  106             [value], allow_record=False, allow_other=False
  107         )
  108 
  109     def maybe_fillna(layout):
  110         if layout.is_option:
  111             return ak._do.fill_none(layout, valuelayout)
  112         else:
  113             return layout
  114 
  115     if axis is None:
  116 
  117         def action(layout, continuation, **kwargs):
  118             return maybe_fillna(continuation())
  119 
  120     else:
  121 
  122         def action(layout, depth, **kwargs):
  123             posaxis = ak._util.maybe_posaxis(layout, axis, depth)
  124             if posaxis is not None and posaxis + 1 < depth:
  125                 return layout
  126             elif posaxis is not None and posaxis + 1 == depth:
  127                 return maybe_fillna(layout)
  128             elif layout.is_leaf:
  129                 raise ak._errors.wrap_error(
  130                     np.AxisError(
  131                         f"axis={axis} exceeds the depth of this array ({depth})"
  132                     )
  133                 )
  134 
  135     out = ak._do.recursively_apply(arraylayout, action, behavior)
  136 
  137     return ak._util.wrap(out, behavior, highlevel)
  138
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/awkward/operations/ak_fill_none.py b/src/awkward/operations/ak_fill_none.py
  --- a/src/awkward/operations/ak_fill_none.py
  +++ b/src/awkward/operations/ak_fill_none.py
  @@ -63,7 +63,7 @@
   
   def _impl(array, value, axis, highlevel, behavior):
       arraylayout = ak.operations.to_layout(array, allow_record=True, allow_other=False)
  -    behavior = ak._util.behavior_of(array, behavior=behavior)
  +    behavior = ak._util.behavior_of(array, value, behavior=behavior)
       backend = ak._backends.backend_of(arraylayout, default=cpu)
   
       # Convert value type to appropriate layout
  @@ -106,25 +106,24 @@
               [value], allow_record=False, allow_other=False
           )
   
  -    def maybe_fillna(layout):
  -        if layout.is_option:
  -            return ak._do.fill_none(layout, valuelayout)
  -        else:
  -            return layout
  -
       if axis is None:
   
           def action(layout, continuation, **kwargs):
  -            return maybe_fillna(continuation())
  +            if layout.is_option:
  +                return ak._do.fill_none(continuation(), valuelayout)
   
       else:
   
           def action(layout, depth, **kwargs):
               posaxis = ak._util.maybe_posaxis(layout, axis, depth)
  -            if posaxis is not None and posaxis + 1 < depth:
  -                return layout
  -            elif posaxis is not None and posaxis + 1 == depth:
  -                return maybe_fillna(layout)
  +            if posaxis is not None and posaxis + 1 == depth:
  +                if layout.is_union or layout.is_record:
  +                    return None
  +                elif layout.is_option:
  +                    return ak._do.fill_none(layout, valuelayout)
  +                else:
  +                    return layout
  +
               elif layout.is_leaf:
                   raise ak._errors.wrap_error(
                       np.AxisError(
  @@ -133,5 +132,4 @@
                   )
   
       out = ak._do.recursively_apply(arraylayout, action, behavior)
  -
       return ak._util.wrap(out, behavior, highlevel)
  
verification_info: {"golden_diff": "diff --git a/src/awkward/operations/ak_fill_none.py b/src/awkward/operations/ak_fill_none.py\n--- a/src/awkward/operations/ak_fill_none.py\n+++ b/src/awkward/operations/ak_fill_none.py\n@@ -63,7 +63,7 @@\n \n def _impl(array, value, axis, highlevel, behavior):\n     arraylayout = ak.operations.to_layout(array, allow_record=True, allow_other=False)\n-    behavior = ak._util.behavior_of(array, behavior=behavior)\n+    behavior = ak._util.behavior_of(array, value, behavior=behavior)\n     backend = ak._backends.backend_of(arraylayout, default=cpu)\n \n     # Convert value type to appropriate layout\n@@ -106,25 +106,24 @@\n             [value], allow_record=False, allow_other=False\n         )\n \n-    def maybe_fillna(layout):\n-        if layout.is_option:\n-            return ak._do.fill_none(layout, valuelayout)\n-        else:\n-            return layout\n-\n     if axis is None:\n \n         def action(layout, continuation, **kwargs):\n-            return maybe_fillna(continuation())\n+            if layout.is_option:\n+                return ak._do.fill_none(continuation(), valuelayout)\n \n     else:\n \n         def action(layout, depth, **kwargs):\n             posaxis = ak._util.maybe_posaxis(layout, axis, depth)\n-            if posaxis is not None and posaxis + 1 < depth:\n-                return layout\n-            elif posaxis is not None and posaxis + 1 == depth:\n-                return maybe_fillna(layout)\n+            if posaxis is not None and posaxis + 1 == depth:\n+                if layout.is_union or layout.is_record:\n+                    return None\n+                elif layout.is_option:\n+                    return ak._do.fill_none(layout, valuelayout)\n+                else:\n+                    return layout\n+\n             elif layout.is_leaf:\n                 raise ak._errors.wrap_error(\n                     np.AxisError(\n@@ -133,5 +132,4 @@\n                 )\n \n     out = ak._do.recursively_apply(arraylayout, action, behavior)\n-\n     return ak._util.wrap(out, behavior, highlevel)\n", "issue": "`ak.fill_none` doesn't support option-in-record\n### Version of Awkward Array\r\n\r\nmain\r\n\r\n### Description and code to reproduce\r\n\r\nThe following example is left unchanged by `ak.fill_none`:\r\n```python\r\nimport awkward as ak\r\n\r\nrecord = ak.zip({\r\n    'x': [1, None],\r\n    'y': [2, 3]\r\n})\r\n\r\nresult = ak.fill_none(record, 0, axis=-1)\r\nresult.show()\r\n```\r\n\r\nI'm fairly sure that this is a bug, because `ak.is_none` walks successfully through records. My understanding of records is that it's only reducers that cannot peer through them. \r\n\r\nOf course, this example would imply\r\n```python\r\nrecord = ak.zip({\r\n    \"x\": [1, 4], \r\n\t\"y\": [2, 3]\r\n}).mask[[True, False]]\r\nassert ak.fill_none(record, 0, axis=-1).to_list() == [\r\n    {\"x\": 1, \"y\": 2},\r\n    0\r\n]\r\n```\r\n\r\nI think this is reasonable; again, `is_none` behaves identically to this. Maybe we _do_ want a parameter in future, e.g. `visit_records` or some such.\n", "before_files": [{"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport numbers\n\nimport awkward as ak\n\nnp = ak._nplikes.NumpyMetadata.instance()\ncpu = ak._backends.NumpyBackend.instance()\n\n\ndef fill_none(array, value, axis=-1, *, highlevel=True, behavior=None):\n    \"\"\"\n    Args:\n        array: Array-like data (anything #ak.to_layout recognizes).\n        value: Data with which to replace None.\n        axis (None or int): If None, replace all None values in the array\n            with the given value; if an int, The dimension at which this\n            operation is applied. The outermost dimension is `0`, followed\n            by `1`, etc., and negative values count backward from the\n            innermost: `-1` is the innermost  dimension, `-2` is the next\n            level up, etc.\n        highlevel (bool): If True, return an #ak.Array; otherwise, return\n            a low-level #ak.contents.Content subclass.\n        behavior (None or dict): Custom #ak.behavior for the output array, if\n            high-level.\n\n    Replaces missing values (None) with a given `value`.\n\n    For example, in the following\n\n        >>> array = ak.Array([[1.1, None, 2.2], [], [None, 3.3, 4.4]])\n\n    The None values could be replaced with `0` by\n\n        >>> ak.fill_none(array, 0)\n        <Array [[1.1, 0, 2.2], [], [0, 3.3, 4.4]] type='3 * var * float64'>\n\n    The replacement value doesn't strictly need the same type as the\n    surrounding data. For example, the None values could also be replaced\n    by a string.\n\n        >>> ak.fill_none(array, \"hi\")\n        <Array [[1.1, 'hi', 2.2], [], ['hi', ...]] type='3 * var * union[float64, s...'>\n\n    The list content now has a union type:\n\n        >>> ak.fill_none(array, \"hi\").type.show()\n        3 * var * union[\n            float64,\n            string\n        ]\n\n    The values could be floating-point numbers or strings.\n    \"\"\"\n    with ak._errors.OperationErrorContext(\n        \"ak.fill_none\",\n        dict(\n            array=array, value=value, axis=axis, highlevel=highlevel, behavior=behavior\n        ),\n    ):\n        return _impl(array, value, axis, highlevel, behavior)\n\n\ndef _impl(array, value, axis, highlevel, behavior):\n    arraylayout = ak.operations.to_layout(array, allow_record=True, allow_other=False)\n    behavior = ak._util.behavior_of(array, behavior=behavior)\n    backend = ak._backends.backend_of(arraylayout, default=cpu)\n\n    # Convert value type to appropriate layout\n    if (\n        isinstance(value, np.ndarray)\n        and issubclass(value.dtype.type, (np.bool_, np.number))\n        and len(value.shape) != 0\n    ):\n        valuelayout = ak.operations.to_layout(\n            backend.nplike.asarray(value)[np.newaxis],\n            allow_record=False,\n            allow_other=False,\n        )\n    elif isinstance(value, (bool, numbers.Number, np.bool_, np.number)) or (\n        isinstance(value, np.ndarray)\n        and issubclass(value.dtype.type, (np.bool_, np.number))\n    ):\n        valuelayout = ak.operations.to_layout(\n            backend.nplike.asarray(value), allow_record=False, allow_other=False\n        )\n    elif (\n        ak._util.is_sized_iterable(value)\n        and not (isinstance(value, (str, bytes)))\n        or isinstance(value, (ak.highlevel.Record, ak.record.Record))\n    ):\n        valuelayout = ak.operations.to_layout(\n            value, allow_record=True, allow_other=False\n        )\n        if isinstance(valuelayout, ak.record.Record):\n            valuelayout = valuelayout.array[valuelayout.at : valuelayout.at + 1]\n        elif len(valuelayout) == 0:\n            offsets = ak.index.Index64(\n                backend.index_nplike.array([0, 0], dtype=np.int64)\n            )\n            valuelayout = ak.contents.ListOffsetArray(offsets, valuelayout)\n        else:\n            valuelayout = ak.contents.RegularArray(valuelayout, len(valuelayout), 1)\n    else:\n        valuelayout = ak.operations.to_layout(\n            [value], allow_record=False, allow_other=False\n        )\n\n    def maybe_fillna(layout):\n        if layout.is_option:\n            return ak._do.fill_none(layout, valuelayout)\n        else:\n            return layout\n\n    if axis is None:\n\n        def action(layout, continuation, **kwargs):\n            return maybe_fillna(continuation())\n\n    else:\n\n        def action(layout, depth, **kwargs):\n            posaxis = ak._util.maybe_posaxis(layout, axis, depth)\n            if posaxis is not None and posaxis + 1 < depth:\n                return layout\n            elif posaxis is not None and posaxis + 1 == depth:\n                return maybe_fillna(layout)\n            elif layout.is_leaf:\n                raise ak._errors.wrap_error(\n                    np.AxisError(\n                        f\"axis={axis} exceeds the depth of this array ({depth})\"\n                    )\n                )\n\n    out = ak._do.recursively_apply(arraylayout, action, behavior)\n\n    return ak._util.wrap(out, behavior, highlevel)\n", "path": "src/awkward/operations/ak_fill_none.py"}], "after_files": [{"content": "# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE\n\nimport numbers\n\nimport awkward as ak\n\nnp = ak._nplikes.NumpyMetadata.instance()\ncpu = ak._backends.NumpyBackend.instance()\n\n\ndef fill_none(array, value, axis=-1, *, highlevel=True, behavior=None):\n    \"\"\"\n    Args:\n        array: Array-like data (anything #ak.to_layout recognizes).\n        value: Data with which to replace None.\n        axis (None or int): If None, replace all None values in the array\n            with the given value; if an int, The dimension at which this\n            operation is applied. The outermost dimension is `0`, followed\n            by `1`, etc., and negative values count backward from the\n            innermost: `-1` is the innermost  dimension, `-2` is the next\n            level up, etc.\n        highlevel (bool): If True, return an #ak.Array; otherwise, return\n            a low-level #ak.contents.Content subclass.\n        behavior (None or dict): Custom #ak.behavior for the output array, if\n            high-level.\n\n    Replaces missing values (None) with a given `value`.\n\n    For example, in the following\n\n        >>> array = ak.Array([[1.1, None, 2.2], [], [None, 3.3, 4.4]])\n\n    The None values could be replaced with `0` by\n\n        >>> ak.fill_none(array, 0)\n        <Array [[1.1, 0, 2.2], [], [0, 3.3, 4.4]] type='3 * var * float64'>\n\n    The replacement value doesn't strictly need the same type as the\n    surrounding data. For example, the None values could also be replaced\n    by a string.\n\n        >>> ak.fill_none(array, \"hi\")\n        <Array [[1.1, 'hi', 2.2], [], ['hi', ...]] type='3 * var * union[float64, s...'>\n\n    The list content now has a union type:\n\n        >>> ak.fill_none(array, \"hi\").type.show()\n        3 * var * union[\n            float64,\n            string\n        ]\n\n    The values could be floating-point numbers or strings.\n    \"\"\"\n    with ak._errors.OperationErrorContext(\n        \"ak.fill_none\",\n        dict(\n            array=array, value=value, axis=axis, highlevel=highlevel, behavior=behavior\n        ),\n    ):\n        return _impl(array, value, axis, highlevel, behavior)\n\n\ndef _impl(array, value, axis, highlevel, behavior):\n    arraylayout = ak.operations.to_layout(array, allow_record=True, allow_other=False)\n    behavior = ak._util.behavior_of(array, value, behavior=behavior)\n    backend = ak._backends.backend_of(arraylayout, default=cpu)\n\n    # Convert value type to appropriate layout\n    if (\n        isinstance(value, np.ndarray)\n        and issubclass(value.dtype.type, (np.bool_, np.number))\n        and len(value.shape) != 0\n    ):\n        valuelayout = ak.operations.to_layout(\n            backend.nplike.asarray(value)[np.newaxis],\n            allow_record=False,\n            allow_other=False,\n        )\n    elif isinstance(value, (bool, numbers.Number, np.bool_, np.number)) or (\n        isinstance(value, np.ndarray)\n        and issubclass(value.dtype.type, (np.bool_, np.number))\n    ):\n        valuelayout = ak.operations.to_layout(\n            backend.nplike.asarray(value), allow_record=False, allow_other=False\n        )\n    elif (\n        ak._util.is_sized_iterable(value)\n        and not (isinstance(value, (str, bytes)))\n        or isinstance(value, (ak.highlevel.Record, ak.record.Record))\n    ):\n        valuelayout = ak.operations.to_layout(\n            value, allow_record=True, allow_other=False\n        )\n        if isinstance(valuelayout, ak.record.Record):\n            valuelayout = valuelayout.array[valuelayout.at : valuelayout.at + 1]\n        elif len(valuelayout) == 0:\n            offsets = ak.index.Index64(\n                backend.index_nplike.array([0, 0], dtype=np.int64)\n            )\n            valuelayout = ak.contents.ListOffsetArray(offsets, valuelayout)\n        else:\n            valuelayout = ak.contents.RegularArray(valuelayout, len(valuelayout), 1)\n    else:\n        valuelayout = ak.operations.to_layout(\n            [value], allow_record=False, allow_other=False\n        )\n\n    if axis is None:\n\n        def action(layout, continuation, **kwargs):\n            if layout.is_option:\n                return ak._do.fill_none(continuation(), valuelayout)\n\n    else:\n\n        def action(layout, depth, **kwargs):\n            posaxis = ak._util.maybe_posaxis(layout, axis, depth)\n            if posaxis is not None and posaxis + 1 == depth:\n                if layout.is_union or layout.is_record:\n                    return None\n                elif layout.is_option:\n                    return ak._do.fill_none(layout, valuelayout)\n                else:\n                    return layout\n\n            elif layout.is_leaf:\n                raise ak._errors.wrap_error(\n                    np.AxisError(\n                        f\"axis={axis} exceeds the depth of this array ({depth})\"\n                    )\n                )\n\n    out = ak._do.recursively_apply(arraylayout, action, behavior)\n    return ak._util.wrap(out, behavior, highlevel)\n", "path": "src/awkward/operations/ak_fill_none.py"}]}