Repository: edgedb/edgedb

Issue:
Explicit references to subject type in schemas break in presence of inheritance
This happens with basically every place it can happen, but one example:
```
edgedb> create type A { create property z -> str; create property zed := A.z; };
OK: CREATE TYPE
edgedb> create type B extending A;
OK: CREATE TYPE
edgedb> insert A { z := "1" }; insert A { z := "2" }; insert B { z := "3" };
[{"id": "bb03847c-0a0b-11ed-b000-bf55cc7ccfd7"}]
[{"id": "bb03847d-0a0b-11ed-b000-87ad3b679fe5"}]
[{"id": "bb03847e-0a0b-11ed-b000-8b28fd0e4fe7"}]
edgedb> select B { multi oops := .zed };
[{"oops": ["1", "2", "3"]}]
edgedb> select B { zed };
edgedb error: InternalServerError: more than one row returned by a subquery used as an expression
```

Here, we define a computed property on `A` that directly references `A` -- this is obviously interpreted as referring to the source A.

But when we select it on `B`, it is intepreted as referring to `A` still!


Discussion:

Resolving patch:
diff --git a/edb/edgeql/compiler/setgen.py b/edb/edgeql/compiler/setgen.py
--- a/edb/edgeql/compiler/setgen.py
+++ b/edb/edgeql/compiler/setgen.py
@@ -1515,21 +1515,33 @@ def _get_schema_computed_ctx(
     @contextlib.contextmanager
     def newctx() -> Iterator[context.ContextLevel]:
         with ctx.detached() as subctx:
-            source_stype = get_set_type(source, ctx=ctx)
-
             source_scope = pathctx.get_set_scope(rptr.source, ctx=ctx)
             if source_scope and source_scope.namespaces:
                 subctx.path_id_namespace |= source_scope.namespaces
 
-            inner_path_id = pathctx.get_path_id(source_stype, ctx=subctx)
-
-            remapped_source = new_set_from_set(
-                rptr.source,
-                rptr=rptr.source.rptr,
-                ctx=ctx,
-            )
-            key = inner_path_id.strip_namespace(inner_path_id.namespace)
-            subctx.view_map[key] = ((inner_path_id, remapped_source),)
+            # Get the type of the actual location where the computed pointer
+            # was defined in the schema, since that is the type that must
+            # be used in the view map, since that is the type that might
+            # be *referenced in the definition*.
+            ptr = typegen.ptrcls_from_ptrref(rptr.ptrref, ctx=ctx)
+            assert isinstance(ptr, s_pointers.Pointer)
+            ptr = ptr.maybe_get_topmost_concrete_base(ctx.env.schema) or ptr
+            src = ptr.get_source(ctx.env.schema)
+
+            # If the source is an abstract pointer, then we don't have
+            # a full path to bind in the computed. Otherwise use a
+            # path derived from the pointer source.
+            if not (
+                isinstance(src, s_pointers.Pointer)
+                and src.generic(ctx.env.schema)
+            ):
+                inner_path_id = not_none(irast.PathId.from_pointer(
+                    ctx.env.schema, ptr, namespace=subctx.path_id_namespace,
+                ).src_path())
+                remapped_source = new_set_from_set(
+                    rptr.source, rptr=rptr.source.rptr, ctx=ctx
+                )
+                update_view_map(inner_path_id, remapped_source, ctx=subctx)
 
             yield subctx
 


Test patch:
diff --git a/tests/test_edgeql_scope.py b/tests/test_edgeql_scope.py
--- a/tests/test_edgeql_scope.py
+++ b/tests/test_edgeql_scope.py
@@ -3868,3 +3868,51 @@ async def test_edgeql_scope_union_backlink_01(self):
                     {"name": "Carol"}, {"name": "Dave"}]}
             ],
         )
+
+    async def test_edgeql_scope_schema_computed_01(self):
+        await self.con.execute('''
+            alter type User
+            create link lcards := (
+                select Card filter Card.name[0] = User.name[0]);
+        ''')
+
+        await self.assert_query_result(
+            r'''
+                with U := User,
+                select U { name } filter exists .lcards;
+            ''',
+            tb.bag([
+                {"name": "Bob"},
+                {"name": "Dave"},
+            ]),
+        )
+
+        await self.assert_query_result(
+            r'''
+                select Bot { lcards: {name} }
+            ''',
+            [
+                {
+                    "lcards": tb.bag([
+                        {"name": "Dragon"},
+                        {"name": "Dwarf"},
+                        {"name": "Djinn"}
+                    ])
+                }
+            ]
+        )
+
+    async def test_edgeql_scope_schema_computed_02(self):
+        await self.con.execute('''
+            alter type Named
+            create property foo := count(User)
+        ''')
+
+        # Make sure that 'User' doesn't get captured when evaluating
+        # the schema computed here.
+        await self.assert_query_result(
+            r'''
+                select User { foo }
+            ''',
+            [{'foo': 4}, {'foo': 4}, {'foo': 4}, {'foo': 4}]
+        )