diff --git a/hphp/hack/src/annotated_ast/aast_defs.ml b/hphp/hack/src/annotated_ast/aast_defs.ml index bb0721ec0e076..49406501cc25c 100644 --- a/hphp/hack/src/annotated_ast/aast_defs.ml +++ b/hphp/hack/src/annotated_ast/aast_defs.ml @@ -881,12 +881,16 @@ and ('ex, 'en) call_expr = { (** function *) targs: 'ex targ list; (** explicit type annotations *) - args: ((Ast_defs.param_kind[@transform.opaque]) * ('ex, 'en) expr) list; + args: ('ex, 'en) argument list; (** positional args, plus their calling convention *) unpacked_arg: ('ex, 'en) expr option; (** unpacked arg *) } +and ('ex, 'en) argument = + | Ainout of (pos[@transform.opaque]) * ('ex, 'en) expr + | Anormal of ('ex, 'en) expr + and ('ex, 'en) user_attribute = { ua_name: sid; ua_params: ('ex, 'en) expr list; diff --git a/hphp/hack/src/annotated_ast/aast_utils.ml b/hphp/hack/src/annotated_ast/aast_utils.ml index d8fdf1af82c57..e809981a60977 100644 --- a/hphp/hack/src/annotated_ast/aast_utils.ml +++ b/hphp/hack/src/annotated_ast/aast_utils.ml @@ -89,7 +89,7 @@ let get_return_from_fun e = let get_virtual_expr_from_et et = let get_body_helper e = match e with - | (_, _, Call { args = _ :: (Pnormal, (_, _, Shape fields)) :: _; _ }) -> + | (_, _, Call { args = _ :: Anormal (_, _, Shape fields) :: _; _ }) -> (match find_shape_field "type" fields with | Some (_, e) -> get_return_from_fun e | None -> None) @@ -233,3 +233,18 @@ let get_param_default param = | Param_optional e -> e let get_expr_pos (_, p, _) = p + +let get_argument_pos a = + match a with + | Anormal e -> get_expr_pos e + | Ainout (_, e) -> get_expr_pos e + +let arg_to_expr arg = + match arg with + | Anormal e -> e + | Ainout (_, e) -> e + +let expr_to_arg pk e = + match pk with + | Ast_defs.Pnormal -> Anormal e + | Ast_defs.Pinout p -> Ainout (p, e) diff --git a/hphp/hack/src/annotated_ast/aast_utils.mli b/hphp/hack/src/annotated_ast/aast_utils.mli index 4166927fbc537..e691416a54994 100644 --- a/hphp/hack/src/annotated_ast/aast_utils.mli +++ b/hphp/hack/src/annotated_ast/aast_utils.mli @@ -57,3 +57,13 @@ val get_param_default : ('a, 'b) Aast_defs.fun_param -> ('a, 'b) Aast_defs.expr option val get_expr_pos : ('a, 'b) Aast_defs.expr -> Pos.t + +(* Gets the position of the argument expression (not of the inout, if present) *) +val get_argument_pos : ('a, 'b) Aast_defs.argument -> Pos.t + +(** Convert an argument to an expression, ignoring whether it's inout or not *) +val arg_to_expr : ('a, 'b) Aast_defs.argument -> ('a, 'b) Aast_defs.expr + +(** Convert an an expression to an argument, using the supplied inout *) +val expr_to_arg : + Ast_defs.param_kind -> ('a, 'b) Aast_defs.expr -> ('a, 'b) Aast_defs.argument diff --git a/hphp/hack/src/client/ide_service/code_actions_services/refactors/flip_around_comma.ml b/hphp/hack/src/client/ide_service/code_actions_services/refactors/flip_around_comma.ml index f10dfde5373ef..849e2c15fa53f 100644 --- a/hphp/hack/src/client/ide_service/code_actions_services/refactors/flip_around_comma.ml +++ b/hphp/hack/src/client/ide_service/code_actions_services/refactors/flip_around_comma.ml @@ -161,11 +161,11 @@ let visitor ~(cursor : Pos.t) = args |> List.map ~f: - Ast_defs.( + Aast_defs.( function - | (Pinout inout_pos, expr) -> + | Ainout (inout_pos, expr) -> Pos.merge inout_pos (pos_of_expr expr) - | (Pnormal, expr) -> pos_of_expr expr) + | Anormal expr -> pos_of_expr expr) |> find_in_positions | Aast_defs.ValCollection (_, _, exprs) | Aast_defs.List exprs diff --git a/hphp/hack/src/client/ide_service/code_actions_services/refactors/inline_method/inline_method_find_candidate.ml b/hphp/hack/src/client/ide_service/code_actions_services/refactors/inline_method/inline_method_find_candidate.ml index 49b3591029407..204626adadc4a 100644 --- a/hphp/hack/src/client/ide_service/code_actions_services/refactors/inline_method/inline_method_find_candidate.ml +++ b/hphp/hack/src/client/ide_service/code_actions_services/refactors/inline_method/inline_method_find_candidate.ml @@ -110,8 +110,7 @@ let find_candidate ~(cursor : Pos.t) ~entry ctx : T.candidate option = 1 + Option.value count_opt ~default:0); if Pos.contains call_id_pos cursor then let call_arg_positions = - List.map param_kind_arg_pairs ~f:(fun (_, (_, arg_pos, _)) -> - arg_pos) + List.map param_kind_arg_pairs ~f:Aast_utils.get_argument_pos in call_info := Some diff --git a/hphp/hack/src/client_and_server/autocompleteService.ml b/hphp/hack/src/client_and_server/autocompleteService.ml index bc9cc43630a2f..95faf3fadeb02 100644 --- a/hphp/hack/src/client_and_server/autocompleteService.ml +++ b/hphp/hack/src/client_and_server/autocompleteService.ml @@ -1121,9 +1121,9 @@ let autocomplete_enum_class_label_call env f args = ~f:(fun (arg, arg_ty) -> (* If the argument was wrapped in a hole, remove it *) let arg = - match arg with - | (_, (_, _, Aast.Hole (e, _, _, _))) -> e - | _ -> snd arg + match Aast_utils.arg_to_expr arg with + | (_, _, Aast.Hole (e, _, _, _)) -> e + | e -> e in match (arg, get_node (expand_and_strip_dynamic env arg_ty.fp_type)) with | ( (_, p, Aast.EnumClassLabel (None, n)), @@ -1230,9 +1230,7 @@ let unwrap_holes ((_, _, e_) as e : Tast.expr) : Tast.expr = takes_shape(shape('x' => 123, '|')); *) let autocomplete_shape_literal_in_call - env - (ft : Typing_defs.locl_fun_type) - (args : (Ast_defs.param_kind * Tast.expr) list) : unit = + env (ft : Typing_defs.locl_fun_type) (args : Tast.argument list) : unit = let add_shape_key_result pos key = let ty = Tprim Aast_defs.Tstring in let reason = Typing_reason.witness pos in @@ -1268,7 +1266,9 @@ let autocomplete_shape_literal_in_call | _ -> None in - let args = List.map args ~f:(fun (_, e) -> unwrap_holes e) in + let args = + List.map args ~f:(fun arg -> unwrap_holes (Aast_utils.arg_to_expr arg)) + in List.iter ~f:(fun (arg, expected_ty) -> @@ -1492,7 +1492,9 @@ let autocomplete_enum_case env (expr : Tast.expr) (cases : Tast.case list) = takes_enum(AUTO332); *) let autocomplete_enum_value_in_call env (ft : Typing_defs.locl_fun_type) args : unit = - let args = List.map args ~f:(fun (_, e) -> unwrap_holes e) in + let args = + List.map args ~f:(fun arg -> unwrap_holes (Aast_utils.arg_to_expr arg)) + in List.iter ~f:(fun (arg, expected_ty) -> diff --git a/hphp/hack/src/client_and_server/identifySymbolService.ml b/hphp/hack/src/client_and_server/identifySymbolService.ml index 51e45d96145a0..b1d5356e9b41c 100644 --- a/hphp/hack/src/client_and_server/identifySymbolService.ml +++ b/hphp/hack/src/client_and_server/identifySymbolService.ml @@ -142,12 +142,11 @@ let process_arg_names recv (args : Tast.expr list) : Result_set.t = //^ Hover shows: Parameter: $name *) let process_callee_arg_names - enclosing_class - (recv : Tast.expr) - (args : (Ast_defs.param_kind * Tast.expr) list) : Result_set.t = + enclosing_class (recv : Tast.expr) (args : Tast.argument list) : + Result_set.t = let enclosing_class_name = Option.map ~f:snd enclosing_class in let recv = get_callee enclosing_class_name recv in - process_arg_names recv (List.map ~f:snd args) + process_arg_names recv (List.map ~f:Aast_utils.arg_to_expr args) (* Add parameter names for all arguments at an instantiation site. This enables us to show hover information on arguments. @@ -466,12 +465,12 @@ let visitor = Call { func = (_, _, Class_const (_, (_, methName))); - args = [(_, arg)]; + args = [arg]; _; }) when String.equal methName SN.ExpressionTrees.symbolType -> (* Treat MyVisitor::symbolType(foo<>) as just foo(). *) - self#on_expr env arg + self#on_argument env arg | _ -> self#zero else let expr_ = @@ -498,7 +497,7 @@ let visitor = in let tala = self#on_list self#on_targ env tal in - let ela = self#on_list self#on_expr env (List.map ~f:snd el) in + let ela = self#on_list self#on_argument env el in let arg_names = process_callee_arg_names !class_name e el in let uea = Option.value_map diff --git a/hphp/hack/src/client_and_server/serverInferType.ml b/hphp/hack/src/client_and_server/serverInferType.ml index 1cd4a8fc0b0b9..53f4e7322d290 100644 --- a/hphp/hack/src/client_and_server/serverInferType.ml +++ b/hphp/hack/src/client_and_server/serverInferType.ml @@ -230,7 +230,7 @@ let base_visitor ~human_friendly ~under_dynamic line_char_pairs = match (args, ft_params) with | (arg :: args, fp :: ft_params) -> let { Typing_defs.fp_type; _ } = fp in - let (_, (arg_type, p, expr_)) = arg in + let (arg_type, p, expr_) = Aast_utils.arg_to_expr arg in let fp = match (expr_, Typing_defs.get_node arg_type) with | (Aast.EnumClassLabel (None, label), _) diff --git a/hphp/hack/src/client_and_server/serverUtils.ml b/hphp/hack/src/client_and_server/serverUtils.ml index bfcbfe21688eb..67913ad98e4f8 100644 --- a/hphp/hack/src/client_and_server/serverUtils.ml +++ b/hphp/hack/src/client_and_server/serverUtils.ml @@ -271,7 +271,7 @@ let resugar_invariant_call env (cond : Tast.expr) (then_body : Tast.block) : recv_pos, Id (name_pos, SN.AutoimportedFunctions.invariant) ); targs = []; - args = (Ast_defs.Pnormal, invariant_cond) :: args; + args = Aast_defs.Anormal invariant_cond :: args; unpacked_arg = None; }) ) | _ -> None diff --git a/hphp/hack/src/elab/lift_await.rs b/hphp/hack/src/elab/lift_await.rs index 47e93effdb850..2748206a522d2 100644 --- a/hphp/hack/src/elab/lift_await.rs +++ b/hphp/hack/src/elab/lift_await.rs @@ -182,7 +182,7 @@ fn check_await_usage(expr: &Expr) -> AwaitUsage { }) => { let res = args .iter() - .map(|(_, arg)| check_await_usage(arg)) + .map(|arg| check_await_usage(arg.to_expr_ref())) .fold(check_await_usage(func), combine_con); unpacked_arg .iter() @@ -554,8 +554,8 @@ impl LiftAwait { unpacked_arg, }) => { self.extract_await(func, con, seq, tmps); - for (_, arg) in args { - self.extract_await(arg, con, seq, tmps) + for arg in args { + self.extract_await(arg.to_expr_mut(), con, seq, tmps) } if let Some(unpack) = unpacked_arg { self.extract_await(unpack, con, seq, tmps) diff --git a/hphp/hack/src/elab/pass.rs b/hphp/hack/src/elab/pass.rs index a965f33095319..df8a96830dd88 100644 --- a/hphp/hack/src/elab/pass.rs +++ b/hphp/hack/src/elab/pass.rs @@ -3,7 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. // -// @generated SignedSource<> +// @generated SignedSource<> // // To regenerate this file, run: // hphp/hack/src/oxidized_regen.sh @@ -536,6 +536,22 @@ pub trait Pass: PassClone { Continue(()) } #[inline(always)] + fn on_ty_argument_top_down( + &mut self, + env: &Env, + elem: &mut Argument, + ) -> ControlFlow<()> { + Continue(()) + } + #[inline(always)] + fn on_ty_argument_bottom_up( + &mut self, + env: &Env, + elem: &mut Argument, + ) -> ControlFlow<()> { + Continue(()) + } + #[inline(always)] fn on_ty_user_attribute_top_down( &mut self, env: &Env, @@ -2130,6 +2146,28 @@ impl Pass for Passes { Continue(()) } #[inline(always)] + fn on_ty_argument_top_down( + &mut self, + env: &Env, + elem: &mut Argument, + ) -> ControlFlow<()> { + for pass in &mut self.passes { + pass.on_ty_argument_top_down(env, elem)?; + } + Continue(()) + } + #[inline(always)] + fn on_ty_argument_bottom_up( + &mut self, + env: &Env, + elem: &mut Argument, + ) -> ControlFlow<()> { + for pass in &mut self.passes { + pass.on_ty_argument_bottom_up(env, elem)?; + } + Continue(()) + } + #[inline(always)] fn on_ty_user_attribute_top_down( &mut self, env: &Env, diff --git a/hphp/hack/src/elab/passes/elab_cross_package.rs b/hphp/hack/src/elab/passes/elab_cross_package.rs index 93df220a234c0..53fae516fc1f4 100644 --- a/hphp/hack/src/elab/passes/elab_cross_package.rs +++ b/hphp/hack/src/elab/passes/elab_cross_package.rs @@ -12,9 +12,9 @@ use nast::Expr_; use nast::Fun_; use nast::Id; use nast::Method_; -use nast::ParamKind; use nast::Stmt; use nast::Stmt_; +use oxidized::ast; use oxidized::ast::Pos; use crate::prelude::*; @@ -67,29 +67,21 @@ fn assert_package_is_loaded(pkg: &Expr) -> Stmt { ), targs: vec![], args: vec![ - ( - ParamKind::Pnormal, - Expr( - (), - pos(), - Expr_::Call(Box::new(CallExpr { - func: Expr( - (), - pos(), - Expr_::Id(Box::new(Id( - pos(), - pseudo_functions::PACKAGE_EXISTS.into(), - ))), - ), - targs: vec![], - args: vec![(ParamKind::Pnormal, { pkg.clone() })], - unpacked_arg: None, - })), - ), - ), - (ParamKind::Pnormal, { - Expr((), pos(), Expr_::String(msg.into())) - }), + ast::Argument::Anormal(Expr( + (), + pos(), + Expr_::Call(Box::new(CallExpr { + func: Expr( + (), + pos(), + Expr_::Id(Box::new(Id(pos(), pseudo_functions::PACKAGE_EXISTS.into()))), + ), + targs: vec![], + args: vec![ast::Argument::Anormal(pkg.clone())], + unpacked_arg: None, + })), + )), + ast::Argument::Anormal(Expr((), pos(), Expr_::String(msg.into()))), ], unpacked_arg: None, })), diff --git a/hphp/hack/src/elab/passes/elab_expr_package.rs b/hphp/hack/src/elab/passes/elab_expr_package.rs index 75582ca4e47fd..4722984003187 100644 --- a/hphp/hack/src/elab/passes/elab_expr_package.rs +++ b/hphp/hack/src/elab/passes/elab_expr_package.rs @@ -8,7 +8,7 @@ use nast::CallExpr; use nast::Expr; use nast::Expr_; use nast::Id; -use nast::ParamKind; +use oxidized::ast; use crate::prelude::*; @@ -27,10 +27,11 @@ impl Pass for ElabExprPackagePass { Expr_::mk_id(Id(pos.clone(), pseudo_functions::PACKAGE_EXISTS.into())), ), targs: vec![], - args: vec![( - ParamKind::Pnormal, - Expr::new((), pkg.pos().clone(), Expr_::mk_string(pkg.name().into())), - )], + args: vec![ast::Argument::Anormal(Expr::new( + (), + pkg.pos().clone(), + Expr_::mk_string(pkg.name().into()), + ))], unpacked_arg: None, })); Break(()) @@ -67,7 +68,8 @@ mod tests { args, .. }) if fn_name == pseudo_functions::PACKAGE_EXISTS => { - if let [(ParamKind::Pnormal, Expr(_, _, Expr_::String(fn_param_name)))] = &args[..] + if let [ast::Argument::Anormal(Expr(_, _, Expr_::String(fn_param_name)))] = + &args[..] { fn_param_name == "foo" } else { diff --git a/hphp/hack/src/elab/transform.rs b/hphp/hack/src/elab/transform.rs index 2a4ddd0320d0d..91d0e8c2b4930 100644 --- a/hphp/hack/src/elab/transform.rs +++ b/hphp/hack/src/elab/transform.rs @@ -3,7 +3,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. // -// @generated SignedSource<<6f5e023411c62a93f680149e18b781cf>> +// @generated SignedSource<> // // To regenerate this file, run: // hphp/hack/src/oxidized_regen.sh @@ -1209,6 +1209,27 @@ impl Transform for CallExpr { } } } +impl Transform for Argument { + fn transform(&mut self, env: &Env, pass: &mut (impl Pass + Clone)) { + let mut in_pass = pass.clone(); + if let Break(..) = pass.on_ty_argument_top_down(env, self) { + return; + } + stack_limit::maybe_grow(|| self.traverse(env, pass)); + in_pass.on_ty_argument_bottom_up(env, self); + } + fn traverse(&mut self, env: &Env, pass: &mut (impl Pass + Clone)) { + match self { + Argument::Ainout(ref mut __binding_0, ref mut __binding_1) => { + { + __binding_0.transform(env, &mut pass.clone()) + } + { __binding_1.transform(env, &mut pass.clone()) } + } + Argument::Anormal(ref mut __binding_0) => __binding_0.transform(env, &mut pass.clone()), + } + } +} impl Transform for UserAttribute { fn transform(&mut self, env: &Env, pass: &mut (impl Pass + Clone)) { let mut in_pass = pass.clone(); diff --git a/hphp/hack/src/hackc/compile/closure_convert.rs b/hphp/hack/src/hackc/compile/closure_convert.rs index 3c7127a51eb98..dddb8d5bd981b 100644 --- a/hphp/hack/src/hackc/compile/closure_convert.rs +++ b/hphp/hack/src/hackc/compile/closure_convert.rs @@ -1125,9 +1125,9 @@ impl<'a: 'b, 'b> ClosureVisitor<'a, 'b> { } else { false }; - if let [(pk_c, cexpr), (pk_f, fexpr)] = &mut *x.args { - error::ensure_normal_paramkind(pk_c)?; - error::ensure_normal_paramkind(pk_f)?; + if let [carg, farg] = &mut *x.args { + let cexpr = error::expect_normal_paramkind(carg)?; + let fexpr = error::expect_normal_paramkind(farg)?; let mut res = make_dyn_meth_caller_lambda(pos, cexpr, fexpr, force); res.recurse(scope, self)?; Ok(res) @@ -1140,9 +1140,9 @@ impl<'a: 'b, 'b> ClosureVisitor<'a, 'b> { #[inline(never)] fn visit_meth_caller(&mut self, scope: &mut Scope<'b>, mut x: Box) -> Result { - if let [(pk_cls, Expr(_, pc, cls)), (pk_f, Expr(_, pf, func))] = &mut *x.args { - error::ensure_normal_paramkind(pk_cls)?; - error::ensure_normal_paramkind(pk_f)?; + if let [carg, farg] = &mut *x.args { + let Expr(_, pc, cls) = error::expect_normal_paramkind_mut(carg)?; + let Expr(_, pf, func) = error::expect_normal_paramkind(farg)?; match (&cls, func.as_string()) { (Expr_::ClassConst(cc), Some(_)) if string_utils::is_class(&(cc.1).1) => { let mut cls_const = cls.as_class_const_mut(); @@ -1413,7 +1413,7 @@ fn strip_unsafe_casts(e: &mut Expr_) -> Expr_ { } => { // Select first argument - let Expr(_, _, e) = x.args.swap_remove(0).1; + let Expr(_, _, e) = x.args.swap_remove(0).to_expr(); e_owned = e; } _ => break e_owned, diff --git a/hphp/hack/src/hackc/emitter/emit_expression.rs b/hphp/hack/src/hackc/emitter/emit_expression.rs index e0e3adf26e8d4..80d48f290be88 100644 --- a/hphp/hack/src/hackc/emitter/emit_expression.rs +++ b/hphp/hack/src/hackc/emitter/emit_expression.rs @@ -79,7 +79,6 @@ use oxidized::aast_visitor::Visitor; use oxidized::aast_visitor::VisitorMut; use oxidized::ast; use oxidized::ast_defs; -use oxidized::ast_defs::ParamKind; use oxidized::local_id; use oxidized::pos::Pos; use oxidized_by_ref::typing_defs; @@ -140,7 +139,6 @@ mod inout_locals { use super::Emitter; use super::Env; use super::Local; - use super::ParamKind; pub(super) struct AliasInfo { first_inout: isize, @@ -227,28 +225,45 @@ mod inout_locals { pub(super) fn collect_written_variables<'ast>( env: &Env<'ast>, - args: &'ast [(ParamKind, ast::Expr)], + args: &'ast [ast::Argument], ) -> AliasInfoMap<'ast> { let mut acc = HashMap::default(); args.iter() .enumerate() - .for_each(|(i, (pk, arg))| handle_arg(env, true, i, pk, arg, &mut acc)); + .for_each(|(i, arg)| handle_arg(env, true, i, arg, &mut acc)); acc } + fn handle_arg_expr<'ast>( + env: &Env<'ast>, + i: usize, + e: &'ast ast::Expr, + acc: &mut AliasInfoMap<'ast>, + ) { + // $v + if let Some(Lid(_, (_, id))) = e.2.as_lvar() { + return add_use(id.as_str(), acc); + } + // dive into argument value + aast_visitor::visit( + &mut Visitor(PhantomData), + &mut Ctx { state: acc, env, i }, + e, + ) + .unwrap(); + } + fn handle_arg<'ast>( env: &Env<'ast>, is_top: bool, i: usize, - pk: &ParamKind, - arg: &'ast ast::Expr, + arg: &'ast ast::Argument, acc: &mut AliasInfoMap<'ast>, ) { use ast::Expr; use ast::Expr_; - let Expr(_, _, e) = arg; // inout $v - if let (ParamKind::Pinout(_), Expr_::Lvar(lid)) = (pk, e) { + if let ast::Argument::Ainout(_, Expr(_, _, Expr_::Lvar(lid))) = arg { let Lid(_, lid) = &**lid; if !super::is_local_this(env, lid) { add_use(&lid.1, acc); @@ -260,16 +275,7 @@ mod inout_locals { } } // $v - if let Some(Lid(_, (_, id))) = e.as_lvar() { - return add_use(id.as_str(), acc); - } - // dive into argument value - aast_visitor::visit( - &mut Visitor(PhantomData), - &mut Ctx { state: acc, env, i }, - arg, - ) - .unwrap(); + handle_arg_expr(env, i, arg.to_expr_ref(), acc) } struct Visitor<'r>(PhantomData<&'r ()>); @@ -294,9 +300,9 @@ mod inout_locals { args, unpacked_arg, .. } = &**expr; args.iter() - .for_each(|(pk, arg)| handle_arg(c.env, false, c.i, pk, arg, c.state)); + .for_each(|arg| handle_arg(c.env, false, c.i, arg, c.state)); if let Some(arg) = unpacked_arg.as_ref() { - handle_arg(c.env, false, c.i, &ParamKind::Pnormal, arg, c.state) + handle_arg_expr(c.env, c.i, arg, c.state) } Ok(()) } else { @@ -553,7 +559,7 @@ pub fn emit_expr<'a, 'd>( fn emit_exprs_and_error_on_inout<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, - exprs: &[(ParamKind, ast::Expr)], + exprs: &[ast::Argument], fn_name: &str, ) -> Result { if exprs.is_empty() { @@ -562,9 +568,9 @@ fn emit_exprs_and_error_on_inout<'a, 'd>( Ok(InstrSeq::gather( exprs .iter() - .map(|(pk, expr)| match pk { - ParamKind::Pnormal => emit_expr(e, env, expr), - ParamKind::Pinout(p) => Err(Error::fatal_parse( + .map(|arg| match arg { + ast::Argument::Anormal(expr) => emit_expr(e, env, expr), + ast::Argument::Ainout(p, expr) => Err(Error::fatal_parse( &Pos::merge(p, expr.pos()).map_err(Error::unrecoverable)?, format!( "Unexpected `inout` argument on pseudofunction: `{}`", @@ -1649,15 +1655,15 @@ fn emit_call_isset_expr<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, outer_pos: &Pos, - pk: &ParamKind, - expr: &ast::Expr, + arg: &ast::Argument, ) -> Result { - if pk.is_pinout() { + if arg.is_inout() { return Err(Error::fatal_parse( outer_pos, "`isset` cannot take an argument by `inout`", )); } + let expr = arg.to_expr_ref(); let pos = &expr.1; if let Some((base_expr, opt_elem_expr)) = expr.2.as_array_get() { return Ok(emit_array_get( @@ -1717,14 +1723,14 @@ fn emit_call_isset_exprs<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, pos: &Pos, - exprs: &[(ParamKind, ast::Expr)], + exprs: &[ast::Argument], ) -> Result { match exprs { [] => Err(Error::fatal_parse( pos, "Cannot use isset() without any arguments", )), - [(pk, expr)] => emit_call_isset_expr(e, env, pos, pk, expr), + [arg] => emit_call_isset_expr(e, env, pos, arg), _ => { let its_done = e.label_gen_mut().next_regular(); Ok(InstrSeq::gather(vec![ @@ -1732,9 +1738,9 @@ fn emit_call_isset_exprs<'a, 'd>( exprs .iter() .enumerate() - .map(|(i, (pk, expr))| { + .map(|(i, arg)| { Ok(InstrSeq::gather(vec![ - emit_call_isset_expr(e, env, pos, pk, expr)?, + emit_call_isset_expr(e, env, pos, arg)?, if i < exprs.len() - 1 { InstrSeq::gather(vec![ instr::dup(), @@ -1758,7 +1764,7 @@ fn emit_tag_provenance_here<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, pos: &Pos, - es: &[(ParamKind, ast::Expr)], + es: &[ast::Argument], ) -> Result { let pop = if es.len() == 1 { instr::empty() @@ -1776,7 +1782,7 @@ fn emit_array_mark_legacy<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, pos: &Pos, - es: &[(ParamKind, ast::Expr)], + es: &[ast::Argument], legacy: bool, ) -> Result { let default = if es.len() == 1 { @@ -1801,7 +1807,7 @@ fn emit_idx<'a, 'd>( e: &mut Emitter<'d>, env: &Env<'a>, pos: &Pos, - es: &[(ParamKind, ast::Expr)], + es: &[ast::Argument], ) -> Result { let default = if es.len() == 2 { instr::null() @@ -1822,7 +1828,7 @@ fn emit_call<'a, 'd>( pos: &Pos, expr: &ast::Expr, targs: &[ast::Targ], - args: &[(ParamKind, ast::Expr)], + args: &[ast::Argument], uarg: Option<&ast::Expr>, async_eager_label: Option