Default `disable_unset_class_const` to `true` and remove
[hiphop-php.git] / hphp / hack / src / parser / lowerer / lowerer.rs
blob4a76021246b50bac203ea907fe59302058332cb0
1 // Copyright (c) 2019, Facebook, Inc.
2 // All rights reserved.
3 //
4 // This source code is licensed under the MIT license found in the
5 // LICENSE file in the "hack" directory of this source tree.
7 use crate::{desugar_expression_tree::desugar, modifier};
8 use bstr::{BString, B};
9 use bumpalo::Bump;
10 use escaper::*;
11 use hash::{HashMap, HashSet};
12 use itertools::{Either, Itertools};
13 use lint_rust::LintError;
14 use naming_special_names_rust::{
15     classes as special_classes, literal, special_functions, special_idents,
16     typehints as special_typehints, user_attributes as special_attrs,
18 use ocaml_helper::{int_of_string_opt, parse_int, ParseIntError};
19 use ocamlrep::rc::RcOc;
20 use oxidized::{
21     aast,
22     aast_visitor::{AstParams, Node, Visitor},
23     ast,
24     ast::Expr_ as E_,
25     doc_comment::DocComment,
26     errors::{Error as HHError, Naming, NastCheck},
27     file_info,
28     global_options::GlobalOptions,
29     namespace_env::Env as NamespaceEnv,
30     pos::Pos,
32 use parser_core_types::{
33     indexed_source_text::IndexedSourceText,
34     lexable_token::{LexablePositionedToken, LexableToken},
35     source_text::SourceText,
36     syntax::SyntaxValueWithKind,
37     syntax_by_ref::{
38         positioned_token::{PositionedToken, TokenFactory as PositionedTokenFactory},
39         positioned_value::PositionedValue,
40         syntax::Syntax,
41         syntax_variant_generated::{SyntaxVariant::*, *},
42     },
43     syntax_error, syntax_kind,
44     syntax_trait::SyntaxTrait,
45     token_factory::TokenMutator,
46     token_kind::TokenKind as TK,
48 use regex::bytes::Regex;
49 use stack_limit::StackLimit;
50 use std::{
51     cell::{Ref, RefCell, RefMut},
52     matches, mem,
53     rc::Rc,
54     slice::Iter,
55     str::FromStr,
58 fn unescape_single(s: &str) -> Result<BString, escaper::InvalidString> {
59     Ok(escaper::unescape_single(s)?.into())
62 fn unescape_nowdoc(s: &str) -> Result<BString, escaper::InvalidString> {
63     Ok(escaper::unescape_nowdoc(s)?.into())
66 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
67 pub enum LiftedAwaitKind {
68     LiftedFromStatement,
69     LiftedFromConcurrent,
72 type LiftedAwaitExprs = Vec<(Option<ast::Lid>, ast::Expr)>;
74 #[derive(Debug, Clone)]
75 pub struct LiftedAwaits {
76     pub awaits: LiftedAwaitExprs,
77     lift_kind: LiftedAwaitKind,
80 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
81 pub enum ExprLocation {
82     TopLevel,
83     MemberSelect,
84     InDoubleQuotedString,
85     AsStatement,
86     RightOfAssignment,
87     RightOfAssignmentInUsingStatement,
88     RightOfReturn,
89     UsingStatement,
90     CallReceiver,
93 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
94 pub enum SuspensionKind {
95     SKSync,
96     SKAsync,
99 #[derive(Copy, Clone, Eq, PartialEq)]
100 pub enum TokenOp {
101     Skip,
102     Noop,
103     LeftTrim(usize),
104     RightTrim(usize),
107 #[derive(Debug)]
108 pub struct FunHdr {
109     suspension_kind: SuspensionKind,
110     readonly_this: Option<ast::ReadonlyKind>,
111     name: ast::Sid,
112     constrs: Vec<ast::WhereConstraintHint>,
113     type_parameters: Vec<ast::Tparam>,
114     parameters: Vec<ast::FunParam>,
115     contexts: Option<ast::Contexts>,
116     unsafe_contexts: Option<ast::Contexts>,
117     readonly_return: Option<ast::ReadonlyKind>,
118     return_type: Option<ast::Hint>,
121 impl FunHdr {
122     fn make_empty(env: &Env<'_>) -> Self {
123         Self {
124             suspension_kind: SuspensionKind::SKSync,
125             readonly_this: None,
126             name: ast::Id(env.mk_none_pos(), String::from("<ANONYMOUS>")),
127             constrs: vec![],
128             type_parameters: vec![],
129             parameters: vec![],
130             contexts: None,
131             unsafe_contexts: None,
132             readonly_return: None,
133             return_type: None,
134         }
135     }
138 #[derive(Debug)]
139 pub struct State {
140     // bool represents reification
141     pub cls_generics: HashMap<String, bool>,
142     // fn_generics also used for methods; maps are separate due to shadowing
143     pub fn_generics: HashMap<String, bool>,
144     pub in_static_method: bool,
145     pub parent_maybe_reified: bool,
146     /// This provides a generic mechanism to delay raising parsing errors;
147     /// since we're moving FFP errors away from CST to a stage after lowering
148     /// _and_ want to prioritize errors before lowering, the lowering errors
149     /// must be merely stored when the lowerer runs (until check for FFP runs (on AST)
150     /// and raised _after_ FFP error checking (unless we run the lowerer twice,
151     /// which would be expensive).
152     pub lowpri_errors: Vec<(Pos, String)>,
153     /// hh_errors captures errors after parsing, naming, nast, etc.
154     pub hh_errors: Vec<HHError>,
155     pub lint_errors: Vec<LintError>,
156     pub doc_comments: Vec<Option<DocComment>>,
158     pub local_id_counter: isize,
160     // TODO(hrust): this check is to avoid crash in Ocaml.
161     // Remove it after all Ocaml callers are eliminated.
162     pub exp_recursion_depth: usize,
165 const EXP_RECUSION_LIMIT: usize = 30_000;
167 #[derive(Clone)]
168 pub struct Env<'a> {
169     pub codegen: bool,
170     pub keep_errors: bool,
171     quick_mode: bool,
172     /// Show errors even in quick mode. Does not override keep_errors. Hotfix
173     /// until we can properly set up saved states to surface parse errors during
174     /// typechecking properly.
175     pub show_all_errors: bool,
176     fail_open: bool,
177     file_mode: file_info::Mode,
178     pub top_level_statements: bool, /* Whether we are (still) considering TLSs*/
180     // Cache none pos, lazy_static doesn't allow Rc.
181     pos_none: Pos,
182     pub empty_ns_env: RcOc<NamespaceEnv>,
184     pub saw_yield: bool, /* Information flowing back up */
185     pub lifted_awaits: Option<LiftedAwaits>,
186     pub tmp_var_counter: isize,
188     pub indexed_source_text: &'a IndexedSourceText<'a>,
189     pub parser_options: &'a GlobalOptions,
190     pub stack_limit: Option<&'a StackLimit>,
192     pub token_factory: PositionedTokenFactory<'a>,
193     pub arena: &'a Bump,
195     state: Rc<RefCell<State>>,
198 impl<'a> Env<'a> {
199     pub fn make(
200         codegen: bool,
201         quick_mode: bool,
202         keep_errors: bool,
203         show_all_errors: bool,
204         fail_open: bool,
205         mode: file_info::Mode,
206         indexed_source_text: &'a IndexedSourceText<'a>,
207         parser_options: &'a GlobalOptions,
208         namespace_env: RcOc<NamespaceEnv>,
209         stack_limit: Option<&'a StackLimit>,
210         token_factory: PositionedTokenFactory<'a>,
211         arena: &'a Bump,
212     ) -> Self {
213         Env {
214             codegen,
215             keep_errors,
216             quick_mode,
217             show_all_errors,
218             fail_open,
219             file_mode: mode,
220             top_level_statements: true,
221             saw_yield: false,
222             lifted_awaits: None,
223             tmp_var_counter: 1,
224             indexed_source_text,
225             parser_options,
226             pos_none: Pos::make_none(),
227             empty_ns_env: namespace_env,
228             stack_limit,
229             token_factory,
230             arena,
232             state: Rc::new(RefCell::new(State {
233                 cls_generics: HashMap::default(),
234                 fn_generics: HashMap::default(),
235                 in_static_method: false,
236                 parent_maybe_reified: false,
237                 lowpri_errors: vec![],
238                 doc_comments: vec![],
239                 local_id_counter: 1,
240                 hh_errors: vec![],
241                 lint_errors: vec![],
242                 exp_recursion_depth: 0,
243             })),
244         }
245     }
247     fn file_mode(&self) -> file_info::Mode {
248         self.file_mode
249     }
251     fn should_surface_error(&self) -> bool {
252         (!self.quick_mode || self.show_all_errors) && self.keep_errors
253     }
255     fn is_typechecker(&self) -> bool {
256         !self.codegen
257     }
259     fn codegen(&self) -> bool {
260         self.codegen
261     }
263     fn source_text(&self) -> &SourceText<'a> {
264         self.indexed_source_text.source_text()
265     }
267     fn fail_open(&self) -> bool {
268         self.fail_open
269     }
271     fn cls_generics_mut(&mut self) -> RefMut<'_, HashMap<String, bool>> {
272         RefMut::map(self.state.borrow_mut(), |s| &mut s.cls_generics)
273     }
275     fn fn_generics_mut(&mut self) -> RefMut<'_, HashMap<String, bool>> {
276         RefMut::map(self.state.borrow_mut(), |s| &mut s.fn_generics)
277     }
279     pub fn clear_generics(&mut self) {
280         let mut s = self.state.borrow_mut();
281         s.cls_generics = HashMap::default();
282         s.fn_generics = HashMap::default();
283     }
285     // avoids returning a reference to the env
286     pub fn get_reification(&self, id: &str) -> Option<bool> {
287         let s = self.state.borrow();
288         if let Some(reif) = s.fn_generics.get(id) {
289             Some(*reif)
290         } else {
291             s.cls_generics.get(id).copied()
292         }
293     }
295     fn in_static_method(&mut self) -> RefMut<'_, bool> {
296         RefMut::map(self.state.borrow_mut(), |s| &mut s.in_static_method)
297     }
299     fn parent_maybe_reified(&mut self) -> RefMut<'_, bool> {
300         RefMut::map(self.state.borrow_mut(), |s| &mut s.parent_maybe_reified)
301     }
303     pub fn lowpri_errors(&mut self) -> RefMut<'_, Vec<(Pos, String)>> {
304         RefMut::map(self.state.borrow_mut(), |s| &mut s.lowpri_errors)
305     }
307     pub fn hh_errors(&mut self) -> RefMut<'_, Vec<HHError>> {
308         RefMut::map(self.state.borrow_mut(), |s| &mut s.hh_errors)
309     }
311     pub fn lint_errors(&mut self) -> RefMut<'_, Vec<LintError>> {
312         RefMut::map(self.state.borrow_mut(), |s| &mut s.lint_errors)
313     }
315     fn top_docblock(&self) -> Ref<'_, Option<DocComment>> {
316         Ref::map(self.state.borrow(), |s| {
317             s.doc_comments.last().unwrap_or(&None)
318         })
319     }
321     fn exp_recursion_depth(&self) -> RefMut<'_, usize> {
322         RefMut::map(self.state.borrow_mut(), |s| &mut s.exp_recursion_depth)
323     }
325     fn next_local_id(&self) -> isize {
326         let mut id = RefMut::map(self.state.borrow_mut(), |s| &mut s.local_id_counter);
327         *id += 1;
328         *id
329     }
331     fn push_docblock(&mut self, doc_comment: Option<DocComment>) {
332         RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).push(doc_comment)
333     }
335     fn pop_docblock(&mut self) {
336         RefMut::map(self.state.borrow_mut(), |s| &mut s.doc_comments).pop();
337     }
339     fn make_tmp_var_name(&mut self) -> String {
340         let name = String::from(special_idents::TMP_VAR_PREFIX) + &self.tmp_var_counter.to_string();
341         self.tmp_var_counter += 1;
342         name
343     }
345     fn mk_none_pos(&self) -> Pos {
346         self.pos_none.clone()
347     }
349     fn clone_and_unset_toplevel_if_toplevel<'b, 'c>(
350         e: &'b mut Env<'c>,
351     ) -> impl AsMut<Env<'c>> + 'b {
352         if e.top_level_statements {
353             let mut cloned = e.clone();
354             cloned.top_level_statements = false;
355             Either::Left(cloned)
356         } else {
357             Either::Right(e)
358         }
359     }
361     fn check_stack_limit(&self) {
362         if let Some(limit) = &self.stack_limit {
363             limit.panic_if_exceeded()
364         }
365     }
368 impl<'a> AsMut<Env<'a>> for Env<'a> {
369     fn as_mut(&mut self) -> &mut Env<'a> {
370         self
371     }
374 #[derive(Debug)]
375 pub enum Error {
376     MissingSyntax {
377         expecting: String,
378         pos: Pos,
379         node_name: String,
380         kind: syntax_kind::SyntaxKind,
381     },
382     Failwith(String),
385 type S<'arena> = &'arena Syntax<'arena, PositionedToken<'arena>, PositionedValue<'arena>>;
387 fn p_pos<'a>(node: S<'a>, env: &Env<'_>) -> Pos {
388     node.position_exclusive(env.indexed_source_text)
389         .unwrap_or_else(|| env.mk_none_pos())
392 fn raise_parsing_error<'a>(node: S<'a>, env: &mut Env<'a>, msg: &str) {
393     raise_parsing_error_(Either::Left(node), env, msg)
396 fn raise_parsing_error_pos<'a>(pos: &Pos, env: &mut Env<'a>, msg: &str) {
397     raise_parsing_error_(Either::Right(pos), env, msg)
400 fn raise_parsing_error_<'a>(node_or_pos: Either<S<'a>, &Pos>, env: &mut Env<'a>, msg: &str) {
401     if env.should_surface_error() {
402         let pos = node_or_pos.either(|node| p_pos(node, env), |pos| pos.clone());
403         env.lowpri_errors().push((pos, String::from(msg)))
404     } else if env.codegen() {
405         let pos = node_or_pos.either(
406             |node| {
407                 node.position_exclusive(env.indexed_source_text)
408                     .unwrap_or_else(|| env.mk_none_pos())
409             },
410             |pos| pos.clone(),
411         );
412         env.lowpri_errors().push((pos, String::from(msg)))
413     }
416 fn raise_hh_error(env: &mut Env<'_>, err: HHError) {
417     env.hh_errors().push(err);
420 fn raise_lint_error(env: &mut Env<'_>, err: LintError) {
421     env.lint_errors().push(err);
424 fn failwith<N>(msg: impl Into<String>) -> Result<N, Error> {
425     Err(Error::Failwith(msg.into()))
428 fn text<'a>(node: S<'a>, env: &Env<'_>) -> String {
429     String::from(node.text(env.source_text()))
432 fn text_str<'b, 'a>(node: S<'a>, env: &'b Env<'_>) -> &'b str {
433     node.text(env.source_text())
436 fn lowering_error(env: &mut Env<'_>, pos: &Pos, text: &str, syntax_kind: &str) {
437     if env.is_typechecker() && env.lowpri_errors().is_empty() {
438         raise_parsing_error_pos(
439             pos,
440             env,
441             &syntax_error::lowering_parsing_error(text, syntax_kind),
442         )
443     }
446 fn missing_syntax_<N>(
447     fallback: Option<N>,
448     expecting: &str,
449     node: S<'_>,
450     env: &mut Env<'_>,
451 ) -> Result<N, Error> {
452     let pos = p_pos(node, env);
453     let text = text(node, env);
454     lowering_error(env, &pos, &text, expecting);
455     if let Some(x) = fallback {
456         if env.fail_open() {
457             return Ok(x);
458         }
459     }
460     Err(Error::MissingSyntax {
461         expecting: String::from(expecting),
462         pos: p_pos(node, env),
463         node_name: text,
464         kind: node.kind(),
465     })
468 fn missing_syntax<'a, N>(expecting: &str, node: S<'a>, env: &mut Env<'a>) -> Result<N, Error> {
469     missing_syntax_(None, expecting, node, env)
472 fn mp_optional<'a, F, R>(p: F, node: S<'a>, env: &mut Env<'a>) -> Result<Option<R>, Error>
473 where
474     F: FnOnce(S<'a>, &mut Env<'a>) -> Result<R, Error>,
476     match &node.children {
477         Missing => Ok(None),
478         _ => p(node, env).map(Some),
479     }
482 fn pos_qualified_name<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Sid, Error> {
483     if let QualifiedName(c) = &node.children {
484         if let SyntaxList(l) = &c.parts.children {
485             let p = p_pos(node, env);
486             let mut s = String::with_capacity(node.width());
487             for i in l.iter() {
488                 match &i.children {
489                     ListItem(li) => {
490                         s += text_str(&li.item, env);
491                         s += text_str(&li.separator, env);
492                     }
493                     _ => s += text_str(i, env),
494                 }
495             }
496             return Ok(ast::Id(p, s));
497         }
498     }
499     missing_syntax("qualified name", node, env)
502 fn pos_name<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Sid, Error> {
503     pos_name_(node, env, None)
506 fn lid_from_pos_name<'a>(pos: Pos, name: S<'a>, env: &mut Env<'a>) -> Result<ast::Lid, Error> {
507     let name = pos_name(name, env)?;
508     Ok(ast::Lid::new(pos, name.1))
511 fn lid_from_name<'a>(name: S<'a>, env: &mut Env<'a>) -> Result<ast::Lid, Error> {
512     let name = pos_name(name, env)?;
513     Ok(ast::Lid::new(name.0, name.1))
516 fn p_pstring<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Pstring, Error> {
517     p_pstring_(node, env, None)
520 fn p_pstring_<'a>(
521     node: S<'a>,
522     env: &mut Env<'a>,
523     drop_prefix: Option<char>,
524 ) -> Result<ast::Pstring, Error> {
525     let ast::Id(p, id) = pos_name_(node, env, drop_prefix)?;
526     Ok((p, id))
529 fn drop_prefix(s: &str, prefix: char) -> &str {
530     if !s.is_empty() && s.starts_with(prefix) {
531         &s[1..]
532     } else {
533         s
534     }
537 fn pos_name_<'a>(
538     node: S<'a>,
539     env: &mut Env<'a>,
540     drop_prefix_c: Option<char>,
541 ) -> Result<ast::Sid, Error> {
542     match &node.children {
543         QualifiedName(_) => pos_qualified_name(node, env),
544         SimpleTypeSpecifier(c) => pos_name_(&c.specifier, env, drop_prefix_c),
545         _ => {
546             let mut name = node.text(env.indexed_source_text.source_text());
547             if let Some(prefix) = drop_prefix_c {
548                 name = drop_prefix(name, prefix);
549             }
550             let p = p_pos(node, env);
551             Ok(ast::Id(p, String::from(name)))
552         }
553     }
556 fn mk_str<'a, F>(node: S<'a>, env: &mut Env<'a>, unescaper: F, mut content: &str) -> BString
557 where
558     F: Fn(&str) -> Result<BString, InvalidString>,
560     if let Some('b') = content.chars().next() {
561         content = content.get(1..).unwrap();
562     }
564     let len = content.len();
565     let no_quotes_result = extract_unquoted_string(content, 0, len);
566     match no_quotes_result {
567         Ok(no_quotes) => {
568             let result = unescaper(&no_quotes);
569             match result {
570                 Ok(s) => s,
571                 Err(_) => {
572                     raise_parsing_error(
573                         node,
574                         env,
575                         &format!("Malformed string literal <<{}>>", &no_quotes),
576                     );
577                     BString::from("")
578                 }
579             }
580         }
581         Err(_) => {
582             raise_parsing_error(
583                 node,
584                 env,
585                 &format!("Malformed string literal <<{}>>", &content),
586             );
587             BString::from("")
588         }
589     }
592 fn unesc_dbl(s: &str) -> Result<BString, InvalidString> {
593     let unesc_s = unescape_double(s)?;
594     if unesc_s == B("''") || unesc_s == B("\"\"") {
595         Ok(BString::from(""))
596     } else {
597         Ok(unesc_s)
598     }
601 // TODO: return Cow<[u8]>
602 fn unesc_xhp(s: &[u8]) -> Vec<u8> {
603     lazy_static! {
604         static ref WHITESPACE: Regex = Regex::new("[\x20\t\n\r\x0c]+").unwrap();
605     }
606     WHITESPACE.replace_all(s, &b" "[..]).into_owned()
609 fn unesc_xhp_attr(s: &[u8]) -> Vec<u8> {
610     // TODO: change unesc_dbl to &[u8] -> BString
611     let r = get_quoted_content(s);
612     let r = unsafe { std::str::from_utf8_unchecked(r) };
613     unesc_dbl(r).unwrap().into()
616 fn get_quoted_content(s: &[u8]) -> &[u8] {
617     lazy_static! {
618         static ref QUOTED: Regex = Regex::new(r#"^[\x20\t\n\r\x0c]*"((?:.|\n)*)""#).unwrap();
619     }
620     QUOTED
621         .captures(s)
622         .and_then(|c| c.get(1))
623         .map_or(s, |m| m.as_bytes())
626 fn token_kind<'a>(node: S<'a>) -> Option<TK> {
627     match &node.children {
628         Token(t) => Some(t.kind()),
629         _ => None,
630     }
633 fn check_valid_reified_hint<'a>(env: &mut Env<'a>, node: S<'a>, hint: &ast::Hint) {
634     struct Checker<F: FnMut(&String)>(F);
635     impl<'ast, F: FnMut(&String)> Visitor<'ast> for Checker<F> {
636         type Params = AstParams<(), ()>;
638         fn object(&mut self) -> &mut dyn Visitor<'ast, Params = Self::Params> {
639             self
640         }
642         fn visit_hint(&mut self, c: &mut (), h: &ast::Hint) -> Result<(), ()> {
643             match h.1.as_ref() {
644                 ast::Hint_::Happly(id, _) => {
645                     self.0(&id.1);
646                 }
647                 ast::Hint_::Haccess(_, ids) => {
648                     ids.iter().for_each(|id| self.0(&id.1));
649                 }
650                 _ => {}
651             }
652             h.recurse(c, self)
653         }
654     }
656     if *env.in_static_method() {
657         let f = |id: &String| {
658             fail_if_invalid_reified_generic(node, env, id);
659         };
660         let mut visitor = Checker(f);
661         visitor.visit_hint(&mut (), hint).unwrap();
662     }
665 fn p_closure_parameter<'a>(
666     node: S<'a>,
667     env: &mut Env<'a>,
668 ) -> Result<(ast::Hint, Option<ast::HfParamInfo>), Error> {
669     match &node.children {
670         ClosureParameterTypeSpecifier(c) => {
671             let kind = p_param_kind(&c.call_convention, env)?;
672             let readonlyness = mp_optional(p_readonly, &c.readonly, env)?;
673             let info = Some(ast::HfParamInfo { kind, readonlyness });
674             let hint = p_hint(&c.type_, env)?;
675             Ok((hint, info))
676         }
677         _ => missing_syntax("closure parameter", node, env),
678     }
681 fn mp_shape_expression_field<'a, F, R>(
682     f: F,
683     node: S<'a>,
684     env: &mut Env<'a>,
685 ) -> Result<(ast::ShapeFieldName, R), Error>
686 where
687     F: Fn(S<'a>, &mut Env<'a>) -> Result<R, Error>,
689     match &node.children {
690         FieldInitializer(c) => {
691             let name = p_shape_field_name(&c.name, env)?;
692             let value = f(&c.value, env)?;
693             Ok((name, value))
694         }
695         _ => missing_syntax("shape field", node, env),
696     }
699 fn p_shape_field_name<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::ShapeFieldName, Error> {
700     use ast::ShapeFieldName::*;
701     let is_valid_shape_literal = |t: &PositionedToken<'a>| {
702         let is_str =
703             t.kind() == TK::SingleQuotedStringLiteral || t.kind() == TK::DoubleQuotedStringLiteral;
704         let text = t.text(env.source_text());
705         let is_empty = text == "\'\'" || text == "\"\"";
706         is_str && !is_empty
707     };
708     if let LiteralExpression(c) = &node.children {
709         if let Token(t) = &c.expression.children {
710             if is_valid_shape_literal(t) {
711                 let ast::Id(p, n) = pos_name(node, env)?;
712                 let unescp = if t.kind() == TK::SingleQuotedStringLiteral {
713                     unescape_single
714                 } else {
715                     unesc_dbl
716                 };
717                 let str_ = mk_str(node, env, unescp, &n);
718                 if int_of_string_opt(&str_).is_some() {
719                     raise_parsing_error(node, env, &syntax_error::shape_field_int_like_string)
720                 }
721                 return Ok(SFlitStr((p, str_)));
722             }
723         }
724     }
725     match &node.children {
726         ScopeResolutionExpression(c) => Ok(SFclassConst(
727             pos_name(&c.qualifier, env)?,
728             p_pstring(&c.name, env)?,
729         )),
730         _ => {
731             raise_parsing_error(node, env, &syntax_error::invalid_shape_field_name);
732             let ast::Id(p, n) = pos_name(node, env)?;
733             Ok(SFlitStr((p, mk_str(node, env, unesc_dbl, &n))))
734         }
735     }
738 fn p_shape_field<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::ShapeFieldInfo, Error> {
739     match &node.children {
740         FieldSpecifier(c) => {
741             let optional = !c.question.is_missing();
742             let name = p_shape_field_name(&c.name, env)?;
743             let hint = p_hint(&c.type_, env)?;
744             Ok(ast::ShapeFieldInfo {
745                 optional,
746                 hint,
747                 name,
748             })
749         }
750         _ => {
751             let (name, hint) = mp_shape_expression_field(p_hint, node, env)?;
752             Ok(ast::ShapeFieldInfo {
753                 optional: false,
754                 name,
755                 hint,
756             })
757         }
758     }
761 fn p_targ<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Targ, Error> {
762     Ok(ast::Targ((), p_hint(node, env)?))
765 fn p_hint_<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Hint_, Error> {
766     use ast::Hint_::*;
767     let unary =
768         |kw, ty, env: &mut Env<'a>| Ok(Happly(pos_name(kw, env)?, could_map(p_hint, ty, env)?));
769     let binary = |kw, key, ty, env: &mut Env<'a>| {
770         let kw = pos_name(kw, env)?;
771         let key = p_hint(key, env)?;
772         let value = p_hint(ty, env)?;
773         Ok(Happly(kw, vec![key, value]))
774     };
776     match &node.children {
777         Token(token) if token.kind() == TK::Variable => {
778             let ast::Id(_pos, name) = pos_name(node, env)?;
779             Ok(Hvar(name))
780         }
781         /* Dirty hack; CastExpression can have type represented by token */
782         Token(_) | SimpleTypeSpecifier(_) | QualifiedName(_) => {
783             let ast::Id(pos, name) = pos_name(node, env)?;
784             let mut suggest = |name: &str, canonical: &str| {
785                 raise_parsing_error(
786                     node,
787                     env,
788                     &syntax_error::invalid_typehint_alias(name, canonical),
789                 );
790             };
791             if "integer".eq_ignore_ascii_case(&name) {
792                 suggest(&name, special_typehints::INT);
793             } else if "boolean".eq_ignore_ascii_case(&name) {
794                 suggest(&name, special_typehints::BOOL);
795             } else if "double".eq_ignore_ascii_case(&name) || "real".eq_ignore_ascii_case(&name) {
796                 suggest(&name, special_typehints::FLOAT);
797             }
799             use naming_special_names_rust::coeffects::{CAPABILITIES, CONTEXTS};
800             if env.file_mode() != file_info::Mode::Mhhi && !env.codegen() {
801                 let sn = strip_ns(&name);
802                 if sn.starts_with(CONTEXTS) || sn.starts_with(CAPABILITIES) {
803                     raise_parsing_error(node, env, &syntax_error::direct_coeffects_reference);
804                 }
805             }
806             Ok(Happly(ast::Id(pos, name), vec![]))
807         }
808         ShapeTypeSpecifier(c) => {
809             let allows_unknown_fields = !c.ellipsis.is_missing();
810             /* if last element lacks a separator and ellipsis is present, error */
811             if allows_unknown_fields {
812                 if let SyntaxList(items) = &c.fields.children {
813                     if let Some(ListItem(item)) = items.last().map(|i| &i.children) {
814                         if item.separator.is_missing() {
815                             raise_parsing_error(
816                                 node,
817                                 env,
818                                 &syntax_error::shape_type_ellipsis_without_trailing_comma,
819                             )
820                         }
821                     }
822                 }
823             }
825             let field_map = could_map(p_shape_field, &c.fields, env)?;
826             let mut set = HashSet::default();
827             for f in field_map.iter() {
828                 if !set.insert(f.name.get_name()) {
829                     raise_hh_error(env, Naming::fd_name_already_bound(f.name.get_pos().clone()));
830                 }
831             }
833             Ok(Hshape(ast::NastShapeInfo {
834                 allows_unknown_fields,
835                 field_map,
836             }))
837         }
838         TupleTypeSpecifier(c) => Ok(Htuple(could_map(p_hint, &c.types, env)?)),
839         UnionTypeSpecifier(c) => Ok(Hunion(could_map(&p_hint, &c.types, env)?)),
840         IntersectionTypeSpecifier(c) => Ok(Hintersection(could_map(&p_hint, &c.types, env)?)),
841         KeysetTypeSpecifier(c) => Ok(Happly(
842             pos_name(&c.keyword, env)?,
843             could_map(p_hint, &c.type_, env)?,
844         )),
845         VectorTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
846         ClassnameTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
847         TupleTypeExplicitSpecifier(c) => unary(&c.keyword, &c.types, env),
848         VarrayTypeSpecifier(c) => unary(&c.keyword, &c.type_, env),
849         DarrayTypeSpecifier(c) => binary(&c.keyword, &c.key, &c.value, env),
850         DictionaryTypeSpecifier(c) => unary(&c.keyword, &c.members, env),
851         GenericTypeSpecifier(c) => {
852             let name = pos_name(&c.class_type, env)?;
853             let args = &c.argument_list;
854             let type_args = match &args.children {
855                 TypeArguments(c) => could_map(p_hint, &c.types, env)?,
856                 _ => missing_syntax("generic type arguments", args, env)?,
857             };
858             Ok(Happly(name, type_args))
859         }
860         NullableTypeSpecifier(c) => Ok(Hoption(p_hint(&c.type_, env)?)),
861         LikeTypeSpecifier(c) => Ok(Hlike(p_hint(&c.type_, env)?)),
862         SoftTypeSpecifier(c) => Ok(Hsoft(p_hint(&c.type_, env)?)),
863         ClosureTypeSpecifier(c) => {
864             let (param_list, variadic_hints): (Vec<S<'a>>, Vec<S<'a>>) = c
865                 .parameter_list
866                 .syntax_node_to_list_skip_separator()
867                 .partition(|n| match &n.children {
868                     VariadicParameter(_) => false,
869                     _ => true,
870                 });
871             let (type_hints, info) = param_list
872                 .iter()
873                 .map(|p| p_closure_parameter(p, env))
874                 .collect::<Result<Vec<_>, _>>()?
875                 .into_iter()
876                 .unzip();
877             let variadic_hints = variadic_hints
878                 .iter()
879                 .map(|v| match &v.children {
880                     VariadicParameter(c) => {
881                         if c.type_.is_missing() {
882                             raise_parsing_error(v, env, "Cannot use ... without a typehint");
883                         }
884                         Ok(Some(p_hint(&c.type_, env)?))
885                     }
886                     _ => panic!("expect variadic parameter"),
887                 })
888                 .collect::<Result<Vec<_>, _>>()?;
889             if variadic_hints.len() > 1 {
890                 return failwith(format!(
891                     "{} variadic parameters found. There should be no more than one.",
892                     variadic_hints.len()
893                 ));
894             }
895             let ctxs = p_contexts(&c.contexts, env)?;
896             Ok(Hfun(ast::HintFun {
897                 is_readonly: mp_optional(p_readonly, &c.readonly_keyword, env)?,
898                 param_tys: type_hints,
899                 param_info: info,
900                 variadic_ty: variadic_hints.into_iter().next().unwrap_or(None),
901                 ctxs,
902                 return_ty: p_hint(&c.return_type, env)?,
903                 is_readonly_return: mp_optional(p_readonly, &c.readonly_return, env)?,
904             }))
905         }
906         AttributizedSpecifier(c) => {
907             let attrs = p_user_attribute(&c.attribute_spec, env)?;
908             let hint = p_hint(&c.type_, env)?;
909             if attrs.iter().any(|attr| attr.name.1 != special_attrs::SOFT) {
910                 raise_parsing_error(node, env, &syntax_error::only_soft_allowed);
911             }
912             Ok(*soften_hint(&attrs, hint).1)
913         }
914         FunctionCtxTypeSpecifier(c) => {
915             let ast::Id(_p, n) = pos_name(&c.variable, env)?;
916             Ok(HfunContext(n))
917         }
918         TypeConstant(c) => {
919             let child = pos_name(&c.right_type, env)?;
920             match p_hint_(&c.left_type, env)? {
921                 Haccess(root, mut cs) => {
922                     cs.push(child);
923                     Ok(Haccess(root, cs))
924                 }
925                 Hvar(n) => {
926                     let pos = p_pos(&c.left_type, env);
927                     let root = ast::Hint::new(pos, Hvar(n));
928                     Ok(Haccess(root, vec![child]))
929                 }
930                 Happly(ty, param) => {
931                     if param.is_empty() {
932                         let root = ast::Hint::new(ty.0.clone(), Happly(ty, param));
933                         Ok(Haccess(root, vec![child]))
934                     } else {
935                         missing_syntax("type constant base", node, env)
936                     }
937                 }
938                 _ => missing_syntax("type constant base", node, env),
939             }
940         }
941         ReifiedTypeArgument(_) => {
942             raise_parsing_error(node, env, &syntax_error::invalid_reified);
943             missing_syntax("refied type", node, env)
944         }
945         _ => missing_syntax("type hint", node, env),
946     }
949 fn p_hint<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Hint, Error> {
950     let hint_ = p_hint_(node, env)?;
951     let pos = p_pos(node, env);
952     let hint = ast::Hint::new(pos, hint_);
953     check_valid_reified_hint(env, node, &hint);
954     Ok(hint)
957 fn p_simple_initializer<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Expr, Error> {
958     match &node.children {
959         SimpleInitializer(c) => p_expr(&c.value, env),
960         _ => missing_syntax("simple initializer", node, env),
961     }
964 fn p_member<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<(ast::Expr, ast::Expr), Error> {
965     match &node.children {
966         ElementInitializer(c) => Ok((p_expr(&c.key, env)?, p_expr(&c.value, env)?)),
967         _ => missing_syntax("darray intrinsic expression element", node, env),
968     }
971 fn expand_type_args<'a>(ty: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Hint>, Error> {
972     match &ty.children {
973         TypeArguments(c) => could_map(p_hint, &c.types, env),
974         _ => Ok(vec![]),
975     }
978 fn p_afield<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Afield, Error> {
979     match &node.children {
980         ElementInitializer(c) => Ok(ast::Afield::AFkvalue(
981             p_expr(&c.key, env)?,
982             p_expr(&c.value, env)?,
983         )),
984         _ => Ok(ast::Afield::AFvalue(p_expr(node, env)?)),
985     }
987 // We lower readonly lambda declarations as making the inner lambda have readonly_this.
988 fn process_readonly_expr(mut e: ast::Expr) -> ast::Expr_ {
989     use aast::Expr_::*;
990     match &mut e {
991         ast::Expr(_, _, Efun(ref mut e)) => {
992             e.0.readonly_this = Some(ast::ReadonlyKind::Readonly);
993         }
994         ast::Expr(_, _, Lfun(ref mut l)) => {
995             l.0.readonly_this = Some(ast::ReadonlyKind::Readonly);
996         }
997         _ => {}
998     }
999     E_::mk_readonly_expr(e)
1002 fn check_intrinsic_type_arg_varity<'a>(
1003     node: S<'a>,
1004     env: &mut Env<'a>,
1005     tys: Vec<ast::Hint>,
1006 ) -> Option<ast::CollectionTarg> {
1007     let count = tys.len();
1008     let mut tys = tys.into_iter();
1009     match count {
1010         2 => Some(ast::CollectionTarg::CollectionTKV(
1011             ast::Targ((), tys.next().unwrap()),
1012             ast::Targ((), tys.next().unwrap()),
1013         )),
1014         1 => Some(ast::CollectionTarg::CollectionTV(ast::Targ(
1015             (),
1016             tys.next().unwrap(),
1017         ))),
1018         0 => None,
1019         _ => {
1020             raise_parsing_error(node, env, &syntax_error::collection_intrinsic_many_typeargs);
1021             None
1022         }
1023     }
1026 fn p_import_flavor<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::ImportFlavor, Error> {
1027     use ast::ImportFlavor::*;
1028     match token_kind(node) {
1029         Some(TK::Include) => Ok(Include),
1030         Some(TK::Require) => Ok(Require),
1031         Some(TK::Include_once) => Ok(IncludeOnce),
1032         Some(TK::Require_once) => Ok(RequireOnce),
1033         _ => missing_syntax("import flavor", node, env),
1034     }
1037 fn p_null_flavor<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::OgNullFlavor, Error> {
1038     use ast::OgNullFlavor::*;
1039     match token_kind(node) {
1040         Some(TK::QuestionMinusGreaterThan) => Ok(OGNullsafe),
1041         Some(TK::MinusGreaterThan) => Ok(OGNullthrows),
1042         _ => missing_syntax("null flavor", node, env),
1043     }
1046 fn wrap_unescaper<F>(unescaper: F, s: &str) -> Result<BString, Error>
1047 where
1048     F: FnOnce(&str) -> Result<BString, InvalidString>,
1050     unescaper(s).map_err(|e| Error::Failwith(e.msg))
1053 fn fail_if_invalid_class_creation<'a>(node: S<'a>, env: &mut Env<'a>, id: impl AsRef<str>) {
1054     let id = id.as_ref();
1055     let is_in_static_method = *env.in_static_method();
1056     if is_in_static_method
1057         && ((id == special_classes::SELF && env.cls_generics_mut().values().any(|reif| *reif))
1058             || (id == special_classes::PARENT && *env.parent_maybe_reified()))
1059     {
1060         raise_parsing_error(node, env, &syntax_error::static_method_reified_obj_creation);
1061     }
1064 fn fail_if_invalid_reified_generic<'a>(node: S<'a>, env: &mut Env<'a>, id: impl AsRef<str>) {
1065     let is_in_static_method = *env.in_static_method();
1066     if is_in_static_method && *env.cls_generics_mut().get(id.as_ref()).unwrap_or(&false) {
1067         raise_parsing_error(
1068             node,
1069             env,
1070             &syntax_error::cls_reified_generic_in_static_method,
1071         );
1072     }
1075 fn rfind(s: &[u8], mut i: usize, c: u8) -> Result<usize, Error> {
1076     if i >= s.len() {
1077         return failwith("index out of range");
1078     }
1079     i += 1;
1080     while i > 0 {
1081         i -= 1;
1082         if s[i] == c {
1083             return Ok(i);
1084         }
1085     }
1086     failwith("char not found")
1089 fn prep_string2<'a>(
1090     nodes: &'a [Syntax<'a, PositionedToken<'a>, PositionedValue<'a>>],
1091     env: &mut Env<'a>,
1092 ) -> Result<(TokenOp, TokenOp), Error> {
1093     use TokenOp::*;
1094     let is_qoute = |c| c == b'\"' || c == b'`';
1095     let start_is_qoute = |s: &[u8]| {
1096         (!s.is_empty() && is_qoute(s[0])) || (s.len() > 1 && (s[0] == b'b' && s[1] == b'\"'))
1097     };
1098     let last_is_qoute = |s: &[u8]| !s.is_empty() && is_qoute(s[s.len() - 1]);
1099     let is_heredoc = |s: &[u8]| (s.len() > 3 && &s[0..3] == b"<<<");
1100     let mut nodes = nodes.iter();
1101     let first = nodes.next();
1102     match first.map(|n| &n.children) {
1103         Some(Token(t)) => {
1104             let raise = |env| {
1105                 raise_parsing_error(first.unwrap(), env, "Malformed String2 SyntaxList");
1106             };
1107             let text = t.text_raw(env.source_text());
1108             if start_is_qoute(text) {
1109                 let first_token_op = match text[0] {
1110                     b'b' if text.len() > 2 => LeftTrim(2),
1111                     _ if is_qoute(text[0]) && text.len() > 1 => LeftTrim(1),
1112                     _ => Skip,
1113                 };
1114                 if let Some(Token(t)) = nodes.last().map(|n| &n.children) {
1115                     let last_text = t.text_raw(env.source_text());
1116                     if last_is_qoute(last_text) {
1117                         let last_taken_op = match last_text.len() {
1118                             n if n > 1 => RightTrim(1),
1119                             _ => Skip,
1120                         };
1121                         return Ok((first_token_op, last_taken_op));
1122                     }
1123                 }
1124                 raise(env);
1125                 Ok((first_token_op, Noop))
1126             } else if is_heredoc(text) {
1127                 let trim_size = text
1128                     .iter()
1129                     .position(|c| *c == b'\n')
1130                     .ok_or_else(|| Error::Failwith(String::from("newline not found")))?
1131                     + 1;
1132                 let first_token_op = match trim_size {
1133                     _ if trim_size == text.len() => Skip,
1134                     _ => LeftTrim(trim_size),
1135                 };
1136                 if let Some(Token(t)) = nodes.last().map(|n| &n.children) {
1137                     let text = t.text_raw(env.source_text());
1138                     let len = text.len();
1139                     if len != 0 {
1140                         let n = rfind(text, len - 2, b'\n')?;
1141                         let last_token_op = match n {
1142                             0 => Skip,
1143                             _ => RightTrim(len - n),
1144                         };
1145                         return Ok((first_token_op, last_token_op));
1146                     }
1147                 }
1148                 raise(env);
1149                 Ok((first_token_op, Noop))
1150             } else {
1151                 Ok((Noop, Noop))
1152             }
1153         }
1154         _ => Ok((Noop, Noop)),
1155     }
1158 fn process_token_op<'a>(
1159     env: &mut Env<'a>,
1160     op: TokenOp,
1161     node: S<'a>,
1162 ) -> Result<Option<S<'a>>, Error> {
1163     use TokenOp::*;
1164     match op {
1165         LeftTrim(n) => match &node.children {
1166             Token(t) => {
1167                 let token = env.token_factory.trim_left(t, n);
1168                 let node = env.arena.alloc(Syntax::make_token(token));
1169                 Ok(Some(node))
1170             }
1171             _ => failwith("Token expected"),
1172         },
1173         RightTrim(n) => match &node.children {
1174             Token(t) => {
1175                 let token = env.token_factory.trim_right(t, n);
1176                 let node = env.arena.alloc(Syntax::make_token(token));
1177                 Ok(Some(node))
1178             }
1179             _ => failwith("Token expected"),
1180         },
1181         _ => Ok(None),
1182     }
1185 fn p_string2<'a>(
1186     nodes: &'a [Syntax<'a, PositionedToken<'a>, PositionedValue<'a>>],
1187     env: &mut Env<'a>,
1188 ) -> Result<Vec<ast::Expr>, Error> {
1189     use TokenOp::*;
1190     let (head_op, tail_op) = prep_string2(nodes, env)?;
1191     let mut result = Vec::with_capacity(nodes.len());
1192     let mut i = 0;
1193     let last = nodes.len() - 1;
1194     while i <= last {
1195         let op = match i {
1196             0 => head_op,
1197             _ if i == last => tail_op,
1198             _ => Noop,
1199         };
1201         if op == Skip {
1202             i += 1;
1203             continue;
1204         }
1206         let node = process_token_op(env, op, &nodes[i])?;
1207         let node = node.unwrap_or(&nodes[i]);
1209         if token_kind(node) == Some(TK::Dollar) && i < last {
1210             if let EmbeddedBracedExpression(_) = &nodes[i + 1].children {
1211                 raise_parsing_error(&nodes[i + 1], env, &syntax_error::outside_dollar_str_interp);
1213                 result.push(p_expr_with_loc(
1214                     ExprLocation::InDoubleQuotedString,
1215                     &nodes[i + 1],
1216                     env,
1217                 )?);
1218                 i += 2;
1219                 continue;
1220             }
1221         }
1223         result.push(p_expr_with_loc(
1224             ExprLocation::InDoubleQuotedString,
1225             node,
1226             env,
1227         )?);
1228         i += 1;
1229     }
1230     Ok(result)
1233 fn p_expr_l<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Expr>, Error> {
1234     let p_expr = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr, Error> {
1235         p_expr_with_loc(ExprLocation::TopLevel, n, e)
1236     };
1237     could_map(p_expr, node, env)
1240 fn p_expr<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Expr, Error> {
1241     p_expr_with_loc(ExprLocation::TopLevel, node, env)
1244 fn p_expr_for_function_call_arguments<'a>(
1245     node: S<'a>,
1246     env: &mut Env<'a>,
1247 ) -> Result<(ast::ParamKind, ast::Expr), Error> {
1248     match &node.children {
1249         DecoratedExpression(DecoratedExpressionChildren {
1250             decorator,
1251             expression,
1252         }) if token_kind(decorator) == Some(TK::Inout) => Ok((
1253             ast::ParamKind::Pinout(p_pos(decorator, env)),
1254             p_expr(expression, env)?,
1255         )),
1256         _ => Ok((ast::ParamKind::Pnormal, p_expr(node, env)?)),
1257     }
1260 fn p_expr_for_normal_argument<'a>(
1261     node: S<'a>,
1262     env: &mut Env<'a>,
1263 ) -> Result<(ast::ParamKind, ast::Expr), Error> {
1264     Ok((ast::ParamKind::Pnormal, p_expr(node, env)?))
1267 fn p_expr_with_loc<'a>(
1268     location: ExprLocation,
1269     node: S<'a>,
1270     env: &mut Env<'a>,
1271 ) -> Result<ast::Expr, Error> {
1272     p_expr_impl(location, node, env, None)
1275 fn p_expr_impl<'a>(
1276     location: ExprLocation,
1277     node: S<'a>,
1278     env: &mut Env<'a>,
1279     parent_pos: Option<Pos>,
1280 ) -> Result<ast::Expr, Error> {
1281     // We use location=CallReceiver to set PropOrMethod::IsMethod on ObjGet
1282     // But only if it is the immediate node.
1283     let location = match (location, &node.children) {
1284         (
1285             ExprLocation::CallReceiver,
1286             MemberSelectionExpression(_)
1287             | SafeMemberSelectionExpression(_)
1288             | EmbeddedMemberSelectionExpression(_)
1289             | ScopeResolutionExpression(_),
1290         ) => location,
1291         (ExprLocation::CallReceiver, _) => ExprLocation::TopLevel,
1292         (_, _) => location,
1293     };
1294     match &node.children {
1295         BracedExpression(c) => {
1296             // Either a dynamic method lookup on a dynamic value:
1297             //   $foo->{$meth_name}();
1298             // or an XHP splice.
1299             //   <p id={$id}>hello</p>;
1300             // In both cases, unwrap, consistent with parentheses.
1301             p_expr_impl(location, &c.expression, env, parent_pos)
1302         }
1303         ParenthesizedExpression(c) => p_expr_impl(location, &c.expression, env, parent_pos),
1304         ETSpliceExpression(c) => {
1305             let pos = p_pos(node, env);
1307             let inner_pos = p_pos(&c.expression, env);
1308             let inner_expr_ = p_expr_impl_(location, &c.expression, env, parent_pos)?;
1309             let inner_expr = ast::Expr::new((), inner_pos, inner_expr_);
1310             Ok(ast::Expr::new(
1311                 (),
1312                 pos,
1313                 ast::Expr_::ETSplice(Box::new(inner_expr)),
1314             ))
1315         }
1316         _ => {
1317             let pos = p_pos(node, env);
1318             let expr_ = p_expr_impl_(location, node, env, parent_pos)?;
1319             Ok(ast::Expr::new((), pos, expr_))
1320         }
1321     }
1324 fn p_expr_lit<'a>(
1325     location: ExprLocation,
1326     _parent: S<'a>,
1327     expr: S<'a>,
1328     env: &mut Env<'a>,
1329 ) -> Result<ast::Expr_, Error> {
1330     match &expr.children {
1331         Token(_) => {
1332             let s = expr.text(env.indexed_source_text.source_text());
1333             let check_lint_err = |e: &mut Env<'a>, s: &str, expected: &str| {
1334                 if !e.codegen() && s != expected {
1335                     raise_lint_error(e, LintError::lowercase_constant(p_pos(expr, e), s));
1336                 }
1337             };
1338             match (location, token_kind(expr)) {
1339                 (ExprLocation::InDoubleQuotedString, _) if env.codegen() => {
1340                     Ok(E_::String(mk_str(expr, env, unesc_dbl, s)))
1341                 }
1342                 (_, Some(TK::DecimalLiteral))
1343                 | (_, Some(TK::OctalLiteral))
1344                 | (_, Some(TK::HexadecimalLiteral))
1345                 | (_, Some(TK::BinaryLiteral)) => {
1346                     let s = s.replace("_", "");
1347                     match parse_int(&s) {
1348                         Err(ParseIntError::OutOfRange) => {
1349                             raise_parsing_error(expr, env, &syntax_error::out_of_int_range(&s));
1350                         }
1351                         Err(ParseIntError::InvalidDigit(int_kind)) => {
1352                             raise_parsing_error(
1353                                 expr,
1354                                 env,
1355                                 &syntax_error::invalid_integer_digit(int_kind),
1356                             );
1357                             missing_syntax(&format!("{}", int_kind), expr, env)?;
1358                         }
1359                         Err(ParseIntError::Empty) => {
1360                             failwith("Unexpected int literal error")?;
1361                         }
1362                         Ok(_) => {}
1363                     }
1364                     Ok(E_::Int(s))
1365                 }
1366                 (_, Some(TK::FloatingLiteral)) => {
1367                     // f64::from_str accepts more string than Hacklang, invalid Hack float literal
1368                     // is caught in lexer.
1369                     if f64::from_str(s).is_err() {
1370                         raise_parsing_error(expr, env, &syntax_error::out_of_float_range(s))
1371                     }
1372                     Ok(E_::Float(s.into()))
1373                 }
1374                 (_, Some(TK::SingleQuotedStringLiteral)) => {
1375                     Ok(E_::String(mk_str(expr, env, unescape_single, s)))
1376                 }
1377                 (_, Some(TK::DoubleQuotedStringLiteral)) => {
1378                     Ok(E_::String(mk_str(expr, env, unescape_double, s)))
1379                 }
1380                 (_, Some(TK::HeredocStringLiteral)) => {
1381                     Ok(E_::String(mk_str(expr, env, unescape_heredoc, s)))
1382                 }
1383                 (_, Some(TK::NowdocStringLiteral)) => {
1384                     Ok(E_::String(mk_str(expr, env, unescape_nowdoc, s)))
1385                 }
1386                 (_, Some(TK::NullLiteral)) => {
1387                     check_lint_err(env, s, literal::NULL);
1388                     Ok(E_::Null)
1389                 }
1390                 (_, Some(TK::BooleanLiteral)) => {
1391                     if s.eq_ignore_ascii_case(literal::FALSE) {
1392                         check_lint_err(env, s, literal::FALSE);
1393                         Ok(E_::False)
1394                     } else if s.eq_ignore_ascii_case(literal::TRUE) {
1395                         check_lint_err(env, s, literal::TRUE);
1396                         Ok(E_::True)
1397                     } else {
1398                         missing_syntax(&format!("boolean (not: {})", s), expr, env)
1399                     }
1400                 }
1401                 _ => missing_syntax("literal", expr, env),
1402             }
1403         }
1404         SyntaxList(ts) => Ok(E_::String2(p_string2(ts, env)?)),
1405         _ => missing_syntax("literal expressoin", expr, env),
1406     }
1409 fn p_expr_with_loc_<'a>(
1410     location: ExprLocation,
1411     node: S<'a>,
1412     env: &mut Env<'a>,
1413 ) -> Result<ast::Expr_, Error> {
1414     p_expr_impl_(location, node, env, None)
1417 fn p_expr_impl_<'a>(
1418     location: ExprLocation,
1419     node: S<'a>,
1420     env: &mut Env<'a>,
1421     parent_pos: Option<Pos>,
1422 ) -> Result<ast::Expr_, Error> {
1423     if *env.exp_recursion_depth() >= EXP_RECUSION_LIMIT {
1424         Err(Error::Failwith("Expression recursion limit reached".into()))
1425     } else {
1426         *env.exp_recursion_depth() += 1;
1427         let r = p_expr_impl__(location, node, env, parent_pos);
1428         *env.exp_recursion_depth() -= 1;
1429         r
1430     }
1433 fn split_args_vararg<'a>(
1434     arg_list_node: S<'a>,
1435     e: &mut Env<'a>,
1436 ) -> Result<(Vec<(ast::ParamKind, ast::Expr)>, Option<ast::Expr>), Error> {
1437     let mut arg_list: Vec<_> = arg_list_node.syntax_node_to_list_skip_separator().collect();
1438     if let Some(last_arg) = arg_list.last() {
1439         if let DecoratedExpression(c) = &last_arg.children {
1440             if token_kind(&c.decorator) == Some(TK::DotDotDot) {
1441                 let _ = arg_list.pop();
1442                 let args: Result<Vec<_>, _> = arg_list
1443                     .iter()
1444                     .map(|a| p_expr_for_function_call_arguments(a, e))
1445                     .collect();
1446                 let args = args?;
1447                 let vararg = p_expr(&c.expression, e)?;
1448                 return Ok((args, Some(vararg)));
1449             }
1450         }
1451     }
1452     Ok((
1453         could_map(p_expr_for_function_call_arguments, arg_list_node, e)?,
1454         None,
1455     ))
1458 fn p_expr_impl__<'a>(
1459     location: ExprLocation,
1460     node: S<'a>,
1461     env: &mut Env<'a>,
1462     parent_pos: Option<Pos>,
1463 ) -> Result<ast::Expr_, Error> {
1464     env.check_stack_limit();
1465     use ast::Expr as E;
1466     let mk_lid = |p: Pos, s: String| ast::Lid(p, (0, s));
1467     let mk_name_lid = |name: S<'a>, env: &mut Env<'a>| {
1468         let name = pos_name(name, env)?;
1469         Ok(mk_lid(name.0, name.1))
1470     };
1471     let mk_lvar = |name: S<'a>, env: &mut Env<'a>| Ok(E_::mk_lvar(mk_name_lid(name, env)?));
1472     let mk_id_expr = |name: ast::Sid| E::new((), name.0.clone(), E_::mk_id(name));
1473     let p_intri_expr = |kw, ty, v, e: &mut Env<'a>| {
1474         let hints = expand_type_args(ty, e)?;
1475         let hints = check_intrinsic_type_arg_varity(node, e, hints);
1476         Ok(E_::mk_collection(
1477             pos_name(kw, e)?,
1478             hints,
1479             could_map(p_afield, v, e)?,
1480         ))
1481     };
1482     let p_special_call = |recv: S<'a>, args: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr_, Error> {
1483         // Mark expression as CallReceiver so that we can correctly set PropOrMethod field in ObjGet and ClassGet
1484         let recv = p_expr_with_loc(ExprLocation::CallReceiver, recv, e)?;
1485         let (args, varargs) = split_args_vararg(args, e)?;
1486         Ok(E_::mk_call(recv, vec![], args, varargs))
1487     };
1488     let p_obj_get =
1489         |recv: S<'a>, op: S<'a>, name: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr_, Error> {
1490             if recv.is_object_creation_expression() && !e.codegen() {
1491                 raise_parsing_error(recv, e, &syntax_error::invalid_constructor_method_call);
1492             }
1493             let recv = p_expr(recv, e)?;
1494             let name = p_expr_with_loc(ExprLocation::MemberSelect, name, e)?;
1495             let op = p_null_flavor(op, e)?;
1496             Ok(E_::mk_obj_get(
1497                 recv,
1498                 name,
1499                 op,
1500                 match location {
1501                     ExprLocation::CallReceiver => ast::PropOrMethod::IsMethod,
1502                     _ => ast::PropOrMethod::IsProp,
1503                 },
1504             ))
1505         };
1506     let pos = match parent_pos {
1507         None => p_pos(node, env),
1508         Some(p) => p,
1509     };
1510     match &node.children {
1511         LambdaExpression(c) => {
1512             let suspension_kind = mk_suspension_kind(&c.async_);
1513             let (params, (ctxs, unsafe_ctxs), readonly_ret, ret) = match &c.signature.children {
1514                 LambdaSignature(c) => {
1515                     let params = could_map(p_fun_param, &c.parameters, env)?;
1516                     let readonly_ret = mp_optional(p_readonly, &c.readonly_return, env)?;
1517                     let ctxs = p_contexts(&c.contexts, env)?;
1518                     let unsafe_ctxs = ctxs.clone();
1519                     if has_polymorphic_context(env, ctxs.as_ref()) {
1520                         raise_parsing_error(
1521                             &c.contexts,
1522                             env,
1523                             &syntax_error::lambda_effect_polymorphic,
1524                         );
1525                     }
1526                     let ret = mp_optional(p_hint, &c.type_, env)?;
1527                     (params, (ctxs, unsafe_ctxs), readonly_ret, ret)
1528                 }
1529                 Token(_) => {
1530                     let ast::Id(p, n) = pos_name(&c.signature, env)?;
1531                     (
1532                         vec![ast::FunParam {
1533                             annotation: (),
1534                             type_hint: ast::TypeHint((), None),
1535                             is_variadic: false,
1536                             pos: p,
1537                             name: n,
1538                             expr: None,
1539                             callconv: ast::ParamKind::Pnormal,
1540                             readonly: None,
1541                             user_attributes: vec![],
1542                             visibility: None,
1543                         }],
1544                         (None, None),
1545                         None,
1546                         None,
1547                     )
1548                 }
1549                 _ => missing_syntax("lambda signature", &c.signature, env)?,
1550             };
1552             let (body, yield_) = if !c.body.is_compound_statement() {
1553                 mp_yielding(p_function_body, &c.body, env)?
1554             } else {
1555                 let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
1556                 mp_yielding(&p_function_body, &c.body, env1.as_mut())?
1557             };
1558             let external = c.body.is_external();
1559             let fun = ast::Fun_ {
1560                 span: pos.clone(),
1561                 readonly_this: None, // filled in by mk_unop
1562                 annotation: (),
1563                 readonly_ret,
1564                 ret: ast::TypeHint((), ret),
1565                 name: ast::Id(pos, String::from(";anonymous")),
1566                 tparams: vec![],
1567                 where_constraints: vec![],
1568                 body: ast::FuncBody { fb_ast: body },
1569                 fun_kind: mk_fun_kind(suspension_kind, yield_),
1570                 params,
1571                 ctxs,
1572                 unsafe_ctxs,
1573                 user_attributes: p_user_attributes(&c.attribute_spec, env)?,
1574                 external,
1575                 doc_comment: None,
1576             };
1577             Ok(E_::mk_lfun(fun, vec![]))
1578         }
1579         BracedExpression(c) => p_expr_with_loc_(location, &c.expression, env),
1580         EmbeddedBracedExpression(c) => p_expr_impl_(location, &c.expression, env, Some(pos)),
1581         ParenthesizedExpression(c) => p_expr_with_loc_(location, &c.expression, env),
1582         DictionaryIntrinsicExpression(c) => {
1583             p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env)
1584         }
1585         KeysetIntrinsicExpression(c) => p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env),
1586         VectorIntrinsicExpression(c) => p_intri_expr(&c.keyword, &c.explicit_type, &c.members, env),
1587         CollectionLiteralExpression(c) => {
1588             let (collection_name, hints) = match &c.name.children {
1589                 SimpleTypeSpecifier(c) => (pos_name(&c.specifier, env)?, None),
1590                 GenericTypeSpecifier(c) => {
1591                     let hints = expand_type_args(&c.argument_list, env)?;
1592                     let hints = check_intrinsic_type_arg_varity(node, env, hints);
1593                     (pos_name(&c.class_type, env)?, hints)
1594                 }
1595                 _ => (pos_name(&c.name, env)?, None),
1596             };
1597             Ok(E_::mk_collection(
1598                 collection_name,
1599                 hints,
1600                 could_map(p_afield, &c.initializers, env)?,
1601             ))
1602         }
1603         VarrayIntrinsicExpression(c) => {
1604             let hints = expand_type_args(&c.explicit_type, env)?;
1605             let hints = check_intrinsic_type_arg_varity(node, env, hints);
1606             let targ = match hints {
1607                 Some(ast::CollectionTarg::CollectionTV(ty)) => Some(ty),
1608                 None => None,
1609                 _ => missing_syntax("VarrayIntrinsicExpression type args", node, env)?,
1610             };
1611             Ok(E_::mk_varray(targ, could_map(p_expr, &c.members, env)?))
1612         }
1613         DarrayIntrinsicExpression(c) => {
1614             let hints = expand_type_args(&c.explicit_type, env)?;
1615             let hints = check_intrinsic_type_arg_varity(node, env, hints);
1616             match hints {
1617                 Some(ast::CollectionTarg::CollectionTKV(tk, tv)) => Ok(E_::mk_darray(
1618                     Some((tk, tv)),
1619                     could_map(p_member, &c.members, env)?,
1620                 )),
1621                 None => Ok(E_::mk_darray(None, could_map(p_member, &c.members, env)?)),
1622                 _ => missing_syntax("DarrayIntrinsicExpression type args", node, env),
1623             }
1624         }
1625         ListExpression(c) => {
1626             /* TODO: Or tie in with other intrinsics and post-process to List */
1627             let p_binder_or_ignore = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr, Error> {
1628                 match &n.children {
1629                     Missing => Ok(E::new((), e.mk_none_pos(), E_::Omitted)),
1630                     _ => p_expr(n, e),
1631                 }
1632             };
1633             Ok(E_::List(could_map(&p_binder_or_ignore, &c.members, env)?))
1634         }
1635         EvalExpression(c) => p_special_call(&c.keyword, &c.argument, env),
1636         IssetExpression(c) => p_special_call(&c.keyword, &c.argument_list, env),
1637         TupleExpression(c) => Ok(E_::mk_tuple(could_map(p_expr, &c.items, env)?)),
1638         FunctionCallExpression(c) => {
1639             let recv = &c.receiver;
1640             let args = &c.argument_list;
1641             let get_hhas_adata = || {
1642                 if text_str(recv, env) == "__hhas_adata" {
1643                     if let SyntaxList(l) = &args.children {
1644                         if let Some(li) = l.first() {
1645                             if let ListItem(i) = &li.children {
1646                                 if let LiteralExpression(le) = &i.item.children {
1647                                     let expr = &le.expression;
1648                                     if token_kind(expr) == Some(TK::NowdocStringLiteral) {
1649                                         return Some(expr);
1650                                     }
1651                                 }
1652                             }
1653                         }
1654                     }
1655                 }
1656                 None
1657             };
1658             match get_hhas_adata() {
1659                 Some(expr) => {
1660                     let literal_expression_pos = p_pos(expr, env);
1661                     let s = extract_unquoted_string(text_str(expr, env), 0, expr.width())
1662                         .map_err(|e| Error::Failwith(e.msg))?;
1663                     Ok(E_::mk_call(
1664                         p_expr(recv, env)?,
1665                         vec![],
1666                         vec![(
1667                             ast::ParamKind::Pnormal,
1668                             E::new((), literal_expression_pos, E_::String(s.into())),
1669                         )],
1670                         None,
1671                     ))
1672                 }
1673                 None => {
1674                     let targs = match (&recv.children, &c.type_args.children) {
1675                         (_, TypeArguments(c)) => could_map(p_targ, &c.types, env)?,
1676                         /* TODO might not be needed */
1677                         (GenericTypeSpecifier(c), _) => match &c.argument_list.children {
1678                             TypeArguments(c) => could_map(p_targ, &c.types, env)?,
1679                             _ => vec![],
1680                         },
1681                         _ => vec![],
1682                     };
1684                     // Mark expression as CallReceiver so that we can correctly set PropOrMethod field in ObjGet and ClassGet
1685                     let recv = p_expr_with_loc(ExprLocation::CallReceiver, recv, env)?;
1686                     let (mut args, varargs) = split_args_vararg(args, env)?;
1688                     // If the function has an enum class label expression, that's
1689                     // the first argument.
1690                     if let EnumClassLabelExpression(e) = &c.enum_class_label.children {
1691                         assert!(
1692                             e.qualifier.is_missing(),
1693                             "Parser error: function call with enum class labels"
1694                         );
1695                         let pos = p_pos(&c.enum_class_label, env);
1696                         let enum_class_label = ast::Expr::new(
1697                             (),
1698                             pos,
1699                             E_::mk_enum_class_label(None, pos_name(&e.expression, env)?.1),
1700                         );
1701                         args.insert(0, (ast::ParamKind::Pnormal, enum_class_label));
1702                     }
1704                     Ok(E_::mk_call(recv, targs, args, varargs))
1705                 }
1706             }
1707         }
1708         FunctionPointerExpression(c) => {
1709             let targs = match &c.type_args.children {
1710                 TypeArguments(c) => could_map(p_targ, &c.types, env)?,
1711                 _ => vec![],
1712             };
1714             let recv = p_expr(&c.receiver, env)?;
1716             match &recv.2 {
1717                 aast::Expr_::Id(id) => Ok(E_::mk_function_pointer(
1718                     aast::FunctionPtrId::FPId(*(id.to_owned())),
1719                     targs,
1720                 )),
1721                 aast::Expr_::ClassConst(c) => {
1722                     if let aast::ClassId_::CIexpr(aast::Expr(_, _, aast::Expr_::Id(_))) = (c.0).2 {
1723                         Ok(E_::mk_function_pointer(
1724                             aast::FunctionPtrId::FPClassConst(c.0.to_owned(), c.1.to_owned()),
1725                             targs,
1726                         ))
1727                     } else {
1728                         raise_parsing_error(node, env, &syntax_error::function_pointer_bad_recv);
1729                         missing_syntax("function or static method", node, env)
1730                     }
1731                 }
1732                 _ => {
1733                     raise_parsing_error(node, env, &syntax_error::function_pointer_bad_recv);
1734                     missing_syntax("function or static method", node, env)
1735                 }
1736             }
1737         }
1738         QualifiedName(_) => match location {
1739             ExprLocation::InDoubleQuotedString => {
1740                 let ast::Id(_, n) = pos_qualified_name(node, env)?;
1741                 Ok(E_::String(n.into()))
1742             }
1743             _ => Ok(E_::mk_id(pos_qualified_name(node, env)?)),
1744         },
1745         VariableExpression(c) => Ok(E_::mk_lvar(lid_from_pos_name(pos, &c.expression, env)?)),
1746         PipeVariableExpression(_) => Ok(E_::mk_lvar(mk_lid(
1747             pos,
1748             special_idents::DOLLAR_DOLLAR.into(),
1749         ))),
1750         InclusionExpression(c) => Ok(E_::mk_import(
1751             p_import_flavor(&c.require, env)?,
1752             p_expr(&c.filename, env)?,
1753         )),
1754         MemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1755         SafeMemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1756         EmbeddedMemberSelectionExpression(c) => p_obj_get(&c.object, &c.operator, &c.name, env),
1757         PrefixUnaryExpression(_) | PostfixUnaryExpression(_) | DecoratedExpression(_) => {
1758             let (operand, op, postfix) = match &node.children {
1759                 PrefixUnaryExpression(c) => (&c.operand, &c.operator, false),
1760                 PostfixUnaryExpression(c) => (&c.operand, &c.operator, true),
1761                 DecoratedExpression(c) => (&c.expression, &c.decorator, false),
1762                 _ => missing_syntax("unary exppr", node, env)?,
1763             };
1765             /**
1766              * FFP does not destinguish between ++$i and $i++ on the level of token
1767              * kind annotation. Prevent duplication by switching on `postfix` for
1768              * the two operatores for which AST /does/ differentiate between
1769              * fixities.
1770              */
1771             use ast::Uop::*;
1772             let mk_unop = |op, e| Ok(E_::mk_unop(op, e));
1773             let op_kind = token_kind(op);
1774             if let Some(TK::At) = op_kind {
1775                 if env.parser_options.po_disallow_silence {
1776                     raise_parsing_error(op, env, &syntax_error::no_silence);
1777                 }
1778                 if env.codegen() {
1779                     let expr = p_expr(operand, env)?;
1780                     mk_unop(Usilence, expr)
1781                 } else {
1782                     let expr = p_expr_impl(ExprLocation::TopLevel, operand, env, Some(pos))?;
1783                     Ok(expr.2)
1784                 }
1785             } else {
1786                 let expr = p_expr(operand, env)?;
1787                 match op_kind {
1788                     Some(TK::PlusPlus) if postfix => mk_unop(Upincr, expr),
1789                     Some(TK::MinusMinus) if postfix => mk_unop(Updecr, expr),
1790                     Some(TK::PlusPlus) => mk_unop(Uincr, expr),
1791                     Some(TK::MinusMinus) => mk_unop(Udecr, expr),
1792                     Some(TK::Exclamation) => mk_unop(Unot, expr),
1793                     Some(TK::Tilde) => mk_unop(Utild, expr),
1794                     Some(TK::Plus) => mk_unop(Uplus, expr),
1795                     Some(TK::Minus) => mk_unop(Uminus, expr),
1796                     Some(TK::Await) => lift_await(pos, expr, env, location),
1797                     Some(TK::Readonly) => Ok(process_readonly_expr(expr)),
1798                     Some(TK::Clone) => Ok(E_::mk_clone(expr)),
1799                     Some(TK::Print) => Ok(E_::mk_call(
1800                         E::new(
1801                             (),
1802                             pos.clone(),
1803                             E_::mk_id(ast::Id(pos, special_functions::ECHO.into())),
1804                         ),
1805                         vec![],
1806                         vec![(ast::ParamKind::Pnormal, expr)],
1807                         None,
1808                     )),
1809                     Some(TK::Dollar) => {
1810                         raise_parsing_error(op, env, &syntax_error::invalid_variable_name);
1811                         Ok(E_::Omitted)
1812                     }
1813                     _ => missing_syntax("unary operator", node, env),
1814                 }
1815             }
1816         }
1817         BinaryExpression(c) => {
1818             use ExprLocation::*;
1819             let rlocation = if token_kind(&c.operator) == Some(TK::Equal) {
1820                 match location {
1821                     AsStatement => RightOfAssignment,
1822                     UsingStatement => RightOfAssignmentInUsingStatement,
1823                     _ => TopLevel,
1824                 }
1825             } else {
1826                 TopLevel
1827             };
1828             let bop_ast_node = p_bop(
1829                 pos,
1830                 &c.operator,
1831                 p_expr(&c.left_operand, env)?,
1832                 p_expr_with_loc(rlocation, &c.right_operand, env)?,
1833                 env,
1834             )?;
1835             if let Some((ast::Bop::Eq(_), lhs, _)) = bop_ast_node.as_binop() {
1836                 check_lvalue(lhs, env);
1837             }
1838             Ok(bop_ast_node)
1839         }
1840         Token(t) => {
1841             use ExprLocation::*;
1842             match (location, t.kind()) {
1843                 (MemberSelect, TK::Variable) => mk_lvar(node, env),
1844                 (InDoubleQuotedString, TK::HeredocStringLiteral)
1845                 | (InDoubleQuotedString, TK::HeredocStringLiteralHead)
1846                 | (InDoubleQuotedString, TK::HeredocStringLiteralTail) => Ok(E_::String(
1847                     wrap_unescaper(unescape_heredoc, text_str(node, env))?,
1848                 )),
1849                 (InDoubleQuotedString, _) => {
1850                     Ok(E_::String(wrap_unescaper(unesc_dbl, text_str(node, env))?))
1851                 }
1852                 (MemberSelect, _)
1853                 | (TopLevel, _)
1854                 | (AsStatement, _)
1855                 | (UsingStatement, _)
1856                 | (RightOfAssignment, _)
1857                 | (RightOfAssignmentInUsingStatement, _)
1858                 | (RightOfReturn, _)
1859                 | (CallReceiver, _) => Ok(E_::mk_id(pos_name(node, env)?)),
1860             }
1861         }
1862         YieldExpression(c) => {
1863             use ExprLocation::*;
1864             env.saw_yield = true;
1865             if location != AsStatement
1866                 && location != RightOfAssignment
1867                 && location != RightOfAssignmentInUsingStatement
1868             {
1869                 raise_parsing_error(node, env, &syntax_error::invalid_yield);
1870             }
1871             if c.operand.is_missing() {
1872                 Ok(E_::mk_yield(ast::Afield::AFvalue(E::new(
1873                     (),
1874                     pos,
1875                     E_::Null,
1876                 ))))
1877             } else {
1878                 Ok(E_::mk_yield(p_afield(&c.operand, env)?))
1879             }
1880         }
1881         ScopeResolutionExpression(c) => {
1882             let qual = p_expr(&c.qualifier, env)?;
1883             if let E_::Id(id) = &qual.2 {
1884                 fail_if_invalid_reified_generic(node, env, &id.1);
1885             }
1886             match &c.name.children {
1887                 Token(token) if token.kind() == TK::Variable => {
1888                     let ast::Id(p, name) = pos_name(&c.name, env)?;
1889                     Ok(E_::mk_class_get(
1890                         ast::ClassId((), pos, ast::ClassId_::CIexpr(qual)),
1891                         ast::ClassGetExpr::CGstring((p, name)),
1892                         match location {
1893                             ExprLocation::CallReceiver => ast::PropOrMethod::IsMethod,
1894                             _ => ast::PropOrMethod::IsProp,
1895                         },
1896                     ))
1897                 }
1898                 _ => {
1899                     let E(_, p, expr_) = p_expr(&c.name, env)?;
1900                     match expr_ {
1901                         E_::String(id) => Ok(E_::mk_class_const(
1902                             ast::ClassId((), pos, ast::ClassId_::CIexpr(qual)),
1903                             (
1904                                 p,
1905                                 String::from_utf8(id.into())
1906                                     .map_err(|e| Error::Failwith(e.to_string()))?,
1907                             ),
1908                         )),
1909                         E_::Id(id) => {
1910                             let ast::Id(p, n) = *id;
1911                             Ok(E_::mk_class_const(
1912                                 ast::ClassId((), pos, ast::ClassId_::CIexpr(qual)),
1913                                 (p, n),
1914                             ))
1915                         }
1916                         E_::Lvar(id) => {
1917                             let ast::Lid(p, (_, n)) = *id;
1918                             Ok(E_::mk_class_get(
1919                                 ast::ClassId((), pos, ast::ClassId_::CIexpr(qual)),
1920                                 ast::ClassGetExpr::CGstring((p, n)),
1921                                 match location {
1922                                     ExprLocation::CallReceiver => ast::PropOrMethod::IsMethod,
1923                                     _ => ast::PropOrMethod::IsProp,
1924                                 },
1925                             ))
1926                         }
1927                         _ => Ok(E_::mk_class_get(
1928                             ast::ClassId((), pos, ast::ClassId_::CIexpr(qual)),
1929                             ast::ClassGetExpr::CGexpr(E((), p, expr_)),
1930                             match location {
1931                                 ExprLocation::CallReceiver => ast::PropOrMethod::IsMethod,
1932                                 _ => ast::PropOrMethod::IsProp,
1933                             },
1934                         )),
1935                     }
1936                 }
1937             }
1938         }
1939         CastExpression(c) => Ok(E_::mk_cast(
1940             p_hint(&c.type_, env)?,
1941             p_expr(&c.operand, env)?,
1942         )),
1943         PrefixedCodeExpression(c) => {
1944             let src_expr = p_expr(&c.expression, env)?;
1946             let hint = p_hint(&c.prefix, env)?;
1948             let desugar_result = desugar(&hint, src_expr, env);
1949             for (pos, msg) in desugar_result.errors {
1950                 raise_parsing_error_pos(&pos, env, &msg);
1951             }
1953             Ok(desugar_result.expr.2)
1954         }
1955         ConditionalExpression(c) => {
1956             let alter = p_expr(&c.alternative, env)?;
1957             let consequence = mp_optional(p_expr, &c.consequence, env)?;
1958             let condition = p_expr(&c.test, env)?;
1959             Ok(E_::mk_eif(condition, consequence, alter))
1960         }
1961         SubscriptExpression(c) => Ok(E_::mk_array_get(
1962             p_expr(&c.receiver, env)?,
1963             mp_optional(p_expr, &c.index, env)?,
1964         )),
1965         EmbeddedSubscriptExpression(c) => Ok(E_::mk_array_get(
1966             p_expr(&c.receiver, env)?,
1967             mp_optional(|n, e| p_expr_with_loc(location, n, e), &c.index, env)?,
1968         )),
1969         ShapeExpression(c) => Ok(E_::Shape(could_map(
1970             |n: S<'a>, e: &mut Env<'a>| mp_shape_expression_field(&p_expr, n, e),
1971             &c.fields,
1972             env,
1973         )?)),
1974         ObjectCreationExpression(c) => p_expr_impl_(location, &c.object, env, Some(pos)),
1975         ConstructorCall(c) => {
1976             let (args, varargs) = split_args_vararg(&c.argument_list, env)?;
1977             let (e, hl) = match &c.type_.children {
1978                 GenericTypeSpecifier(c) => {
1979                     let name = pos_name(&c.class_type, env)?;
1980                     let hints = match &c.argument_list.children {
1981                         TypeArguments(c) => could_map(p_targ, &c.types, env)?,
1982                         _ => missing_syntax("generic type arguments", &c.argument_list, env)?,
1983                     };
1984                     (mk_id_expr(name), hints)
1985                 }
1986                 SimpleTypeSpecifier(_) => {
1987                     let name = pos_name(&c.type_, env)?;
1988                     (mk_id_expr(name), vec![])
1989                 }
1990                 _ => (p_expr(&c.type_, env)?, vec![]),
1991             };
1992             if let E_::Id(name) = &e.2 {
1993                 fail_if_invalid_reified_generic(node, env, &name.1);
1994                 fail_if_invalid_class_creation(node, env, &name.1);
1995             }
1996             Ok(E_::mk_new(
1997                 ast::ClassId((), pos, ast::ClassId_::CIexpr(e)),
1998                 hl,
1999                 args.into_iter().map(|(_, e)| e).collect(),
2000                 varargs,
2001                 (),
2002             ))
2003         }
2004         GenericTypeSpecifier(c) => {
2005             if !c.argument_list.is_missing() {
2006                 raise_parsing_error(&c.argument_list, env, &syntax_error::targs_not_allowed)
2007             }
2008             Ok(E_::mk_id(pos_name(&c.class_type, env)?))
2009         }
2010         LiteralExpression(c) => p_expr_lit(location, node, &c.expression, env),
2011         PrefixedStringExpression(c) => {
2012             /* Temporarily allow only`re`- prefixed strings */
2013             let name_text = text(&c.name, env);
2014             if name_text != "re" {
2015                 raise_parsing_error(node, env, &syntax_error::non_re_prefix);
2016             }
2017             Ok(E_::mk_prefixed_string(name_text, p_expr(&c.str, env)?))
2018         }
2019         IsExpression(c) => Ok(E_::mk_is(
2020             p_expr(&c.left_operand, env)?,
2021             p_hint(&c.right_operand, env)?,
2022         )),
2023         AsExpression(c) => Ok(E_::mk_as(
2024             p_expr(&c.left_operand, env)?,
2025             p_hint(&c.right_operand, env)?,
2026             false,
2027         )),
2028         NullableAsExpression(c) => Ok(E_::mk_as(
2029             p_expr(&c.left_operand, env)?,
2030             p_hint(&c.right_operand, env)?,
2031             true,
2032         )),
2033         UpcastExpression(c) => Ok(E_::mk_upcast(
2034             p_expr(&c.left_operand, env)?,
2035             p_hint(&c.right_operand, env)?,
2036         )),
2037         AnonymousFunction(c) => {
2038             let p_arg = |n: S<'a>, e: &mut Env<'a>| match &n.children {
2039                 Token(_) => mk_name_lid(n, e),
2040                 _ => missing_syntax("use variable", n, e),
2041             };
2042             let ctxs = p_contexts(&c.ctx_list, env)?;
2043             let unsafe_ctxs = ctxs.clone();
2044             let p_use = |n: S<'a>, e: &mut Env<'a>| match &n.children {
2045                 AnonymousFunctionUseClause(c) => could_map(p_arg, &c.variables, e),
2046                 _ => Ok(vec![]),
2047             };
2048             let suspension_kind = mk_suspension_kind(&c.async_keyword);
2049             let (body, yield_) = {
2050                 let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
2051                 mp_yielding(&p_function_body, &c.body, env1.as_mut())?
2052             };
2053             let doc_comment = extract_docblock(node, env).or_else(|| env.top_docblock().clone());
2054             let user_attributes = p_user_attributes(&c.attribute_spec, env)?;
2055             let external = c.body.is_external();
2056             let params = could_map(p_fun_param, &c.parameters, env)?;
2057             let name_pos = p_fun_pos(node, env);
2058             let fun = ast::Fun_ {
2059                 span: p_pos(node, env),
2060                 readonly_this: None, // set in process_readonly_expr
2061                 annotation: (),
2062                 readonly_ret: mp_optional(p_readonly, &c.readonly_return, env)?,
2063                 ret: ast::TypeHint((), mp_optional(p_hint, &c.type_, env)?),
2064                 name: ast::Id(name_pos, String::from(";anonymous")),
2065                 tparams: vec![],
2066                 where_constraints: vec![],
2067                 body: ast::FuncBody { fb_ast: body },
2068                 fun_kind: mk_fun_kind(suspension_kind, yield_),
2069                 params,
2070                 ctxs,
2071                 unsafe_ctxs,
2072                 user_attributes,
2073                 external,
2074                 doc_comment,
2075             };
2076             let uses = p_use(&c.use_, env).unwrap_or_else(|_| vec![]);
2077             Ok(E_::mk_efun(fun, uses))
2078         }
2079         AwaitableCreationExpression(c) => {
2080             let suspension_kind = mk_suspension_kind(&c.async_);
2081             let (blk, yld) = mp_yielding(&p_function_body, &c.compound_statement, env)?;
2082             let user_attributes = p_user_attributes(&c.attribute_spec, env)?;
2083             let external = c.compound_statement.is_external();
2084             let name_pos = p_fun_pos(node, env);
2085             let body = ast::Fun_ {
2086                 span: pos.clone(),
2087                 annotation: (),
2088                 readonly_this: None, // set in process_readonly_expr
2089                 readonly_ret: None,  // TODO: awaitable creation expression
2090                 ret: ast::TypeHint((), None),
2091                 name: ast::Id(name_pos, String::from(";anonymous")),
2092                 tparams: vec![],
2093                 where_constraints: vec![],
2094                 body: ast::FuncBody {
2095                     fb_ast: if blk.is_empty() {
2096                         let pos = p_pos(&c.compound_statement, env);
2097                         vec![ast::Stmt::noop(pos)]
2098                     } else {
2099                         blk
2100                     },
2101                 },
2102                 fun_kind: mk_fun_kind(suspension_kind, yld),
2103                 params: vec![],
2104                 ctxs: None,        // TODO(T70095684)
2105                 unsafe_ctxs: None, // TODO(T70095684)
2106                 user_attributes,
2107                 external,
2108                 doc_comment: None,
2109             };
2110             Ok(E_::mk_call(
2111                 E::new((), pos, E_::mk_lfun(body, vec![])),
2112                 vec![],
2113                 vec![],
2114                 None,
2115             ))
2116         }
2117         XHPExpression(c) if c.open.is_xhp_open() => {
2118             if let XHPOpen(c1) = &c.open.children {
2119                 let name = pos_name(&c1.name, env)?;
2120                 let attrs = could_map(p_xhp_attr, &c1.attributes, env)?;
2121                 let exprs = aggregate_xhp_tokens(env, &c.body)?
2122                     .iter()
2123                     .map(|n| p_xhp_embedded(unesc_xhp, n, env))
2124                     .collect::<Result<Vec<_>, _>>()?;
2126                 let id = if env.empty_ns_env.disable_xhp_element_mangling {
2127                     ast::Id(name.0, name.1)
2128                 } else {
2129                     ast::Id(name.0, String::from(":") + &name.1)
2130                 };
2132                 Ok(E_::mk_xml(
2133                     // TODO: update pos_name to support prefix
2134                     id, attrs, exprs,
2135                 ))
2136             } else {
2137                 failwith("expect xhp open")
2138             }
2139         }
2140         EnumClassLabelExpression(c) => {
2141             /* Foo#Bar can be the following:
2142              * - short version: Foo is None/missing and we only have #Bar
2143              * - Foo is a name -> fully qualified Foo#Bar
2144              * - Foo is a function call prefix (can happen during auto completion)
2145              *   $c->foo#Bar or C::foo#Bar
2146              */
2147             let ast::Id(label_pos, label_name) = pos_name(&c.expression, env)?;
2148             if c.qualifier.is_missing() {
2149                 Ok(E_::mk_enum_class_label(None, label_name))
2150             } else if c.qualifier.is_name() {
2151                 let name = pos_name(&c.qualifier, env)?;
2152                 Ok(E_::mk_enum_class_label(Some(name), label_name))
2153             } else if label_name.ends_with("AUTO332") {
2154                 // This can happen during parsing in auto-complete mode
2155                 // In such case, the "label_name" must end with AUTO332
2156                 // We want to treat this as a method call even though we haven't yet seen the arguments
2157                 let recv = p_expr_with_loc(ExprLocation::CallReceiver, &c.qualifier, env);
2158                 match recv {
2159                     Ok(recv) => {
2160                         let enum_class_label = E_::mk_enum_class_label(None, label_name);
2161                         let enum_class_label = ast::Expr::new((), label_pos, enum_class_label);
2162                         Ok(E_::mk_call(
2163                             recv,
2164                             vec![],
2165                             vec![(ast::ParamKind::Pnormal, enum_class_label)],
2166                             None,
2167                         ))
2168                     }
2169                     Err(err) => Err(err),
2170                 }
2171             } else {
2172                 missing_syntax_(Some(E_::Null), "method call", node, env)
2173             }
2174         }
2175         _ => missing_syntax_(Some(E_::Null), "expression", node, env),
2176     }
2179 fn check_lvalue<'a>(ast::Expr(_, p, expr_): &ast::Expr, env: &mut Env<'a>) {
2180     use aast::Expr_::*;
2181     let mut raise = |s| raise_parsing_error_pos(p, env, s);
2182     match expr_ {
2183         ObjGet(og) => {
2184             if og.as_ref().3 == ast::PropOrMethod::IsMethod {
2185                 raise("Invalid lvalue")
2186             } else {
2187                 match og.as_ref() {
2188                     (_, ast::Expr(_, _, Id(_)), ast::OgNullFlavor::OGNullsafe, _) => {
2189                         raise("?-> syntax is not supported for lvalues")
2190                     }
2191                     (_, ast::Expr(_, _, Id(sid)), _, _) if sid.1.as_bytes()[0] == b':' => {
2192                         raise("->: syntax is not supported for lvalues")
2193                     }
2194                     _ => {}
2195                 }
2196             }
2197         }
2198         ArrayGet(ag) => {
2199             if let ClassConst(_) = (ag.0).2 {
2200                 raise("Array-like class consts are not valid lvalues");
2201             }
2202         }
2203         List(l) => {
2204             for i in l.iter() {
2205                 check_lvalue(i, env);
2206             }
2207         }
2208         Darray(_) | Varray(_) | Shape(_) | Collection(_) | Null | True | False | Id(_)
2209         | Clone(_) | ClassConst(_) | Int(_) | Float(_) | PrefixedString(_) | String(_)
2210         | String2(_) | Yield(_) | Await(_) | Cast(_) | Unop(_) | Binop(_) | Eif(_) | New(_)
2211         | Efun(_) | Lfun(_) | Xml(_) | Import(_) | Pipe(_) | Is(_) | As(_) | Call(_) => {
2212             raise("Invalid lvalue")
2213         }
2214         _ => {}
2215     }
2218 fn p_xhp_embedded<'a, F>(escaper: F, node: S<'a>, env: &mut Env<'a>) -> Result<ast::Expr, Error>
2219 where
2220     F: FnOnce(&[u8]) -> Vec<u8>,
2222     if let Some(kind) = token_kind(node) {
2223         if env.codegen() && TK::XHPStringLiteral == kind {
2224             let p = p_pos(node, env);
2225             /* for XHP string literals (attribute values) just extract
2226             value from quotes and decode HTML entities  */
2227             let text = html_entities::decode(get_quoted_content(node.full_text(env.source_text())));
2228             Ok(ast::Expr::new((), p, E_::make_string(text)))
2229         } else if env.codegen() && TK::XHPBody == kind {
2230             let p = p_pos(node, env);
2231             /* for XHP body - only decode HTML entities */
2232             let text = html_entities::decode(&unesc_xhp(node.full_text(env.source_text())));
2233             Ok(ast::Expr::new((), p, E_::make_string(text)))
2234         } else {
2235             let p = p_pos(node, env);
2236             let s = escaper(node.full_text(env.source_text()));
2237             Ok(ast::Expr::new((), p, E_::make_string(s)))
2238         }
2239     } else {
2240         p_expr(node, env)
2241     }
2244 fn p_xhp_attr<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::XhpAttribute, Error> {
2245     match &node.children {
2246         XHPSimpleAttribute(c) => {
2247             let attr_expr = &c.expression;
2248             let name = p_pstring(&c.name, env)?;
2249             let expr = if attr_expr.is_braced_expression()
2250                 && env.file_mode() == file_info::Mode::Mhhi
2251                 && !env.codegen()
2252             {
2253                 ast::Expr::new((), env.mk_none_pos(), E_::Null)
2254             } else {
2255                 p_xhp_embedded(unesc_xhp_attr, attr_expr, env)?
2256             };
2257             let xhp_simple = ast::XhpSimple {
2258                 name,
2259                 type_: (),
2260                 expr,
2261             };
2262             Ok(ast::XhpAttribute::XhpSimple(xhp_simple))
2263         }
2264         XHPSpreadAttribute(c) => {
2265             let expr = p_xhp_embedded(unesc_xhp, &c.expression, env)?;
2266             Ok(ast::XhpAttribute::XhpSpread(expr))
2267         }
2268         _ => missing_syntax("XHP attribute", node, env),
2269     }
2272 fn aggregate_xhp_tokens<'a>(env: &mut Env<'a>, nodes: S<'a>) -> Result<Vec<S<'a>>, Error> {
2273     let nodes = nodes.syntax_node_to_list_skip_separator();
2274     let mut state = (None, None, vec![]); // (start, end, result)
2275     let mut combine = |state: &mut (Option<S<'a>>, Option<S<'a>>, Vec<S<'a>>)| {
2276         match (state.0, state.1) {
2277             (Some(s), None) => state.2.push(s),
2278             (Some(s), Some(e)) => {
2279                 let token = env
2280                     .token_factory
2281                     .concatenate(s.get_token().unwrap(), e.get_token().unwrap());
2282                 let node = env.arena.alloc(Syntax::make_token(token));
2283                 state.2.push(node)
2284             }
2285             _ => {}
2286         }
2287         state.0 = None;
2288         state.1 = None;
2289         Ok(())
2290     };
2291     for n in nodes {
2292         match &n.children {
2293             Token(t) if t.kind() == TK::XHPComment => {
2294                 if state.0.is_some() {
2295                     combine(&mut state)?;
2296                 }
2297             }
2298             Token(_) => {
2299                 if state.0.is_none() {
2300                     state.0 = Some(n)
2301                 } else {
2302                     state.1 = Some(n)
2303                 }
2304             }
2305             _ => {
2306                 combine(&mut state)?;
2307                 state.2.push(n);
2308             }
2309         }
2310     }
2311     combine(&mut state)?;
2312     Ok(state.2)
2315 fn p_bop<'a>(
2316     pos: Pos,
2317     node: S<'a>,
2318     lhs: ast::Expr,
2319     rhs: ast::Expr,
2320     env: &mut Env<'a>,
2321 ) -> Result<ast::Expr_, Error> {
2322     use ast::Bop::*;
2323     let mk = |op, l, r| Ok(E_::mk_binop(op, l, r));
2324     let mk_eq = |op, l, r| Ok(E_::mk_binop(Eq(Some(Box::new(op))), l, r));
2325     match token_kind(node) {
2326         Some(TK::Equal) => mk(Eq(None), lhs, rhs),
2327         Some(TK::Bar) => mk(Bar, lhs, rhs),
2328         Some(TK::Ampersand) => mk(Amp, lhs, rhs),
2329         Some(TK::Plus) => mk(Plus, lhs, rhs),
2330         Some(TK::Minus) => mk(Minus, lhs, rhs),
2331         Some(TK::Star) => mk(Star, lhs, rhs),
2332         Some(TK::Carat) => mk(Xor, lhs, rhs),
2333         Some(TK::Slash) => mk(Slash, lhs, rhs),
2334         Some(TK::Dot) => mk(Dot, lhs, rhs),
2335         Some(TK::Percent) => mk(Percent, lhs, rhs),
2336         Some(TK::LessThan) => mk(Lt, lhs, rhs),
2337         Some(TK::GreaterThan) => mk(Gt, lhs, rhs),
2338         Some(TK::EqualEqual) => mk(Eqeq, lhs, rhs),
2339         Some(TK::LessThanEqual) => mk(Lte, lhs, rhs),
2340         Some(TK::GreaterThanEqual) => mk(Gte, lhs, rhs),
2341         Some(TK::StarStar) => mk(Starstar, lhs, rhs),
2342         Some(TK::ExclamationEqual) => mk(Diff, lhs, rhs),
2343         Some(TK::BarEqual) => mk_eq(Bar, lhs, rhs),
2344         Some(TK::PlusEqual) => mk_eq(Plus, lhs, rhs),
2345         Some(TK::MinusEqual) => mk_eq(Minus, lhs, rhs),
2346         Some(TK::StarEqual) => mk_eq(Star, lhs, rhs),
2347         Some(TK::StarStarEqual) => mk_eq(Starstar, lhs, rhs),
2348         Some(TK::SlashEqual) => mk_eq(Slash, lhs, rhs),
2349         Some(TK::DotEqual) => mk_eq(Dot, lhs, rhs),
2350         Some(TK::PercentEqual) => mk_eq(Percent, lhs, rhs),
2351         Some(TK::CaratEqual) => mk_eq(Xor, lhs, rhs),
2352         Some(TK::AmpersandEqual) => mk_eq(Amp, lhs, rhs),
2353         Some(TK::BarBar) => mk(Barbar, lhs, rhs),
2354         Some(TK::AmpersandAmpersand) => mk(Ampamp, lhs, rhs),
2355         Some(TK::LessThanLessThan) => mk(Ltlt, lhs, rhs),
2356         Some(TK::GreaterThanGreaterThan) => mk(Gtgt, lhs, rhs),
2357         Some(TK::EqualEqualEqual) => mk(Eqeqeq, lhs, rhs),
2358         Some(TK::LessThanLessThanEqual) => mk_eq(Ltlt, lhs, rhs),
2359         Some(TK::GreaterThanGreaterThanEqual) => mk_eq(Gtgt, lhs, rhs),
2360         Some(TK::ExclamationEqualEqual) => mk(Diff2, lhs, rhs),
2361         Some(TK::LessThanEqualGreaterThan) => mk(Cmp, lhs, rhs),
2362         Some(TK::QuestionQuestion) => mk(QuestionQuestion, lhs, rhs),
2363         Some(TK::QuestionQuestionEqual) => mk_eq(QuestionQuestion, lhs, rhs),
2364         /* The ugly duckling; In the FFP, `|>` is parsed as a
2365          * `BinaryOperator`, whereas the typed AST has separate constructors for
2366          * Pipe and Binop. This is why we don't just project onto a
2367          * `bop`, but a `expr -> expr -> expr_`.
2368          */
2369         Some(TK::BarGreaterThan) => {
2370             let lid =
2371                 ast::Lid::from_counter(pos, env.next_local_id(), special_idents::DOLLAR_DOLLAR);
2372             Ok(E_::mk_pipe(lid, lhs, rhs))
2373         }
2374         Some(TK::QuestionColon) => Ok(E_::mk_eif(lhs, None, rhs)),
2375         _ => missing_syntax("binary operator", node, env),
2376     }
2379 fn p_exprs_with_loc<'a>(n: S<'a>, e: &mut Env<'a>) -> Result<(Pos, Vec<ast::Expr>), Error> {
2380     let loc = p_pos(n, e);
2381     let p_expr = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr, Error> {
2382         p_expr_with_loc(ExprLocation::UsingStatement, n, e)
2383     };
2384     Ok((loc, could_map(p_expr, n, e)?))
2387 fn p_stmt_list_<'a>(
2388     pos: &Pos,
2389     mut nodes: Iter<'_, S<'a>>,
2390     env: &mut Env<'a>,
2391 ) -> Result<Vec<ast::Stmt>, Error> {
2392     let mut r = vec![];
2393     loop {
2394         match nodes.next() {
2395             Some(n) => match &n.children {
2396                 UsingStatementFunctionScoped(c) => {
2397                     let body = p_stmt_list_(pos, nodes, env)?;
2398                     let f = |e: &mut Env<'a>| {
2399                         Ok(ast::Stmt::new(
2400                             pos.clone(),
2401                             ast::Stmt_::mk_using(ast::UsingStmt {
2402                                 is_block_scoped: false,
2403                                 has_await: !c.await_keyword.is_missing(),
2404                                 exprs: p_exprs_with_loc(&c.expression, e)?,
2405                                 block: body,
2406                             }),
2407                         ))
2408                     };
2409                     let using = lift_awaits_in_statement_(f, Either::Right(pos), env)?;
2410                     r.push(using);
2411                     break Ok(r);
2412                 }
2413                 _ => {
2414                     r.push(p_stmt(n, env)?);
2415                 }
2416             },
2417             _ => break Ok(r),
2418         }
2419     }
2422 fn handle_loop_body<'a>(pos: Pos, node: S<'a>, env: &mut Env<'a>) -> Result<ast::Stmt, Error> {
2423     let list: Vec<_> = node.syntax_node_to_list_skip_separator().collect();
2424     let blk: Vec<_> = p_stmt_list_(&pos, list.iter(), env)?
2425         .into_iter()
2426         .filter(|stmt| !stmt.1.is_noop())
2427         .collect();
2428     let body = if blk.is_empty() {
2429         vec![mk_noop(env)]
2430     } else {
2431         blk
2432     };
2433     Ok(ast::Stmt::new(pos, ast::Stmt_::mk_block(body)))
2436 fn is_simple_assignment_await_expression<'a>(node: S<'a>) -> bool {
2437     match &node.children {
2438         BinaryExpression(c) => {
2439             token_kind(&c.operator) == Some(TK::Equal)
2440                 && is_simple_await_expression(&c.right_operand)
2441         }
2442         _ => false,
2443     }
2446 fn is_simple_await_expression<'a>(node: S<'a>) -> bool {
2447     match &node.children {
2448         PrefixUnaryExpression(c) => token_kind(&c.operator) == Some(TK::Await),
2449         _ => false,
2450     }
2453 fn with_new_nonconcurrent_scope<'a, F, R>(f: F, env: &mut Env<'a>) -> R
2454 where
2455     F: FnOnce(&mut Env<'a>) -> R,
2457     let saved_lifted_awaits = env.lifted_awaits.take();
2458     let result = f(env);
2459     env.lifted_awaits = saved_lifted_awaits;
2460     result
2463 fn with_new_concurrent_scope<'a, F, R>(
2464     f: F,
2465     env: &mut Env<'a>,
2466 ) -> Result<(LiftedAwaitExprs, R), Error>
2467 where
2468     F: FnOnce(&mut Env<'a>) -> Result<R, Error>,
2470     let saved_lifted_awaits = env.lifted_awaits.replace(LiftedAwaits {
2471         awaits: vec![],
2472         lift_kind: LiftedAwaitKind::LiftedFromConcurrent,
2473     });
2474     let result = f(env);
2475     let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved_lifted_awaits);
2476     let result = result?;
2477     let awaits = match lifted_awaits {
2478         Some(la) => process_lifted_awaits(la)?,
2479         None => failwith("lifted awaits should not be None")?,
2480     };
2481     Ok((awaits, result))
2484 fn process_lifted_awaits(mut awaits: LiftedAwaits) -> Result<LiftedAwaitExprs, Error> {
2485     for await_ in awaits.awaits.iter() {
2486         if (await_.1).1.is_none() {
2487             return failwith("none pos in lifted awaits");
2488         }
2489     }
2490     awaits
2491         .awaits
2492         .sort_unstable_by(|a1, a2| Pos::cmp(&(a1.1).1, &(a2.1).1));
2493     Ok(awaits.awaits)
2496 fn clear_statement_scope<'a, F, R>(f: F, env: &mut Env<'a>) -> R
2497 where
2498     F: FnOnce(&mut Env<'a>) -> R,
2500     use LiftedAwaitKind::*;
2501     match &env.lifted_awaits {
2502         Some(LiftedAwaits { lift_kind, .. }) if *lift_kind == LiftedFromStatement => {
2503             let saved_lifted_awaits = env.lifted_awaits.take();
2504             let result = f(env);
2505             env.lifted_awaits = saved_lifted_awaits;
2506             result
2507         }
2508         _ => f(env),
2509     }
2512 fn lift_awaits_in_statement<'a, F>(f: F, node: S<'a>, env: &mut Env<'a>) -> Result<ast::Stmt, Error>
2513 where
2514     F: FnOnce(&mut Env<'a>) -> Result<ast::Stmt, Error>,
2516     lift_awaits_in_statement_(f, Either::Left(node), env)
2519 fn lift_awaits_in_statement_<'a, F>(
2520     f: F,
2521     pos: Either<S<'a>, &Pos>,
2522     env: &mut Env<'a>,
2523 ) -> Result<ast::Stmt, Error>
2524 where
2525     F: FnOnce(&mut Env<'a>) -> Result<ast::Stmt, Error>,
2527     use LiftedAwaitKind::*;
2528     let (lifted_awaits, result) = match env.lifted_awaits {
2529         Some(LiftedAwaits { lift_kind, .. }) if lift_kind == LiftedFromConcurrent => {
2530             (None, f(env)?)
2531         }
2532         _ => {
2533             let saved = env.lifted_awaits.replace(LiftedAwaits {
2534                 awaits: vec![],
2535                 lift_kind: LiftedFromStatement,
2536             });
2537             let result = f(env);
2538             let lifted_awaits = mem::replace(&mut env.lifted_awaits, saved);
2539             let result = result?;
2540             (lifted_awaits, result)
2541         }
2542     };
2543     if let Some(lifted_awaits) = lifted_awaits {
2544         if !lifted_awaits.awaits.is_empty() {
2545             let awaits = process_lifted_awaits(lifted_awaits)?;
2546             let pos = match pos {
2547                 Either::Left(n) => p_pos(n, env),
2548                 Either::Right(p) => p.clone(),
2549             };
2550             return Ok(ast::Stmt::new(
2551                 pos,
2552                 ast::Stmt_::mk_awaitall(awaits, vec![result]),
2553             ));
2554         }
2555     }
2556     Ok(result)
2559 fn lift_await<'a>(
2560     parent_pos: Pos,
2561     expr: ast::Expr,
2562     env: &mut Env<'a>,
2563     location: ExprLocation,
2564 ) -> Result<ast::Expr_, Error> {
2565     use ExprLocation::*;
2566     match (&env.lifted_awaits, location) {
2567         (_, UsingStatement) | (_, RightOfAssignmentInUsingStatement) | (None, _) => {
2568             Ok(E_::mk_await(expr))
2569         }
2570         (Some(_), _) => {
2571             if location != AsStatement {
2572                 let name = env.make_tmp_var_name();
2573                 let lid = ast::Lid::new(parent_pos, name.clone());
2574                 let await_lid = ast::Lid::new(expr.1.clone(), name);
2575                 let await_ = (Some(await_lid), expr);
2576                 if let Some(aw) = env.lifted_awaits.as_mut() {
2577                     aw.awaits.push(await_)
2578                 }
2579                 Ok(E_::mk_lvar(lid))
2580             } else {
2581                 if let Some(aw) = env.lifted_awaits.as_mut() {
2582                     aw.awaits.push((None, expr))
2583                 }
2584                 Ok(E_::Null)
2585             }
2586         }
2587     }
2590 fn p_stmt<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Stmt, Error> {
2591     clear_statement_scope(
2592         |e: &mut Env<'a>| {
2593             let docblock = extract_docblock(node, e);
2594             e.push_docblock(docblock);
2595             let result = p_stmt_(node, e);
2596             e.pop_docblock();
2597             result
2598         },
2599         env,
2600     )
2603 fn p_stmt_<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Stmt, Error> {
2604     let pos = p_pos(node, env);
2605     use ast::{Stmt, Stmt_ as S_};
2606     let new = Stmt::new;
2607     match &node.children {
2608         SwitchStatement(c) => {
2609             let p_label = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::GenCase, Error> {
2610                 match &n.children {
2611                     CaseLabel(c) => Ok(aast::GenCase::Case(aast::Case(
2612                         p_expr(&c.expression, e)?,
2613                         vec![],
2614                     ))),
2615                     DefaultLabel(_) => Ok(aast::GenCase::Default(aast::DefaultCase(
2616                         p_pos(n, e),
2617                         vec![],
2618                     ))),
2619                     _ => missing_syntax("switch label", n, e),
2620                 }
2621             };
2622             let p_section = |n: S<'a>, e: &mut Env<'a>| -> Result<Vec<ast::GenCase>, Error> {
2623                 match &n.children {
2624                     SwitchSection(c) => {
2625                         let mut blk = could_map(p_stmt, &c.statements, e)?;
2626                         if !c.fallthrough.is_missing() {
2627                             blk.push(new(e.mk_none_pos(), S_::Fallthrough));
2628                         }
2629                         let mut labels = could_map(p_label, &c.labels, e)?;
2630                         match labels.last_mut() {
2631                             Some(aast::GenCase::Default(aast::DefaultCase(_, b))) => *b = blk,
2632                             Some(aast::GenCase::Case(aast::Case(_, b))) => *b = blk,
2633                             _ => raise_parsing_error(n, e, "Malformed block result"),
2634                         }
2635                         Ok(labels)
2636                     }
2637                     _ => missing_syntax("switch section", n, e),
2638                 }
2639             };
2641             let f = |env: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2642                 let cases = itertools::concat(could_map(p_section, &c.sections, env)?);
2644                 let last_is_default = matches!(cases.last(), Some(aast::GenCase::Default(_)));
2646                 let (cases, mut defaults): (Vec<ast::Case>, Vec<ast::DefaultCase>) =
2647                     cases.into_iter().partition_map(|case| match case {
2648                         aast::GenCase::Case(x @ aast::Case(..)) => Either::Left(x),
2649                         aast::GenCase::Default(x @ aast::DefaultCase(..)) => Either::Right(x),
2650                     });
2652                 if defaults.len() > 1 {
2653                     let aast::DefaultCase(pos, _) = &defaults[1];
2654                     raise_parsing_error_pos(pos, env, &syntax_error::multiple_defaults_in_switch);
2655                 }
2657                 let default = match defaults.pop() {
2658                     Some(default @ aast::DefaultCase(..)) => {
2659                         if last_is_default {
2660                             Some(default)
2661                         } else {
2662                             let aast::DefaultCase(pos, _) = default;
2663                             raise_parsing_error_pos(
2664                                 &pos,
2665                                 env,
2666                                 &syntax_error::default_switch_case_not_last,
2667                             );
2668                             None
2669                         }
2670                     }
2672                     None => None,
2673                 };
2675                 Ok(new(
2676                     pos,
2677                     S_::mk_switch(p_expr(&c.expression, env)?, cases, default),
2678                 ))
2679             };
2680             lift_awaits_in_statement(f, node, env)
2681         }
2682         IfStatement(c) => {
2683             let p_else_if = |n: S<'a>, e: &mut Env<'a>| -> Result<(ast::Expr, ast::Block), Error> {
2684                 match &n.children {
2685                     ElseifClause(c) => {
2686                         Ok((p_expr(&c.condition, e)?, p_block(true, &c.statement, e)?))
2687                     }
2688                     _ => missing_syntax("elseif clause", n, e),
2689                 }
2690             };
2691             let f = |env: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2692                 let condition = p_expr(&c.condition, env)?;
2693                 let statement = p_block(true /* remove noop */, &c.statement, env)?;
2694                 let else_ = match &c.else_clause.children {
2695                     ElseClause(c) => p_block(true, &c.statement, env)?,
2696                     Missing => vec![mk_noop(env)],
2697                     _ => missing_syntax("else clause", &c.else_clause, env)?,
2698                 };
2699                 let else_ifs = could_map(p_else_if, &c.elseif_clauses, env)?;
2700                 let else_if = else_ifs
2701                     .into_iter()
2702                     .rev()
2703                     .fold(else_, |child, (cond, stmts)| {
2704                         vec![new(pos.clone(), S_::mk_if(cond, stmts, child))]
2705                     });
2706                 Ok(new(pos, S_::mk_if(condition, statement, else_if)))
2707             };
2708             lift_awaits_in_statement(f, node, env)
2709         }
2710         ExpressionStatement(c) => {
2711             let expr = &c.expression;
2712             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2713                 if expr.is_missing() {
2714                     Ok(new(pos, S_::Noop))
2715                 } else {
2716                     Ok(new(
2717                         pos,
2718                         S_::mk_expr(p_expr_with_loc(ExprLocation::AsStatement, expr, e)?),
2719                     ))
2720                 }
2721             };
2722             if is_simple_assignment_await_expression(expr) || is_simple_await_expression(expr) {
2723                 f(env)
2724             } else {
2725                 lift_awaits_in_statement(f, node, env)
2726             }
2727         }
2728         CompoundStatement(c) => handle_loop_body(pos, &c.statements, env),
2729         SyntaxList(_) => handle_loop_body(pos, node, env),
2730         ThrowStatement(c) => lift_awaits_in_statement(
2731             |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2732                 Ok(new(pos, S_::mk_throw(p_expr(&c.expression, e)?)))
2733             },
2734             node,
2735             env,
2736         ),
2737         DoStatement(c) => Ok(new(
2738             pos,
2739             S_::mk_do(
2740                 p_block(false /* remove noop */, &c.body, env)?,
2741                 p_expr(&c.condition, env)?,
2742             ),
2743         )),
2744         WhileStatement(c) => Ok(new(
2745             pos,
2746             S_::mk_while(p_expr(&c.condition, env)?, p_block(true, &c.body, env)?),
2747         )),
2748         UsingStatementBlockScoped(c) => {
2749             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2750                 Ok(new(
2751                     pos,
2752                     S_::mk_using(ast::UsingStmt {
2753                         is_block_scoped: true,
2754                         has_await: !&c.await_keyword.is_missing(),
2755                         exprs: p_exprs_with_loc(&c.expressions, e)?,
2756                         block: p_block(false, &c.body, e)?,
2757                     }),
2758                 ))
2759             };
2760             lift_awaits_in_statement(f, node, env)
2761         }
2762         UsingStatementFunctionScoped(c) => {
2763             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2764                 Ok(new(
2765                     pos,
2766                     S_::mk_using(ast::UsingStmt {
2767                         is_block_scoped: false,
2768                         has_await: !&c.await_keyword.is_missing(),
2769                         exprs: p_exprs_with_loc(&c.expression, e)?,
2770                         block: vec![mk_noop(e)],
2771                     }),
2772                 ))
2773             };
2774             lift_awaits_in_statement(f, node, env)
2775         }
2776         ForStatement(c) => {
2777             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2778                 let ini = p_expr_l(&c.initializer, e)?;
2779                 let ctr = mp_optional(p_expr, &c.control, e)?;
2780                 let eol = p_expr_l(&c.end_of_loop, e)?;
2781                 let blk = p_block(true, &c.body, e)?;
2782                 Ok(Stmt::new(pos, S_::mk_for(ini, ctr, eol, blk)))
2783             };
2784             lift_awaits_in_statement(f, node, env)
2785         }
2786         ForeachStatement(c) => {
2787             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2788                 let col = p_expr(&c.collection, e)?;
2789                 let akw = match token_kind(&c.await_keyword) {
2790                     Some(TK::Await) => Some(p_pos(&c.await_keyword, e)),
2791                     _ => None,
2792                 };
2793                 let value = p_expr(&c.value, e)?;
2794                 let akv = match (akw, &c.key.children) {
2795                     (Some(p), Missing) => ast::AsExpr::AwaitAsV(p, value),
2796                     (None, Missing) => ast::AsExpr::AsV(value),
2797                     (Some(p), _) => ast::AsExpr::AwaitAsKv(p, p_expr(&c.key, e)?, value),
2798                     (None, _) => ast::AsExpr::AsKv(p_expr(&c.key, e)?, value),
2799                 };
2800                 let blk = p_block(true, &c.body, e)?;
2801                 Ok(new(pos, S_::mk_foreach(col, akv, blk)))
2802             };
2803             lift_awaits_in_statement(f, node, env)
2804         }
2805         TryStatement(c) => Ok(new(
2806             pos,
2807             S_::mk_try(
2808                 p_block(false, &c.compound_statement, env)?,
2809                 could_map(
2810                     |n: S<'a>, e| match &n.children {
2811                         CatchClause(c) => Ok(ast::Catch(
2812                             pos_name(&c.type_, e)?,
2813                             lid_from_name(&c.variable, e)?,
2814                             p_block(true, &c.body, e)?,
2815                         )),
2816                         _ => missing_syntax("catch clause", n, e),
2817                     },
2818                     &c.catch_clauses,
2819                     env,
2820                 )?,
2821                 match &c.finally_clause.children {
2822                     FinallyClause(c) => p_block(false, &c.body, env)?,
2823                     _ => vec![],
2824                 },
2825             ),
2826         )),
2827         ReturnStatement(c) => {
2828             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2829                 let expr = match &c.expression.children {
2830                     Missing => None,
2831                     _ => Some(p_expr_with_loc(
2832                         ExprLocation::RightOfReturn,
2833                         &c.expression,
2834                         e,
2835                     )?),
2836                 };
2837                 Ok(ast::Stmt::new(pos, ast::Stmt_::mk_return(expr)))
2838             };
2839             if is_simple_await_expression(&c.expression) {
2840                 f(env)
2841             } else {
2842                 lift_awaits_in_statement(f, node, env)
2843             }
2844         }
2845         YieldBreakStatement(_) => Ok(ast::Stmt::new(pos, ast::Stmt_::mk_yield_break())),
2846         EchoStatement(c) => {
2847             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2848                 let echo = match &c.keyword.children {
2849                     QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2850                         let name = pos_name(&c.keyword, e)?;
2851                         ast::Expr::new((), name.0.clone(), E_::mk_id(name))
2852                     }
2853                     _ => missing_syntax("id", &c.keyword, e)?,
2854                 };
2855                 let args = could_map(p_expr_for_normal_argument, &c.expressions, e)?;
2856                 Ok(new(
2857                     pos.clone(),
2858                     S_::mk_expr(ast::Expr::new(
2859                         (),
2860                         pos,
2861                         E_::mk_call(echo, vec![], args, None),
2862                     )),
2863                 ))
2864             };
2865             lift_awaits_in_statement(f, node, env)
2866         }
2867         UnsetStatement(c) => {
2868             let f = |e: &mut Env<'a>| -> Result<ast::Stmt, Error> {
2869                 let args = could_map(p_expr_for_normal_argument, &c.variables, e)?;
2870                 args.iter()
2871                     .for_each(|(_, arg)| check_mutate_class_const(arg, node, e));
2872                 let unset = match &c.keyword.children {
2873                     QualifiedName(_) | SimpleTypeSpecifier(_) | Token(_) => {
2874                         let name = pos_name(&c.keyword, e)?;
2875                         ast::Expr::new((), name.0.clone(), E_::mk_id(name))
2876                     }
2877                     _ => missing_syntax("id", &c.keyword, e)?,
2878                 };
2879                 Ok(new(
2880                     pos.clone(),
2881                     S_::mk_expr(ast::Expr::new(
2882                         (),
2883                         pos,
2884                         E_::mk_call(unset, vec![], args, None),
2885                     )),
2886                 ))
2887             };
2888             lift_awaits_in_statement(f, node, env)
2889         }
2890         BreakStatement(_) => Ok(new(pos, S_::Break)),
2891         ContinueStatement(_) => Ok(new(pos, S_::Continue)),
2892         ConcurrentStatement(c) => {
2893             let keyword_pos = p_pos(&c.keyword, env);
2894             let (lifted_awaits, Stmt(stmt_pos, stmt)) =
2895                 with_new_concurrent_scope(|e: &mut Env<'a>| p_stmt(&c.statement, e), env)?;
2896             let stmt = match stmt {
2897                 S_::Block(stmts) => {
2898                     use ast::Bop::Eq;
2899                     use ast::Expr as E;
2900                     /* Reuse tmp vars from lifted_awaits, this is safe because there will
2901                      * always be more awaits with tmp vars than statements with assignments */
2902                     let mut tmp_vars = lifted_awaits
2903                         .iter()
2904                         .filter_map(|lifted_await| lifted_await.0.as_ref().map(|x| &x.1));
2905                     let mut body_stmts = vec![];
2906                     let mut assign_stmts = vec![];
2907                     for n in stmts.into_iter() {
2908                         if !n.is_assign_expr() {
2909                             body_stmts.push(n);
2910                             continue;
2911                         }
2913                         if let Some(tv) = tmp_vars.next() {
2914                             if let Stmt(p1, S_::Expr(expr)) = n {
2915                                 if let E(_, p2, E_::Binop(bop)) = *expr {
2916                                     if let (Eq(op), e1, e2) = *bop {
2917                                         let tmp_n = E::mk_lvar(&e2.1, &(tv.1));
2918                                         if tmp_n.lvar_name() != e2.lvar_name() {
2919                                             let new_n = new(
2920                                                 p1.clone(),
2921                                                 S_::mk_expr(E::new(
2922                                                     (),
2923                                                     p2.clone(),
2924                                                     E_::mk_binop(
2925                                                         Eq(None),
2926                                                         tmp_n.clone(),
2927                                                         e2.clone(),
2928                                                     ),
2929                                                 )),
2930                                             );
2931                                             body_stmts.push(new_n);
2932                                         }
2933                                         let assign_stmt = new(
2934                                             p1,
2935                                             S_::mk_expr(E::new(
2936                                                 (),
2937                                                 p2,
2938                                                 E_::mk_binop(Eq(op), e1, tmp_n),
2939                                             )),
2940                                         );
2941                                         assign_stmts.push(assign_stmt);
2942                                         continue;
2943                                     }
2944                                 }
2945                             }
2947                             failwith("Expect assignment stmt")?;
2948                         } else {
2949                             raise_parsing_error_pos(
2950                                 &stmt_pos,
2951                                 env,
2952                                 &syntax_error::statement_without_await_in_concurrent_block,
2953                             );
2954                             body_stmts.push(n)
2955                         }
2956                     }
2957                     body_stmts.append(&mut assign_stmts);
2958                     new(stmt_pos, S_::mk_block(body_stmts))
2959                 }
2960                 _ => failwith("Unexpected concurrent stmt structure")?,
2961             };
2962             Ok(new(keyword_pos, S_::mk_awaitall(lifted_awaits, vec![stmt])))
2963         }
2964         MarkupSection(_) => p_markup(node, env),
2965         _ => missing_syntax_(
2966             Some(new(env.mk_none_pos(), S_::Noop)),
2967             "statement",
2968             node,
2969             env,
2970         ),
2971     }
2973 fn check_mutate_class_const<'a>(e: &ast::Expr, node: S<'a>, env: &mut Env<'a>) {
2974     match &e.2 {
2975         E_::ArrayGet(c) if c.1.is_some() => check_mutate_class_const(&c.0, node, env),
2976         E_::ClassConst(_) => raise_parsing_error(node, env, &syntax_error::const_mutation),
2977         _ => {}
2978     }
2981 fn p_markup<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Stmt, Error> {
2982     match &node.children {
2983         MarkupSection(c) => {
2984             let markup_hashbang = &c.hashbang;
2985             let markup_suffix = &c.suffix;
2986             let pos = p_pos(node, env);
2987             let f = pos.filename();
2988             let expected_suffix_offset = if markup_hashbang.is_missing() {
2989                 0
2990             } else {
2991                 markup_hashbang.width() + 1 /* for newline */
2992             };
2993             if (f.has_extension("hack") || f.has_extension("hackpartial"))
2994                 && !(markup_suffix.is_missing())
2995             {
2996                 let ext = f.path().extension().unwrap(); // has_extension ensures this is a Some
2997                 raise_parsing_error(node, env, &syntax_error::error1060(ext.to_str().unwrap()));
2998             } else if f.has_extension("php")
2999                 && !markup_suffix.is_missing()
3000                 && markup_suffix.offset() != Some(expected_suffix_offset)
3001             {
3002                 raise_parsing_error(markup_suffix, env, &syntax_error::error1001);
3003             }
3004             let stmt_ = ast::Stmt_::mk_markup((pos.clone(), text(markup_hashbang, env)));
3005             Ok(ast::Stmt::new(pos, stmt_))
3006         }
3007         _ => failwith("invalid node"),
3008     }
3011 fn p_modifiers<'a, F: Fn(R, modifier::Kind) -> R, R>(
3012     on_kind: F,
3013     mut init: R,
3014     node: S<'a>,
3015     env: &mut Env<'a>,
3016 ) -> Result<(modifier::KindSet, R), Error> {
3017     let mut kind_set = modifier::KindSet::new();
3018     for n in node.syntax_node_to_list_skip_separator() {
3019         let token_kind = token_kind(n).and_then(modifier::from_token_kind);
3020         match token_kind {
3021             Some(kind) => {
3022                 kind_set.add(kind);
3023                 init = on_kind(init, kind);
3024             }
3025             _ => missing_syntax("kind", n, env)?,
3026         }
3027     }
3028     Ok((kind_set, init))
3031 fn p_kinds<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<modifier::KindSet, Error> {
3032     p_modifiers(|_, _| {}, (), node, env).map(|r| r.0)
3035 /// Apply `f` to every item in `node`, and build a vec of the values returned.
3036 fn could_map<'a, R, F>(f: F, node: S<'a>, env: &mut Env<'a>) -> Result<Vec<R>, Error>
3037 where
3038     F: Fn(S<'a>, &mut Env<'a>) -> Result<R, Error>,
3040     let nodes = node.syntax_node_to_list_skip_separator();
3041     let mut res = Vec::with_capacity(nodes.size_hint().0);
3042     for n in nodes {
3043         res.push(f(n, env)?);
3044     }
3045     Ok(res)
3048 fn p_visibility<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Option<ast::Visibility>, Error> {
3049     let first_vis = |r: Option<ast::Visibility>, kind| r.or_else(|| modifier::to_visibility(kind));
3050     p_modifiers(first_vis, None, node, env).map(|r| r.1)
3053 fn p_visibility_last_win<'a>(
3054     node: S<'a>,
3055     env: &mut Env<'a>,
3056 ) -> Result<Option<ast::Visibility>, Error> {
3057     let last_vis = |r, kind| modifier::to_visibility(kind).or(r);
3058     p_modifiers(last_vis, None, node, env).map(|r| r.1)
3061 fn p_visibility_last_win_or<'a>(
3062     node: S<'a>,
3063     env: &mut Env<'a>,
3064     default: ast::Visibility,
3065 ) -> Result<ast::Visibility, Error> {
3066     p_visibility_last_win(node, env).map(|v| v.unwrap_or(default))
3069 fn has_soft(attrs: &[ast::UserAttribute]) -> bool {
3070     attrs.iter().any(|attr| attr.name.1 == special_attrs::SOFT)
3073 fn soften_hint(attrs: &[ast::UserAttribute], hint: ast::Hint) -> ast::Hint {
3074     if has_soft(attrs) {
3075         ast::Hint::new(hint.0.clone(), ast::Hint_::Hsoft(hint))
3076     } else {
3077         hint
3078     }
3081 fn strip_ns(name: &str) -> &str {
3082     match name.chars().next() {
3083         Some('\\') => &name[1..],
3084         _ => name,
3085     }
3088 fn has_polymorphic_context_single<'a>(env: &mut Env<'a>, hint: &ast::Hint) -> bool {
3089     use ast::Hint_::{Haccess, Happly, HfunContext, Hvar};
3090     match *hint.1 {
3091         HfunContext(_) => true,
3092         Haccess(ref root, _) => match &*root.1 {
3093             Happly(oxidized::ast::Id(_, id), _) => {
3094                 let s = id.as_str();
3095                 /* TODO(coeffects) There is an opportunity to represent this structurally
3096                  * in the AST if we refactor so generic hints lower as Habstr instead of
3097                  * Happly, like we do in the direct decl parser. */
3098                 strip_ns(s) == naming_special_names_rust::typehints::THIS
3099                     || env.fn_generics_mut().contains_key(s)
3100                     || env.cls_generics_mut().contains_key(s)
3101             }
3102             Hvar(_) => true,
3103             _ => false,
3104         },
3105         _ => false,
3106     }
3109 fn has_polymorphic_context<'a>(env: &mut Env<'a>, contexts: Option<&ast::Contexts>) -> bool {
3110     if let Some(ast::Contexts(_, ref context_hints)) = contexts {
3111         return context_hints
3112             .iter()
3113             .any(|c| has_polymorphic_context_single(env, c));
3114     } else {
3115         false
3116     }
3119 fn has_any_policied_context(contexts: Option<&ast::Contexts>) -> bool {
3120     if let Some(ast::Contexts(_, ref context_hints)) = contexts {
3121         return context_hints.iter().any(|hint| match &*hint.1 {
3122             ast::Hint_::Happly(ast::Id(_, id), _) => {
3123                 naming_special_names_rust::coeffects::is_any_zoned(id)
3124             }
3125             _ => false,
3126         });
3127     } else {
3128         false
3129     }
3132 // For polymorphic context with form `ctx $f`
3133 // require that `(function (ts)[_]: t) $f` exists
3134 // rewrite as `(function (ts)[ctx $f]: t) $f`
3135 // add a type parameter named "T/[ctx $f]"
3136 fn rewrite_fun_ctx<'a>(
3137     env: &mut Env<'a>,
3138     tparams: &mut Vec<ast::Tparam>,
3139     hint: &mut ast::Hint,
3140     name: &str,
3141 ) {
3142     use ast::{Hint_, ReifyKind, Variance};
3144     let mut invalid =
3145         |p| raise_parsing_error_pos(p, env, &syntax_error::ctx_fun_invalid_type_hint(name));
3146     match *hint.1 {
3147         Hint_::Hfun(ref mut hf) => {
3148             if let Some(ast::Contexts(ref p, ref mut hl)) = &mut hf.ctxs {
3149                 if let [ref mut h] = *hl.as_mut_slice() {
3150                     if let Hint_::Happly(ast::Id(ref pos, s), _) = &*h.1 {
3151                         if s == "_" {
3152                             *h.1 = Hint_::HfunContext(name.to_string());
3153                             tparams.push(ast::Tparam {
3154                                 variance: Variance::Invariant,
3155                                 name: ast::Id(h.0.clone(), format!("T/[ctx {}]", name)),
3156                                 parameters: vec![],
3157                                 constraints: vec![],
3158                                 reified: ReifyKind::Erased,
3159                                 user_attributes: vec![],
3160                             });
3161                         } else {
3162                             invalid(pos);
3163                         }
3164                     } else {
3165                         invalid(p);
3166                     }
3167                 } else {
3168                     invalid(p);
3169                 }
3170             } else {
3171                 invalid(&hint.0);
3172             }
3173         }
3174         Hint_::Hlike(ref mut h) | Hint_::Hoption(ref mut h) => {
3175             rewrite_fun_ctx(env, tparams, h, name)
3176         }
3177         Hint_::Happly(ast::Id(_, ref type_name), ref mut targs)
3178             if type_name == special_typehints::SUPPORTDYN =>
3179         {
3180             if let Some(ref mut h) = targs.first_mut() {
3181                 rewrite_fun_ctx(env, tparams, h, name)
3182             } else {
3183                 invalid(&hint.0)
3184             }
3185         }
3186         _ => invalid(&hint.0),
3187     }
3189 fn rewrite_effect_polymorphism<'a>(
3190     env: &mut Env<'a>,
3191     params: &mut Vec<ast::FunParam>,
3192     tparams: &mut Vec<ast::Tparam>,
3193     contexts: Option<&ast::Contexts>,
3194     where_constraints: &mut Vec<ast::WhereConstraintHint>,
3195 ) {
3196     use ast::{Hint, Hint_, ReifyKind, Variance};
3197     use Hint_::{Haccess, Happly, HfunContext, Hvar};
3199     if !has_polymorphic_context(env, contexts) {
3200         return;
3201     }
3202     let ast::Contexts(ref _p, ref context_hints) = contexts.as_ref().unwrap();
3203     let tp = |name, v| ast::Tparam {
3204         variance: Variance::Invariant,
3205         name,
3206         parameters: vec![],
3207         constraints: v,
3208         reified: ReifyKind::Erased,
3209         user_attributes: vec![],
3210     };
3212     // For polymorphic context with form `$g::C`
3213     // if $g's type is not a type parameter
3214     //   add one named "T/$g" constrained by $g's type
3215     //   replace $g's type hint
3216     // let Tg denote $g's final type (must be a type parameter).
3217     // add a type parameter "T/[$g::C]"
3218     // add a where constraint T/[$g::C] = Tg :: C
3219     let rewrite_arg_ctx = |
3220         env: &mut Env<'a>,
3221         tparams: &mut Vec<ast::Tparam>,
3222         where_constraints: &mut Vec<ast::WhereConstraintHint>,
3223         hint: &mut Hint,
3224         param_pos: &Pos,
3225         name: &str,
3226         context_pos: &Pos,
3227         cst: &ast::Id,
3228     | match *hint.1 {
3229         Happly(ast::Id(_, ref type_name), _) => {
3230             if !tparams.iter().any(|h| h.name.1 == *type_name) {
3231                 // If the parameter is X $g, create tparam `T$g as X` and replace $g's type hint
3232                 let id = ast::Id(param_pos.clone(), "T/".to_string() + name);
3233                 tparams.push(tp(
3234                     id.clone(),
3235                     vec![(ast::ConstraintKind::ConstraintAs, hint.clone())],
3236                 ));
3237                 *hint = ast::Hint::new(param_pos.clone(), Happly(id, vec![]));
3238             };
3239             let right = ast::Hint::new(
3240                 context_pos.clone(),
3241                 Haccess(hint.clone(), vec![cst.clone()]),
3242             );
3243             let left_id = ast::Id(context_pos.clone(), format!("T/[{}::{}]", name, &cst.1));
3244             tparams.push(tp(left_id.clone(), vec![]));
3245             let left = ast::Hint::new(context_pos.clone(), Happly(left_id, vec![]));
3246             where_constraints.push(ast::WhereConstraintHint(
3247                 left,
3248                 ast::ConstraintKind::ConstraintEq,
3249                 right,
3250             ))
3251         }
3252         _ => raise_parsing_error_pos(&hint.0, env, &syntax_error::ctx_var_invalid_type_hint(name)),
3253     };
3255     let mut hint_by_param: HashMap<&str, (&mut Option<ast::Hint>, &Pos, aast::IsVariadic)> =
3256         HashMap::default();
3257     for param in params.iter_mut() {
3258         hint_by_param.insert(
3259             param.name.as_ref(),
3260             (&mut param.type_hint.1, &param.pos, param.is_variadic),
3261         );
3262     }
3265     for context_hint in context_hints {
3266         match *context_hint.1 {
3267             HfunContext(ref name) => match hint_by_param.get_mut::<str>(name) {
3268                 Some((hint_opt, param_pos, _is_variadic)) => match hint_opt {
3269                     Some(_) if env.codegen() => {}
3270                     Some(ref mut param_hint) => rewrite_fun_ctx(env, tparams, param_hint, name),
3271                     None => raise_parsing_error_pos(
3272                         param_pos,
3273                         env,
3274                         &syntax_error::ctx_var_missing_type_hint(name),
3275                     ),
3276                 },
3278                 None => raise_parsing_error_pos(
3279                     &context_hint.0,
3280                     env,
3281                     &syntax_error::ctx_var_invalid_parameter(name),
3282                 ),
3283             },
3284             Haccess(ref root, ref csts) => {
3285                 if let Hvar(ref name) = *root.1 {
3286                     match hint_by_param.get_mut::<str>(name) {
3287                         Some((hint_opt, param_pos, is_variadic)) => {
3288                             if *is_variadic {
3289                                 raise_parsing_error_pos(
3290                                     param_pos,
3291                                     env,
3292                                     &syntax_error::ctx_var_variadic(name),
3293                                 )
3294                             } else {
3295                                 match hint_opt {
3296                                     Some(_) if env.codegen() => {}
3297                                     Some(ref mut param_hint) => {
3298                                         let mut rewrite = |h| {
3299                                             rewrite_arg_ctx(
3300                                                 env,
3301                                                 tparams,
3302                                                 where_constraints,
3303                                                 h,
3304                                                 param_pos,
3305                                                 name,
3306                                                 &context_hint.0,
3307                                                 &csts[0],
3308                                             )
3309                                         };
3310                                         match *param_hint.1 {
3311                                             Hint_::Hlike(ref mut h) => match *h.1 {
3312                                                 Hint_::Hoption(ref mut hinner) => rewrite(hinner),
3313                                                 _ => rewrite(h),
3314                                             },
3315                                             Hint_::Hoption(ref mut h) => rewrite(h),
3316                                             _ => rewrite(param_hint),
3317                                         }
3318                                     }
3319                                     None => raise_parsing_error_pos(
3320                                         param_pos,
3321                                         env,
3322                                         &syntax_error::ctx_var_missing_type_hint(name),
3323                                     ),
3324                                 }
3325                             }
3326                         }
3327                         None => raise_parsing_error_pos(
3328                             &root.0,
3329                             env,
3330                             &syntax_error::ctx_var_invalid_parameter(name),
3331                         ),
3332                     }
3333                 } else if let Happly(ast::Id(_, ref id), _) = *root.1 {
3334                     // For polymorphic context with form `T::*::C` where `T` is a reified generic
3335                     // add a type parameter "T/[T::*::C]"
3336                     // add a where constraint T/[T::*::C] = T :: C
3337                     let haccess_string = |id, csts: &Vec<aast::Sid>| {
3338                         format!("{}::{}", id, csts.iter().map(|c| c.1.clone()).join("::"))
3339                     };
3341                     match env.get_reification(id) {
3342                         None => {} // not a generic
3343                         Some(false) => raise_parsing_error_pos(
3344                             &root.0,
3345                             env,
3346                             &syntax_error::ctx_generic_invalid(id, haccess_string(id, csts)),
3347                         ),
3348                         Some(true) if env.codegen() => {}
3349                         Some(true) => {
3350                             let left_id = ast::Id(
3351                                 context_hint.0.clone(),
3352                                 format!("T/[{}]", haccess_string(id, csts)),
3353                             );
3354                             tparams.push(tp(left_id.clone(), vec![]));
3355                             let left =
3356                                 ast::Hint::new(context_hint.0.clone(), Happly(left_id, vec![]));
3357                             where_constraints.push(ast::WhereConstraintHint(
3358                                 left,
3359                                 ast::ConstraintKind::ConstraintEq,
3360                                 context_hint.clone(),
3361                             ));
3362                         }
3363                     }
3364                 }
3365             }
3366             _ => {}
3367         }
3368     }
3371 fn p_fun_param_default_value<'a>(
3372     node: S<'a>,
3373     env: &mut Env<'a>,
3374 ) -> Result<Option<ast::Expr>, Error> {
3375     match &node.children {
3376         SimpleInitializer(c) => mp_optional(p_expr, &c.value, env),
3377         _ => Ok(None),
3378     }
3381 fn p_param_kind<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::ParamKind, Error> {
3382     match token_kind(node) {
3383         Some(TK::Inout) => Ok(ast::ParamKind::Pinout(p_pos(node, env))),
3384         None => Ok(ast::ParamKind::Pnormal),
3385         _ => missing_syntax("param kind", node, env),
3386     }
3389 fn p_readonly<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::ReadonlyKind, Error> {
3390     match token_kind(node) {
3391         Some(TK::Readonly) => Ok(ast::ReadonlyKind::Readonly),
3392         _ => missing_syntax("readonly", node, env),
3393     }
3396 fn param_template<'a>(node: S<'a>, env: &Env<'_>) -> ast::FunParam {
3397     let pos = p_pos(node, env);
3398     ast::FunParam {
3399         annotation: (),
3400         type_hint: ast::TypeHint((), None),
3401         is_variadic: false,
3402         pos,
3403         name: text(node, env),
3404         expr: None,
3405         callconv: ast::ParamKind::Pnormal,
3406         readonly: None,
3407         user_attributes: vec![],
3408         visibility: None,
3409     }
3412 fn p_fun_param<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::FunParam, Error> {
3413     match &node.children {
3414         ParameterDeclaration(ParameterDeclarationChildren {
3415             attribute,
3416             visibility,
3417             call_convention,
3418             readonly,
3419             type_,
3420             name,
3421             default_value,
3422         }) => {
3423             let (is_variadic, name) = match &name.children {
3424                 DecoratedExpression(DecoratedExpressionChildren {
3425                     decorator,
3426                     expression,
3427                 }) => {
3428                     let decorator = text_str(decorator, env);
3429                     match &expression.children {
3430                         DecoratedExpression(c) => {
3431                             let nested_expression = &c.expression;
3432                             let nested_decorator = text_str(&c.decorator, env);
3433                             (
3434                                 decorator == "..." || nested_decorator == "...",
3435                                 nested_expression,
3436                             )
3437                         }
3438                         _ => (decorator == "...", expression),
3439                     }
3440                 }
3441                 _ => (false, name),
3442             };
3443             let user_attributes = p_user_attributes(attribute, env)?;
3444             let pos = p_pos(name, env);
3445             let name = text(name, env);
3446             let hint = mp_optional(p_hint, type_, env)?;
3447             let hint = hint.map(|h| soften_hint(&user_attributes, h));
3449             if is_variadic && !user_attributes.is_empty() {
3450                 raise_parsing_error(
3451                     node,
3452                     env,
3453                     &syntax_error::no_attributes_on_variadic_parameter,
3454                 );
3455             }
3456             Ok(ast::FunParam {
3457                 annotation: (),
3458                 type_hint: ast::TypeHint((), hint),
3459                 user_attributes,
3460                 is_variadic,
3461                 pos,
3462                 name,
3463                 expr: p_fun_param_default_value(default_value, env)?,
3464                 callconv: p_param_kind(call_convention, env)?,
3465                 readonly: mp_optional(p_readonly, readonly, env)?,
3466                 /* implicit field via constructor parameter.
3467                  * This is always None except for constructors and the modifier
3468                  * can be only Public or Protected or Private.
3469                  */
3470                 visibility: p_visibility(visibility, env)?,
3471             })
3472         }
3473         VariadicParameter(_) => {
3474             let mut param = param_template(node, env);
3475             param.is_variadic = true;
3476             Ok(param)
3477         }
3478         Token(_) if text_str(node, env) == "..." => {
3479             let mut param = param_template(node, env);
3480             param.is_variadic = true;
3481             Ok(param)
3482         }
3483         _ => missing_syntax("function parameter", node, env),
3484     }
3487 fn p_tconstraint_ty<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Hint, Error> {
3488     match &node.children {
3489         TypeConstraint(c) => p_hint(&c.type_, env),
3490         _ => missing_syntax("type constraint", node, env),
3491     }
3494 fn p_tconstraint<'a>(
3495     node: S<'a>,
3496     env: &mut Env<'a>,
3497 ) -> Result<(ast::ConstraintKind, ast::Hint), Error> {
3498     match &node.children {
3499         TypeConstraint(c) => Ok((
3500             match token_kind(&c.keyword) {
3501                 Some(TK::As) => ast::ConstraintKind::ConstraintAs,
3502                 Some(TK::Super) => ast::ConstraintKind::ConstraintSuper,
3503                 Some(TK::Equal) => ast::ConstraintKind::ConstraintEq,
3504                 _ => missing_syntax("constraint operator", &c.keyword, env)?,
3505             },
3506             p_hint(&c.type_, env)?,
3507         )),
3508         _ => missing_syntax("type constraint", node, env),
3509     }
3512 fn p_tparam<'a>(is_class: bool, node: S<'a>, env: &mut Env<'a>) -> Result<ast::Tparam, Error> {
3513     match &node.children {
3514         TypeParameter(TypeParameterChildren {
3515             attribute_spec,
3516             reified,
3517             variance,
3518             name,
3519             param_params,
3520             constraints,
3521         }) => {
3522             let user_attributes = p_user_attributes(attribute_spec, env)?;
3523             let is_reified = !reified.is_missing();
3525             let type_name = text(name, env);
3526             if is_class {
3527                 env.cls_generics_mut().insert(type_name, is_reified);
3528             } else {
3529                 // this is incorrect for type aliases, but it doesn't affect any check
3530                 env.fn_generics_mut().insert(type_name, is_reified);
3531             }
3533             let variance = match token_kind(variance) {
3534                 Some(TK::Plus) => ast::Variance::Covariant,
3535                 Some(TK::Minus) => ast::Variance::Contravariant,
3536                 _ => ast::Variance::Invariant,
3537             };
3538             if is_reified && variance != ast::Variance::Invariant {
3539                 raise_parsing_error(node, env, &syntax_error::non_invariant_reified_generic);
3540             }
3541             let reified = match (is_reified, has_soft(&user_attributes)) {
3542                 (true, true) => ast::ReifyKind::SoftReified,
3543                 (true, false) => ast::ReifyKind::Reified,
3544                 _ => ast::ReifyKind::Erased,
3545             };
3546             let parameters = p_tparam_l(is_class, param_params, env)?;
3547             Ok(ast::Tparam {
3548                 variance,
3549                 name: pos_name(name, env)?,
3550                 parameters,
3551                 constraints: could_map(p_tconstraint, constraints, env)?,
3552                 reified,
3553                 user_attributes,
3554             })
3555         }
3556         _ => missing_syntax("type parameter", node, env),
3557     }
3560 fn p_tparam_l<'a>(
3561     is_class: bool,
3562     node: S<'a>,
3563     env: &mut Env<'a>,
3564 ) -> Result<Vec<ast::Tparam>, Error> {
3565     match &node.children {
3566         Missing => Ok(vec![]),
3567         TypeParameters(c) => could_map(|n, e| p_tparam(is_class, n, e), &c.parameters, env),
3568         _ => missing_syntax("type parameter", node, env),
3569     }
3572 /// Lowers multiple constraints into a hint pair (lower_bound, upper_bound)
3573 fn p_ctx_constraints<'a>(
3574     node: S<'a>,
3575     env: &mut Env<'a>,
3576 ) -> Result<(Option<ast::Hint>, Option<ast::Hint>), Error> {
3577     let constraints = could_map(
3578         |node, env| {
3579             if let ContextConstraint(c) = &node.children {
3580                 if let Some(hint) = p_context_list_to_intersection(&c.ctx_list, env)? {
3581                     Ok(match token_kind(&c.keyword) {
3582                         Some(TK::Super) => Either::Left(hint),
3583                         Some(TK::As) => Either::Right(hint),
3584                         _ => missing_syntax("constraint operator", &c.keyword, env)?,
3585                     })
3586                 } else {
3587                     missing_syntax("contexts", &c.keyword, env)?
3588                 }
3589             } else {
3590                 missing_syntax("context constraint", node, env)?
3591             }
3592         },
3593         node,
3594         env,
3595     )?;
3596     let (super_constraint, as_constraint) = constraints.into_iter().partition_map(|x| x);
3597     let require_one = &mut |kind: &str, cs: Vec<_>| {
3598         if cs.len() > 1 {
3599             let msg = format!(
3600                 "Multiple `{}` constraints on a ctx constant are not allowed",
3601                 kind
3602             );
3603             raise_parsing_error(node, env, &msg);
3604         }
3605         cs.into_iter().next()
3606     };
3607     Ok((
3608         require_one("super", super_constraint),
3609         require_one("as", as_constraint),
3610     ))
3613 fn p_contexts<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Option<ast::Contexts>, Error> {
3614     match &node.children {
3615         Missing => Ok(None),
3616         Contexts(c) => {
3617             let hints = could_map(&p_hint, &c.types, env)?;
3618             let pos = p_pos(node, env);
3619             let ctxs = ast::Contexts(pos, hints);
3620             Ok(Some(ctxs))
3621         }
3622         _ => missing_syntax("contexts", node, env),
3623     }
3626 fn p_context_list_to_intersection<'a>(
3627     ctx_list: S<'a>,
3628     env: &mut Env<'a>,
3629 ) -> Result<Option<ast::Hint>, Error> {
3630     Ok(p_contexts(ctx_list, env)?.map(|t| ast::Hint::new(t.0, ast::Hint_::Hintersection(t.1))))
3633 fn p_fun_hdr<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<FunHdr, Error> {
3634     match &node.children {
3635         FunctionDeclarationHeader(FunctionDeclarationHeaderChildren {
3636             modifiers,
3637             name,
3638             where_clause,
3639             type_parameter_list,
3640             parameter_list,
3641             type_,
3642             contexts,
3643             readonly_return,
3644             ..
3645         }) => {
3646             if name.value.is_missing() {
3647                 raise_parsing_error(name, env, &syntax_error::empty_method_name);
3648             }
3649             let kinds = p_kinds(modifiers, env)?;
3650             let has_async = kinds.has(modifier::ASYNC);
3651             let readonly_this = if kinds.has(modifier::READONLY) {
3652                 Some(ast::ReadonlyKind::Readonly)
3653             } else {
3654                 None
3655             };
3656             let readonly_ret = mp_optional(p_readonly, readonly_return, env)?;
3657             let mut type_parameters = p_tparam_l(false, type_parameter_list, env)?;
3658             let mut parameters = could_map(p_fun_param, parameter_list, env)?;
3659             let contexts = p_contexts(contexts, env)?;
3660             let mut constrs = p_where_constraint(false, node, where_clause, env)?;
3661             rewrite_effect_polymorphism(
3662                 env,
3663                 &mut parameters,
3664                 &mut type_parameters,
3665                 contexts.as_ref(),
3666                 &mut constrs,
3667             );
3668             let return_type = mp_optional(p_hint, type_, env)?;
3669             let suspension_kind = mk_suspension_kind_(has_async);
3670             let name = pos_name(name, env)?;
3671             let unsafe_contexts = contexts.clone();
3672             Ok(FunHdr {
3673                 suspension_kind,
3674                 readonly_this,
3675                 name,
3676                 constrs,
3677                 type_parameters,
3678                 parameters,
3679                 contexts,
3680                 unsafe_contexts,
3681                 readonly_return: readonly_ret,
3682                 return_type,
3683             })
3684         }
3685         LambdaSignature(LambdaSignatureChildren {
3686             parameters,
3687             contexts,
3688             type_,
3689             readonly_return,
3690             ..
3691         }) => {
3692             let readonly_ret = mp_optional(p_readonly, readonly_return, env)?;
3693             let mut header = FunHdr::make_empty(env);
3694             header.parameters = could_map(p_fun_param, parameters, env)?;
3695             let contexts = p_contexts(contexts, env)?;
3696             let unsafe_contexts = contexts.clone();
3697             header.contexts = contexts;
3698             header.unsafe_contexts = unsafe_contexts;
3699             header.return_type = mp_optional(p_hint, type_, env)?;
3700             header.readonly_return = readonly_ret;
3701             Ok(header)
3702         }
3703         Token(_) => Ok(FunHdr::make_empty(env)),
3704         _ => missing_syntax("function header", node, env),
3705     }
3708 fn p_fun_pos<'a>(node: S<'a>, env: &Env<'_>) -> Pos {
3709     let get_pos = |n: S<'a>, p: Pos| -> Pos {
3710         if let FunctionDeclarationHeader(c1) = &n.children {
3711             if !c1.keyword.is_missing() {
3712                 return Pos::btw_nocheck(p_pos(&c1.keyword, env), p);
3713             }
3714         }
3715         p
3716     };
3717     let p = p_pos(node, env);
3718     match &node.children {
3719         FunctionDeclaration(c) if env.codegen() => get_pos(&c.declaration_header, p),
3720         MethodishDeclaration(c) if env.codegen() => get_pos(&c.function_decl_header, p),
3721         _ => p,
3722     }
3725 fn p_block<'a>(remove_noop: bool, node: S<'a>, env: &mut Env<'a>) -> Result<ast::Block, Error> {
3726     let ast::Stmt(p, stmt_) = p_stmt(node, env)?;
3727     if let ast::Stmt_::Block(blk) = stmt_ {
3728         if remove_noop && blk.len() == 1 && blk[0].1.is_noop() {
3729             return Ok(vec![]);
3730         }
3731         Ok(blk)
3732     } else {
3733         Ok(vec![ast::Stmt(p, stmt_)])
3734     }
3737 fn mk_noop(env: &Env<'_>) -> ast::Stmt {
3738     ast::Stmt::noop(env.mk_none_pos())
3741 fn p_function_body<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Block, Error> {
3742     let mk_noop_result = |e: &Env<'_>| Ok(vec![mk_noop(e)]);
3743     let f = |e: &mut Env<'a>| -> Result<ast::Block, Error> {
3744         match &node.children {
3745             Missing => Ok(vec![]),
3746             CompoundStatement(c) => {
3747                 let compound_statements = &c.statements.children;
3748                 let compound_right_brace = &c.right_brace.children;
3749                 match (compound_statements, compound_right_brace) {
3750                     (Missing, Token(_)) => mk_noop_result(e),
3751                     (SyntaxList(t), _) if t.len() == 1 && t[0].is_yield() => {
3752                         e.saw_yield = true;
3753                         mk_noop_result(e)
3754                     }
3755                     _ => {
3756                         if !e.top_level_statements
3757                             && ((e.file_mode() == file_info::Mode::Mhhi && !e.codegen())
3758                                 || e.quick_mode)
3759                         {
3760                             mk_noop_result(e)
3761                         } else {
3762                             p_block(false /*remove noop*/, node, e)
3763                         }
3764                     }
3765                 }
3766             }
3767             _ => {
3768                 let f = |e: &mut Env<'a>| {
3769                     let expr = p_expr(node, e)?;
3770                     Ok(ast::Stmt::new(
3771                         expr.1.clone(),
3772                         ast::Stmt_::mk_return(Some(expr)),
3773                     ))
3774                 };
3775                 if is_simple_await_expression(node) {
3776                     Ok(vec![f(e)?])
3777                 } else {
3778                     Ok(vec![lift_awaits_in_statement(f, node, e)?])
3779                 }
3780             }
3781         }
3782     };
3783     with_new_nonconcurrent_scope(f, env)
3786 fn mk_suspension_kind<'a>(async_keyword: S<'a>) -> SuspensionKind {
3787     mk_suspension_kind_(!async_keyword.is_missing())
3790 fn mk_suspension_kind_(has_async: bool) -> SuspensionKind {
3791     if has_async {
3792         SuspensionKind::SKAsync
3793     } else {
3794         SuspensionKind::SKSync
3795     }
3798 fn mk_fun_kind(suspension_kind: SuspensionKind, yield_: bool) -> ast::FunKind {
3799     use ast::FunKind::*;
3800     use SuspensionKind::*;
3801     match (suspension_kind, yield_) {
3802         (SKSync, true) => FGenerator,
3803         (SKAsync, true) => FAsyncGenerator,
3804         (SKSync, false) => FSync,
3805         (SKAsync, false) => FAsync,
3806     }
3809 fn process_attribute_constructor_call<'a>(
3810     node: S<'a>,
3811     constructor_call_argument_list: S<'a>,
3812     constructor_call_type: S<'a>,
3813     env: &mut Env<'a>,
3814 ) -> Result<ast::UserAttribute, Error> {
3815     let name = pos_name(constructor_call_type, env)?;
3816     if name.1.eq_ignore_ascii_case("__reified") || name.1.eq_ignore_ascii_case("__hasreifiedparent")
3817     {
3818         raise_parsing_error(node, env, &syntax_error::reified_attribute);
3819     } else if name.1.eq_ignore_ascii_case(special_attrs::SOFT)
3820         && constructor_call_argument_list
3821             .syntax_node_to_list_skip_separator()
3822             .count()
3823             > 0
3824     {
3825         raise_parsing_error(node, env, &syntax_error::soft_no_arguments);
3826     }
3827     let params = could_map(
3828         |n: S<'a>, e: &mut Env<'a>| -> Result<ast::Expr, Error> {
3829             is_valid_attribute_arg(n, e);
3830             p_expr(n, e)
3831         },
3832         constructor_call_argument_list,
3833         env,
3834     )?;
3835     Ok(ast::UserAttribute { name, params })
3838 // Arguments to attributes must be literals (int, string, etc), collections
3839 // (eg vec, dict, keyset, etc), Foo::class strings, shapes, string
3840 // concatenations, or tuples.
3841 fn is_valid_attribute_arg<'a>(node: S<'a>, env: &mut Env<'a>) {
3842     let mut is_valid_list = |nodes: S<'a>| {
3843         let _ = could_map(
3844             |n, e| {
3845                 is_valid_attribute_arg(n, e);
3846                 Ok(())
3847             },
3848             nodes,
3849             env,
3850         );
3851     };
3852     match &node.children {
3853         ParenthesizedExpression(c) => is_valid_attribute_arg(&c.expression, env),
3854         // Normal literals (string, int, etc)
3855         LiteralExpression(_) => {}
3856         // ::class strings
3857         ScopeResolutionExpression(c) => {
3858             if let Some(TK::Class) = token_kind(&c.name) {
3859             } else {
3860                 raise_parsing_error(node, env, &syntax_error::expression_as_attribute_arguments);
3861             }
3862         }
3863         // Negations
3864         PrefixUnaryExpression(c) => {
3865             is_valid_attribute_arg(&c.operand, env);
3866             match token_kind(&c.operator) {
3867                 Some(TK::Minus) => {}
3868                 Some(TK::Plus) => {}
3869                 _ => {
3870                     raise_parsing_error(node, env, &syntax_error::expression_as_attribute_arguments)
3871                 }
3872             }
3873         }
3874         // String concatenation
3875         BinaryExpression(c) => {
3876             if let Some(TK::Dot) = token_kind(&c.operator) {
3877                 is_valid_attribute_arg(&c.left_operand, env);
3878                 is_valid_attribute_arg(&c.right_operand, env);
3879             } else {
3880                 raise_parsing_error(node, env, &syntax_error::expression_as_attribute_arguments);
3881             }
3882         }
3883         // Top-level Collections
3884         DarrayIntrinsicExpression(c) => is_valid_list(&c.members),
3885         DictionaryIntrinsicExpression(c) => is_valid_list(&c.members),
3886         KeysetIntrinsicExpression(c) => is_valid_list(&c.members),
3887         VarrayIntrinsicExpression(c) => is_valid_list(&c.members),
3888         VectorIntrinsicExpression(c) => is_valid_list(&c.members),
3889         ShapeExpression(c) => is_valid_list(&c.fields),
3890         TupleExpression(c) => is_valid_list(&c.items),
3891         // Collection Internals
3892         FieldInitializer(c) => {
3893             is_valid_attribute_arg(&c.name, env);
3894             is_valid_attribute_arg(&c.value, env);
3895         }
3896         ElementInitializer(c) => {
3897             is_valid_attribute_arg(&c.key, env);
3898             is_valid_attribute_arg(&c.value, env);
3899         }
3900         // Everything else is not allowed
3901         _ => raise_parsing_error(node, env, &syntax_error::expression_as_attribute_arguments),
3902     }
3905 fn p_user_attribute<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::UserAttribute>, Error> {
3906     let p_attr = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::UserAttribute, Error> {
3907         match &n.children {
3908             ConstructorCall(c) => {
3909                 process_attribute_constructor_call(node, &c.argument_list, &c.type_, e)
3910             }
3911             _ => missing_syntax("attribute", node, e),
3912         }
3913     };
3914     match &node.children {
3915         FileAttributeSpecification(c) => could_map(p_attr, &c.attributes, env),
3916         OldAttributeSpecification(c) => could_map(p_attr, &c.attributes, env),
3917         AttributeSpecification(c) => could_map(
3918             |n: S<'a>, e: &mut Env<'a>| -> Result<ast::UserAttribute, Error> {
3919                 match &n.children {
3920                     Attribute(c) => p_attr(&c.attribute_name, e),
3921                     _ => missing_syntax("attribute", node, e),
3922                 }
3923             },
3924             &c.attributes,
3925             env,
3926         ),
3927         _ => missing_syntax("attribute specification", node, env),
3928     }
3931 fn p_user_attributes<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::UserAttribute>, Error> {
3932     let attributes = could_map(&p_user_attribute, node, env)?;
3933     Ok(attributes.into_iter().flatten().collect())
3936 fn mp_yielding<'a, F, R>(p: F, node: S<'a>, env: &mut Env<'a>) -> Result<(R, bool), Error>
3937 where
3938     F: FnOnce(S<'a>, &mut Env<'a>) -> Result<R, Error>,
3940     let outer_saw_yield = env.saw_yield;
3941     env.saw_yield = false;
3942     let r = p(node, env);
3943     let saw_yield = env.saw_yield;
3944     env.saw_yield = outer_saw_yield;
3945     Ok((r?, saw_yield))
3948 fn mk_empty_ns_env(env: &Env<'_>) -> RcOc<NamespaceEnv> {
3949     RcOc::clone(&env.empty_ns_env)
3952 fn extract_docblock<'a>(node: S<'a>, env: &Env<'_>) -> Option<DocComment> {
3953     #[derive(Copy, Clone, Eq, PartialEq)]
3954     enum ScanState {
3955         DocComment,
3956         EmbeddedCmt,
3957         EndDoc,
3958         EndEmbedded,
3959         Free,
3960         LineCmt,
3961         MaybeDoc,
3962         MaybeDoc2,
3963         SawSlash,
3964     }
3965     use ScanState::*;
3966     // `parse` mixes loop and recursion to use less stack space.
3967     fn parse(
3968         str: &str,
3969         start: usize,
3970         state: ScanState,
3971         idx: usize,
3972     ) -> Option<(usize, usize, String)> {
3973         let is_whitespace = |c| c == ' ' || c == '\t' || c == '\n' || c == '\r';
3974         let mut s = (start, state, idx);
3975         let chars = str.as_bytes();
3976         loop {
3977             if s.2 == str.len() {
3978                 break None;
3979             }
3981             let next = s.2 + 1;
3982             match (s.1, chars[s.2] as char) {
3983                 (LineCmt, '\n') => s = (next, Free, next),
3984                 (EndEmbedded, '/') => s = (next, Free, next),
3985                 (EndDoc, '/') => {
3986                     let r = parse(str, next, Free, next);
3987                     match r {
3988                         d @ Some(_) => break d,
3989                         None => break Some((s.0, s.2 + 1, String::from(&str[s.0..s.2 + 1]))),
3990                     }
3991                 }
3992                 /* PHP has line comments delimited by a # */
3993                 (Free, '#') => s = (next, LineCmt, next),
3994                 /* All other comment delimiters start with a / */
3995                 (Free, '/') => s = (s.2, SawSlash, next),
3996                 /* After a / in trivia, we must see either another / or a * */
3997                 (SawSlash, '/') => s = (next, LineCmt, next),
3998                 (SawSlash, '*') => s = (s.0, MaybeDoc, next),
3999                 (MaybeDoc, '*') => s = (s.0, MaybeDoc2, next),
4000                 (MaybeDoc, _) => s = (s.0, EmbeddedCmt, next),
4001                 (MaybeDoc2, '/') => s = (next, Free, next),
4002                 /* Doc comments have a space after the second star */
4003                 (MaybeDoc2, c) if is_whitespace(c) => s = (s.0, DocComment, s.2),
4004                 (MaybeDoc2, _) => s = (s.0, EmbeddedCmt, next),
4005                 (DocComment, '*') => s = (s.0, EndDoc, next),
4006                 (DocComment, _) => s = (s.0, DocComment, next),
4007                 (EndDoc, _) => s = (s.0, DocComment, next),
4008                 /* A * without a / does not end an embedded comment */
4009                 (EmbeddedCmt, '*') => s = (s.0, EndEmbedded, next),
4010                 (EndEmbedded, '*') => s = (s.0, EndEmbedded, next),
4011                 (EndEmbedded, _) => s = (s.0, EmbeddedCmt, next),
4012                 /* Whitespace skips everywhere else */
4013                 (_, c) if is_whitespace(c) => s = (s.0, s.1, next),
4014                 /* When scanning comments, anything else is accepted */
4015                 (LineCmt, _) => s = (s.0, s.1, next),
4016                 (EmbeddedCmt, _) => s = (s.0, s.1, next),
4017                 _ => break None,
4018             }
4019         }
4020     }
4021     let str = node.leading_text(env.indexed_source_text.source_text());
4022     parse(str, 0, Free, 0).map(|(start, end, txt)| {
4023         let anchor = node.leading_start_offset();
4024         let pos = env
4025             .indexed_source_text
4026             .relative_pos(anchor + start, anchor + end);
4027         let ps = (pos, txt);
4028         oxidized::doc_comment::DocComment::new(ps)
4029     })
4032 fn p_xhp_child<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::XhpChild, Error> {
4033     use ast::XhpChild::*;
4034     use ast::XhpChildOp::*;
4035     match &node.children {
4036         Token(_) => pos_name(node, env).map(ChildName),
4037         PostfixUnaryExpression(c) => {
4038             let operand = p_xhp_child(&c.operand, env)?;
4039             let operator = match token_kind(&c.operator) {
4040                 Some(TK::Question) => ChildQuestion,
4041                 Some(TK::Plus) => ChildPlus,
4042                 Some(TK::Star) => ChildStar,
4043                 _ => missing_syntax("xhp children operator", node, env)?,
4044             };
4045             Ok(ChildUnary(Box::new(operand), operator))
4046         }
4047         BinaryExpression(c) => {
4048             let left = p_xhp_child(&c.left_operand, env)?;
4049             let right = p_xhp_child(&c.right_operand, env)?;
4050             Ok(ChildBinary(Box::new(left), Box::new(right)))
4051         }
4052         XHPChildrenParenthesizedList(c) => {
4053             let children: Result<Vec<_>, _> = c
4054                 .xhp_children
4055                 .syntax_node_to_list_skip_separator()
4056                 .map(|c| p_xhp_child(c, env))
4057                 .collect();
4058             Ok(ChildList(children?))
4059         }
4060         _ => missing_syntax("xhp children", node, env),
4061     }
4064 fn p_class_elt_<'a>(class: &mut ast::Class_, node: S<'a>, env: &mut Env<'a>) -> Result<(), Error> {
4065     use ast::Visibility;
4066     let doc_comment_opt = extract_docblock(node, env);
4067     let has_fun_header =
4068         |m: &MethodishDeclarationChildren<'_, PositionedToken<'a>, PositionedValue<'a>>| {
4069             matches!(
4070                 m.function_decl_header.children,
4071                 FunctionDeclarationHeader(_)
4072             )
4073         };
4074     let p_method_vis =
4075         |node: S<'a>, name_pos: &Pos, env: &mut Env<'a>| -> Result<Visibility, Error> {
4076             match p_visibility_last_win(node, env)? {
4077                 None => {
4078                     raise_hh_error(env, Naming::method_needs_visibility(name_pos.clone()));
4079                     Ok(Visibility::Public)
4080                 }
4081                 Some(v) => Ok(v),
4082             }
4083         };
4084     match &node.children {
4085         ConstDeclaration(c) => {
4086             let user_attributes = p_user_attributes(&c.attribute_spec, env)?;
4087             let kinds = p_kinds(&c.modifiers, env)?;
4088             let has_abstract = kinds.has(modifier::ABSTRACT);
4089             // TODO: make wrap `type_` `doc_comment` by `Rc` in ClassConst to avoid clone
4090             let type_ = mp_optional(p_hint, &c.type_specifier, env)?;
4091             // ocaml's behavior is that if anything throw, it will
4092             // discard all lowered elements. So adding to class
4093             // must be at the last.
4094             let mut class_consts = could_map(
4095                 |n: S<'a>, e: &mut Env<'a>| -> Result<ast::ClassConst, Error> {
4096                     match &n.children {
4097                         ConstantDeclarator(c) => {
4098                             let id = pos_name(&c.name, e)?;
4099                             use aast::ClassConstKind::*;
4100                             let kind = if has_abstract {
4101                                 CCAbstract(mp_optional(p_simple_initializer, &c.initializer, e)?)
4102                             } else {
4103                                 CCConcrete(p_simple_initializer(&c.initializer, e)?)
4104                             };
4105                             Ok(ast::ClassConst {
4106                                 user_attributes: user_attributes.clone(),
4107                                 type_: type_.clone(),
4108                                 id,
4109                                 kind,
4110                                 doc_comment: doc_comment_opt.clone(),
4111                             })
4112                         }
4113                         _ => missing_syntax("constant declarator", n, e),
4114                     }
4115                 },
4116                 &c.declarators,
4117                 env,
4118             )?;
4119             Ok(class.consts.append(&mut class_consts))
4120         }
4121         TypeConstDeclaration(c) => {
4122             use ast::ClassTypeconst::{TCAbstract, TCConcrete};
4123             if !c.type_parameters.is_missing() {
4124                 raise_parsing_error(node, env, &syntax_error::tparams_in_tconst);
4125             }
4126             let user_attributes = p_user_attributes(&c.attribute_spec, env)?;
4127             let type__ = mp_optional(p_hint, &c.type_specifier, env)?
4128                 .map(|hint| soften_hint(&user_attributes, hint));
4129             let kinds = p_kinds(&c.modifiers, env)?;
4130             let name = pos_name(&c.name, env)?;
4131             let as_constraint = mp_optional(p_tconstraint_ty, &c.type_constraint, env)?;
4132             let span = p_pos(node, env);
4133             let has_abstract = kinds.has(modifier::ABSTRACT);
4134             let kind = if has_abstract {
4135                 TCAbstract(ast::ClassAbstractTypeconst {
4136                     as_constraint,
4137                     super_constraint: None,
4138                     default: type__,
4139                 })
4140             } else if let Some(type_) = type__ {
4141                 if env.is_typechecker() && as_constraint.is_some() {
4142                     raise_hh_error(
4143                         env,
4144                         NastCheck::partially_abstract_typeconst_definition(name.0.clone()),
4145                     );
4146                 }
4147                 TCConcrete(ast::ClassConcreteTypeconst { c_tc_type: type_ })
4148             } else {
4149                 raise_hh_error(
4150                     env,
4151                     NastCheck::not_abstract_without_typeconst(name.0.clone()),
4152                 );
4153                 missing_syntax("value for the type constant", node, env)?
4154             };
4155             Ok(class.typeconsts.push(ast::ClassTypeconstDef {
4156                 name,
4157                 kind,
4158                 user_attributes,
4159                 span,
4160                 doc_comment: doc_comment_opt,
4161                 is_ctx: false,
4162             }))
4163         }
4164         ContextConstDeclaration(c) => {
4165             use ast::ClassTypeconst::{TCAbstract, TCConcrete};
4166             if !c.type_parameters.is_missing() {
4167                 raise_parsing_error(node, env, &syntax_error::tparams_in_tconst);
4168             }
4169             let name = pos_name(&c.name, env)?;
4170             let context = p_context_list_to_intersection(&c.ctx_list, env)?;
4171             if let Some(ref hint) = context {
4172                 use ast::Hint_::{Happly, Hintersection};
4173                 let ast::Hint(_, ref h) = hint;
4174                 if let Hintersection(hl) = &**h {
4175                     for h in hl {
4176                         if has_polymorphic_context_single(env, h) {
4177                             raise_parsing_error(
4178                                 &c.constraint,
4179                                 env,
4180                                 "Polymorphic contexts on ctx constants are not allowed",
4181                             );
4182                         }
4183                         let ast::Hint(_, ref h) = h;
4184                         if let Happly(oxidized::ast::Id(_, id), _) = &**h {
4185                             if id.as_str().ends_with("_local") {
4186                                 raise_parsing_error(
4187                                     &c.ctx_list,
4188                                     env,
4189                                     "Local contexts on ctx constants are not allowed",
4190                                 );
4191                             }
4192                         }
4193                     }
4194                 }
4195             }
4196             let span = p_pos(node, env);
4197             let kinds = p_kinds(&c.modifiers, env)?;
4198             let has_abstract = kinds.has(modifier::ABSTRACT);
4199             let (super_constraint, as_constraint) = p_ctx_constraints(&c.constraint, env)?;
4200             let kind = if has_abstract {
4201                 TCAbstract(ast::ClassAbstractTypeconst {
4202                     as_constraint,
4203                     super_constraint,
4204                     default: context,
4205                 })
4206             } else if let Some(c_tc_type) = context {
4207                 if env.is_typechecker() && (super_constraint.is_some() || as_constraint.is_some()) {
4208                     raise_parsing_error(
4209                         node,
4210                         env,
4211                         "Constraints on a context constant requires it to be abstract",
4212                     )
4213                 };
4214                 TCConcrete(ast::ClassConcreteTypeconst { c_tc_type })
4215             } else {
4216                 raise_hh_error(
4217                     env,
4218                     NastCheck::not_abstract_without_typeconst(name.0.clone()),
4219                 );
4220                 missing_syntax("value for the context constant", node, env)?
4221             };
4222             Ok(class.typeconsts.push(ast::ClassTypeconstDef {
4223                 name,
4224                 kind,
4225                 user_attributes: vec![],
4226                 span,
4227                 doc_comment: doc_comment_opt,
4228                 is_ctx: true,
4229             }))
4230         }
4231         PropertyDeclaration(c) => {
4232             let user_attributes = p_user_attributes(&c.attribute_spec, env)?;
4233             let type_ =
4234                 mp_optional(p_hint, &c.type_, env)?.map(|t| soften_hint(&user_attributes, t));
4235             let kinds = p_kinds(&c.modifiers, env)?;
4236             let vis = p_visibility_last_win_or(&c.modifiers, env, Visibility::Public)?;
4237             let doc_comment = if env.quick_mode {
4238                 None
4239             } else {
4240                 doc_comment_opt
4241             };
4242             let name_exprs = could_map(
4243                 |n, e| -> Result<(Pos, ast::Sid, Option<ast::Expr>), Error> {
4244                     match &n.children {
4245                         PropertyDeclarator(c) => {
4246                             let name = pos_name_(&c.name, e, Some('$'))?;
4247                             let pos = p_pos(n, e);
4248                             let expr = mp_optional(p_simple_initializer, &c.initializer, e)?;
4249                             Ok((pos, name, expr))
4250                         }
4251                         _ => missing_syntax("property declarator", n, e),
4252                     }
4253                 },
4254                 &c.declarators,
4255                 env,
4256             )?;
4258             for (i, name_expr) in name_exprs.into_iter().enumerate() {
4259                 class.vars.push(ast::ClassVar {
4260                     final_: kinds.has(modifier::FINAL),
4261                     xhp_attr: None,
4262                     abstract_: kinds.has(modifier::ABSTRACT),
4263                     readonly: kinds.has(modifier::READONLY),
4264                     visibility: vis,
4265                     type_: ast::TypeHint((), type_.clone()),
4266                     id: name_expr.1,
4267                     expr: name_expr.2,
4268                     user_attributes: user_attributes.clone(),
4269                     doc_comment: if i == 0 { doc_comment.clone() } else { None },
4270                     is_promoted_variadic: false,
4271                     is_static: kinds.has(modifier::STATIC),
4272                     span: name_expr.0,
4273                 });
4274             }
4275             Ok(())
4276         }
4277         MethodishDeclaration(c) if has_fun_header(c) => {
4278             // keep cls_generics
4279             *env.fn_generics_mut() = HashMap::default();
4280             let classvar_init = |param: &ast::FunParam| -> (ast::Stmt, ast::ClassVar) {
4281                 let cvname = drop_prefix(&param.name, '$');
4282                 let p = &param.pos;
4283                 let span = match &param.expr {
4284                     Some(ast::Expr(_, pos_end, _)) => {
4285                         Pos::btw(p, pos_end).unwrap_or_else(|_| p.clone())
4286                     }
4287                     _ => p.clone(),
4288                 };
4289                 let e = |expr_: ast::Expr_| -> ast::Expr { ast::Expr::new((), p.clone(), expr_) };
4290                 let lid = |s: &str| -> ast::Lid { ast::Lid(p.clone(), (0, s.to_string())) };
4291                 (
4292                     ast::Stmt::new(
4293                         p.clone(),
4294                         ast::Stmt_::mk_expr(e(E_::mk_binop(
4295                             ast::Bop::Eq(None),
4296                             e(E_::mk_obj_get(
4297                                 e(E_::mk_lvar(lid(special_idents::THIS))),
4298                                 e(E_::mk_id(ast::Id(p.clone(), cvname.to_string()))),
4299                                 ast::OgNullFlavor::OGNullthrows,
4300                                 ast::PropOrMethod::IsProp,
4301                             )),
4302                             e(E_::mk_lvar(lid(&param.name))),
4303                         ))),
4304                     ),
4305                     ast::ClassVar {
4306                         final_: false,
4307                         xhp_attr: None,
4308                         abstract_: false,
4309                         // We use the param readonlyness here to represent the
4310                         // ClassVar's readonlyness once lowered
4311                         // TODO(jjwu): Convert this to an enum when we support
4312                         // multiple types of readonlyness
4313                         readonly: param.readonly.is_some(),
4314                         visibility: param.visibility.unwrap(),
4315                         type_: param.type_hint.clone(),
4316                         id: ast::Id(p.clone(), cvname.to_string()),
4317                         expr: None,
4318                         user_attributes: param.user_attributes.clone(),
4319                         doc_comment: None,
4320                         is_promoted_variadic: param.is_variadic,
4321                         is_static: false,
4322                         span,
4323                     },
4324                 )
4325             };
4326             let header = &c.function_decl_header;
4327             let h = match &header.children {
4328                 FunctionDeclarationHeader(h) => h,
4329                 _ => panic!(),
4330             };
4331             let hdr = p_fun_hdr(header, env)?;
4332             let (mut member_init, mut member_def): (Vec<ast::Stmt>, Vec<ast::ClassVar>) = hdr
4333                 .parameters
4334                 .iter()
4335                 .filter_map(|p| p.visibility.map(|_| classvar_init(p)))
4336                 .unzip();
4338             let kinds = p_kinds(&h.modifiers, env)?;
4339             let visibility = p_method_vis(&h.modifiers, &hdr.name.0, env)?;
4340             let is_static = kinds.has(modifier::STATIC);
4341             let readonly_this = kinds.has(modifier::READONLY);
4342             *env.in_static_method() = is_static;
4343             check_effect_polymorphic_reification(hdr.contexts.as_ref(), env, node);
4344             let (mut body, body_has_yield) = mp_yielding(p_function_body, &c.function_body, env)?;
4345             if env.codegen() {
4346                 member_init.reverse();
4347             }
4348             member_init.append(&mut body);
4349             let body = member_init;
4350             *env.in_static_method() = false;
4351             let is_abstract = kinds.has(modifier::ABSTRACT);
4352             let is_external = !is_abstract && c.function_body.is_external();
4353             let user_attributes = p_user_attributes(&c.attribute, env)?;
4354             check_effect_memoized(hdr.contexts.as_ref(), &user_attributes, "method", env);
4355             let method = ast::Method_ {
4356                 span: p_fun_pos(node, env),
4357                 annotation: (),
4358                 final_: kinds.has(modifier::FINAL),
4359                 readonly_this,
4360                 abstract_: is_abstract,
4361                 static_: is_static,
4362                 name: hdr.name,
4363                 visibility,
4364                 tparams: hdr.type_parameters,
4365                 where_constraints: hdr.constrs,
4366                 params: hdr.parameters,
4367                 ctxs: hdr.contexts,
4368                 unsafe_ctxs: hdr.unsafe_contexts,
4369                 body: ast::FuncBody { fb_ast: body },
4370                 fun_kind: mk_fun_kind(hdr.suspension_kind, body_has_yield),
4371                 user_attributes,
4372                 readonly_ret: hdr.readonly_return,
4373                 ret: ast::TypeHint((), hdr.return_type),
4374                 external: is_external,
4375                 doc_comment: doc_comment_opt,
4376             };
4377             class.vars.append(&mut member_def);
4378             Ok(class.methods.push(method))
4379         }
4380         TraitUseConflictResolution(c) => {
4381             type Ret = Result<Either<ast::InsteadofAlias, ast::UseAsAlias>, Error>;
4382             let p_item = |n: S<'a>, e: &mut Env<'a>| -> Ret {
4383                 match &n.children {
4384                     TraitUsePrecedenceItem(c) => {
4385                         let (qualifier, name) = match &c.name.children {
4386                             ScopeResolutionExpression(c) => {
4387                                 (pos_name(&c.qualifier, e)?, p_pstring(&c.name, e)?)
4388                             }
4389                             _ => missing_syntax("trait use precedence item", n, e)?,
4390                         };
4391                         let removed_names = could_map(pos_name, &c.removed_names, e)?;
4392                         raise_hh_error(e, Naming::unsupported_instead_of(name.0.clone()));
4393                         Ok(Either::Left(ast::InsteadofAlias(
4394                             qualifier,
4395                             name,
4396                             removed_names,
4397                         )))
4398                     }
4399                     TraitUseAliasItem(c) => {
4400                         let (qualifier, name) = match &c.aliasing_name.children {
4401                             ScopeResolutionExpression(c) => {
4402                                 (Some(pos_name(&c.qualifier, e)?), p_pstring(&c.name, e)?)
4403                             }
4404                             _ => (None, p_pstring(&c.aliasing_name, e)?),
4405                         };
4406                         let (kinds, mut vis_raw) = p_modifiers(
4407                             |mut acc, kind| -> Vec<ast::UseAsVisibility> {
4408                                 if let Some(v) = modifier::to_use_as_visibility(kind) {
4409                                     acc.push(v);
4410                                 }
4411                                 acc
4412                             },
4413                             vec![],
4414                             &c.modifiers,
4415                             e,
4416                         )?;
4417                         let vis = if kinds.is_empty() || kinds.has_any(modifier::VISIBILITIES) {
4418                             vis_raw
4419                         } else {
4420                             let mut v = vec![ast::UseAsVisibility::UseAsPublic];
4421                             v.append(&mut vis_raw);
4422                             v
4423                         };
4424                         let aliased_name = if !c.aliased_name.is_missing() {
4425                             Some(pos_name(&c.aliased_name, e)?)
4426                         } else {
4427                             None
4428                         };
4429                         raise_hh_error(e, Naming::unsupported_trait_use_as(name.0.clone()));
4430                         Ok(Either::Right(ast::UseAsAlias(
4431                             qualifier,
4432                             name,
4433                             aliased_name,
4434                             vis,
4435                         )))
4436                     }
4437                     _ => missing_syntax("trait use conflict resolution item", n, e),
4438                 }
4439             };
4440             let mut uses = could_map(p_hint, &c.names, env)?;
4441             let elts = could_map(p_item, &c.clauses, env)?;
4442             class.uses.append(&mut uses);
4443             for elt in elts.into_iter() {
4444                 match elt {
4445                     Either::Left(l) => class.insteadof_alias.push(l),
4446                     Either::Right(r) => class.use_as_alias.push(r),
4447                 }
4448             }
4449             Ok(())
4450         }
4451         TraitUse(c) => {
4452             let mut uses = could_map(p_hint, &c.names, env)?;
4453             Ok(class.uses.append(&mut uses))
4454         }
4455         RequireClause(c) => {
4456             let hint = p_hint(&c.name, env)?;
4457             let is_extends = match token_kind(&c.kind) {
4458                 Some(TK::Implements) => false,
4459                 Some(TK::Extends) => true,
4460                 _ => missing_syntax("trait require kind", &c.kind, env)?,
4461             };
4462             Ok(class.reqs.push((hint, is_extends)))
4463         }
4464         XHPClassAttributeDeclaration(c) => {
4465             type Ret = Result<Either<ast::XhpAttr, ast::Hint>, Error>;
4466             let p_attr = |node: S<'a>, env: &mut Env<'a>| -> Ret {
4467                 let mk_attr_use = |n: S<'a>, env: &mut Env<'a>| {
4468                     Ok(Either::Right(ast::Hint(
4469                         p_pos(n, env),
4470                         Box::new(ast::Hint_::Happly(pos_name(n, env)?, vec![])),
4471                     )))
4472                 };
4473                 match &node.children {
4474                     XHPClassAttribute(c) => {
4475                         let ast::Id(p, name) = pos_name(&c.name, env)?;
4476                         if let TypeConstant(_) = &c.type_.children {
4477                             if env.is_typechecker() {
4478                                 raise_parsing_error(
4479                                     &c.type_,
4480                                     env,
4481                                     &syntax_error::xhp_class_attribute_type_constant,
4482                                 )
4483                             }
4484                         }
4485                         let req = match &c.required.children {
4486                             XHPRequired(_) => Some(ast::XhpAttrTag::Required),
4487                             XHPLateinit(_) => Some(ast::XhpAttrTag::LateInit),
4488                             _ => None,
4489                         };
4490                         let pos = if c.initializer.is_missing() {
4491                             p.clone()
4492                         } else {
4493                             Pos::btw(&p, &p_pos(&c.initializer, env)).map_err(Error::Failwith)?
4494                         };
4495                         let (hint, like, enum_values, enum_) = match &c.type_.children {
4496                             XHPEnumType(c1) => {
4497                                 let p = p_pos(&c.type_, env);
4498                                 let like = match &c1.like.children {
4499                                     Missing => None,
4500                                     _ => Some(p_pos(&c1.like, env)),
4501                                 };
4502                                 let vals = could_map(p_expr, &c1.values, env)?;
4503                                 let mut enum_vals = vec![];
4504                                 for val in vals.clone() {
4505                                     match val {
4506                                         ast::Expr(_, _, E_::String(xev)) => enum_vals
4507                                             .push(ast::XhpEnumValue::XEVString(xev.to_string())),
4508                                         ast::Expr(_, _, E_::Int(xev)) => match xev.parse() {
4509                                             Ok(n) => enum_vals.push(ast::XhpEnumValue::XEVInt(n)),
4510                                             Err(_) =>
4511                                                 // Since we have parse checks for
4512                                                 // malformed integer literals already,
4513                                                 // we assume this won't happen and ignore
4514                                                 // the case.
4515                                                 {}
4516                                         },
4517                                         _ => {}
4518                                     }
4519                                 }
4520                                 (None, like, enum_vals, Some((p, vals)))
4521                             }
4522                             _ => (Some(p_hint(&c.type_, env)?), None, vec![], None),
4523                         };
4524                         let init_expr = mp_optional(p_simple_initializer, &c.initializer, env)?;
4525                         let xhp_attr = ast::XhpAttr(
4526                             ast::TypeHint((), hint.clone()),
4527                             ast::ClassVar {
4528                                 final_: false,
4529                                 xhp_attr: Some(ast::XhpAttrInfo {
4530                                     like,
4531                                     tag: req,
4532                                     enum_values,
4533                                 }),
4534                                 abstract_: false,
4535                                 readonly: false,
4536                                 visibility: ast::Visibility::Public,
4537                                 type_: ast::TypeHint((), hint),
4538                                 id: ast::Id(p, String::from(":") + &name),
4539                                 expr: init_expr,
4540                                 user_attributes: vec![],
4541                                 doc_comment: None,
4542                                 is_promoted_variadic: false,
4543                                 is_static: false,
4544                                 span: pos,
4545                             },
4546                             req,
4547                             enum_,
4548                         );
4549                         Ok(Either::Left(xhp_attr))
4550                     }
4551                     XHPSimpleClassAttribute(c) => mk_attr_use(&c.type_, env),
4552                     Token(_) => mk_attr_use(node, env),
4553                     _ => missing_syntax("XHP attribute", node, env),
4554                 }
4555             };
4556             let attrs = could_map(p_attr, &c.attributes, env)?;
4557             for attr in attrs.into_iter() {
4558                 match attr {
4559                     Either::Left(attr) => class.xhp_attrs.push(attr),
4560                     Either::Right(xhp_attr_use) => class.xhp_attr_uses.push(xhp_attr_use),
4561                 }
4562             }
4563             Ok(())
4564         }
4565         XHPChildrenDeclaration(c) => {
4566             let p = p_pos(node, env);
4567             Ok(class
4568                 .xhp_children
4569                 .push((p, p_xhp_child(&c.expression, env)?)))
4570         }
4571         XHPCategoryDeclaration(c) => {
4572             let p = p_pos(node, env);
4573             let categories = could_map(|n, e| p_pstring_(n, e, Some('%')), &c.categories, env)?;
4574             if let Some((_, cs)) = &class.xhp_category {
4575                 if let Some(category) = cs.first() {
4576                     raise_hh_error(env, NastCheck::multiple_xhp_category(category.0.clone()))
4577                 }
4578             }
4579             Ok(class.xhp_category = Some((p, categories)))
4580         }
4581         _ => missing_syntax("class element", node, env),
4582     }
4585 fn p_class_elt<'a>(class: &mut ast::Class_, node: S<'a>, env: &mut Env<'a>) -> Result<(), Error> {
4586     let r = p_class_elt_(class, node, env);
4587     match r {
4588         // match ocaml behavior, don't throw if missing syntax when fail_open is true
4589         Err(Error::MissingSyntax { .. }) if env.fail_open() => Ok(()),
4590         _ => r,
4591     }
4594 fn contains_class_body<'a>(
4595     c: &ClassishDeclarationChildren<'_, PositionedToken<'a>, PositionedValue<'a>>,
4596 ) -> bool {
4597     matches!(&c.body.children, ClassishBody(_))
4600 fn p_where_constraint<'a>(
4601     is_class: bool,
4602     parent: S<'a>,
4603     node: S<'a>,
4604     env: &mut Env<'a>,
4605 ) -> Result<Vec<ast::WhereConstraintHint>, Error> {
4606     match &node.children {
4607         Missing => Ok(vec![]),
4608         WhereClause(c) => {
4609             let f = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::WhereConstraintHint, Error> {
4610                 match &n.children {
4611                     WhereConstraint(c) => {
4612                         use ast::ConstraintKind::*;
4613                         let l = p_hint(&c.left_type, e)?;
4614                         let o = &c.operator;
4615                         let o = match token_kind(o) {
4616                             Some(TK::Equal) => ConstraintEq,
4617                             Some(TK::As) => ConstraintAs,
4618                             Some(TK::Super) => ConstraintSuper,
4619                             _ => missing_syntax("constraint operator", o, e)?,
4620                         };
4621                         Ok(ast::WhereConstraintHint(l, o, p_hint(&c.right_type, e)?))
4622                     }
4623                     _ => missing_syntax("where constraint", n, e),
4624                 }
4625             };
4626             c.constraints
4627                 .syntax_node_to_list_skip_separator()
4628                 .map(|n| f(n, env))
4629                 .collect()
4630         }
4631         _ => {
4632             if is_class {
4633                 missing_syntax("classish declaration constraints", parent, env)
4634             } else {
4635                 missing_syntax("function header constraints", parent, env)
4636             }
4637         }
4638     }
4641 fn p_namespace_use_kind<'a>(kind: S<'a>, env: &mut Env<'a>) -> Result<ast::NsKind, Error> {
4642     use ast::NsKind::*;
4643     match &kind.children {
4644         Missing => Ok(NSClassAndNamespace),
4645         _ => match token_kind(kind) {
4646             Some(TK::Namespace) => Ok(NSNamespace),
4647             Some(TK::Type) => Ok(NSClass),
4648             Some(TK::Function) => Ok(NSFun),
4649             Some(TK::Const) => Ok(NSConst),
4650             _ => missing_syntax("namespace use kind", kind, env),
4651         },
4652     }
4655 fn p_namespace_use_clause<'a>(
4656     prefix: Option<S<'a>>,
4657     kind: Result<ast::NsKind, Error>,
4658     node: S<'a>,
4659     env: &mut Env<'a>,
4660 ) -> Result<(ast::NsKind, ast::Sid, ast::Sid), Error> {
4661     lazy_static! {
4662         static ref NAMESPACE_USE: regex::Regex = regex::Regex::new("[^\\\\]*$").unwrap();
4663     }
4665     match &node.children {
4666         NamespaceUseClause(NamespaceUseClauseChildren {
4667             clause_kind,
4668             alias,
4669             name,
4670             ..
4671         }) => {
4672             let ast::Id(p, n) = match (prefix, pos_name(name, env)?) {
4673                 (None, id) => id,
4674                 (Some(prefix), ast::Id(p, n)) => ast::Id(p, pos_name(prefix, env)?.1 + &n),
4675             };
4676             let alias = if alias.is_missing() {
4677                 let x = NAMESPACE_USE.find(&n).unwrap().as_str();
4678                 ast::Id(p.clone(), x.to_string())
4679             } else {
4680                 pos_name(alias, env)?
4681             };
4682             let kind = if clause_kind.is_missing() {
4683                 kind
4684             } else {
4685                 p_namespace_use_kind(clause_kind, env)
4686             }?;
4687             Ok((
4688                 kind,
4689                 ast::Id(
4690                     p,
4691                     if !n.is_empty() && n.starts_with('\\') {
4692                         n
4693                     } else {
4694                         String::from("\\") + &n
4695                     },
4696                 ),
4697                 alias,
4698             ))
4699         }
4700         _ => missing_syntax("namespace use clause", node, env),
4701     }
4704 fn check_effect_memoized<'a>(
4705     contexts: Option<&ast::Contexts>,
4706     user_attributes: &[aast::UserAttribute<(), ()>],
4707     kind: &str,
4708     env: &mut Env<'a>,
4709 ) {
4710     if has_polymorphic_context(env, contexts) {
4711         if let Some(u) = user_attributes
4712             .iter()
4713             .find(|u| naming_special_names_rust::user_attributes::is_memoized(&u.name.1))
4714         {
4715             raise_parsing_error_pos(
4716                 &u.name.0,
4717                 env,
4718                 &syntax_error::effect_polymorphic_memoized(kind),
4719             )
4720         }
4721     }
4722     let has_policied = has_any_policied_context(contexts);
4723     if has_policied {
4724         if let Some(u) = user_attributes
4725             .iter()
4726             .find(|u| naming_special_names_rust::user_attributes::is_memoized_regular(&u.name.1))
4727         {
4728             raise_parsing_error_pos(
4729                 &u.name.0,
4730                 env,
4731                 &syntax_error::effect_policied_memoized(kind),
4732             )
4733         }
4734     }
4735     if let Some(u) = user_attributes
4736         .iter()
4737         .find(|u| naming_special_names_rust::user_attributes::is_memoized_policy_sharded(&u.name.1))
4738     {
4739         if !has_policied {
4740             raise_parsing_error_pos(
4741                 &u.name.0,
4742                 env,
4743                 &syntax_error::policy_sharded_memoized_without_policied(kind),
4744             )
4745         }
4746     }
4749 fn check_context_has_this<'a>(contexts: Option<&ast::Contexts>, env: &mut Env<'a>) {
4750     use ast::Hint_::{Haccess, Happly};
4751     if let Some(ast::Contexts(pos, ref context_hints)) = contexts {
4752         context_hints.iter().for_each(|c| match *c.1 {
4753             Haccess(ref root, _) => match &*root.1 {
4754                 Happly(oxidized::ast::Id(_, id), _)
4755                     if strip_ns(id.as_str()) == naming_special_names_rust::typehints::THIS =>
4756                 {
4757                     raise_parsing_error_pos(
4758                         pos,
4759                         env,
4760                         "this:: context is not allowed on top level functions",
4761                     )
4762                 }
4763                 _ => {}
4764             },
4765             _ => {}
4766         });
4767     }
4770 fn check_effect_polymorphic_reification<'a>(
4771     contexts: Option<&ast::Contexts>,
4772     env: &mut Env<'a>,
4773     node: S<'a>,
4774 ) {
4775     use ast::Hint_::{Haccess, Happly};
4776     if let Some(ast::Contexts(_, ref context_hints)) = contexts {
4777         context_hints.iter().for_each(|c| match *c.1 {
4778             Haccess(ref root, _) => match &*root.1 {
4779                 Happly(oxidized::ast::Id(_, id), _) => {
4780                     fail_if_invalid_reified_generic(node, env, strip_ns(id.as_str()))
4781                 }
4782                 _ => {}
4783             },
4784             _ => {}
4785         });
4786     }
4789 fn p_def<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<Vec<ast::Def>, Error> {
4790     let doc_comment_opt = extract_docblock(node, env);
4791     match &node.children {
4792         FunctionDeclaration(FunctionDeclarationChildren {
4793             attribute_spec,
4794             declaration_header,
4795             body,
4796         }) => {
4797             let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4798             let env = env.as_mut();
4799             env.clear_generics();
4800             let hdr = p_fun_hdr(declaration_header, env)?;
4801             let is_external = body.is_external();
4802             let (block, yield_) = if is_external {
4803                 (vec![], false)
4804             } else {
4805                 mp_yielding(&p_function_body, body, env)?
4806             };
4807             let user_attributes = p_user_attributes(attribute_spec, env)?;
4808             check_effect_memoized(hdr.contexts.as_ref(), &user_attributes, "function", env);
4809             check_context_has_this(hdr.contexts.as_ref(), env);
4810             let ret = ast::TypeHint((), hdr.return_type);
4812             let fun = ast::Fun_ {
4813                 span: p_fun_pos(node, env),
4814                 readonly_this: hdr.readonly_this,
4815                 annotation: (),
4816                 ret,
4817                 readonly_ret: hdr.readonly_return,
4818                 name: hdr.name,
4819                 tparams: hdr.type_parameters,
4820                 where_constraints: hdr.constrs,
4821                 params: hdr.parameters,
4822                 ctxs: hdr.contexts,
4823                 unsafe_ctxs: hdr.unsafe_contexts,
4824                 body: ast::FuncBody { fb_ast: block },
4825                 fun_kind: mk_fun_kind(hdr.suspension_kind, yield_),
4826                 user_attributes,
4827                 external: is_external,
4828                 doc_comment: doc_comment_opt,
4829             };
4831             Ok(vec![ast::Def::mk_fun(ast::FunDef {
4832                 namespace: mk_empty_ns_env(env),
4833                 file_attributes: vec![],
4834                 mode: env.file_mode(),
4835                 fun,
4836             })])
4837         }
4838         ClassishDeclaration(c) if contains_class_body(c) => {
4839             let mut env = Env::clone_and_unset_toplevel_if_toplevel(env);
4840             let env = env.as_mut();
4841             let mode = env.file_mode();
4842             let user_attributes = p_user_attributes(&c.attribute, env)?;
4843             let kinds = p_kinds(&c.modifiers, env)?;
4844             let final_ = kinds.has(modifier::FINAL);
4845             let is_xhp = matches!(
4846                 token_kind(&c.name),
4847                 Some(TK::XHPElementName) | Some(TK::XHPClassName)
4848             );
4849             let has_xhp_keyword = matches!(token_kind(&c.xhp), Some(TK::XHP));
4850             let name = pos_name(&c.name, env)?;
4851             env.clear_generics();
4852             let tparams = p_tparam_l(true, &c.type_parameters, env)?;
4853             let class_kind = match token_kind(&c.keyword) {
4854                 Some(TK::Class) if kinds.has(modifier::ABSTRACT) => {
4855                     ast::ClassishKind::Cclass(ast::Abstraction::Abstract)
4856                 }
4857                 Some(TK::Class) => ast::ClassishKind::Cclass(ast::Abstraction::Concrete),
4858                 Some(TK::Interface) => ast::ClassishKind::Cinterface,
4859                 Some(TK::Trait) => ast::ClassishKind::Ctrait,
4860                 Some(TK::Enum) => ast::ClassishKind::Cenum,
4861                 _ => missing_syntax("class kind", &c.keyword, env)?,
4862             };
4863             let extends = could_map(p_hint, &c.extends_list, env)?;
4864             *env.parent_maybe_reified() = match extends.first().map(|h| h.1.as_ref()) {
4865                 Some(ast::Hint_::Happly(_, hl)) => !hl.is_empty(),
4866                 _ => false,
4867             };
4868             let implements = could_map(p_hint, &c.implements_list, env)?;
4869             let where_constraints = p_where_constraint(true, node, &c.where_clause, env)?;
4870             let namespace = mk_empty_ns_env(env);
4871             let span = p_pos(node, env);
4872             let mut class_ = ast::Class_ {
4873                 span,
4874                 annotation: (),
4875                 mode,
4876                 final_,
4877                 is_xhp,
4878                 has_xhp_keyword,
4879                 kind: class_kind,
4880                 name,
4881                 tparams,
4882                 extends,
4883                 uses: vec![],
4884                 use_as_alias: vec![],
4885                 insteadof_alias: vec![],
4886                 xhp_attr_uses: vec![],
4887                 xhp_category: None,
4888                 reqs: vec![],
4889                 implements,
4890                 where_constraints,
4891                 consts: vec![],
4892                 typeconsts: vec![],
4893                 vars: vec![],
4894                 methods: vec![],
4895                 // TODO: what is this attbiute? check ast_to_aast
4896                 attributes: vec![],
4897                 xhp_children: vec![],
4898                 xhp_attrs: vec![],
4899                 namespace,
4900                 user_attributes,
4901                 file_attributes: vec![],
4902                 enum_: None,
4903                 doc_comment: doc_comment_opt,
4904                 emit_id: None,
4905             };
4906             match &c.body.children {
4907                 ClassishBody(c1) => {
4908                     for elt in c1.elements.syntax_node_to_list_skip_separator() {
4909                         p_class_elt(&mut class_, elt, env)?;
4910                     }
4911                 }
4912                 _ => missing_syntax("classish body", &c.body, env)?,
4913             }
4914             Ok(vec![ast::Def::mk_class(class_)])
4915         }
4916         ConstDeclaration(c) => {
4917             let ty = &c.type_specifier;
4918             let decls = c.declarators.syntax_node_to_list_skip_separator();
4919             let mut defs = vec![];
4920             for decl in decls {
4921                 let def = match &decl.children {
4922                     ConstantDeclarator(c) => {
4923                         let name = &c.name;
4924                         let init = &c.initializer;
4925                         let gconst = ast::Gconst {
4926                             annotation: (),
4927                             mode: env.file_mode(),
4928                             name: pos_name(name, env)?,
4929                             type_: mp_optional(p_hint, ty, env)?,
4930                             value: p_simple_initializer(init, env)?,
4931                             namespace: mk_empty_ns_env(env),
4932                             span: p_pos(node, env),
4933                             emit_id: None,
4934                         };
4935                         ast::Def::mk_constant(gconst)
4936                     }
4937                     _ => missing_syntax("constant declaration", decl, env)?,
4938                 };
4939                 defs.push(def);
4940             }
4941             Ok(defs)
4942         }
4943         AliasDeclaration(c) => {
4944             let tparams = p_tparam_l(false, &c.generic_parameter, env)?;
4945             for tparam in tparams.iter() {
4946                 if tparam.reified != ast::ReifyKind::Erased {
4947                     raise_parsing_error(node, env, &syntax_error::invalid_reified)
4948                 }
4949             }
4950             Ok(vec![ast::Def::mk_typedef(ast::Typedef {
4951                 annotation: (),
4952                 name: pos_name(&c.name, env)?,
4953                 tparams,
4954                 constraint: mp_optional(p_tconstraint, &c.constraint, env)?.map(|x| x.1),
4955                 user_attributes: itertools::concat(
4956                     c.attribute_spec
4957                         .syntax_node_to_list_skip_separator()
4958                         .map(|attr| p_user_attribute(attr, env))
4959                         .collect::<Result<Vec<Vec<_>>, _>>()?,
4960                 ),
4961                 file_attributes: vec![],
4962                 namespace: mk_empty_ns_env(env),
4963                 mode: env.file_mode(),
4964                 vis: match token_kind(&c.keyword) {
4965                     Some(TK::Type) => ast::TypedefVisibility::Transparent,
4966                     Some(TK::Newtype) => ast::TypedefVisibility::Opaque,
4967                     _ => missing_syntax("kind", &c.keyword, env)?,
4968                 },
4969                 kind: p_hint(&c.type_, env)?,
4970                 span: p_pos(node, env),
4971                 emit_id: None,
4972                 is_ctx: false,
4973             })])
4974         }
4975         ContextAliasDeclaration(c) => {
4976             let (_super_constraint, as_constraint) = p_ctx_constraints(&c.as_constraint, env)?;
4978             let pos_name = pos_name(&c.name, env)?;
4979             if let Some(first_char) = pos_name.1.chars().next() {
4980                 if first_char.is_lowercase() {
4981                     raise_parsing_error(
4982                         &c.name,
4983                         env,
4984                         &syntax_error::user_ctx_should_be_caps(&pos_name.1),
4985                     )
4986                 }
4987             }
4988             if as_constraint.is_none() {
4989                 raise_parsing_error(
4990                     &c.name,
4991                     env,
4992                     &syntax_error::user_ctx_require_as(&pos_name.1),
4993                 )
4994             }
4995             let kind = match p_context_list_to_intersection(&c.context, env)? {
4996                 Some(h) => h,
4997                 None => {
4998                     let pos = pos_name.0.clone();
4999                     let hint_ =
5000                         ast::Hint_::Happly(ast::Id(pos.clone(), String::from("defaults")), vec![]);
5001                     ast::Hint::new(pos, hint_)
5002                 }
5003             };
5004             Ok(vec![ast::Def::mk_typedef(ast::Typedef {
5005                 annotation: (),
5006                 name: pos_name,
5007                 tparams: vec![],
5008                 constraint: as_constraint,
5009                 user_attributes: itertools::concat(
5010                     c.attribute_spec
5011                         .syntax_node_to_list_skip_separator()
5012                         .map(|attr| p_user_attribute(attr, env))
5013                         .collect::<Result<Vec<Vec<_>>, _>>()?,
5014                 ),
5015                 namespace: mk_empty_ns_env(env),
5016                 mode: env.file_mode(),
5017                 file_attributes: vec![],
5018                 vis: ast::TypedefVisibility::Opaque,
5019                 kind,
5020                 span: p_pos(node, env),
5021                 emit_id: None,
5022                 is_ctx: true,
5023             })])
5024         }
5025         EnumDeclaration(c) => {
5026             let p_enumerator = |n: S<'a>, e: &mut Env<'a>| -> Result<ast::ClassConst, Error> {
5027                 match &n.children {
5028                     Enumerator(c) => Ok(ast::ClassConst {
5029                         user_attributes: vec![],
5030                         type_: None,
5031                         id: pos_name(&c.name, e)?,
5032                         kind: ast::ClassConstKind::CCConcrete(p_expr(&c.value, e)?),
5033                         doc_comment: None,
5034                     }),
5035                     _ => missing_syntax("enumerator", n, e),
5036                 }
5037             };
5039             let mut includes = vec![];
5041             let mut p_enum_use = |n: S<'a>, e: &mut Env<'a>| -> Result<(), Error> {
5042                 match &n.children {
5043                     EnumUse(c) => {
5044                         let mut uses = could_map(p_hint, &c.names, e)?;
5045                         Ok(includes.append(&mut uses))
5046                     }
5047                     _ => missing_syntax("enum_use", node, e),
5048                 }
5049             };
5051             for elt in c.use_clauses.syntax_node_to_list_skip_separator() {
5052                 p_enum_use(elt, env)?;
5053             }
5055             Ok(vec![ast::Def::mk_class(ast::Class_ {
5056                 annotation: (),
5057                 mode: env.file_mode(),
5058                 user_attributes: p_user_attributes(&c.attribute_spec, env)?,
5059                 file_attributes: vec![],
5060                 final_: false,
5061                 kind: ast::ClassishKind::Cenum,
5062                 is_xhp: false,
5063                 has_xhp_keyword: false,
5064                 name: pos_name(&c.name, env)?,
5065                 tparams: vec![],
5066                 extends: vec![],
5067                 implements: vec![],
5068                 where_constraints: vec![],
5069                 consts: could_map(p_enumerator, &c.enumerators, env)?,
5070                 namespace: mk_empty_ns_env(env),
5071                 span: p_pos(node, env),
5072                 enum_: Some(ast::Enum_ {
5073                     base: p_hint(&c.base, env)?,
5074                     constraint: mp_optional(p_tconstraint_ty, &c.type_, env)?,
5075                     includes,
5076                 }),
5077                 doc_comment: doc_comment_opt,
5078                 uses: vec![],
5079                 use_as_alias: vec![],
5080                 insteadof_alias: vec![],
5081                 xhp_attr_uses: vec![],
5082                 xhp_category: None,
5083                 reqs: vec![],
5084                 vars: vec![],
5085                 typeconsts: vec![],
5086                 methods: vec![],
5087                 attributes: vec![],
5088                 xhp_children: vec![],
5089                 xhp_attrs: vec![],
5090                 emit_id: None,
5091             })])
5092         }
5094         EnumClassDeclaration(c) => {
5095             let name = pos_name(&c.name, env)?;
5096             // Adding __EnumClass
5097             let mut user_attributes = p_user_attributes(&c.attribute_spec, env)?;
5098             let enum_class_attribute = ast::UserAttribute {
5099                 name: ast::Id(name.0.clone(), special_attrs::ENUM_CLASS.to_string()),
5100                 params: vec![],
5101             };
5102             user_attributes.push(enum_class_attribute);
5103             // During lowering we store the base type as is. It will be updated during
5104             // the naming phase
5105             let base_type = p_hint(&c.base, env)?;
5107             let name_s = name.1.clone(); // TODO: can I avoid this clone ?
5109             let kinds = p_kinds(&c.modifiers, env)?;
5111             let class_kind = if kinds.has(modifier::ABSTRACT) {
5112                 ast::ClassishKind::CenumClass(ast::Abstraction::Abstract)
5113             } else {
5114                 ast::ClassishKind::CenumClass(ast::Abstraction::Concrete)
5115             };
5117             // Helper to build X -> HH\MemberOf<enum_name, X>
5118             let build_elt = |p: Pos, ty: ast::Hint| -> ast::Hint {
5119                 let enum_name = ast::Id(p.clone(), name_s.clone());
5120                 let enum_class = ast::Hint_::mk_happly(enum_name, vec![]);
5121                 let enum_class = ast::Hint::new(p.clone(), enum_class);
5122                 let elt_id = ast::Id(p.clone(), special_classes::MEMBER_OF.to_string());
5123                 let full_type = ast::Hint_::mk_happly(elt_id, vec![enum_class, ty]);
5124                 ast::Hint::new(p, full_type)
5125             };
5127             let extends = could_map(p_hint, &c.extends_list, env)?;
5129             let mut enum_class = ast::Class_ {
5130                 annotation: (),
5131                 mode: env.file_mode(),
5132                 user_attributes,
5133                 file_attributes: vec![],
5134                 final_: false, // TODO(T77095784): support final EDTs
5135                 kind: class_kind,
5136                 is_xhp: false,
5137                 has_xhp_keyword: false,
5138                 name,
5139                 tparams: vec![],
5140                 extends: extends.clone(),
5141                 implements: vec![],
5142                 where_constraints: vec![],
5143                 consts: vec![],
5144                 namespace: mk_empty_ns_env(env),
5145                 span: p_pos(node, env),
5146                 enum_: Some(ast::Enum_ {
5147                     base: base_type,
5148                     constraint: None,
5149                     includes: extends,
5150                 }),
5151                 doc_comment: doc_comment_opt,
5152                 uses: vec![],
5153                 use_as_alias: vec![],
5154                 insteadof_alias: vec![],
5155                 xhp_attr_uses: vec![],
5156                 xhp_category: None,
5157                 reqs: vec![],
5158                 vars: vec![],
5159                 typeconsts: vec![],
5160                 methods: vec![],
5161                 attributes: vec![],
5162                 xhp_children: vec![],
5163                 xhp_attrs: vec![],
5164                 emit_id: None,
5165             };
5167             for n in c.elements.syntax_node_to_list_skip_separator() {
5168                 match &n.children {
5169                     // TODO(T77095784): check pos and span usage
5170                     EnumClassEnumerator(c) => {
5171                         // we turn:
5172                         // - type name = expression;
5173                         // into
5174                         // - const MemberOf<enum_name, type> name = expression
5175                         let name = pos_name(&c.name, env)?;
5176                         let pos = &name.0;
5177                         let kinds = p_kinds(&c.modifiers, env)?;
5178                         let has_abstract = kinds.has(modifier::ABSTRACT);
5179                         let elt_type = p_hint(&c.type_, env)?;
5180                         let full_type = build_elt(pos.clone(), elt_type);
5181                         let kind = if has_abstract {
5182                             ast::ClassConstKind::CCAbstract(None)
5183                         } else {
5184                             ast::ClassConstKind::CCConcrete(p_simple_initializer(
5185                                 &c.initializer,
5186                                 env,
5187                             )?)
5188                         };
5189                         let class_const = ast::ClassConst {
5190                             user_attributes: vec![],
5191                             type_: Some(full_type),
5192                             id: name,
5193                             kind,
5194                             doc_comment: None,
5195                         };
5196                         enum_class.consts.push(class_const)
5197                     }
5198                     _ => {
5199                         let pos = p_pos(n, env);
5200                         raise_parsing_error_pos(
5201                             &pos,
5202                             env,
5203                             &syntax_error::invalid_enum_class_enumerator,
5204                         )
5205                     }
5206                 }
5207             }
5208             Ok(vec![ast::Def::mk_class(enum_class)])
5209         }
5210         InclusionDirective(c) if env.file_mode() != file_info::Mode::Mhhi || env.codegen() => {
5211             let expr = p_expr(&c.expression, env)?;
5212             Ok(vec![ast::Def::mk_stmt(ast::Stmt::new(
5213                 p_pos(node, env),
5214                 ast::Stmt_::mk_expr(expr),
5215             ))])
5216         }
5217         NamespaceDeclaration(c) => {
5218             let name = if let NamespaceDeclarationHeader(h) = &c.header.children {
5219                 &h.name
5220             } else {
5221                 return missing_syntax("namespace_declaration_header", node, env);
5222             };
5223             let defs = match &c.body.children {
5224                 NamespaceBody(c) => {
5225                     let mut env1 = Env::clone_and_unset_toplevel_if_toplevel(env);
5226                     let env1 = env1.as_mut();
5227                     itertools::concat(
5228                         c.declarations
5229                             .syntax_node_to_list_skip_separator()
5230                             .map(|n| p_def(n, env1))
5231                             .collect::<Result<Vec<Vec<_>>, _>>()?,
5232                     )
5233                 }
5234                 _ => vec![],
5235             };
5236             Ok(vec![ast::Def::mk_namespace(pos_name(name, env)?, defs)])
5237         }
5238         NamespaceGroupUseDeclaration(c) => {
5239             let uses: Result<Vec<_>, _> = c
5240                 .clauses
5241                 .syntax_node_to_list_skip_separator()
5242                 .map(|n| {
5243                     p_namespace_use_clause(
5244                         Some(&c.prefix),
5245                         p_namespace_use_kind(&c.kind, env),
5246                         n,
5247                         env,
5248                     )
5249                 })
5250                 .collect();
5251             Ok(vec![ast::Def::mk_namespace_use(uses?)])
5252         }
5253         NamespaceUseDeclaration(c) => {
5254             let uses: Result<Vec<_>, _> = c
5255                 .clauses
5256                 .syntax_node_to_list_skip_separator()
5257                 .map(|n| p_namespace_use_clause(None, p_namespace_use_kind(&c.kind, env), n, env))
5258                 .collect();
5259             Ok(vec![ast::Def::mk_namespace_use(uses?)])
5260         }
5261         FileAttributeSpecification(_) => {
5262             Ok(vec![ast::Def::mk_file_attributes(ast::FileAttribute {
5263                 user_attributes: p_user_attribute(node, env)?,
5264                 namespace: mk_empty_ns_env(env),
5265             })])
5266         }
5267         ModuleDeclaration(md) => Ok(vec![ast::Def::mk_module(ast::ModuleDef {
5268             name: pos_name(&md.name, env)?,
5269             user_attributes: p_user_attributes(&md.attribute_spec, env)?,
5270             span: p_pos(node, env),
5271             mode: env.file_mode(),
5272         })]),
5273         _ if env.file_mode() == file_info::Mode::Mhhi => Ok(vec![]),
5274         _ => Ok(vec![ast::Def::mk_stmt(p_stmt(node, env)?)]),
5275     }
5278 fn post_process<'a>(env: &mut Env<'a>, program: Vec<ast::Def>, acc: &mut Vec<ast::Def>) {
5279     use aast::{Def, Def::*, Stmt_::*};
5280     let mut saw_ns: Option<(ast::Sid, Vec<ast::Def>)> = None;
5281     for def in program.into_iter() {
5282         if let Namespace(_) = &def {
5283             if let Some((n, ns_acc)) = saw_ns {
5284                 acc.push(Def::mk_namespace(n, ns_acc));
5285                 saw_ns = None;
5286             }
5287         }
5289         if let Namespace(ns) = def {
5290             let (n, defs) = *ns;
5291             if defs.is_empty() {
5292                 saw_ns = Some((n, vec![]));
5293             } else {
5294                 let mut acc_ = vec![];
5295                 post_process(env, defs, &mut acc_);
5296                 acc.push(Def::mk_namespace(n, acc_));
5297             }
5299             continue;
5300         }
5302         if let Stmt(s) = &def {
5303             if s.1.is_noop() {
5304                 continue;
5305             }
5306             let raise_error = match &s.1 {
5307                 Markup(_) => false,
5308                 Expr(expr)
5309                     if expr.as_ref().is_import()
5310                         && !env.parser_options.po_disallow_toplevel_requires =>
5311                 {
5312                     false
5313                 }
5314                 _ => {
5315                     use file_info::Mode::*;
5316                     let mode = env.file_mode();
5317                     env.keep_errors && env.is_typechecker() && (mode == Mstrict)
5318                 }
5319             };
5320             if raise_error {
5321                 raise_parsing_error_pos(&s.0, env, &syntax_error::toplevel_statements);
5322             }
5323         }
5325         if let Some((_, ns_acc)) = &mut saw_ns {
5326             ns_acc.push(def);
5327         } else {
5328             acc.push(def);
5329         };
5330     }
5331     if let Some((n, defs)) = saw_ns {
5332         acc.push(Def::mk_namespace(n, defs));
5333     }
5336 fn p_program<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Program, Error> {
5337     let nodes = node.syntax_node_to_list_skip_separator();
5338     let mut acc = vec![];
5339     for n in nodes {
5340         match &n.children {
5341             EndOfFile(_) => break,
5342             _ => match p_def(n, env) {
5343                 Err(Error::MissingSyntax { .. }) if env.fail_open => {}
5344                 Err(e) => return Err(e),
5345                 Ok(mut def) => acc.append(&mut def),
5346             },
5347         }
5348     }
5349     let mut program = vec![];
5350     post_process(env, acc, &mut program);
5351     Ok(ast::Program(program))
5354 fn p_script<'a>(node: S<'a>, env: &mut Env<'a>) -> Result<ast::Program, Error> {
5355     match &node.children {
5356         Script(c) => p_program(&c.declarations, env),
5357         _ => missing_syntax("script", node, env),
5358     }
5361 pub fn lower<'a>(env: &mut Env<'a>, script: S<'a>) -> Result<ast::Program, String> {
5362     p_script(script, env).map_err(|e| match e {
5363         Error::MissingSyntax {
5364             expecting,
5365             pos,
5366             node_name,
5367             kind,
5368         } => format!(
5369             "missing case in {:?}.\n - pos: {:?}\n - unexpected: '{:?}'\n - kind: {:?}\n",
5370             expecting, pos, node_name, kind,
5371         ),
5372         Error::Failwith(msg) => msg,
5373     })