Repository: edgedb/edgedb

Issue:
InvalidReferenceError: reference to 'expr~4' changes the interpretation of 'expr~4' elsewhere in the query
- EdgeDB Version: 2.0-dev.6475+local

Steps to Reproduce:

```edgeql
select (
  select default::Movie limit 1
).actors {
  linkprop := @character_name
}
```

Schema:
(schema from edgedb.com/tutorial)
```sdl
using extension notebook version \'1.0\';
module default {
    type Account {
        multi link watchlist -> default::Content;
        required property username -> std::str {
            constraint std::exclusive;
        };
    };
    abstract type Content {
        multi link actors -> default::Person {
            property character_name -> std::str;
        };
        required property title -> std::str;
    };
    type Movie extending default::Content {
        property release_year -> std::int32;
    };
    type Person {
        link filmography := (.<actors[is default::Content]);
        required property name -> std::str;
    };
    type Season {
        required link show -> default::Show;
        required property number -> std::int32;
    };
    type Show extending default::Content {
        property num_seasons := (std::count(.<show[is default::Season]));
    };
};
```


Discussion:
huh, we shouldn't really be trying to allow the computed linkprop reference at all, right, since it's on a semi-joined link?
We don't allow it if is is just listed bare...
Hm, that's not right, though, since we /do/ allow things like `select Movie.actors@character_name`, and it suppresses the semijoining...

Resolving patch:
diff --git a/edb/ir/scopetree.py b/edb/ir/scopetree.py
--- a/edb/ir/scopetree.py
+++ b/edb/ir/scopetree.py
@@ -605,11 +605,19 @@ def _check_factoring_errors(
 
             assert offending_node.path_id is not None
 
+            imp = ''
+            offending_id = f'{offending_node.path_id.pformat()!r}'
+            existing_id = f'{existing.path_id.pformat()!r}'
+            # If the id is generated, don't leak meaningless info
+            # and try to explain that the reference is implicit.
+            if '~' in offending_id:
+                imp = 'implicit '
+                offending_id = 'an object'
+                existing_id = 'it'
+
             raise errors.InvalidReferenceError(
-                f'reference to '
-                f'{offending_node.path_id.pformat()!r} '
-                f'changes the interpretation of '
-                f'{existing.path_id.pformat()!r} '
+                f'{imp}reference to {offending_id} '
+                f'changes the interpretation of {existing_id} '
                 f'elsewhere in the query',
                 context=context,
             )


Test patch:
diff --git a/tests/test_edgeql_linkprops.py b/tests/test_edgeql_linkprops.py
--- a/tests/test_edgeql_linkprops.py
+++ b/tests/test_edgeql_linkprops.py
@@ -1302,3 +1302,19 @@ async def test_edgeql_props_intersect_01(self):
                 }
             ]
         )
+
+    async def test_edgeql_props_bogus_01(self):
+        with self.assertRaisesRegex(
+                edgedb.QueryError,
+                r"implicit reference to an object changes the "
+                r"interpretation of it elsewhere in the query"):
+
+            await self.con.query(
+                r'''
+                    select (
+                      select User
+                    ).deck {
+                      linkprop := @count
+                    };
+                '''
+            )