Repository: edgedb/edgedb

Issue:
Unable to index into tuple on link property
- EdgeDB Version: 2.7+ad94380
- EdgeDB CLI Version: 2.2.6+7eabbf9
- OS Version: macOS 13.0.1

Steps to Reproduce:

Simplified schema
```
type Org {}

type User {
    multi link orgs -> Org {
        property roles -> tuple<role1: bool, role2: bool>;
    }
}
```

I am able to select the entire tuple, but not its members. `select User.orgs@roles;` works, but `select User.orgs@roles.role1;` or `select User.orgs@roles.0` fail with:

```
edgedb error: InternalServerError: cannot find scope statement for (default::User).>orgs[IS default::Org]
```

Full trace:
``` 
Server traceback:
      Traceback (most recent call last):
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/__init__.py", line 120, in compile_ir_to_sql_tree
          qtree = dispatch.compile(ir_expr, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/functools.py", line 889, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 60, in compile_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 114, in _compile_set_impl
          _compile_set(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 677, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 162, in get_set_rvar
          return _process_toplevel_query(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 265, in _process_toplevel_query
          rvars = _get_set_rvar(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 304, in _get_set_rvar
          rvars = process_set_as_subquery(ir_set, stmt, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 1396, in process_set_as_subquery
          dispatch.visit(expr, ctx=newctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/functools.py", line 889, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/dispatch.py", line 44, in visit
          compile(ir, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/functools.py", line 889, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/stmt.py", line 89, in compile_SelectStmt
          outvar = clauses.compile_output(stmt.result, ctx=ictx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/clauses.py", line 213, in compile_output
          dispatch.visit(ir_set, ctx=newctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/functools.py", line 889, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 85, in visit_Set
          _compile_set_impl(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 114, in _compile_set_impl
          _compile_set(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/expr.py", line 677, in _compile_set
          relgen.get_set_rvar(ir_set, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 209, in get_set_rvar
          rvars = _get_set_rvar(ir_set, ctx=subctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 422, in _get_set_rvar
          rvars = process_set_as_tuple_indirection(ir_set, stmt, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 2018, in process_set_as_tuple_indirection
          rvar = get_set_rvar(tuple_set, ctx=subctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 209, in get_set_rvar
          rvars = _get_set_rvar(ir_set, ctx=subctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 426, in _get_set_rvar
          rvars = process_set_as_path(ir_set, stmt, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 1128, in process_set_as_path
          srvars = process_set_as_link_property_ref(ir_set, stmt, ctx=ctx)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relgen.py", line 807, in process_set_as_link_property_ref
          source_scope_stmt = relctx.get_scope_stmt(
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/relctx.py", line 1221, in get_scope_stmt
          raise LookupError(f'cannot find scope statement for {path_id}')
      LookupError: cannot find scope statement for (default::User).>orgs[IS default::Org]
      
      The above exception was the direct cause of the following exception:
      
      Traceback (most recent call last):
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler_pool/worker_proc.py", line 55, in worker
          res = meth(*args)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler_pool/worker.py", line 160, in compile
          units, cstate = COMPILER.compile(
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 2277, in compile
          unit_group = self._compile(ctx=ctx, source=source)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1807, in _compile
          return self._try_compile(ctx=ctx, source=source)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1871, in _try_compile
          comp, capabilities = self._compile_dispatch_ql(
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 1781, in _compile_dispatch_ql
          query = self._compile_ql_query(ctx, ql, script_info=script_info)
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/server/compiler/compiler.py", line 672, in _compile_ql_query
          sql_text, argmap = pg_compiler.compile_ir_to_sql(
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/__init__.py", line 152, in compile_ir_to_sql
          qtree = compile_ir_to_sql_tree(
        File "/Users/dustinpomerleau/Library/Application Support/edgedb/portable/2.7/lib/python3.10/site-packages/edb/pgsql/compiler/__init__.py", line 135, in compile_ir_to_sql_tree
          raise errors.InternalServerError(*args) from e
      edb.errors.InternalServerError: cannot find scope statement for (default::User).>orgs[IS default::Org]
```


Discussion:
As a workaround, it seems that `select (select User.orgs@roles).role1`  works...

Resolving patch:
diff --git a/edb/ir/pathid.py b/edb/ir/pathid.py
--- a/edb/ir/pathid.py
+++ b/edb/ir/pathid.py
@@ -718,6 +718,8 @@ def _get_prefix(self, size: int) -> PathId:
         result._norm_path = self._norm_path[0:size]
         result._prefix = self._prefix
         result._namespace = self._namespace
+        if rptr := result.rptr():
+            result._is_linkprop = rptr.source_ptr is not None
 
         if size < len(self._path) and self._norm_path[size][2]:  # type: ignore
             # A link property ref has been chopped off.


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
@@ -1354,3 +1354,23 @@ async def test_edgeql_props_modification_01(self):
                     insert Src { l := assert_single(Tgt { @y := "..." }) };
                 '''
             )
+
+    async def test_edgeql_props_tuples_01(self):
+        await self.con.execute(r'''
+            create type Org;
+            create type Foo {
+                create multi link orgs -> Org {
+                    create property roles -> tuple<role1: bool, role2: bool>;
+                }
+            };
+            insert Org;
+            insert Foo { orgs := (select Org {
+                @roles := (role1 := true, role2 := false) }) };
+        ''')
+
+        await self.assert_query_result(
+            '''
+            select Foo.orgs@roles.role1;
+            ''',
+            [True],
+        )