Repository: scikit-hep/awkward

Issue:
to_packed on typetracer fails
### Version of Awkward Array

awkward@main

### Description and code to reproduce

Using dask_awkward for convenience and context.

```python3
import awkward as ak
import dask_awkward as dak

x = ak.Array([[1],[2,3],[4,5,6,7]])
dx = dak.from_awkward(x, 1)
ak.to_packed(dx._meta)
```

Fails with:
```
Traceback (most recent call last):
  File "to_packed.py", line 6, in <module>
    ak.to_packed(dx._meta)
  File "/Users/lgray/coffea-dev/awkward/src/awkward/operations/ak_to_packed.py", line 71, in to_packed
    return _impl(array, highlevel, behavior)
  File "/Users/lgray/coffea-dev/awkward/src/awkward/operations/ak_to_packed.py", line 76, in _impl
    out = layout.to_packed()
  File "/Users/lgray/coffea-dev/awkward/src/awkward/contents/listoffsetarray.py", line 2153, in to_packed
    and content.length
  File "/Users/lgray/coffea-dev/awkward/src/awkward/_nplikes/shape.py", line 75, in __eq__
    raise wrap_error(
TypeError: while calling

    ak.to_packed(
        array = <Array-typetracer [...] type='## * var * int64'>
        highlevel = True
        behavior = None
    )

Error details: cannot compare unknown lengths against known values
```


Discussion:

Resolving patch:
diff --git a/src/awkward/contents/listoffsetarray.py b/src/awkward/contents/listoffsetarray.py
--- a/src/awkward/contents/listoffsetarray.py
+++ b/src/awkward/contents/listoffsetarray.py
@@ -2148,10 +2148,13 @@ def continuation():
     def to_packed(self) -> Self:
         next = self.to_ListOffsetArray64(True)
         content = next._content.to_packed()
+        packed_length = self._backend.index_nplike.index_as_shape_item(
+            next._offsets[-1]
+        )
         if (
             content.length is not unknown_length
-            and content.length
-            != self._backend.index_nplike.index_as_shape_item(next._offsets[-1])
+            and packed_length is not unknown_length
+            and content.length != packed_length
         ):
             content = content[: next._offsets[-1]]
         return ListOffsetArray(next._offsets, content, parameters=next._parameters)


Test patch:
diff --git a/tests/test_2198_almost_equal.py b/tests/test_2198_almost_equal.py
--- a/tests/test_2198_almost_equal.py
+++ b/tests/test_2198_almost_equal.py
@@ -147,5 +147,5 @@ def test_numpy_array():
 
 def test_typetracer():
     array = ak.Array([[[1, 2, 3]], [[5, 4]]], backend="typetracer")
-    with pytest.raises(TypeError):
+    with pytest.raises(NotImplementedError):
         ak.almost_equal(array, 2 * array)
diff --git a/tests/test_2263_to_packed_list.py b/tests/test_2263_to_packed_list.py
new file mode 100644
--- /dev/null
+++ b/tests/test_2263_to_packed_list.py
@@ -0,0 +1,18 @@
+# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
+
+import numpy as np
+import pytest  # noqa: F401
+
+import awkward as ak
+from awkward._backends import TypeTracerBackend
+
+
+def test():
+    backend = TypeTracerBackend.instance()
+    layout = ak.contents.ListOffsetArray(
+        ak.index.Index64(
+            backend.index_nplike.asarray([0, 1, 3, 7], dtype=np.dtype("int64"))
+        ),
+        ak.contents.NumpyArray(backend.nplike.asarray([1, 2, 3, 4, 5, 6, 7])),
+    )
+    assert layout.to_packed().length == 3