Repository: edgedb/edgedb

Issue:
ISE: AssertionError
The query is obviously wrong but it should fail with a proper error:

```
SELECT schema::ObjectType {
      name,
      is_abstract: {
        name,
      } ORDER BY @index ASC,
} FILTER .name = 'sys::Role';
```

Currently fails with 

```
ERROR: InternalServerError:
  Hint: This is most likely a bug in EdgeDB. Please consider opening an issue ticket at https://github.com/edgedb/edgedb/issues/new?template=bug_report.md
  Server traceback:
      Traceback (most recent call last):
        File "/Users/yury/dev/edge/edgedb/edb/server/procpool/worker.py", line 75, in worker
          res = await meth(*args)
        File "/Users/yury/dev/edge/edgedb/edb/server/compiler/compiler.py", line 1795, in compile_eql_tokens
          return self._compile(ctx=ctx, tokens=eql_tokens)
        File "/Users/yury/dev/edge/edgedb/edb/server/compiler/compiler.py", line 1429, in _compile
          comp: dbstate.BaseQuery = self._compile_dispatch_ql(ctx, stmt)
        File "/Users/yury/dev/edge/edgedb/edb/server/compiler/compiler.py", line 1392, in _compile_dispatch_ql
          return self._compile_ql_query(ctx, ql)
        File "/Users/yury/dev/edge/edgedb/edb/server/compiler/compiler.py", line 592, in _compile_ql_query
          ir = qlcompiler.compile_ast_to_ir(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/__init__.py", line 175, in wrapper
          return func(*args, **kwargs)
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/__init__.py", line 223, in compile_ast_to_ir
          ir_set = dispatch_mod.compile(tree, ctx=ctx)
        File "/opt/local/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/functools.py", line 874, in wrapper
          return dispatch(args[0].__class__)(*args, **kw)
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/stmt.py", line 84, in compile_SelectQuery
          stmt.result = compile_result_clause(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/stmt.py", line 1017, in compile_result_clause
          ir_result = compile_query_subject(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/stmt.py", line 1097, in compile_query_subject
          view_scls = viewgen.process_view(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/viewgen.py", line 86, in process_view
          view_scls = _process_view(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/viewgen.py", line 173, in _process_view
          pointer = _normalize_view_ptr_expr(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/viewgen.py", line 549, in _normalize_view_ptr_expr
          ptr_target = _process_view(
        File "/Users/yury/dev/edge/edgedb/edb/edgeql/compiler/viewgen.py", line 160, in _process_view
          assert isinstance(view_scls, s_objtypes.ObjectType)
      AssertionError
```


Discussion:

Resolving patch:
diff --git a/edb/edgeql/compiler/stmt.py b/edb/edgeql/compiler/stmt.py
--- a/edb/edgeql/compiler/stmt.py
+++ b/edb/edgeql/compiler/stmt.py
@@ -27,6 +27,7 @@
 
 from collections import defaultdict
 from edb import errors
+from edb.common import context as pctx
 
 from edb.ir import ast as irast
 from edb.ir import typeutils
@@ -825,7 +826,8 @@ def compile_Shape(
     if not isinstance(expr_stype, s_objtypes.ObjectType):
         raise errors.QueryError(
             f'shapes cannot be applied to '
-            f'{expr_stype.get_verbosename(ctx.env.schema)}'
+            f'{expr_stype.get_verbosename(ctx.env.schema)}',
+            context=shape.context,
         )
     view_type = viewgen.process_view(
         stype=expr_stype, path_id=expr.path_id,
@@ -1038,7 +1040,8 @@ def compile_result_clause(
             result_alias=result_alias,
             view_scls=view_scls,
             compile_views=ctx.stmt is ctx.toplevel_stmt,
-            ctx=sctx)
+            ctx=sctx,
+            parser_context=result.context)
 
         ctx.partial_path_prefix = ir_result
 
@@ -1056,6 +1059,7 @@ def compile_query_subject(
         is_insert: bool=False,
         is_update: bool=False,
         is_delete: bool=False,
+        parser_context: Optional[pctx.ParserContext]=None,
         ctx: context.ContextLevel) -> irast.Set:
 
     expr_stype = setgen.get_set_type(expr, ctx=ctx)
@@ -1110,7 +1114,8 @@ def compile_query_subject(
         if not isinstance(expr_stype, s_objtypes.ObjectType):
             raise errors.QueryError(
                 f'shapes cannot be applied to '
-                f'{expr_stype.get_verbosename(ctx.env.schema)}'
+                f'{expr_stype.get_verbosename(ctx.env.schema)}',
+                context=parser_context,
             )
 
         view_scls = viewgen.process_view(
diff --git a/edb/edgeql/compiler/viewgen.py b/edb/edgeql/compiler/viewgen.py
--- a/edb/edgeql/compiler/viewgen.py
+++ b/edb/edgeql/compiler/viewgen.py
@@ -34,6 +34,7 @@
 from edb.schema import links as s_links
 from edb.schema import name as sn
 from edb.schema import objtypes as s_objtypes
+from edb.schema import objects as s_objects
 from edb.schema import pointers as s_pointers
 from edb.schema import types as s_types
 
@@ -157,7 +158,7 @@ def _process_view(
         derived_name=view_name,
         ctx=ctx,
     )
-    assert isinstance(view_scls, s_objtypes.ObjectType)
+    assert isinstance(view_scls, s_objtypes.ObjectType), view_scls
     is_mutation = is_insert or is_update
     is_defining_shape = ctx.expr_exposed or is_mutation
 
@@ -359,7 +360,7 @@ def _normalize_view_ptr_expr(
     # class, which is equivalent to Expr[IS Type].
     plen = len(steps)
     ptrsource: s_sources.Source = view_scls
-    qlexpr = None
+    qlexpr: Optional[qlast.Expr] = None
     target_typexpr = None
     source: qlast.Base
     base_ptrcls_is_alias = False
@@ -412,7 +413,7 @@ def _normalize_view_ptr_expr(
     assert isinstance(lexpr, qlast.Ptr)
     ptrname = lexpr.ptr.name
 
-    compexpr = shape_el.compexpr
+    compexpr: Optional[qlast.Expr] = shape_el.compexpr
     if compexpr is None and is_insert and shape_el.elements:
         # Short shape form in INSERT, e.g
         #     INSERT Foo { bar: Spam { name := 'name' }}
@@ -420,6 +421,8 @@ def _normalize_view_ptr_expr(
         raise errors.EdgeQLSyntaxError(
             "unexpected ':'", context=steps[-1].context)
 
+    ptrcls: Optional[s_pointers.Pointer]
+
     if compexpr is None:
         ptrcls = setgen.resolve_ptr(ptrsource, ptrname, ctx=ctx)
         if is_polymorphic:
@@ -460,6 +463,7 @@ def _normalize_view_ptr_expr(
                 ])
 
             qlexpr = astutils.ensure_qlstmt(qlexpr)
+            assert isinstance(qlexpr, qlast.SelectQuery)
             qlexpr.where = shape_el.where
             qlexpr.orderby = shape_el.orderby
 
@@ -479,18 +483,21 @@ def _normalize_view_ptr_expr(
                 )
 
         if target_typexpr is not None:
+            assert isinstance(target_typexpr, qlast.TypeName)
             intersector_type = schemactx.get_schema_type(
                 target_typexpr.maintype, ctx=ctx)
 
             int_result = schemactx.apply_intersection(
-                ptrcls.get_target(ctx.env.schema),
+                ptrcls.get_target(ctx.env.schema),  # type: ignore
                 intersector_type,
                 ctx=ctx,
             )
 
             ptr_target = int_result.stype
         else:
-            ptr_target = ptrcls.get_target(ctx.env.schema)
+            _ptr_target = ptrcls.get_target(ctx.env.schema)
+            assert _ptr_target
+            ptr_target = _ptr_target
 
         if base_ptrcls in ctx.pending_cardinality:
             # We do not know the parent's pointer cardinality yet.
@@ -527,6 +534,13 @@ def _normalize_view_ptr_expr(
             ctx.path_scope.attach_path(sub_path_id,
                                        context=shape_el.context)
 
+            if not isinstance(ptr_target, s_objtypes.ObjectType):
+                raise errors.QueryError(
+                    f'shapes cannot be applied to '
+                    f'{ptr_target.get_verbosename(ctx.env.schema)}',
+                    context=shape_el.context,
+                )
+
             if is_update:
                 for subel in shape_el.elements or []:
                     is_prop = (
@@ -765,7 +779,8 @@ def _normalize_view_ptr_expr(
             derived_name_quals=[src_scls.get_name(ctx.env.schema)],
             ctx=ctx)
 
-        existing = ctx.env.schema.get(derived_name, None)
+        existing: Optional[s_objects.Object] = (
+            ctx.env.schema.get(derived_name, None))
         if existing is not None:
             assert isinstance(existing, s_pointers.Pointer)
             existing_target = existing.get_target(ctx.env.schema)
@@ -889,7 +904,7 @@ def _normalize_view_ptr_expr(
                     f'{ptrcls.get_verbosename(ctx.env.schema)}: '
                     f'it is defined as {base_cardinality.as_ptr_qual()!r} '
                     f'in the base {base_src_name}',
-                    context=compexpr.context,
+                    context=compexpr and compexpr.context,
                 )
             # The required flag may be inherited from the base
             specified_required = shape_el.required or base_required
@@ -925,7 +940,7 @@ def _normalize_view_ptr_expr(
         raise errors.QueryError(
             f'cannot update {ptrcls.get_verbosename(ctx.env.schema)}: '
             f'it is declared as read-only',
-            context=compexpr.context,
+            context=compexpr and compexpr.context,
         )
 
     return ptrcls


Test patch:
diff --git a/tests/test_edgeql_select.py b/tests/test_edgeql_select.py
--- a/tests/test_edgeql_select.py
+++ b/tests/test_edgeql_select.py
@@ -6023,3 +6023,15 @@ async def test_edgeql_select_big_set_literal(self):
         """)
 
         assert len(res) == 100
+
+    async def test_edgeql_select_shape_on_scalar(self):
+        with self.assertRaisesRegex(
+            edgedb.QueryError,
+            "shapes cannot be applied to scalar type 'std::str'",
+        ):
+            await self.con.execute("""
+                WITH MODULE test
+                SELECT User {
+                    todo: { name: {bogus} }
+                }
+            """)