示例#1
0
def new_array_set(elements: typing.List[irast.Base], *,
                  ctx: context.ContextLevel) -> irast.Set:

    arr = irast.Array(elements=elements)
    if elements:
        stype = inference.infer_type(arr, env=ctx.env)
        typeref = irtyputils.type_to_typeref(ctx.env.schema, stype)
    else:
        stype = typeref = None
    arr = irast.Array(elements=elements, typeref=typeref)
    return ensure_set(arr, type_override=stype, ctx=ctx)
示例#2
0
文件: setgen.py 项目: mrs45p/edgedb
def new_array_set(
        elements: Sequence[irast.Base], *,
        ctx: context.ContextLevel,
        srcctx: Optional[parsing.ParserContext]=None) -> irast.Set:

    arr = irast.Array(elements=elements)
    if elements:
        stype = inference.infer_type(arr, env=ctx.env)
    else:
        anytype = s_pseudo.Any.create()
        stype = s_types.Array.from_subtypes(ctx.env.schema, [anytype])
        if srcctx is not None:
            ctx.env.type_origins[anytype] = srcctx

    typeref = typegen.type_to_typeref(stype, env=ctx.env)
    arr = irast.Array(elements=elements, typeref=typeref)
    return ensure_set(arr, type_override=stype, ctx=ctx)
示例#3
0
def ql_typeref_to_ir_typeref(
        ql_t: qlast.TypeExpr, *,
        ctx: context.ContextLevel) -> typing.Union[irast.Array, irast.TypeRef]:

    types = _ql_typeexpr_to_ir_typeref(ql_t, ctx=ctx)
    if len(types) > 1:
        return irast.Array(elements=types)
    else:
        return types[0]
示例#4
0
def _cast_array_literal(
        ir_set: irast.Set,
        orig_stype: s_types.Type,
        new_stype: s_types.Type, *,
        srcctx: Optional[parsing.ParserContext],
        ctx: context.ContextLevel) -> irast.Set:

    assert isinstance(ir_set.expr, irast.Array)

    orig_typeref = typegen.type_to_typeref(orig_stype, env=ctx.env)
    new_typeref = typegen.type_to_typeref(new_stype, env=ctx.env)
    direct_cast = _find_cast(orig_stype, new_stype, srcctx=srcctx, ctx=ctx)

    if direct_cast is None:
        if not new_stype.is_array():
            raise errors.QueryError(
                f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
                f'to {new_stype.get_displayname(ctx.env.schema)!r}',
                context=srcctx) from None
        assert isinstance(new_stype, s_types.Array)
        el_type = new_stype.get_subtypes(ctx.env.schema)[0]
        intermediate_stype = orig_stype

    else:
        el_type = new_stype
        ctx.env.schema, intermediate_stype = s_types.Array.from_subtypes(
            ctx.env.schema, [el_type])

    intermediate_typeref = typegen.type_to_typeref(
        intermediate_stype, env=ctx.env)

    casted_els = []
    for el in ir_set.expr.elements:
        el = compile_cast(el, el_type,
                          cardinality_mod=qlast.CardinalityModifier.Required,
                          ctx=ctx, srcctx=srcctx)
        casted_els.append(el)

    new_array = setgen.ensure_set(
        irast.Array(elements=casted_els, typeref=intermediate_typeref),
        ctx=ctx)

    if direct_cast is not None:
        return _cast_to_ir(
            new_array, direct_cast, intermediate_stype, new_stype, ctx=ctx)

    else:
        cast_ir = irast.TypeCast(
            expr=new_array,
            from_type=orig_typeref,
            to_type=new_typeref,
            sql_cast=True,
            sql_expr=False,
        )

    return setgen.ensure_set(cast_ir, ctx=ctx)
示例#5
0
文件: cast.py 项目: xing0713/edgedb
def _cast_array_literal(ir_set: irast.Set, orig_stype: s_types.Type,
                        new_stype: s_types.Type, *,
                        srcctx: parsing.ParserContext,
                        ctx: context.ContextLevel) -> irast.Base:

    orig_typeref = irtyputils.type_to_typeref(ctx.env.schema, orig_stype)
    new_typeref = irtyputils.type_to_typeref(ctx.env.schema, new_stype)

    direct_cast = _find_cast(orig_stype, new_stype, srcctx=srcctx, ctx=ctx)

    if direct_cast is None:
        if not new_stype.is_array():
            raise errors.QueryError(
                f'cannot cast {orig_stype.get_displayname(ctx.env.schema)!r} '
                f'to {new_stype.get_displayname(ctx.env.schema)!r}',
                context=srcctx) from None
        el_type = new_stype.get_subtypes(ctx.env.schema)[0]
    else:
        el_type = new_stype

    casted_els = []
    for el in ir_set.expr.elements:
        el = compile_cast(el, el_type, ctx=ctx, srcctx=srcctx)
        casted_els.append(el)

    new_array = setgen.ensure_set(irast.Array(elements=casted_els,
                                              typeref=orig_typeref),
                                  ctx=ctx)

    if direct_cast is not None:
        return _cast_to_ir(new_array,
                           direct_cast,
                           orig_stype,
                           new_stype,
                           ctx=ctx)

    else:
        cast_ir = irast.TypeCast(
            expr=new_array,
            from_type=orig_typeref,
            to_type=new_typeref,
            sql_cast=True,
        )

    return setgen.ensure_set(cast_ir, ctx=ctx)
示例#6
0
文件: expr.py 项目: yew1eb/edgedb
def compile_TypeCast(expr: qlast.TypeCast, *,
                     ctx: context.ContextLevel) -> irast.Set:
    target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx)
    ir_expr: irast.Base

    if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements
            and irtyputils.is_array(target_typeref)):
        ir_expr = irast.Array()

    elif isinstance(expr.expr, qlast.Parameter):
        pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)

        if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema))
                and not ctx.env.options.func_params):
            raise errors.QueryError(
                'cannot pass tuples as query parameters',
                context=expr.expr.context,
            )

        if (isinstance(pt, s_types.Collection)
                and pt.contains_array_of_tuples(ctx.env.schema)
                and not ctx.env.options.func_params):
            raise errors.QueryError(
                'cannot pass collections with tuple elements'
                ' as query parameters',
                context=expr.expr.context,
            )

        param_name = expr.expr.name
        if expr.cardinality_mod:
            if expr.cardinality_mod == qlast.CardinalityModifier.Optional:
                required = False
            elif expr.cardinality_mod == qlast.CardinalityModifier.Required:
                required = True
            else:
                raise NotImplementedError(
                    f"cardinality modifier {expr.cardinality_mod}")
        else:
            required = True

        if ctx.env.options.json_parameters:
            if param_name.isdecimal():
                raise errors.QueryError(
                    'queries compiled to accept JSON parameters do not '
                    'accept positional parameters',
                    context=expr.expr.context)

            typeref = typegen.type_to_typeref(
                ctx.env.get_track_schema_type('std::json'),
                env=ctx.env,
            )

            param = casts.compile_cast(
                irast.Parameter(
                    typeref=typeref,
                    name=param_name,
                    required=required,
                    context=expr.expr.context,
                ),
                pt,
                srcctx=expr.expr.context,
                ctx=ctx,
            )

        else:
            typeref = typegen.type_to_typeref(pt, env=ctx.env)
            param = setgen.ensure_set(
                irast.Parameter(
                    typeref=typeref,
                    name=param_name,
                    required=required,
                    context=expr.expr.context,
                ),
                ctx=ctx,
            )

        if param_name not in ctx.env.query_parameters:
            if ctx.env.query_parameters:
                first_key: str = next(iter(ctx.env.query_parameters))
                if first_key.isdecimal():
                    if not param_name.isdecimal():
                        raise errors.QueryError(
                            f'cannot combine positional and named parameters '
                            f'in the same query',
                            context=expr.expr.context)
                else:
                    if param_name.isdecimal():
                        raise errors.QueryError(f'expected a named argument',
                                                context=expr.expr.context)
            ctx.env.query_parameters[param_name] = irast.Param(
                name=param_name,
                required=required,
                schema_type=pt,
                ir_type=typeref,
            )
        else:
            param_first_type = ctx.env.query_parameters[param_name].schema_type
            if not param_first_type.explicitly_castable_to(pt, ctx.env.schema):
                raise errors.QueryError(
                    f'cannot cast '
                    f'{param_first_type.get_displayname(ctx.env.schema)} to '
                    f'{pt.get_displayname(ctx.env.schema)}',
                    context=expr.expr.context)

        return param

    else:
        with ctx.new() as subctx:
            # We use "exposed" mode in case this is a type of a cast
            # that wants view shapes, e.g. a std::json cast.  We do
            # this wholesale to support tuple and array casts without
            # having to analyze the target type (which is cumbersome
            # in QL AST).
            subctx.expr_exposed = True
            ir_expr = dispatch.compile(expr.expr, ctx=subctx)

    new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)
    return casts.compile_cast(ir_expr,
                              new_stype,
                              cardinality_mod=expr.cardinality_mod,
                              ctx=ctx,
                              srcctx=expr.expr.context)
示例#7
0
def compile_TypeCast(expr: qlast.TypeCast, *,
                     ctx: context.ContextLevel) -> irast.Set:
    target_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)
    target_typeref = typegen.type_to_typeref(target_stype, env=ctx.env)
    ir_expr: Union[irast.Set, irast.Expr]

    if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements
            and irtyputils.is_array(target_typeref)):
        ir_expr = irast.Array(elements=[], typeref=target_typeref)

    elif isinstance(expr.expr, qlast.Parameter):
        pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)

        if ((pt.is_tuple(ctx.env.schema) or pt.is_anytuple(ctx.env.schema))
                and not ctx.env.options.func_params):
            raise errors.QueryError(
                'cannot pass tuples as query parameters',
                context=expr.expr.context,
            )

        if (isinstance(pt, s_types.Collection)
                and pt.contains_array_of_tuples(ctx.env.schema)
                and not ctx.env.options.func_params):
            raise errors.QueryError(
                'cannot pass collections with tuple elements'
                ' as query parameters',
                context=expr.expr.context,
            )

        param_name = expr.expr.name
        if expr.cardinality_mod:
            if expr.cardinality_mod == qlast.CardinalityModifier.Optional:
                required = False
            elif expr.cardinality_mod == qlast.CardinalityModifier.Required:
                required = True
            else:
                raise NotImplementedError(
                    f"cardinality modifier {expr.cardinality_mod}")
        else:
            required = True

        if ctx.env.options.json_parameters:
            if param_name.isdecimal():
                raise errors.QueryError(
                    'queries compiled to accept JSON parameters do not '
                    'accept positional parameters',
                    context=expr.expr.context)

            typeref = typegen.type_to_typeref(
                ctx.env.get_track_schema_type(sn.QualName('std', 'json')),
                env=ctx.env,
            )

            param = casts.compile_cast(
                irast.Parameter(
                    typeref=typeref,
                    name=param_name,
                    required=required,
                    context=expr.expr.context,
                ),
                pt,
                srcctx=expr.expr.context,
                ctx=ctx,
            )

        else:
            typeref = typegen.type_to_typeref(pt, env=ctx.env)
            param = setgen.ensure_set(
                irast.Parameter(
                    typeref=typeref,
                    name=param_name,
                    required=required,
                    context=expr.expr.context,
                ),
                ctx=ctx,
            )

        if param_name not in ctx.env.query_parameters:
            if ctx.env.query_parameters:
                first_key: str = next(iter(ctx.env.query_parameters))
                if first_key.isdecimal():
                    if not param_name.isdecimal():
                        raise errors.QueryError(
                            f'cannot combine positional and named parameters '
                            f'in the same query',
                            context=expr.expr.context)
                else:
                    if param_name.isdecimal():
                        raise errors.QueryError(f'expected a named argument',
                                                context=expr.expr.context)
            ctx.env.query_parameters[param_name] = irast.Param(
                name=param_name,
                required=required,
                schema_type=pt,
                ir_type=typeref,
            )
        else:
            param_first_type = ctx.env.query_parameters[param_name].schema_type
            if not param_first_type.castable_to(pt, ctx.env.schema):
                raise errors.QueryError(
                    f'cannot cast '
                    f'{param_first_type.get_displayname(ctx.env.schema)} to '
                    f'{pt.get_displayname(ctx.env.schema)}',
                    context=expr.expr.context)

        return param

    else:
        with ctx.new() as subctx:
            if target_stype.contains_json(subctx.env.schema):
                # JSON wants type shapes and acts as an output sink.
                subctx.expr_exposed = True
                subctx.inhibit_implicit_limit = True
                subctx.implicit_id_in_shapes = False
                subctx.implicit_tid_in_shapes = False
                subctx.implicit_tname_in_shapes = False
            ir_expr = dispatch.compile(expr.expr, ctx=subctx)

    return casts.compile_cast(ir_expr,
                              target_stype,
                              cardinality_mod=expr.cardinality_mod,
                              ctx=ctx,
                              srcctx=expr.expr.context)
示例#8
0
def compile_cast(
        ir_expr: Union[irast.Set, irast.Expr],
        new_stype: s_types.Type,
        *,
        srcctx: Optional[parsing.ParserContext],
        ctx: context.ContextLevel,
        cardinality_mod: Optional[qlast.CardinalityModifier] = None
) -> irast.Set:

    if isinstance(ir_expr, irast.EmptySet):
        # For the common case of casting an empty set, we simply
        # generate a new EmptySet node of the requested type.
        return setgen.new_empty_set(
            stype=new_stype,
            alias=ir_expr.path_id.target_name_hint.name,
            ctx=ctx,
            srcctx=ir_expr.context)

    elif irutils.is_untyped_empty_array_expr(ir_expr):
        # Ditto for empty arrays.
        new_typeref = typegen.type_to_typeref(new_stype, ctx.env)
        return setgen.ensure_set(irast.Array(elements=[], typeref=new_typeref),
                                 ctx=ctx)

    ir_set = setgen.ensure_set(ir_expr, ctx=ctx)
    orig_stype = setgen.get_set_type(ir_set, ctx=ctx)

    if (orig_stype == new_stype
            and cardinality_mod is not qlast.CardinalityModifier.Required):
        return ir_set
    elif orig_stype.is_object_type() and new_stype.is_object_type():
        # Object types cannot be cast between themselves,
        # as cast is a _constructor_ operation, and the only
        # valid way to construct an object is to INSERT it.
        raise errors.QueryError(
            f'cannot cast object type '
            f'{orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}, use '
            f'`...[IS {new_stype.get_displayname(ctx.env.schema)}]` instead',
            context=srcctx)

    if isinstance(ir_set.expr, irast.Array):
        return _cast_array_literal(ir_set,
                                   orig_stype,
                                   new_stype,
                                   srcctx=srcctx,
                                   ctx=ctx)

    elif orig_stype.is_tuple(ctx.env.schema):
        return _cast_tuple(ir_set,
                           orig_stype,
                           new_stype,
                           srcctx=srcctx,
                           ctx=ctx)

    elif orig_stype.issubclass(ctx.env.schema, new_stype):
        # The new type is a supertype of the old type,
        # and is always a wider domain, so we simply reassign
        # the stype.
        return _inheritance_cast_to_ir(ir_set,
                                       orig_stype,
                                       new_stype,
                                       cardinality_mod=cardinality_mod,
                                       ctx=ctx)

    elif new_stype.issubclass(ctx.env.schema, orig_stype):
        # The new type is a subtype, so may potentially have
        # a more restrictive domain, generate a cast call.
        return _inheritance_cast_to_ir(ir_set,
                                       orig_stype,
                                       new_stype,
                                       cardinality_mod=cardinality_mod,
                                       ctx=ctx)

    elif orig_stype.is_array():
        return _cast_array(ir_set,
                           orig_stype,
                           new_stype,
                           srcctx=srcctx,
                           ctx=ctx)

    else:
        json_t = ctx.env.get_track_schema_type('std::json')
        if (new_stype.issubclass(ctx.env.schema, json_t)
                and ir_set.path_id.is_objtype_path()):
            # JSON casts of objects are special: we want the full shape
            # and not just an identity.
            with ctx.new() as subctx:
                subctx.implicit_id_in_shapes = False
                subctx.implicit_tid_in_shapes = False
                viewgen.compile_view_shapes(ir_set, ctx=subctx)
        elif (orig_stype.issubclass(ctx.env.schema, json_t)
              and new_stype.is_enum(ctx.env.schema)):
            # Casts from json to enums need some special handling
            # here, where we have access to the enum type. Just turn
            # it into json->str and str->enum.
            str_typ = ctx.env.get_track_schema_type('std::str')
            str_ir = compile_cast(ir_expr, str_typ, srcctx=srcctx, ctx=ctx)
            return compile_cast(str_ir,
                                new_stype,
                                cardinality_mod=cardinality_mod,
                                srcctx=srcctx,
                                ctx=ctx)
        elif (orig_stype.issubclass(ctx.env.schema, json_t)
              and isinstance(new_stype, s_types.Array)
              and not new_stype.get_subtypes(ctx.env.schema)[0].issubclass(
                  ctx.env.schema, json_t)):
            # Turn casts from json->array<T> into json->array<json>
            # and array<json>->array<T>.
            ctx.env.schema, json_array_typ = s_types.Array.from_subtypes(
                ctx.env.schema, [json_t])
            json_array_ir = compile_cast(ir_expr,
                                         json_array_typ,
                                         srcctx=srcctx,
                                         ctx=ctx)
            return compile_cast(json_array_ir,
                                new_stype,
                                cardinality_mod=cardinality_mod,
                                srcctx=srcctx,
                                ctx=ctx)
        elif (orig_stype.issubclass(ctx.env.schema, json_t)
              and isinstance(new_stype, s_types.Tuple)):
            return _cast_json_to_tuple(ir_set,
                                       orig_stype,
                                       new_stype,
                                       srcctx=srcctx,
                                       ctx=ctx)

        return _compile_cast(ir_expr,
                             orig_stype,
                             new_stype,
                             cardinality_mod=cardinality_mod,
                             srcctx=srcctx,
                             ctx=ctx)
示例#9
0
文件: expr.py 项目: willingc/edgedb
def compile_TypeCast(expr: qlast.TypeCast, *,
                     ctx: context.ContextLevel) -> irast.Set:
    target_typeref = typegen.ql_typeexpr_to_ir_typeref(expr.type, ctx=ctx)
    ir_expr: irast.Base

    if (isinstance(expr.expr, qlast.Array) and not expr.expr.elements
            and irtyputils.is_array(target_typeref)):
        ir_expr = irast.Array()

    elif isinstance(expr.expr, qlast.Parameter):
        pt = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)
        param_name = expr.expr.name
        if param_name not in ctx.env.query_parameters:
            if ctx.env.query_parameters:
                first_key: str = next(iter(ctx.env.query_parameters))
                if first_key.isdecimal():
                    if not param_name.isdecimal():
                        raise errors.QueryError(
                            f'cannot combine positional and named parameters '
                            f'in the same query',
                            context=expr.expr.context)
                else:
                    if param_name.isdecimal():
                        raise errors.QueryError(f'expected a named argument',
                                                context=expr.expr.context)
            ctx.env.query_parameters[param_name] = pt
        else:
            param_first_type = ctx.env.query_parameters[param_name]
            if not param_first_type.explicitly_castable_to(pt, ctx.env.schema):
                raise errors.QueryError(
                    f'cannot cast '
                    f'{param_first_type.get_displayname(ctx.env.schema)} to '
                    f'{pt.get_displayname(ctx.env.schema)}',
                    context=expr.expr.context)

        if ctx.env.json_parameters:
            if param_name.isdecimal():
                raise errors.QueryError(
                    'queries compiled to accept JSON parameters do not '
                    'accept positional parameters',
                    context=expr.expr.context)

            json_typeref = irtyputils.type_to_typeref(
                ctx.env.schema, ctx.env.get_track_schema_type('std::json'))

            param = cast.compile_cast(
                irast.Parameter(
                    typeref=json_typeref,
                    name=param_name,
                    context=expr.expr.context,
                ),
                pt,
                srcctx=expr.expr.context,
                ctx=ctx,
            )

        else:
            param = setgen.ensure_set(
                irast.Parameter(
                    typeref=irtyputils.type_to_typeref(ctx.env.schema, pt),
                    name=param_name,
                    context=expr.expr.context,
                ),
                ctx=ctx,
            )

        return param

    else:
        with ctx.new() as subctx:
            # We use "exposed" mode in case this is a type of a cast
            # that wants view shapes, e.g. a std::json cast.  We do
            # this wholesale to support tuple and array casts without
            # having to analyze the target type (which is cumbersome
            # in QL AST).
            subctx.expr_exposed = True
            ir_expr = dispatch.compile(expr.expr, ctx=subctx)

    new_stype = typegen.ql_typeexpr_to_type(expr.type, ctx=ctx)
    return cast.compile_cast(ir_expr,
                             new_stype,
                             ctx=ctx,
                             srcctx=expr.expr.context)
示例#10
0
文件: cast.py 项目: xing0713/edgedb
def compile_cast(ir_expr: irast.Base, new_stype: s_types.Type, *,
                 srcctx: parsing.ParserContext,
                 ctx: context.ContextLevel) -> irast.OperatorCall:

    if isinstance(ir_expr, irast.EmptySet):
        # For the common case of casting an empty set, we simply
        # generate a new EmptySet node of the requested type.
        return setgen.new_empty_set(
            stype=new_stype,
            alias=ir_expr.path_id.target_name_hint.name,
            ctx=ctx,
            srcctx=ir_expr.context)

    elif irutils.is_untyped_empty_array_expr(ir_expr):
        # Ditto for empty arrays.
        new_typeref = irtyputils.type_to_typeref(ctx.env.schema, new_stype)
        return setgen.ensure_set(irast.Array(elements=[], typeref=new_typeref),
                                 ctx=ctx)

    ir_set = setgen.ensure_set(ir_expr, ctx=ctx)
    orig_stype = setgen.get_set_type(ir_set, ctx=ctx)

    if orig_stype == new_stype:
        return ir_set
    elif orig_stype.is_object_type() and new_stype.is_object_type():
        # Object types cannot be cast between themselves,
        # as cast is a _constructor_ operation, and the only
        # valid way to construct an object is to INSERT it.
        raise errors.QueryError(
            f'cannot cast object type '
            f'{orig_stype.get_displayname(ctx.env.schema)!r} '
            f'to {new_stype.get_displayname(ctx.env.schema)!r}, use '
            f'`...[IS {new_stype.get_displayname(ctx.env.schema)}]` instead',
            context=srcctx)

    if isinstance(ir_set.expr, irast.Array):
        return _cast_array_literal(ir_set,
                                   orig_stype,
                                   new_stype,
                                   srcctx=srcctx,
                                   ctx=ctx)

    elif orig_stype.is_tuple():
        return _cast_tuple(ir_set,
                           orig_stype,
                           new_stype,
                           srcctx=srcctx,
                           ctx=ctx)

    elif orig_stype.issubclass(ctx.env.schema, new_stype):
        # The new type is a supertype of the old type,
        # and is always a wider domain, so we simply reassign
        # the stype.
        return _inheritance_cast_to_ir(ir_set, orig_stype, new_stype, ctx=ctx)

    elif new_stype.issubclass(ctx.env.schema, orig_stype):
        # The new type is a subtype, so may potentially have
        # a more restrictive domain, generate a cast call.
        return _inheritance_cast_to_ir(ir_set, orig_stype, new_stype, ctx=ctx)

    elif orig_stype.is_array():
        return _cast_array(ir_set,
                           orig_stype,
                           new_stype,
                           srcctx=srcctx,
                           ctx=ctx)

    else:
        json_t = ctx.env.get_track_schema_object('std::json')

        if (new_stype.issubclass(ctx.env.schema, json_t)
                and ir_set.path_id.is_objtype_path()):
            # JSON casts of objects are special: we want the full shape
            # and not just an identity.
            with ctx.new() as subctx:
                subctx.implicit_id_in_shapes = False
                subctx.implicit_tid_in_shapes = False
                viewgen.compile_view_shapes(ir_set, ctx=subctx)

        return _compile_cast(ir_expr,
                             orig_stype,
                             new_stype,
                             srcctx=srcctx,
                             ctx=ctx)