diff --git a/edb/edgeql/compiler/func.py b/edb/edgeql/compiler/func.py index 066d37572fa0..9cc52c00f6ac 100644 --- a/edb/edgeql/compiler/func.py +++ b/edb/edgeql/compiler/func.py @@ -208,7 +208,7 @@ def compile_FunctionCall( sn.QualName('default', 'foo'), ] ): - inline_func = s_func.compile_function( + inline_func = s_func.compile_function_inline( schema=ctx.env.schema, context=sd.CommandContext( # Probably not correct. Need to store modaliases while compiling @@ -448,8 +448,7 @@ def compile_FunctionCall( ) argument_inliner = ArgumentInliner(inline_args, ctx=ctx) - inline_func_expr = inline_func.irast.expr - res.body = argument_inliner.visit(inline_func_expr) + res.body = argument_inliner.visit(inline_func) res.inline_arg_path_ids = argument_inliner.mapped_args else: res = fcall diff --git a/edb/schema/functions.py b/edb/schema/functions.py index 0df140c2e8d4..908bceea1b3e 100644 --- a/edb/schema/functions.py +++ b/edb/schema/functions.py @@ -2397,21 +2397,13 @@ def compile_function( ) -> s_expr.CompiledExpression: assert language is qlast.Language.EdgeQL - has_inlined_defaults = bool(params.find_named_only(schema)) - - param_anchors = get_params_symtable( - params, - schema, - inlined_defaults=has_inlined_defaults, - ) - compiled = body.compiled( schema, - options=qlcompiler.CompilerOptions( - anchors=param_anchors, + options=get_compiler_options( + schema, + context, func_name=func_name, - func_params=params, - apply_query_rewrites=not context.stdmode, + params=params, track_schema_ref_exprs=track_schema_ref_exprs, ), inlining_context=inlining_context, @@ -2452,3 +2444,93 @@ def compile_function( ) return compiled + + +def compile_function_inline( + schema: s_schema.Schema, + context: sd.CommandContext, + *, + body: s_expr.Expression, + func_name: sn.QualName, + params: FuncParameterList, + language: qlast.Language, + return_type: s_types.Type, + return_typemod: ft.TypeModifier, + track_schema_ref_exprs: bool=False, + inlining_context: Optional[qlcontext.ContextLevel] = None, +) -> irast.Set: + """Compile a function body to be inlined.""" + assert language is qlast.Language.EdgeQL + + from edb.edgeql.compiler import dispatch + from edb.edgeql.compiler import inference + from edb.edgeql.compiler import pathctx + from edb.edgeql.compiler import setgen + from edb.edgeql.compiler import stmtctx + + ctx = stmtctx.init_context( + schema=schema, + options=get_compiler_options( + schema, + context, + func_name=func_name, + params=params, + track_schema_ref_exprs=track_schema_ref_exprs, + ), + inlining_context=inlining_context, + ) + + ql_expr = body.parse() + + # Add implicit limit if present + if ctx.implicit_limit: + ql_expr = qlast.SelectQuery(result=ql_expr, implicit=True) + ql_expr.limit = qlast.Constant.integer(ctx.implicit_limit) + + ir_set: irast.Set = dispatch.compile(ql_expr, ctx=ctx) + + # Copy schema back to inlining context + if inlining_context: + inlining_context.env.schema = ctx.env.schema + + # Create scoped set if necessary + if pathctx.get_set_scope(ir_set, ctx=ctx) is None: + ir_set = setgen.scoped_set(ir_set, ctx=ctx) + + # Infer cardinality, multiplicity, and volatility + inf_ctx = inference.make_ctx(env=ctx.env) + inference.infer_cardinality( + ir_set, scope_tree=ctx.path_scope, ctx=inf_ctx + ) + inference.infer_multiplicity( + ir_set, scope_tree=ctx.path_scope, ctx=inf_ctx + ) + inference.infer_volatility(ir_set, env=ctx.env) + + return ir_set + + +def get_compiler_options( + schema: s_schema.Schema, + context: sd.CommandContext, + *, + func_name: sn.QualName, + params: FuncParameterList, + track_schema_ref_exprs: bool, +) -> qlcompiler.CompilerOptions: + + has_inlined_defaults = bool(params.find_named_only(schema)) + + param_anchors = get_params_symtable( + params, + schema, + inlined_defaults=has_inlined_defaults, + ) + + return qlcompiler.CompilerOptions( + anchors=param_anchors, + func_name=func_name, + func_params=params, + apply_query_rewrites=not context.stdmode, + track_schema_ref_exprs=track_schema_ref_exprs, + )