Repository: geldata/gel
Pull request: Fix "cannot describe type" ISE in cast+array+empty set interactions
Fixes #1586.

Problem statement:
InternalServerError: cannot describe type default::User
<!-- Please search existing issues to avoid creating duplicates. -->
- EdgeDB Version: Docker: `1.0a4-2020071615~buster`

Steps to Reproduce:

Run: ` SELECT <array<User>>{};`

<!-- If the issue is about a query error, please also provide your schema -->
Schema:
```esdl
type User {
            required property nickname -> str;
            required property email -> str;
            required property email_verified -> bool {
                default := false;
            };
            required property password -> bytes;
            required property created_at -> datetime {
                default := datetime_current();
            };
        };
```

Hints from issue discussion:

Commit message: Fix "cannot describe type" ISE in cast+array+empty set interactions

Fixes #1586.

Patch to review:
diff --git a/edb/server/compiler/sertypes.py b/edb/server/compiler/sertypes.py
index 651372d5d99..ad2fdc76724 100644
--- a/edb/server/compiler/sertypes.py
+++ b/edb/server/compiler/sertypes.py
@@ -33,6 +33,7 @@
 
 from edb.schema import links as s_links
 from edb.schema import objects as s_obj
+from edb.schema import objtypes as s_objtypes
 from edb.schema import scalars as s_scalars
 from edb.schema import types as s_types
 
@@ -205,7 +206,17 @@ def _describe_type(self, t, view_shapes, view_shapes_metadata,
         elif isinstance(t, s_types.Collection):
             raise errors.SchemaError(f'unsupported collection type {t!r}')
 
-        elif view_shapes.get(t):
+        elif isinstance(t, s_objtypes.ObjectType):
+            if t not in view_shapes:
+                # If we have an object type that isn't attached to a view,
+                # it must be the case that it doesn't actually appear in
+                # the output, so just return *something* that is well
+                # formed.
+                return self._describe_type(
+                    self.schema.get('std::uuid'), view_shapes,
+                    view_shapes_metadata,
+                )
+
             # This is a view
             self.schema, mt = t.material_type(self.schema)
             base_type_id = mt.id
diff --git a/tests/test_edgeql_casts.py b/tests/test_edgeql_casts.py
index de3b647c63f..b6b12c46153 100644
--- a/tests/test_edgeql_casts.py
+++ b/tests/test_edgeql_casts.py
@@ -2464,3 +2464,11 @@ async def test_edgeql_casts_prohibit_tuple_query_params_02(self):
                 r"SELECT <array<tuple<int64, str>>>$0;",
                 [(0, 'zero'), (1, 'one')],
             )
+
+    async def test_edgeql_cast_empty_set_to_array_01(self):
+        await self.assert_query_result(
+            r'''
+                SELECT <array<Object>>{};
+            ''',
+            [],
+        )


Code review comments:
diff_hunk: @@ -205,7 +206,17 @@ def _describe_type(self, t, view_shapes, view_shapes_metadata,
         elif isinstance(t, s_types.Collection):
             raise errors.SchemaError(f'unsupported collection type {t!r}')
 
-        elif view_shapes.get(t):
+        elif isinstance(t, s_objtypes.ObjectType):
+            if t not in view_shapes:
+                # If we have an object type that isn't attached to a view,
+                # it must be the case that it doesn't actually appear in
+                # the output, so just return *something* that is well
+                # formed.
+                return self._describe_type(
+                    self.schema.get('std::uuid'), view_shapes,
path: edb/server/compiler/sertypes.py
text: @user1:
I feel like a better fix would be to pretend that a `view_shape` exists, but is empty, or, even better, consisting entirely of implicit pointers.  Otherwise there is a danger of the frontend getting confused by an object not being represented properly.