We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Drop support for type union operator for scalars.
At the moment it's possible to apply type union operator to scalars, like `int64 | bigint`. This functions less intuitively than the same operation for object types.
```
edgedb> select 5 is int64;
{true}
edgedb> select 5 is (int64 | bigint);
{false}
edgedb> select (introspect (int64 | float32).name);
{'std::float64'}
```
The issue is that what the operation seems to do is answer the question of "what type would be the result set if you try to UNION values of these two disparate types?"

For object types, all objects are fundamentally related and therefore compatible enough to combine into a single set. The union type may not have all the links and properties directly accessible, but the underlying objects are of their specific types and remain unchanged. In practice it can meaningfully be used to denote a link which can validly take otherwise mostly unrelated object types (say `link attachment -> File | Link | Receipt`).

For scalar types we _cast_ the values, changing them, in order to produce a homogeneous set. So all values in the resulting set are strictly of a specific scalar type without any connection to their "former" type. This makes finding practical usage for scalar type unions much harder.

In addition to the above, we might want to introduce discriminated unions of scalars and the way the current `|` works with scalars could be counter-productive to that.

For all of the above reasons we can restrict `|` and `&` to only work for object types and potentially relax this in the future as the need arises.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `edb/edgeql/compiler/typegen.py`
Content:
```
1 #
2 # This source file is part of the EdgeDB open source project.
3 #
4 # Copyright 2008-present MagicStack Inc. and the EdgeDB authors.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #     http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 
19 
20 """EdgeQL compiler type-related helpers."""
21 
22 
23 from __future__ import annotations
24 
25 from typing import *
26 
27 from edb import errors
28 
29 from edb.ir import ast as irast
30 from edb.ir import typeutils as irtyputils
31 from edb.ir import utils as irutils
32 
33 from edb.schema import abc as s_abc
34 from edb.schema import pointers as s_pointers
35 from edb.schema import types as s_types
36 from edb.schema import utils as s_utils
37 
38 from edb.edgeql import ast as qlast
39 
40 from . import context
41 from . import dispatch
42 from . import schemactx
43 from . import setgen
44 
45 
46 def type_to_ql_typeref(
47     t: s_types.Type,
48     *,
49     _name: Optional[str] = None,
50     ctx: context.ContextLevel,
51 ) -> qlast.TypeExpr:
52     return s_utils.typeref_to_ast(
53         ctx.env.schema,
54         t,
55         disambiguate_std='std' in ctx.modaliases,
56     )
57 
58 
59 def ql_typeexpr_to_ir_typeref(
60         ql_t: qlast.TypeExpr, *,
61         ctx: context.ContextLevel) -> irast.TypeRef:
62 
63     stype = ql_typeexpr_to_type(ql_t, ctx=ctx)
64     return irtyputils.type_to_typeref(
65         ctx.env.schema, stype, cache=ctx.env.type_ref_cache
66     )
67 
68 
69 def ql_typeexpr_to_type(
70         ql_t: qlast.TypeExpr, *,
71         ctx: context.ContextLevel) -> s_types.Type:
72 
73     types = _ql_typeexpr_to_type(ql_t, ctx=ctx)
74     if len(types) > 1:
75         return schemactx.get_union_type(types, ctx=ctx)
76     else:
77         return types[0]
78 
79 
80 def _ql_typeexpr_to_type(
81         ql_t: qlast.TypeExpr, *,
82         ctx: context.ContextLevel) -> List[s_types.Type]:
83 
84     if isinstance(ql_t, qlast.TypeOf):
85         with ctx.new() as subctx:
86             # Use an empty scope tree, to avoid polluting things pointlessly
87             subctx.path_scope = irast.ScopeTreeNode()
88             ir_set = dispatch.compile(ql_t.expr, ctx=subctx)
89             stype = setgen.get_set_type(ir_set, ctx=subctx)
90 
91         return [stype]
92 
93     elif isinstance(ql_t, qlast.TypeOp):
94         if ql_t.op == '|':
95             return (_ql_typeexpr_to_type(ql_t.left, ctx=ctx) +
96                     _ql_typeexpr_to_type(ql_t.right, ctx=ctx))
97 
98         raise errors.UnsupportedFeatureError(
99             f'type operator {ql_t.op!r} is not implemented',
100             context=ql_t.context)
101 
102     elif isinstance(ql_t, qlast.TypeName):
103         return [_ql_typename_to_type(ql_t, ctx=ctx)]
104 
105     else:
106         raise errors.EdgeQLSyntaxError("Unexpected type expression",
107                                        context=ql_t.context)
108 
109 
110 def _ql_typename_to_type(
111         ql_t: qlast.TypeName, *,
112         ctx: context.ContextLevel) -> s_types.Type:
113     if ql_t.subtypes:
114         assert isinstance(ql_t.maintype, qlast.ObjectRef)
115         coll = s_types.Collection.get_class(ql_t.maintype.name)
116         ct: s_types.Type
117 
118         if issubclass(coll, s_abc.Tuple):
119             t_subtypes = {}
120             named = False
121             for si, st in enumerate(ql_t.subtypes):
122                 if st.name:
123                     named = True
124                     type_name = st.name
125                 else:
126                     type_name = str(si)
127 
128                 t_subtypes[type_name] = ql_typeexpr_to_type(st, ctx=ctx)
129 
130             ctx.env.schema, ct = coll.from_subtypes(
131                 ctx.env.schema, t_subtypes, {'named': named})
132             return ct
133         else:
134             a_subtypes = []
135             for st in ql_t.subtypes:
136                 a_subtypes.append(ql_typeexpr_to_type(st, ctx=ctx))
137 
138             ctx.env.schema, ct = coll.from_subtypes(ctx.env.schema, a_subtypes)
139             return ct
140     else:
141         return schemactx.get_schema_type(ql_t.maintype, ctx=ctx)
142 
143 
144 @overload
145 def ptrcls_from_ptrref(  # NoQA: F811
146     ptrref: irast.PointerRef, *,
147     ctx: context.ContextLevel,
148 ) -> s_pointers.Pointer:
149     ...
150 
151 
152 @overload
153 def ptrcls_from_ptrref(  # NoQA: F811
154     ptrref: irast.TupleIndirectionPointerRef, *,
155     ctx: context.ContextLevel,
156 ) -> irast.TupleIndirectionLink:
157     ...
158 
159 
160 @overload
161 def ptrcls_from_ptrref(  # NoQA: F811
162     ptrref: irast.TypeIntersectionPointerRef, *,
163     ctx: context.ContextLevel,
164 ) -> irast.TypeIntersectionLink:
165     ...
166 
167 
168 @overload
169 def ptrcls_from_ptrref(  # NoQA: F811
170     ptrref: irast.BasePointerRef, *,
171     ctx: context.ContextLevel,
172 ) -> s_pointers.PointerLike:
173     ...
174 
175 
176 def ptrcls_from_ptrref(  # NoQA: F811
177     ptrref: irast.BasePointerRef, *,
178     ctx: context.ContextLevel,
179 ) -> s_pointers.PointerLike:
180 
181     cached = ctx.env.ptr_ref_cache.get_ptrcls_for_ref(ptrref)
182     if cached is not None:
183         return cached
184 
185     ctx.env.schema, ptr = irtyputils.ptrcls_from_ptrref(
186         ptrref, schema=ctx.env.schema)
187 
188     return ptr
189 
190 
191 def collapse_type_intersection_rptr(
192     ir_set: irast.Set, *,
193     ctx: context.ContextLevel,
194 ) -> Tuple[irast.Set, List[s_pointers.Pointer]]:
195 
196     ind_prefix, ind_ptrs = irutils.collapse_type_intersection(ir_set)
197     if not ind_ptrs:
198         return ir_set, []
199 
200     rptr_specialization: Set[irast.PointerRef] = set()
201     for ind_ptr in ind_ptrs:
202         for ind_ptr in ind_ptrs:
203             if ind_ptr.ptrref.rptr_specialization:
204                 rptr_specialization.update(
205                     ind_ptr.ptrref.rptr_specialization)
206             elif (
207                 not ind_ptr.ptrref.is_empty
208                 and ind_ptr.source.rptr is not None
209             ):
210                 assert isinstance(ind_ptr.source.rptr.ptrref, irast.PointerRef)
211                 rptr_specialization.add(ind_ptr.source.rptr.ptrref)
212 
213     ptrs = [ptrcls_from_ptrref(ptrref, ctx=ctx)
214             for ptrref in rptr_specialization]
215 
216     return ind_prefix, ptrs
217 
218 
219 def type_to_typeref(
220     t: s_types.Type,
221     env: context.Environment,
222 ) -> irast.TypeRef:
223     schema = env.schema
224     cache = env.type_ref_cache
225     expr_type = t.get_expr_type(env.schema)
226     include_descendants = (
227         expr_type is s_types.ExprType.Update
228         or expr_type is s_types.ExprType.Delete
229     )
230     include_ancestors = (
231         expr_type is s_types.ExprType.Insert
232         or expr_type is s_types.ExprType.Update
233         or expr_type is s_types.ExprType.Delete
234     )
235     return irtyputils.type_to_typeref(
236         schema,
237         t,
238         include_descendants=include_descendants,
239         include_ancestors=include_ancestors,
240         cache=cache,
241     )
242
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/edb/edgeql/compiler/typegen.py b/edb/edgeql/compiler/typegen.py
--- a/edb/edgeql/compiler/typegen.py
+++ b/edb/edgeql/compiler/typegen.py
@@ -92,8 +92,27 @@
 
     elif isinstance(ql_t, qlast.TypeOp):
         if ql_t.op == '|':
-            return (_ql_typeexpr_to_type(ql_t.left, ctx=ctx) +
-                    _ql_typeexpr_to_type(ql_t.right, ctx=ctx))
+            # We need to validate that type ops are applied only to
+            # object types. So we check the base case here, when the
+            # left or right operand is a single type, because if it's
+            # a longer list, then we know that it was already composed
+            # of "|" or "&", or it is the result of inference by
+            # "typeof" and is a list of object types anyway.
+            left = _ql_typeexpr_to_type(ql_t.left, ctx=ctx)
+            right = _ql_typeexpr_to_type(ql_t.right, ctx=ctx)
+
+            if len(left) == 1 and not left[0].is_object_type():
+                raise errors.UnsupportedFeatureError(
+                    f'cannot use type operator {ql_t.op!r} with non-object '
+                    f'type {left[0].get_displayname(ctx.env.schema)}',
+                    context=ql_t.left.context)
+            if len(right) == 1 and not right[0].is_object_type():
+                raise errors.UnsupportedFeatureError(
+                    f'cannot use type operator {ql_t.op!r} with non-object '
+                    f'type {right[0].get_displayname(ctx.env.schema)}',
+                    context=ql_t.right.context)
+
+            return left + right
 
         raise errors.UnsupportedFeatureError(
             f'type operator {ql_t.op!r} is not implemented',

{"golden_diff": "diff --git a/edb/edgeql/compiler/typegen.py b/edb/edgeql/compiler/typegen.py\n--- a/edb/edgeql/compiler/typegen.py\n+++ b/edb/edgeql/compiler/typegen.py\n@@ -92,8 +92,27 @@\n \n     elif isinstance(ql_t, qlast.TypeOp):\n         if ql_t.op == '|':\n-            return (_ql_typeexpr_to_type(ql_t.left, ctx=ctx) +\n-                    _ql_typeexpr_to_type(ql_t.right, ctx=ctx))\n+            # We need to validate that type ops are applied only to\n+            # object types. So we check the base case here, when the\n+            # left or right operand is a single type, because if it's\n+            # a longer list, then we know that it was already composed\n+            # of \"|\" or \"&\", or it is the result of inference by\n+            # \"typeof\" and is a list of object types anyway.\n+            left = _ql_typeexpr_to_type(ql_t.left, ctx=ctx)\n+            right = _ql_typeexpr_to_type(ql_t.right, ctx=ctx)\n+\n+            if len(left) == 1 and not left[0].is_object_type():\n+                raise errors.UnsupportedFeatureError(\n+                    f'cannot use type operator {ql_t.op!r} with non-object '\n+                    f'type {left[0].get_displayname(ctx.env.schema)}',\n+                    context=ql_t.left.context)\n+            if len(right) == 1 and not right[0].is_object_type():\n+                raise errors.UnsupportedFeatureError(\n+                    f'cannot use type operator {ql_t.op!r} with non-object '\n+                    f'type {right[0].get_displayname(ctx.env.schema)}',\n+                    context=ql_t.right.context)\n+\n+            return left + right\n \n         raise errors.UnsupportedFeatureError(\n             f'type operator {ql_t.op!r} is not implemented',\n", "issue": "Drop support for type union operator for scalars.\nAt the moment it's possible to apply type union operator to scalars, like `int64 | bigint`. This functions less intuitively than the same operation for object types.\r\n```\r\nedgedb> select 5 is int64;\r\n{true}\r\nedgedb> select 5 is (int64 | bigint);\r\n{false}\r\nedgedb> select (introspect (int64 | float32).name);\r\n{'std::float64'}\r\n```\r\nThe issue is that what the operation seems to do is answer the question of \"what type would be the result set if you try to UNION values of these two disparate types?\"\r\n\r\nFor object types, all objects are fundamentally related and therefore compatible enough to combine into a single set. The union type may not have all the links and properties directly accessible, but the underlying objects are of their specific types and remain unchanged. In practice it can meaningfully be used to denote a link which can validly take otherwise mostly unrelated object types (say `link attachment -> File | Link | Receipt`).\r\n\r\nFor scalar types we _cast_ the values, changing them, in order to produce a homogeneous set. So all values in the resulting set are strictly of a specific scalar type without any connection to their \"former\" type. This makes finding practical usage for scalar type unions much harder.\r\n\r\nIn addition to the above, we might want to introduce discriminated unions of scalars and the way the current `|` works with scalars could be counter-productive to that.\r\n\r\nFor all of the above reasons we can restrict `|` and `&` to only work for object types and potentially relax this in the future as the need arises.\n", "before_files": [{"content": "#\n# This source file is part of the EdgeDB open source project.\n#\n# Copyright 2008-present MagicStack Inc. and the EdgeDB authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\n\"\"\"EdgeQL compiler type-related helpers.\"\"\"\n\n\nfrom __future__ import annotations\n\nfrom typing import *\n\nfrom edb import errors\n\nfrom edb.ir import ast as irast\nfrom edb.ir import typeutils as irtyputils\nfrom edb.ir import utils as irutils\n\nfrom edb.schema import abc as s_abc\nfrom edb.schema import pointers as s_pointers\nfrom edb.schema import types as s_types\nfrom edb.schema import utils as s_utils\n\nfrom edb.edgeql import ast as qlast\n\nfrom . import context\nfrom . import dispatch\nfrom . import schemactx\nfrom . import setgen\n\n\ndef type_to_ql_typeref(\n    t: s_types.Type,\n    *,\n    _name: Optional[str] = None,\n    ctx: context.ContextLevel,\n) -> qlast.TypeExpr:\n    return s_utils.typeref_to_ast(\n        ctx.env.schema,\n        t,\n        disambiguate_std='std' in ctx.modaliases,\n    )\n\n\ndef ql_typeexpr_to_ir_typeref(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> irast.TypeRef:\n\n    stype = ql_typeexpr_to_type(ql_t, ctx=ctx)\n    return irtyputils.type_to_typeref(\n        ctx.env.schema, stype, cache=ctx.env.type_ref_cache\n    )\n\n\ndef ql_typeexpr_to_type(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> s_types.Type:\n\n    types = _ql_typeexpr_to_type(ql_t, ctx=ctx)\n    if len(types) > 1:\n        return schemactx.get_union_type(types, ctx=ctx)\n    else:\n        return types[0]\n\n\ndef _ql_typeexpr_to_type(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> List[s_types.Type]:\n\n    if isinstance(ql_t, qlast.TypeOf):\n        with ctx.new() as subctx:\n            # Use an empty scope tree, to avoid polluting things pointlessly\n            subctx.path_scope = irast.ScopeTreeNode()\n            ir_set = dispatch.compile(ql_t.expr, ctx=subctx)\n            stype = setgen.get_set_type(ir_set, ctx=subctx)\n\n        return [stype]\n\n    elif isinstance(ql_t, qlast.TypeOp):\n        if ql_t.op == '|':\n            return (_ql_typeexpr_to_type(ql_t.left, ctx=ctx) +\n                    _ql_typeexpr_to_type(ql_t.right, ctx=ctx))\n\n        raise errors.UnsupportedFeatureError(\n            f'type operator {ql_t.op!r} is not implemented',\n            context=ql_t.context)\n\n    elif isinstance(ql_t, qlast.TypeName):\n        return [_ql_typename_to_type(ql_t, ctx=ctx)]\n\n    else:\n        raise errors.EdgeQLSyntaxError(\"Unexpected type expression\",\n                                       context=ql_t.context)\n\n\ndef _ql_typename_to_type(\n        ql_t: qlast.TypeName, *,\n        ctx: context.ContextLevel) -> s_types.Type:\n    if ql_t.subtypes:\n        assert isinstance(ql_t.maintype, qlast.ObjectRef)\n        coll = s_types.Collection.get_class(ql_t.maintype.name)\n        ct: s_types.Type\n\n        if issubclass(coll, s_abc.Tuple):\n            t_subtypes = {}\n            named = False\n            for si, st in enumerate(ql_t.subtypes):\n                if st.name:\n                    named = True\n                    type_name = st.name\n                else:\n                    type_name = str(si)\n\n                t_subtypes[type_name] = ql_typeexpr_to_type(st, ctx=ctx)\n\n            ctx.env.schema, ct = coll.from_subtypes(\n                ctx.env.schema, t_subtypes, {'named': named})\n            return ct\n        else:\n            a_subtypes = []\n            for st in ql_t.subtypes:\n                a_subtypes.append(ql_typeexpr_to_type(st, ctx=ctx))\n\n            ctx.env.schema, ct = coll.from_subtypes(ctx.env.schema, a_subtypes)\n            return ct\n    else:\n        return schemactx.get_schema_type(ql_t.maintype, ctx=ctx)\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.PointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.Pointer:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.TupleIndirectionPointerRef, *,\n    ctx: context.ContextLevel,\n) -> irast.TupleIndirectionLink:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.TypeIntersectionPointerRef, *,\n    ctx: context.ContextLevel,\n) -> irast.TypeIntersectionLink:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.BasePointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.PointerLike:\n    ...\n\n\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.BasePointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.PointerLike:\n\n    cached = ctx.env.ptr_ref_cache.get_ptrcls_for_ref(ptrref)\n    if cached is not None:\n        return cached\n\n    ctx.env.schema, ptr = irtyputils.ptrcls_from_ptrref(\n        ptrref, schema=ctx.env.schema)\n\n    return ptr\n\n\ndef collapse_type_intersection_rptr(\n    ir_set: irast.Set, *,\n    ctx: context.ContextLevel,\n) -> Tuple[irast.Set, List[s_pointers.Pointer]]:\n\n    ind_prefix, ind_ptrs = irutils.collapse_type_intersection(ir_set)\n    if not ind_ptrs:\n        return ir_set, []\n\n    rptr_specialization: Set[irast.PointerRef] = set()\n    for ind_ptr in ind_ptrs:\n        for ind_ptr in ind_ptrs:\n            if ind_ptr.ptrref.rptr_specialization:\n                rptr_specialization.update(\n                    ind_ptr.ptrref.rptr_specialization)\n            elif (\n                not ind_ptr.ptrref.is_empty\n                and ind_ptr.source.rptr is not None\n            ):\n                assert isinstance(ind_ptr.source.rptr.ptrref, irast.PointerRef)\n                rptr_specialization.add(ind_ptr.source.rptr.ptrref)\n\n    ptrs = [ptrcls_from_ptrref(ptrref, ctx=ctx)\n            for ptrref in rptr_specialization]\n\n    return ind_prefix, ptrs\n\n\ndef type_to_typeref(\n    t: s_types.Type,\n    env: context.Environment,\n) -> irast.TypeRef:\n    schema = env.schema\n    cache = env.type_ref_cache\n    expr_type = t.get_expr_type(env.schema)\n    include_descendants = (\n        expr_type is s_types.ExprType.Update\n        or expr_type is s_types.ExprType.Delete\n    )\n    include_ancestors = (\n        expr_type is s_types.ExprType.Insert\n        or expr_type is s_types.ExprType.Update\n        or expr_type is s_types.ExprType.Delete\n    )\n    return irtyputils.type_to_typeref(\n        schema,\n        t,\n        include_descendants=include_descendants,\n        include_ancestors=include_ancestors,\n        cache=cache,\n    )\n", "path": "edb/edgeql/compiler/typegen.py"}], "after_files": [{"content": "#\n# This source file is part of the EdgeDB open source project.\n#\n# Copyright 2008-present MagicStack Inc. and the EdgeDB authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n\n\"\"\"EdgeQL compiler type-related helpers.\"\"\"\n\n\nfrom __future__ import annotations\n\nfrom typing import *\n\nfrom edb import errors\n\nfrom edb.ir import ast as irast\nfrom edb.ir import typeutils as irtyputils\nfrom edb.ir import utils as irutils\n\nfrom edb.schema import abc as s_abc\nfrom edb.schema import pointers as s_pointers\nfrom edb.schema import types as s_types\nfrom edb.schema import utils as s_utils\n\nfrom edb.edgeql import ast as qlast\n\nfrom . import context\nfrom . import dispatch\nfrom . import schemactx\nfrom . import setgen\n\n\ndef type_to_ql_typeref(\n    t: s_types.Type,\n    *,\n    _name: Optional[str] = None,\n    ctx: context.ContextLevel,\n) -> qlast.TypeExpr:\n    return s_utils.typeref_to_ast(\n        ctx.env.schema,\n        t,\n        disambiguate_std='std' in ctx.modaliases,\n    )\n\n\ndef ql_typeexpr_to_ir_typeref(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> irast.TypeRef:\n\n    stype = ql_typeexpr_to_type(ql_t, ctx=ctx)\n    return irtyputils.type_to_typeref(\n        ctx.env.schema, stype, cache=ctx.env.type_ref_cache\n    )\n\n\ndef ql_typeexpr_to_type(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> s_types.Type:\n\n    types = _ql_typeexpr_to_type(ql_t, ctx=ctx)\n    if len(types) > 1:\n        return schemactx.get_union_type(types, ctx=ctx)\n    else:\n        return types[0]\n\n\ndef _ql_typeexpr_to_type(\n        ql_t: qlast.TypeExpr, *,\n        ctx: context.ContextLevel) -> List[s_types.Type]:\n\n    if isinstance(ql_t, qlast.TypeOf):\n        with ctx.new() as subctx:\n            # Use an empty scope tree, to avoid polluting things pointlessly\n            subctx.path_scope = irast.ScopeTreeNode()\n            ir_set = dispatch.compile(ql_t.expr, ctx=subctx)\n            stype = setgen.get_set_type(ir_set, ctx=subctx)\n\n        return [stype]\n\n    elif isinstance(ql_t, qlast.TypeOp):\n        if ql_t.op == '|':\n            # We need to validate that type ops are applied only to\n            # object types. So we check the base case here, when the\n            # left or right operand is a single type, because if it's\n            # a longer list, then we know that it was already composed\n            # of \"|\" or \"&\", or it is the result of inference by\n            # \"typeof\" and is a list of object types anyway.\n            left = _ql_typeexpr_to_type(ql_t.left, ctx=ctx)\n            right = _ql_typeexpr_to_type(ql_t.right, ctx=ctx)\n\n            if len(left) == 1 and not left[0].is_object_type():\n                raise errors.UnsupportedFeatureError(\n                    f'cannot use type operator {ql_t.op!r} with non-object '\n                    f'type {left[0].get_displayname(ctx.env.schema)}',\n                    context=ql_t.left.context)\n            if len(right) == 1 and not right[0].is_object_type():\n                raise errors.UnsupportedFeatureError(\n                    f'cannot use type operator {ql_t.op!r} with non-object '\n                    f'type {right[0].get_displayname(ctx.env.schema)}',\n                    context=ql_t.right.context)\n\n            return left + right\n\n        raise errors.UnsupportedFeatureError(\n            f'type operator {ql_t.op!r} is not implemented',\n            context=ql_t.context)\n\n    elif isinstance(ql_t, qlast.TypeName):\n        return [_ql_typename_to_type(ql_t, ctx=ctx)]\n\n    else:\n        raise errors.EdgeQLSyntaxError(\"Unexpected type expression\",\n                                       context=ql_t.context)\n\n\ndef _ql_typename_to_type(\n        ql_t: qlast.TypeName, *,\n        ctx: context.ContextLevel) -> s_types.Type:\n    if ql_t.subtypes:\n        assert isinstance(ql_t.maintype, qlast.ObjectRef)\n        coll = s_types.Collection.get_class(ql_t.maintype.name)\n        ct: s_types.Type\n\n        if issubclass(coll, s_abc.Tuple):\n            t_subtypes = {}\n            named = False\n            for si, st in enumerate(ql_t.subtypes):\n                if st.name:\n                    named = True\n                    type_name = st.name\n                else:\n                    type_name = str(si)\n\n                t_subtypes[type_name] = ql_typeexpr_to_type(st, ctx=ctx)\n\n            ctx.env.schema, ct = coll.from_subtypes(\n                ctx.env.schema, t_subtypes, {'named': named})\n            return ct\n        else:\n            a_subtypes = []\n            for st in ql_t.subtypes:\n                a_subtypes.append(ql_typeexpr_to_type(st, ctx=ctx))\n\n            ctx.env.schema, ct = coll.from_subtypes(ctx.env.schema, a_subtypes)\n            return ct\n    else:\n        return schemactx.get_schema_type(ql_t.maintype, ctx=ctx)\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.PointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.Pointer:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.TupleIndirectionPointerRef, *,\n    ctx: context.ContextLevel,\n) -> irast.TupleIndirectionLink:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.TypeIntersectionPointerRef, *,\n    ctx: context.ContextLevel,\n) -> irast.TypeIntersectionLink:\n    ...\n\n\n@overload\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.BasePointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.PointerLike:\n    ...\n\n\ndef ptrcls_from_ptrref(  # NoQA: F811\n    ptrref: irast.BasePointerRef, *,\n    ctx: context.ContextLevel,\n) -> s_pointers.PointerLike:\n\n    cached = ctx.env.ptr_ref_cache.get_ptrcls_for_ref(ptrref)\n    if cached is not None:\n        return cached\n\n    ctx.env.schema, ptr = irtyputils.ptrcls_from_ptrref(\n        ptrref, schema=ctx.env.schema)\n\n    return ptr\n\n\ndef collapse_type_intersection_rptr(\n    ir_set: irast.Set, *,\n    ctx: context.ContextLevel,\n) -> Tuple[irast.Set, List[s_pointers.Pointer]]:\n\n    ind_prefix, ind_ptrs = irutils.collapse_type_intersection(ir_set)\n    if not ind_ptrs:\n        return ir_set, []\n\n    rptr_specialization: Set[irast.PointerRef] = set()\n    for ind_ptr in ind_ptrs:\n        for ind_ptr in ind_ptrs:\n            if ind_ptr.ptrref.rptr_specialization:\n                rptr_specialization.update(\n                    ind_ptr.ptrref.rptr_specialization)\n            elif (\n                not ind_ptr.ptrref.is_empty\n                and ind_ptr.source.rptr is not None\n            ):\n                assert isinstance(ind_ptr.source.rptr.ptrref, irast.PointerRef)\n                rptr_specialization.add(ind_ptr.source.rptr.ptrref)\n\n    ptrs = [ptrcls_from_ptrref(ptrref, ctx=ctx)\n            for ptrref in rptr_specialization]\n\n    return ind_prefix, ptrs\n\n\ndef type_to_typeref(\n    t: s_types.Type,\n    env: context.Environment,\n) -> irast.TypeRef:\n    schema = env.schema\n    cache = env.type_ref_cache\n    expr_type = t.get_expr_type(env.schema)\n    include_descendants = (\n        expr_type is s_types.ExprType.Update\n        or expr_type is s_types.ExprType.Delete\n    )\n    include_ancestors = (\n        expr_type is s_types.ExprType.Insert\n        or expr_type is s_types.ExprType.Update\n        or expr_type is s_types.ExprType.Delete\n    )\n    return irtyputils.type_to_typeref(\n        schema,\n        t,\n        include_descendants=include_descendants,\n        include_ancestors=include_ancestors,\n        cache=cache,\n    )\n", "path": "edb/edgeql/compiler/typegen.py"}]}