Repository: edgedb/edgedb

Issue:
Link to self union other types not working
<!-- Please search existing issues to avoid creating duplicates. -->
- EdgeDB Version: nightly
- OS Version: Mac

Steps to Reproduce:

1. Create a schema where you extend from a concrete type
```
    abstract type Entity {
        link parent -> Entity;
    };
    type BaseCourse extending Entity {}
    type Unit extending Entity {
         overloaded link parent -> Unit | BaseCourse;
    }
```
Migrating gives the following error
```
edgedb error: SchemaError: cannot get item data: item '530c3692-c209-11ec-9a1b-0722095a88ba' is not present in the schema <FlatSchema gen:5951 at 0x11338fee0>
edgedb error: cannot proceed until .esdl files are fixed
```


Discussion:

Resolving patch:
diff --git a/edb/schema/objtypes.py b/edb/schema/objtypes.py
--- a/edb/schema/objtypes.py
+++ b/edb/schema/objtypes.py
@@ -572,8 +572,14 @@ def _alter_finalize(
                 delete = union.init_delta_command(schema, sd.DeleteObject)
 
                 context.disable_dep_verification = True
-                nschema = delete.apply(schema, context)
+                delete.apply(schema, context)
                 context.disable_dep_verification = orig_disable
+                # We run the delete to populate the tree, but then instead
+                # of actually deleting the object, we just remove the names.
+                # This is because the pointers in the types we are looking
+                # at might themselves reference the union, so we need
+                # them in the schema to produce the correct as_alter_delta.
+                nschema = _delete_to_delist(delete, schema)
 
                 nschema, nunion = utils.get_union_type(
                     nschema,
@@ -597,6 +603,21 @@ def _alter_finalize(
         return super()._alter_finalize(schema, context)
 
 
+def _delete_to_delist(
+    delete: sd.DeleteObject[so.Object],
+    schema: s_schema.Schema,
+) -> s_schema.Schema:
+    """Delist all of the objects mentioned in a delete tree.
+
+    This removes their names from the schema but preserves the actual
+    objects.
+    """
+    schema = schema.delist(delete.classname)
+    for sub in delete.get_subcommands(type=sd.DeleteObject):
+        schema = _delete_to_delist(sub, schema)
+    return schema
+
+
 class DeleteObjectType(
     ObjectTypeCommand,
     s_types.DeleteType[ObjectType],
diff --git a/edb/schema/schema.py b/edb/schema/schema.py
--- a/edb/schema/schema.py
+++ b/edb/schema/schema.py
@@ -104,6 +104,10 @@ def discard(self: Schema_T, obj: so.Object) -> Schema_T:
     def delete(self: Schema_T, obj: so.Object) -> Schema_T:
         raise NotImplementedError
 
+    @abc.abstractmethod
+    def delist(self: Schema_T, name: sn.Name) -> Schema_T:
+        raise NotImplementedError
+
     @abc.abstractmethod
     def update_obj(
         self: Schema_T,
@@ -962,6 +966,14 @@ def add(
 
         return self.add_raw(id, sclass, data)
 
+    def delist(self, name: sn.Name) -> FlatSchema:
+        name_to_id = self._name_to_id.delete(name)
+        return self._replace(
+            name_to_id=name_to_id,
+            shortname_to_id=self._shortname_to_id,
+            globalname_to_id=self._globalname_to_id,
+        )
+
     def _delete(self, obj: so.Object) -> FlatSchema:
         data = self._id_to_data.get(obj.id)
         if data is None:
@@ -1587,6 +1599,16 @@ def delete(self, obj: so.Object) -> ChainedSchema:
                 self._global_schema,
             )
 
+    def delist(
+        self,
+        name: sn.Name,
+    ) -> ChainedSchema:
+        return ChainedSchema(
+            self._base_schema,
+            self._top_schema.delist(name),
+            self._global_schema,
+        )
+
     def update_obj(
         self,
         obj: so.Object,


Test patch:
diff --git a/tests/test_schema.py b/tests/test_schema.py
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -3214,6 +3214,19 @@ def test_schema_get_migration_default_ptrs_01(self):
 
         self._assert_migration_consistency(schema)
 
+    def test_schema_get_migration_union_ptrs_01(self):
+        schema = r'''
+        abstract type Entity {
+            link parent -> Entity;
+        };
+        type BaseCourse extending Entity {}
+        type Unit extending Entity {
+             overloaded link parent -> Unit | BaseCourse;
+        }
+        '''
+
+        self._assert_migration_consistency(schema)
+
     def test_schema_migrations_equivalence_01(self):
         self._assert_migration_equivalence([r"""
             type Base;