Repository: edgedb/edgedb

Issue:
ISE: Self reference in computed using __source__
<!-- Please search existing issues to avoid creating duplicates. -->

<!--
For the EdgeDB Version: run `edgedb query 'select sys::get_version_as_str()'` from your project directory (or run `select sys::get_version_as_str();` in the EdgeDB interactive shell).
For the EdgeDB CLI Version: Run `edgedb --version` from anywhere
-->

- EdgeDB Version: 3.0-rc.2+eb06d9e
- EdgeDB CLI Version: 3.1.3+2f81fc4
- OS Version: OSX 13.2.1

Steps to Reproduce:

1. start `edgedb watch`
2. add 
   ```
   abstract type Pinnable {
     property pinned := __source__ in <Pinnable>{};
   }
   ```
3. add 
   ```
   type Foo extending Pinnable {}
   ```
```
Schema migration error: InternalServerError: object type 'default::Foo' has no link or property '__type__'
```


Discussion:
Also affects constraints:

```
module person{
    abstract type Person {
        multi link friends : Person{
            constraint expression on (
                    __subject__ != __subject__@source
                );
        };

    }

    type Employee extending Person{
        department : str;
    }
}
```

Resolving patch:
diff --git a/edb/edgeql/compiler/func.py b/edb/edgeql/compiler/func.py
--- a/edb/edgeql/compiler/func.py
+++ b/edb/edgeql/compiler/func.py
@@ -837,8 +837,9 @@ def finalize_args(
             ):
                 arg_type_path_id = pathctx.extend_path_id(
                     arg.path_id,
-                    ptrcls=arg_type.getptr(
-                        ctx.env.schema, sn.UnqualName('__type__')),
+                    ptrcls=setgen.resolve_ptr(
+                        arg_type, '__type__', track_ref=None, ctx=ctx
+                    ),
                     ctx=ctx,
                 )
         else:
diff --git a/edb/schema/inheriting.py b/edb/schema/inheriting.py
--- a/edb/schema/inheriting.py
+++ b/edb/schema/inheriting.py
@@ -223,11 +223,21 @@ def get_inherited_ref_layout(
                 rev_refs = {v: k for k, v in base_refs.items()}
                 base_refs = {
                     rev_refs[v]: v
-                    for v in reversed(
-                        sd.sort_by_cross_refs(schema, base_refs.values()))
+                    for v in sd.sort_by_cross_refs(schema, base_refs.values())
                 }
 
-            for k, v in base_refs.items():
+                # HACK: Because of issue #5661, we previously did not always
+                # properly discover dependencies on __type__ in computeds.
+                # This was fixed, but it may persist in existing databases.
+                # Currently, expr refs are not compared when diffing schemas,
+                # so a schema repair can't fix this. Thus, in addition to
+                # actually fixing the bug, we hack around it by forcing
+                # __type__ to sort to the front.
+                # TODO: Drop this after cherry-picking.
+                if (tname := sn.UnqualName('__type__')) in base_refs:
+                    base_refs[tname] = base_refs.pop(tname)
+
+            for k, v in reversed(base_refs.items()):
                 if not v.should_propagate(schema):
                     continue
                 if base == self.scls and not v.get_owned(schema):


Test patch:
diff --git a/tests/test_schema.py b/tests/test_schema.py
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -8080,6 +8080,49 @@ def test_schema_migrations_rewrites_01(self):
             """,
         ])
 
+    def test_schema_migrations_implicit_type_01(self):
+        self._assert_migration_equivalence([
+            r"""
+                abstract type Pinnable {
+                    property pinned := __source__ in <Pinnable>{};
+                }
+            """,
+            r"""
+                abstract type Pinnable {
+                    property pinned := __source__ in <Pinnable>{};
+                }
+                type Foo extending Pinnable {}
+            """,
+        ])
+
+    def test_schema_migrations_implicit_type_02(self):
+        self._assert_migration_equivalence([
+            r"""
+                abstract type Person {
+                    multi link friends : Person{
+                        constraint expression on (
+                                __subject__ != __subject__@source
+                            );
+                    };
+
+                }
+            """,
+            r"""
+                abstract type Person {
+                    multi link friends : Person{
+                        constraint expression on (
+                                __subject__ != __subject__@source
+                            );
+                    };
+
+                }
+
+                type Employee extending Person{
+                    department: str;
+                }
+            """,
+        ])
+
 
 class TestDescribe(tb.BaseSchemaLoadTest):
     """Test the DESCRIBE command."""
diff --git a/tests/test_sql_query.py b/tests/test_sql_query.py
--- a/tests/test_sql_query.py
+++ b/tests/test_sql_query.py
@@ -879,7 +879,11 @@ async def test_sql_query_copy_01(self):
             "Movie", output=out, format="csv", delimiter="\t"
         )
         out = io.StringIO(out.getvalue().decode("utf-8"))
-        names = set(row[6] for row in csv.reader(out, delimiter="\t"))
+        # FIXME(#5716): Once COPY and information_schema are
+        # harmonized to agree on the order of columns, we should query
+        # information_schema to get the column number instead of
+        # hardcoding it.
+        names = set(row[7] for row in csv.reader(out, delimiter="\t"))
         self.assertEqual(names, {"Forrest Gump", "Saving Private Ryan"})
 
     async def test_sql_query_error_01(self):