overwrite file attribute specification
[hiphop-php.git] / hphp / hack / src / decl / direct_decl_smart_constructors.rs
blobf0a6b5cd0b935c14b79bcd35b7510ff433d31991
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use std::collections::BTreeMap;
7 use std::rc::Rc;
9 use bstr::BStr;
10 use bumpalo::{
11     collections::{String, Vec},
12     Bump,
15 use hh_autoimport_rust as hh_autoimport;
16 use naming_special_names_rust as naming_special_names;
18 use arena_collections::{AssocListMut, List, MultiSetMut};
19 use flatten_smart_constructors::{FlattenOp, FlattenSmartConstructors};
20 use namespaces::ElaborateKind;
21 use namespaces_rust as namespaces;
22 use oxidized_by_ref::{
23     aast,
24     ast_defs::{
25         Abstraction, Bop, ClassishKind, ConstraintKind, FunKind, Id, ShapeFieldName, Uop, Variance,
26         XhpEnumValue,
27     },
28     decl_parser_options::DeclParserOptions,
29     direct_decl_parser::Decls,
30     file_info::Mode,
31     method_flags::MethodFlags,
32     namespace_env::Env as NamespaceEnv,
33     nast,
34     pos::Pos,
35     prop_flags::PropFlags,
36     relative_path::RelativePath,
37     s_map::SMap,
38     shallow_decl_defs::{
39         self, Decl, ShallowClassConst, ShallowMethod, ShallowProp, ShallowTypeconst,
40     },
41     shape_map::ShapeField,
42     t_shape_map::TShapeField,
43     typing_defs::{
44         self, AbstractTypeconst, Capability::*, ClassConstKind, ConcreteTypeconst, ConstDecl,
45         Enforcement, EnumType, FunArity, FunElt, FunImplicitParams, FunParam, FunParams, FunType,
46         IfcFunDecl, ParamMode, PosByteString, PosId, PosString, PossiblyEnforcedTy, RecordFieldReq,
47         ShapeFieldType, ShapeKind, TaccessType, Tparam, TshapeFieldName, Ty, Ty_, Typeconst,
48         TypedefType, WhereConstraint, XhpAttrTag,
49     },
50     typing_defs_flags::{FunParamFlags, FunTypeFlags},
51     typing_modules::Module_,
52     typing_reason::Reason,
54 use parser_core_types::{
55     compact_token::CompactToken, indexed_source_text::IndexedSourceText, source_text::SourceText,
56     syntax_kind::SyntaxKind, token_factory::SimpleTokenFactoryImpl, token_kind::TokenKind,
59 mod direct_decl_smart_constructors_generated;
61 type SK = SyntaxKind;
63 type SSet<'a> = arena_collections::SortedSet<'a, &'a str>;
65 #[derive(Clone)]
66 pub struct DirectDeclSmartConstructors<'a, 'text, S: SourceTextAllocator<'text, 'a>> {
67     pub token_factory: SimpleTokenFactoryImpl<CompactToken>,
69     pub source_text: IndexedSourceText<'text>,
70     pub arena: &'a bumpalo::Bump,
71     pub decls: Decls<'a>,
72     pub file_attributes: List<'a, &'a typing_defs::UserAttribute<'a>>,
73     // const_refs will accumulate all scope-resolution-expressions it enconuters while it's "Some"
74     const_refs: Option<arena_collections::set::Set<'a, typing_defs::ClassConstRef<'a>>>,
75     opts: &'a DeclParserOptions<'a>,
76     filename: &'a RelativePath<'a>,
77     file_mode: Mode,
78     namespace_builder: Rc<NamespaceBuilder<'a>>,
79     classish_name_builder: ClassishNameBuilder<'a>,
80     type_parameters: Rc<Vec<'a, SSet<'a>>>,
81     retain_or_omit_user_attributes_for_facts: bool,
82     simplify_naming_for_facts: bool,
83     previous_token_kind: TokenKind,
85     source_text_allocator: S,
88 impl<'a, 'text, S: SourceTextAllocator<'text, 'a>> DirectDeclSmartConstructors<'a, 'text, S> {
89     pub fn new(
90         opts: &'a DeclParserOptions<'a>,
91         src: &SourceText<'text>,
92         file_mode: Mode,
93         arena: &'a Bump,
94         source_text_allocator: S,
95         retain_or_omit_user_attributes_for_facts: bool,
96         simplify_naming_for_facts: bool,
97     ) -> Self {
98         let source_text = IndexedSourceText::new(src.clone());
99         let path = source_text.source_text().file_path();
100         let prefix = path.prefix();
101         let path = String::from_str_in(path.path_str(), arena).into_bump_str();
102         let filename = RelativePath::make(prefix, path);
103         Self {
104             token_factory: SimpleTokenFactoryImpl::new(),
106             source_text,
107             arena,
108             opts,
109             filename: arena.alloc(filename),
110             file_mode,
111             decls: Decls::empty(),
112             file_attributes: List::empty(),
113             const_refs: None,
114             namespace_builder: Rc::new(NamespaceBuilder::new_in(
115                 opts.auto_namespace_map,
116                 opts.disable_xhp_element_mangling,
117                 simplify_naming_for_facts,
118                 arena,
119             )),
120             classish_name_builder: ClassishNameBuilder::new(),
121             type_parameters: Rc::new(Vec::new_in(arena)),
122             // EndOfFile is used here as a None value (signifying "beginning of
123             // file") to save space. There is no legitimate circumstance where
124             // we would parse a token and the previous token kind would be
125             // EndOfFile.
126             previous_token_kind: TokenKind::EndOfFile,
127             source_text_allocator,
128             retain_or_omit_user_attributes_for_facts,
129             simplify_naming_for_facts,
130         }
131     }
133     #[inline(always)]
134     pub fn alloc<T>(&self, val: T) -> &'a T {
135         self.arena.alloc(val)
136     }
138     fn qualified_name_from_parts(&self, parts: &'a [Node<'a>], pos: &'a Pos<'a>) -> Id<'a> {
139         // Count the length of the qualified name, so that we can allocate
140         // exactly the right amount of space for it in our arena.
141         let mut len = 0;
142         for part in parts {
143             match part {
144                 Node::Name(&(name, _)) => len += name.len(),
145                 Node::Token(t) if t.kind() == TokenKind::Backslash => len += 1,
146                 Node::ListItem(&(Node::Name(&(name, _)), _backslash)) => len += name.len() + 1,
147                 Node::ListItem(&(Node::Token(t), _backslash))
148                     if t.kind() == TokenKind::Namespace =>
149                 {
150                     len += t.width() + 1;
151                 }
152                 _ => {}
153             }
154         }
155         // If there's no internal trivia, then we can just reference the
156         // qualified name in the original source text instead of copying it.
157         let source_len = pos.end_cnum() - pos.start_cnum();
158         if source_len == len {
159             let qualified_name: &'a str = self.str_from_utf8(self.source_text_at_pos(pos));
160             return Id(pos, qualified_name);
161         }
162         // Allocate `len` bytes and fill them with the fully qualified name.
163         let mut qualified_name = String::with_capacity_in(len, self.arena);
164         for part in parts {
165             match part {
166                 Node::Name(&(name, _pos)) => qualified_name.push_str(&name),
167                 Node::Token(t) if t.kind() == TokenKind::Backslash => qualified_name.push('\\'),
168                 &Node::ListItem(&(Node::Name(&(name, _)), _backslash)) => {
169                     qualified_name.push_str(&name);
170                     qualified_name.push_str("\\");
171                 }
172                 &Node::ListItem(&(Node::Token(t), _backslash))
173                     if t.kind() == TokenKind::Namespace =>
174                 {
175                     qualified_name.push_str("namespace\\");
176                 }
177                 _ => {}
178             }
179         }
180         debug_assert_eq!(len, qualified_name.len());
181         debug_assert_eq!(len, qualified_name.capacity());
182         Id(pos, qualified_name.into_bump_str())
183     }
185     /// If the given node is an identifier, XHP name, or qualified name,
186     /// elaborate it in the current namespace and return Some. To be used for
187     /// the name of a decl in its definition (e.g., "C" in `class C {}` or "f"
188     /// in `function f() {}`).
189     fn elaborate_defined_id(&self, name: Node<'a>) -> Option<Id<'a>> {
190         let id = match name {
191             Node::Name(&(name, pos)) => Id(pos, name),
192             Node::XhpName(&(name, pos)) => Id(pos, name),
193             Node::QualifiedName(&(parts, pos)) => self.qualified_name_from_parts(parts, pos),
194             // This is always an error; e.g. using a reserved word where a name
195             // is expected.
196             Node::Token(t) | Node::IgnoredToken(t) => {
197                 let pos = self.token_pos(t);
198                 let text = self.str_from_utf8(self.source_text_at_pos(pos));
199                 Id(pos, text)
200             }
201             _ => return None,
202         };
203         Some(self.namespace_builder.elaborate_defined_id(id))
204     }
206     /// If the given node is a name (i.e., an identifier or a qualified name),
207     /// return Some. No namespace elaboration is performed.
208     fn expect_name(&self, name: Node<'a>) -> Option<Id<'a>> {
209         // If it's a simple identifier, return it.
210         if let id @ Some(_) = name.as_id() {
211             return id;
212         }
213         match name {
214             Node::QualifiedName(&(parts, pos)) => Some(self.qualified_name_from_parts(parts, pos)),
215             // The IgnoredToken case is always an error; e.g. using a reserved
216             // word where a name is expected. The Token case is not an error if
217             // the token is TokenKind::XHP (which is legal to use as a name),
218             // but an error otherwise (since we expect a Name or QualifiedName
219             // here, and the Name case would have been handled in `as_id`
220             // above).
221             Node::Token(t) | Node::IgnoredToken(t) => {
222                 let pos = self.token_pos(t);
223                 let text = self.str_from_utf8(self.source_text_at_pos(pos));
224                 Some(Id(pos, text))
225             }
226             _ => None,
227         }
228     }
230     /// Fully qualify the given identifier as a type name (with consideration
231     /// to `use` statements in scope).
232     fn elaborate_id(&self, id: Id<'a>) -> Id<'a> {
233         let Id(pos, name) = id;
234         Id(pos, self.elaborate_raw_id(name))
235     }
237     /// Fully qualify the given identifier as a type name (with consideration
238     /// to `use` statements in scope).
239     fn elaborate_raw_id(&self, id: &'a str) -> &'a str {
240         self.namespace_builder
241             .elaborate_raw_id(ElaborateKind::Class, id)
242     }
244     /// Fully qualify the given identifier as a constant name (with
245     /// consideration to `use` statements in scope).
246     fn elaborate_const_id(&self, id: Id<'a>) -> Id<'a> {
247         let Id(pos, name) = id;
248         Id(
249             pos,
250             self.namespace_builder
251                 .elaborate_raw_id(ElaborateKind::Const, name),
252         )
253     }
255     fn slice<T>(&self, iter: impl Iterator<Item = T>) -> &'a [T] {
256         let mut result = match iter.size_hint().1 {
257             Some(upper_bound) => Vec::with_capacity_in(upper_bound, self.arena),
258             None => Vec::new_in(self.arena),
259         };
260         for item in iter {
261             result.push(item);
262         }
263         result.into_bump_slice()
264     }
266     fn start_accumulating_const_refs(&mut self) {
267         self.const_refs = Some(arena_collections::set::Set::empty());
268     }
270     fn accumulate_const_ref(&mut self, class_id: &'a aast::ClassId<'_, (), ()>, value_id: &Id<'a>) {
271         // The decl for a class constant stores a list of all the scope-resolution expressions
272         // it contains. For example "const C=A::X" stores A::X, and "const D=self::Y" stores self::Y.
273         // (This is so we can detect cross-type circularity in constant initializers).
274         // TODO: Hack is the wrong place to detect circularity (because we can never do it completely soundly,
275         // and because it's a cross-body problem). The right place to do it is in a linter. All this should be
276         // removed from here and put into a linter.
277         if let Some(const_refs) = self.const_refs {
278             match class_id.2 {
279                 nast::ClassId_::CI(sid) => {
280                     self.const_refs = Some(const_refs.add(
281                         self.arena,
282                         typing_defs::ClassConstRef(
283                             typing_defs::ClassConstFrom::From(sid.1),
284                             value_id.1,
285                         ),
286                     ));
287                 }
288                 nast::ClassId_::CIself => {
289                     self.const_refs = Some(const_refs.add(
290                         self.arena,
291                         typing_defs::ClassConstRef(typing_defs::ClassConstFrom::Self_, value_id.1),
292                     ));
293                 }
294                 // Not allowed
295                 nast::ClassId_::CIparent
296                 | nast::ClassId_::CIstatic
297                 | nast::ClassId_::CIexpr(_) => {}
298             }
299         }
300     }
302     fn stop_accumulating_const_refs(&mut self) -> &'a [typing_defs::ClassConstRef<'a>] {
303         let const_refs = self.const_refs;
304         self.const_refs = None;
305         match const_refs {
306             Some(const_refs) => {
307                 let mut elements: Vec<'_, typing_defs::ClassConstRef<'_>> =
308                     bumpalo::collections::Vec::with_capacity_in(const_refs.count(), self.arena);
309                 elements.extend(const_refs.into_iter());
310                 elements.into_bump_slice()
311             }
312             None => &[],
313         }
314     }
317 pub trait SourceTextAllocator<'text, 'target>: Clone {
318     fn alloc(&self, text: &'text str) -> &'target str;
321 #[derive(Clone)]
322 pub struct NoSourceTextAllocator;
324 impl<'text> SourceTextAllocator<'text, 'text> for NoSourceTextAllocator {
325     #[inline]
326     fn alloc(&self, text: &'text str) -> &'text str {
327         text
328     }
331 #[derive(Clone)]
332 pub struct ArenaSourceTextAllocator<'arena>(pub &'arena bumpalo::Bump);
334 impl<'text, 'arena> SourceTextAllocator<'text, 'arena> for ArenaSourceTextAllocator<'arena> {
335     #[inline]
336     fn alloc(&self, text: &'text str) -> &'arena str {
337         self.0.alloc_str(text)
338     }
341 fn prefix_slash<'a>(arena: &'a Bump, name: &str) -> &'a str {
342     let mut s = String::with_capacity_in(1 + name.len(), arena);
343     s.push('\\');
344     s.push_str(name);
345     s.into_bump_str()
348 fn prefix_colon<'a>(arena: &'a Bump, name: &str) -> &'a str {
349     let mut s = String::with_capacity_in(1 + name.len(), arena);
350     s.push(':');
351     s.push_str(name);
352     s.into_bump_str()
355 fn concat<'a>(arena: &'a Bump, str1: &str, str2: &str) -> &'a str {
356     let mut result = String::with_capacity_in(str1.len() + str2.len(), arena);
357     result.push_str(str1);
358     result.push_str(str2);
359     result.into_bump_str()
362 fn strip_dollar_prefix<'a>(name: &'a str) -> &'a str {
363     name.trim_start_matches("$")
366 const TANY_: Ty_<'_> = Ty_::Tany(oxidized_by_ref::tany_sentinel::TanySentinel);
367 const TANY: &Ty<'_> = &Ty(Reason::none(), TANY_);
369 fn tany() -> &'static Ty<'static> {
370     TANY
373 fn default_ifc_fun_decl<'a>() -> IfcFunDecl<'a> {
374     IfcFunDecl::FDPolicied(Some("PUBLIC"))
377 #[derive(Debug)]
378 struct Modifiers {
379     is_static: bool,
380     visibility: aast::Visibility,
381     is_abstract: bool,
382     is_final: bool,
383     is_readonly: bool,
386 fn read_member_modifiers<'a: 'b, 'b>(modifiers: impl Iterator<Item = &'b Node<'a>>) -> Modifiers {
387     let mut ret = Modifiers {
388         is_static: false,
389         visibility: aast::Visibility::Public,
390         is_abstract: false,
391         is_final: false,
392         is_readonly: false,
393     };
394     for modifier in modifiers {
395         if let Some(vis) = modifier.as_visibility() {
396             ret.visibility = vis;
397         }
398         match modifier.token_kind() {
399             Some(TokenKind::Static) => ret.is_static = true,
400             Some(TokenKind::Abstract) => ret.is_abstract = true,
401             Some(TokenKind::Final) => ret.is_final = true,
402             Some(TokenKind::Readonly) => ret.is_readonly = true,
403             _ => {}
404         }
405     }
406     ret
409 #[derive(Clone, Debug)]
410 struct NamespaceBuilder<'a> {
411     arena: &'a Bump,
412     stack: Vec<'a, NamespaceEnv<'a>>,
413     auto_ns_map: &'a [(&'a str, &'a str)],
414     simplify_naming_for_facts: bool,
417 impl<'a> NamespaceBuilder<'a> {
418     fn new_in(
419         auto_ns_map: &'a [(&'a str, &'a str)],
420         disable_xhp_element_mangling: bool,
421         simplify_naming_for_facts: bool,
422         arena: &'a Bump,
423     ) -> Self {
424         let mut ns_uses = SMap::empty();
425         for &alias in hh_autoimport::NAMESPACES {
426             ns_uses = ns_uses.add(arena, alias, concat(arena, "HH\\", alias));
427         }
428         for (alias, ns) in auto_ns_map.iter() {
429             ns_uses = ns_uses.add(arena, alias, ns);
430         }
432         let mut class_uses = SMap::empty();
433         for &alias in hh_autoimport::TYPES {
434             class_uses = class_uses.add(arena, alias, concat(arena, "HH\\", alias));
435         }
437         NamespaceBuilder {
438             arena,
439             stack: bumpalo::vec![in arena; NamespaceEnv {
440                 ns_uses,
441                 class_uses,
442                 fun_uses: SMap::empty(),
443                 const_uses: SMap::empty(),
444                 record_def_uses: SMap::empty(),
445                 name: None,
446                 auto_ns_map,
447                 is_codegen: false,
448                 disable_xhp_element_mangling,
449             }],
450             auto_ns_map,
451             simplify_naming_for_facts,
452         }
453     }
455     fn push_namespace(&mut self, name: Option<&str>) {
456         let current = self.current_namespace();
457         let nsenv = self.stack.last().unwrap().clone(); // shallow clone
458         if let Some(name) = name {
459             let mut fully_qualified = match current {
460                 None => String::with_capacity_in(name.len(), self.arena),
461                 Some(current) => {
462                     let mut fully_qualified =
463                         String::with_capacity_in(current.len() + name.len() + 1, self.arena);
464                     fully_qualified.push_str(current);
465                     fully_qualified.push('\\');
466                     fully_qualified
467                 }
468             };
469             fully_qualified.push_str(name);
470             self.stack.push(NamespaceEnv {
471                 name: Some(fully_qualified.into_bump_str()),
472                 ..nsenv
473             });
474         } else {
475             self.stack.push(NamespaceEnv {
476                 name: current,
477                 ..nsenv
478             });
479         }
480     }
482     fn pop_namespace(&mut self) {
483         // We'll never push a namespace for a declaration of items in the global
484         // namespace (e.g., `namespace { ... }`), so only pop if we are in some
485         // namespace other than the global one.
486         if self.stack.len() > 1 {
487             self.stack.pop().unwrap();
488         }
489     }
491     // push_namespace(Y) + pop_namespace() + push_namespace(X) should be equivalent to
492     // push_namespace(Y) + push_namespace(X) + pop_previous_namespace()
493     fn pop_previous_namespace(&mut self) {
494         if self.stack.len() > 2 {
495             let last = self.stack.pop().unwrap().name.unwrap_or("\\");
496             let previous = self.stack.pop().unwrap().name.unwrap_or("\\");
497             assert!(last.starts_with(previous));
498             let name = &last[previous.len() + 1..last.len()];
499             self.push_namespace(Some(name));
500         }
501     }
503     fn current_namespace(&self) -> Option<&'a str> {
504         self.stack.last().and_then(|nsenv| nsenv.name)
505     }
507     fn add_import(&mut self, kind: NamespaceUseKind, name: &'a str, aliased_name: Option<&'a str>) {
508         let stack_top = &mut self
509             .stack
510             .last_mut()
511             .expect("Attempted to get the current import map, but namespace stack was empty");
512         let aliased_name = aliased_name.unwrap_or_else(|| {
513             name.rsplit_terminator('\\')
514                 .nth(0)
515                 .expect("Expected at least one entry in import name")
516         });
517         let name = name.trim_end_matches('\\');
518         let name = if name.starts_with('\\') {
519             name
520         } else {
521             prefix_slash(self.arena, name)
522         };
523         match kind {
524             NamespaceUseKind::Type => {
525                 stack_top.class_uses = stack_top.class_uses.add(self.arena, aliased_name, name);
526             }
527             NamespaceUseKind::Namespace => {
528                 stack_top.ns_uses = stack_top.ns_uses.add(self.arena, aliased_name, name);
529             }
530             NamespaceUseKind::Mixed => {
531                 stack_top.class_uses = stack_top.class_uses.add(self.arena, aliased_name, name);
532                 stack_top.ns_uses = stack_top.ns_uses.add(self.arena, aliased_name, name);
533             }
534         }
535     }
537     fn elaborate_raw_id(&self, kind: ElaborateKind, name: &'a str) -> &'a str {
538         if name.starts_with('\\') {
539             return name;
540         }
541         let env = self.stack.last().unwrap();
542         namespaces::elaborate_raw_id_in(self.arena, env, kind, name, self.simplify_naming_for_facts)
543     }
545     fn elaborate_defined_id(&self, id: Id<'a>) -> Id<'a> {
546         let Id(pos, name) = id;
547         let env = self.stack.last().unwrap();
548         let name = if env.disable_xhp_element_mangling && name.contains(':') {
549             let xhp_name_opt = namespaces::elaborate_xhp_namespace(name);
550             let name = xhp_name_opt.map_or(name, |s| self.arena.alloc_str(&s));
551             if !name.starts_with('\\') {
552                 namespaces::elaborate_into_current_ns_in(self.arena, env, name)
553             } else {
554                 name
555             }
556         } else {
557             namespaces::elaborate_into_current_ns_in(self.arena, env, name)
558         };
559         Id(pos, name)
560     }
563 #[derive(Clone, Debug)]
564 enum ClassishNameBuilder<'a> {
565     /// We are not in a classish declaration.
566     NotInClassish,
568     /// We saw a classish keyword token followed by a Name, so we make it
569     /// available as the name of the containing class declaration.
570     InClassish(&'a (&'a str, &'a Pos<'a>, TokenKind)),
573 impl<'a> ClassishNameBuilder<'a> {
574     fn new() -> Self {
575         ClassishNameBuilder::NotInClassish
576     }
578     fn lexed_name_after_classish_keyword(
579         &mut self,
580         arena: &'a Bump,
581         name: &'a str,
582         pos: &'a Pos<'a>,
583         token_kind: TokenKind,
584     ) {
585         use ClassishNameBuilder::*;
586         match self {
587             NotInClassish => {
588                 let name = if name.starts_with(':') {
589                     prefix_slash(arena, name)
590                 } else {
591                     name
592                 };
593                 *self = InClassish(arena.alloc((name, pos, token_kind)))
594             }
595             InClassish(_) => {}
596         }
597     }
599     fn parsed_classish_declaration(&mut self) {
600         *self = ClassishNameBuilder::NotInClassish;
601     }
603     fn get_current_classish_name(&self) -> Option<(&'a str, &'a Pos<'a>)> {
604         use ClassishNameBuilder::*;
605         match self {
606             NotInClassish => None,
607             InClassish((name, pos, _)) => Some((name, pos)),
608         }
609     }
611     fn in_interface(&self) -> bool {
612         use ClassishNameBuilder::*;
613         match self {
614             InClassish((_, _, TokenKind::Interface)) => true,
615             InClassish((_, _, _)) | NotInClassish => false,
616         }
617     }
620 #[derive(Debug)]
621 pub struct FunParamDecl<'a> {
622     attributes: Node<'a>,
623     visibility: Node<'a>,
624     kind: ParamMode,
625     readonly: bool,
626     hint: Node<'a>,
627     pos: &'a Pos<'a>,
628     name: Option<&'a str>,
629     variadic: bool,
630     initializer: Node<'a>,
633 #[derive(Debug)]
634 pub struct FunctionHeader<'a> {
635     name: Node<'a>,
636     modifiers: Node<'a>,
637     type_params: Node<'a>,
638     param_list: Node<'a>,
639     capability: Node<'a>,
640     ret_hint: Node<'a>,
641     readonly_return: Node<'a>,
642     where_constraints: Node<'a>,
645 #[derive(Debug)]
646 pub struct RequireClause<'a> {
647     require_type: Node<'a>,
648     name: Node<'a>,
651 #[derive(Debug)]
652 pub struct TypeParameterDecl<'a> {
653     name: Node<'a>,
654     reified: aast::ReifyKind,
655     variance: Variance,
656     constraints: &'a [(ConstraintKind, Node<'a>)],
657     tparam_params: &'a [&'a Tparam<'a>],
658     user_attributes: &'a [&'a UserAttributeNode<'a>],
661 #[derive(Debug)]
662 pub struct ClosureTypeHint<'a> {
663     args: Node<'a>,
664     ret_hint: Node<'a>,
667 #[derive(Debug)]
668 pub struct NamespaceUseClause<'a> {
669     kind: NamespaceUseKind,
670     id: Id<'a>,
671     as_: Option<&'a str>,
674 #[derive(Copy, Clone, Debug)]
675 enum NamespaceUseKind {
676     Type,
677     Namespace,
678     Mixed,
681 #[derive(Debug)]
682 pub struct ConstructorNode<'a> {
683     method: &'a ShallowMethod<'a>,
684     properties: &'a [ShallowProp<'a>],
687 #[derive(Debug)]
688 pub struct MethodNode<'a> {
689     method: &'a ShallowMethod<'a>,
690     is_static: bool,
693 #[derive(Debug)]
694 pub struct PropertyNode<'a> {
695     decls: &'a [ShallowProp<'a>],
696     is_static: bool,
699 #[derive(Debug)]
700 pub struct XhpClassAttributeDeclarationNode<'a> {
701     xhp_attr_enum_values: &'a [(&'a str, &'a [XhpEnumValue<'a>])],
702     xhp_attr_decls: &'a [ShallowProp<'a>],
703     xhp_attr_uses_decls: &'a [Node<'a>],
706 #[derive(Debug)]
707 pub struct XhpClassAttributeNode<'a> {
708     name: Id<'a>,
709     tag: Option<XhpAttrTag>,
710     needs_init: bool,
711     nullable: bool,
712     hint: Node<'a>,
715 #[derive(Debug)]
716 pub struct ShapeFieldNode<'a> {
717     name: &'a ShapeField<'a>,
718     type_: &'a ShapeFieldType<'a>,
721 #[derive(Copy, Clone, Debug)]
722 struct ClassNameParam<'a> {
723     name: Id<'a>,
724     full_pos: &'a Pos<'a>, // Position of the full expression `Foo::class`
727 #[derive(Debug)]
728 pub struct UserAttributeNode<'a> {
729     name: Id<'a>,
730     classname_params: &'a [ClassNameParam<'a>],
731     string_literal_params: &'a [&'a BStr], // this is only used for __Deprecated attribute message and Cipp parameters
734 mod fixed_width_token {
735     use parser_core_types::token_kind::TokenKind;
737     #[derive(Copy, Clone)]
738     pub struct FixedWidthToken(u64); // { offset: u56, kind: TokenKind }
740     const KIND_BITS: u8 = 8;
741     const KIND_MASK: u64 = u8::MAX as u64;
742     const MAX_OFFSET: u64 = !(KIND_MASK << (64 - KIND_BITS));
744     impl FixedWidthToken {
745         pub fn new(kind: TokenKind, offset: usize) -> Self {
746             // We don't want to spend bits tracking the width of fixed-width
747             // tokens. Since we don't track width, verify that this token kind
748             // is in fact a fixed-width kind.
749             debug_assert!(kind.fixed_width().is_some());
751             let offset: u64 = offset.try_into().unwrap();
752             if offset > MAX_OFFSET {
753                 panic!("FixedWidthToken: offset too large: {}", offset);
754             }
755             Self(offset << KIND_BITS | kind as u8 as u64)
756         }
758         pub fn offset(self) -> usize {
759             (self.0 >> KIND_BITS).try_into().unwrap()
760         }
762         pub fn kind(self) -> TokenKind {
763             TokenKind::try_from_u8(self.0 as u8).unwrap()
764         }
766         pub fn width(self) -> usize {
767             self.kind().fixed_width().unwrap().get()
768         }
769     }
771     impl std::fmt::Debug for FixedWidthToken {
772         fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
773             fmt.debug_struct("FixedWidthToken")
774                 .field("kind", &self.kind())
775                 .field("offset", &self.offset())
776                 .finish()
777         }
778     }
780 use fixed_width_token::FixedWidthToken;
782 #[derive(Copy, Clone, Debug)]
783 pub enum Node<'a> {
784     // Nodes which are not useful in constructing a decl are ignored. We keep
785     // track of the SyntaxKind for two reasons.
786     //
787     // One is that the parser needs to know the SyntaxKind of a parsed node in
788     // some circumstances (this information is exposed to the parser via an
789     // implementation of `smart_constructors::NodeType`). An adapter called
790     // WithKind exists to provide a `NodeType` implementation for arbitrary
791     // nodes by pairing each node with a SyntaxKind, but in the direct decl
792     // parser, we want to avoid the extra 8 bytes of overhead on each node.
793     //
794     // The second reason is that debugging is difficult when nodes are silently
795     // ignored, and providing at least the SyntaxKind of an ignored node helps
796     // in tracking down the reason it was ignored.
797     Ignored(SyntaxKind),
799     // For tokens with a fixed width (like `using`), we also keep its offset in
800     // the source text, so that we can reference the text of the token if it's
801     // (erroneously) used as an identifier (e.g., `function using() {}`).
802     IgnoredToken(FixedWidthToken),
804     List(&'a &'a [Node<'a>]),
805     BracketedList(&'a (&'a Pos<'a>, &'a [Node<'a>], &'a Pos<'a>)),
806     Name(&'a (&'a str, &'a Pos<'a>)),
807     XhpName(&'a (&'a str, &'a Pos<'a>)),
808     Variable(&'a (&'a str, &'a Pos<'a>)),
809     QualifiedName(&'a (&'a [Node<'a>], &'a Pos<'a>)),
810     StringLiteral(&'a (&'a BStr, &'a Pos<'a>)), // For shape keys and const expressions.
811     IntLiteral(&'a (&'a str, &'a Pos<'a>)),     // For const expressions.
812     FloatingLiteral(&'a (&'a str, &'a Pos<'a>)), // For const expressions.
813     BooleanLiteral(&'a (&'a str, &'a Pos<'a>)), // For const expressions.
814     Ty(&'a Ty<'a>),
815     XhpEnumTy(&'a (&'a Ty<'a>, &'a [XhpEnumValue<'a>])),
816     ListItem(&'a (Node<'a>, Node<'a>)),
817     Const(&'a ShallowClassConst<'a>), // For the "X=1" in enums "enum E {X=1}" and enum-classes "enum class C {int X=1}", and also for consts via make_const_declaration
818     ConstInitializer(&'a (Node<'a>, Node<'a>, &'a [typing_defs::ClassConstRef<'a>])), // Stores (X,1,refs) for "X=1" in top-level "const int X=1" and class-const "public const int X=1".
819     FunParam(&'a FunParamDecl<'a>),
820     Attribute(&'a UserAttributeNode<'a>),
821     FunctionHeader(&'a FunctionHeader<'a>),
822     Constructor(&'a ConstructorNode<'a>),
823     Method(&'a MethodNode<'a>),
824     Property(&'a PropertyNode<'a>),
825     EnumUse(&'a Node<'a>),
826     TraitUse(&'a Node<'a>),
827     XhpClassAttributeDeclaration(&'a XhpClassAttributeDeclarationNode<'a>),
828     XhpClassAttribute(&'a XhpClassAttributeNode<'a>),
829     XhpAttributeUse(&'a Node<'a>),
830     TypeConstant(&'a ShallowTypeconst<'a>),
831     ContextConstraint(&'a (ConstraintKind, Node<'a>)),
832     RequireClause(&'a RequireClause<'a>),
833     ClassishBody(&'a &'a [Node<'a>]),
834     TypeParameter(&'a TypeParameterDecl<'a>),
835     TypeConstraint(&'a (ConstraintKind, Node<'a>)),
836     ShapeFieldSpecifier(&'a ShapeFieldNode<'a>),
837     NamespaceUseClause(&'a NamespaceUseClause<'a>),
838     Expr(&'a nast::Expr<'a>),
839     TypeParameters(&'a &'a [&'a Tparam<'a>]),
840     WhereConstraint(&'a WhereConstraint<'a>),
841     RecordField(&'a (Id<'a>, RecordFieldReq)),
843     // Non-ignored, fixed-width tokens (e.g., keywords, operators, braces, etc.).
844     Token(FixedWidthToken),
847 impl<'a> smart_constructors::NodeType for Node<'a> {
848     type R = Node<'a>;
850     fn extract(self) -> Self::R {
851         self
852     }
854     fn is_abstract(&self) -> bool {
855         self.is_token(TokenKind::Abstract) || self.is_ignored_token_with_kind(TokenKind::Abstract)
856     }
857     fn is_name(&self) -> bool {
858         matches!(self, Node::Name(..)) || self.is_ignored_token_with_kind(TokenKind::Name)
859     }
860     fn is_qualified_name(&self) -> bool {
861         matches!(self, Node::QualifiedName(..)) || matches!(self, Node::Ignored(SK::QualifiedName))
862     }
863     fn is_prefix_unary_expression(&self) -> bool {
864         matches!(self, Node::Expr(aast::Expr(_, _, aast::Expr_::Unop(..))))
865             || matches!(self, Node::Ignored(SK::PrefixUnaryExpression))
866     }
867     fn is_scope_resolution_expression(&self) -> bool {
868         matches!(
869             self,
870             Node::Expr(aast::Expr(_, _, aast::Expr_::ClassConst(..)))
871         ) || matches!(self, Node::Ignored(SK::ScopeResolutionExpression))
872     }
873     fn is_missing(&self) -> bool {
874         matches!(self, Node::Ignored(SK::Missing))
875     }
876     fn is_variable_expression(&self) -> bool {
877         matches!(self, Node::Ignored(SK::VariableExpression))
878     }
879     fn is_subscript_expression(&self) -> bool {
880         matches!(self, Node::Ignored(SK::SubscriptExpression))
881     }
882     fn is_member_selection_expression(&self) -> bool {
883         matches!(self, Node::Ignored(SK::MemberSelectionExpression))
884     }
885     fn is_object_creation_expression(&self) -> bool {
886         matches!(self, Node::Ignored(SK::ObjectCreationExpression))
887     }
888     fn is_safe_member_selection_expression(&self) -> bool {
889         matches!(self, Node::Ignored(SK::SafeMemberSelectionExpression))
890     }
891     fn is_function_call_expression(&self) -> bool {
892         matches!(self, Node::Ignored(SK::FunctionCallExpression))
893     }
894     fn is_list_expression(&self) -> bool {
895         matches!(self, Node::Ignored(SK::ListExpression))
896     }
899 impl<'a> Node<'a> {
900     fn is_token(self, kind: TokenKind) -> bool {
901         self.token_kind() == Some(kind)
902     }
904     fn token_kind(self) -> Option<TokenKind> {
905         match self {
906             Node::Token(token) => Some(token.kind()),
907             _ => None,
908         }
909     }
911     fn is_ignored_token_with_kind(self, kind: TokenKind) -> bool {
912         match self {
913             Node::IgnoredToken(token) => token.kind() == kind,
914             _ => false,
915         }
916     }
918     fn as_slice(self, b: &'a Bump) -> &'a [Self] {
919         match self {
920             Node::List(&items) | Node::BracketedList(&(_, items, _)) => items,
921             n if n.is_ignored() => &[],
922             n => std::slice::from_ref(b.alloc(n)),
923         }
924     }
926     fn iter<'b>(&'b self) -> NodeIterHelper<'a, 'b>
927     where
928         'a: 'b,
929     {
930         match self {
931             &Node::List(&items) | Node::BracketedList(&(_, items, _)) => {
932                 NodeIterHelper::Vec(items.iter())
933             }
934             n if n.is_ignored() => NodeIterHelper::Empty,
935             n => NodeIterHelper::Single(n),
936         }
937     }
939     // The number of elements which would be yielded by `self.iter()`.
940     // Must return the upper bound returned by NodeIterHelper::size_hint.
941     fn len(&self) -> usize {
942         match self {
943             &Node::List(&items) | Node::BracketedList(&(_, items, _)) => items.len(),
944             n if n.is_ignored() => 0,
945             _ => 1,
946         }
947     }
949     fn as_visibility(&self) -> Option<aast::Visibility> {
950         match self.token_kind() {
951             Some(TokenKind::Private) => Some(aast::Visibility::Private),
952             Some(TokenKind::Protected) => Some(aast::Visibility::Protected),
953             Some(TokenKind::Public) => Some(aast::Visibility::Public),
954             _ => None,
955         }
956     }
958     // If this node is a simple unqualified identifier, return its position and text.
959     fn as_id(&self) -> Option<Id<'a>> {
960         match self {
961             Node::Name(&(name, pos)) | Node::XhpName(&(name, pos)) => Some(Id(pos, name)),
962             _ => None,
963         }
964     }
966     // If this node is a Variable token, return its position and text.
967     // As an attempt at error recovery (when the dollar sign is omitted), also
968     // return other unqualified identifiers (i.e., the Name token kind).
969     fn as_variable(&self) -> Option<Id<'a>> {
970         match self {
971             Node::Variable(&(name, pos)) | Node::Name(&(name, pos)) => Some(Id(pos, name)),
972             _ => None,
973         }
974     }
976     fn is_ignored(&self) -> bool {
977         matches!(self, Node::Ignored(..) | Node::IgnoredToken(..))
978     }
980     fn is_present(&self) -> bool {
981         !self.is_ignored()
982     }
985 #[derive(Debug)]
986 struct Attributes<'a> {
987     deprecated: Option<&'a str>,
988     reifiable: Option<&'a Pos<'a>>,
989     late_init: bool,
990     const_: bool,
991     lsb: bool,
992     memoizelsb: bool,
993     override_: bool,
994     enforceable: Option<&'a Pos<'a>>,
995     accept_disposable: bool,
996     dynamically_callable: bool,
997     returns_disposable: bool,
998     php_std_lib: bool,
999     ifc_attribute: IfcFunDecl<'a>,
1000     external: bool,
1001     can_call: bool,
1002     via_label: bool,
1003     soft: bool,
1004     support_dynamic_type: bool,
1005     module: Option<&'a Module_<'a>>,
1006     internal: bool,
1009 impl<'a, 'text, S: SourceTextAllocator<'text, 'a>> DirectDeclSmartConstructors<'a, 'text, S> {
1010     fn add_class(&mut self, name: &'a str, decl: &'a shallow_decl_defs::ShallowClass<'a>) {
1011         self.decls.add(name, Decl::Class(decl), self.arena);
1012     }
1013     fn add_fun(&mut self, name: &'a str, decl: &'a typing_defs::FunElt<'a>) {
1014         self.decls.add(name, Decl::Fun(decl), self.arena);
1015     }
1016     fn add_typedef(&mut self, name: &'a str, decl: &'a typing_defs::TypedefType<'a>) {
1017         self.decls.add(name, Decl::Typedef(decl), self.arena);
1018     }
1019     fn add_const(&mut self, name: &'a str, decl: &'a typing_defs::ConstDecl<'a>) {
1020         self.decls.add(name, Decl::Const(decl), self.arena);
1021     }
1022     fn add_record(&mut self, name: &'a str, decl: &'a typing_defs::RecordDefType<'a>) {
1023         self.decls.add(name, Decl::Record(decl), self.arena);
1024     }
1026     #[inline]
1027     fn concat(&self, str1: &str, str2: &str) -> &'a str {
1028         concat(self.arena, str1, str2)
1029     }
1031     fn token_bytes(&self, token: &CompactToken) -> &'text [u8] {
1032         self.source_text
1033             .source_text()
1034             .sub(token.start_offset(), token.width())
1035     }
1037     // Check that the slice is valid UTF-8. If it is, return a &str referencing
1038     // the same data. Otherwise, copy the slice into our arena using
1039     // String::from_utf8_lossy_in, and return a reference to the arena str.
1040     fn str_from_utf8(&self, slice: &'text [u8]) -> &'a str {
1041         if let Ok(s) = std::str::from_utf8(slice) {
1042             self.source_text_allocator.alloc(s)
1043         } else {
1044             String::from_utf8_lossy_in(slice, self.arena).into_bump_str()
1045         }
1046     }
1048     // Check that the slice is valid UTF-8. If it is, return a &str referencing
1049     // the same data. Otherwise, copy the slice into our arena using
1050     // String::from_utf8_lossy_in, and return a reference to the arena str.
1051     fn str_from_utf8_for_bytes_in_arena(&self, slice: &'a [u8]) -> &'a str {
1052         if let Ok(s) = std::str::from_utf8(slice) {
1053             s
1054         } else {
1055             String::from_utf8_lossy_in(slice, self.arena).into_bump_str()
1056         }
1057     }
1059     fn merge(
1060         &self,
1061         pos1: impl Into<Option<&'a Pos<'a>>>,
1062         pos2: impl Into<Option<&'a Pos<'a>>>,
1063     ) -> &'a Pos<'a> {
1064         match (pos1.into(), pos2.into()) {
1065             (None, None) => Pos::none(),
1066             (Some(pos), None) | (None, Some(pos)) => pos,
1067             (Some(pos1), Some(pos2)) => match (pos1.is_none(), pos2.is_none()) {
1068                 (true, true) => Pos::none(),
1069                 (true, false) => pos2,
1070                 (false, true) => pos1,
1071                 (false, false) => Pos::merge_without_checking_filename(self.arena, pos1, pos2),
1072             },
1073         }
1074     }
1076     fn merge_positions(&self, node1: Node<'a>, node2: Node<'a>) -> &'a Pos<'a> {
1077         self.merge(self.get_pos(node1), self.get_pos(node2))
1078     }
1080     fn pos_from_slice(&self, nodes: &[Node<'a>]) -> &'a Pos<'a> {
1081         nodes.iter().fold(Pos::none(), |acc, &node| {
1082             self.merge(acc, self.get_pos(node))
1083         })
1084     }
1086     fn get_pos(&self, node: Node<'a>) -> &'a Pos<'a> {
1087         self.get_pos_opt(node).unwrap_or(Pos::none())
1088     }
1090     fn get_pos_opt(&self, node: Node<'a>) -> Option<&'a Pos<'a>> {
1091         let pos = match node {
1092             Node::Name(&(_, pos)) | Node::Variable(&(_, pos)) => pos,
1093             Node::Ty(ty) => return ty.get_pos(),
1094             Node::XhpName(&(_, pos)) => pos,
1095             Node::QualifiedName(&(_, pos)) => pos,
1096             Node::IntLiteral(&(_, pos))
1097             | Node::FloatingLiteral(&(_, pos))
1098             | Node::StringLiteral(&(_, pos))
1099             | Node::BooleanLiteral(&(_, pos)) => pos,
1100             Node::ListItem(&(fst, snd)) => self.merge_positions(fst, snd),
1101             Node::List(items) => self.pos_from_slice(&items),
1102             Node::BracketedList(&(first_pos, inner_list, second_pos)) => self.merge(
1103                 first_pos,
1104                 self.merge(self.pos_from_slice(inner_list), second_pos),
1105             ),
1106             Node::Expr(&aast::Expr(_, pos, _)) => pos,
1107             Node::Token(token) => self.token_pos(token),
1108             _ => return None,
1109         };
1110         if pos.is_none() { None } else { Some(pos) }
1111     }
1113     fn token_pos(&self, token: FixedWidthToken) -> &'a Pos<'a> {
1114         let start = token.offset();
1115         let end = start + token.width();
1116         let start = self.source_text.offset_to_file_pos_triple(start);
1117         let end = self.source_text.offset_to_file_pos_triple(end);
1118         Pos::from_lnum_bol_cnum(self.arena, self.filename, start, end)
1119     }
1121     fn node_to_expr(&self, node: Node<'a>) -> Option<&'a nast::Expr<'a>> {
1122         let expr_ = match node {
1123             Node::Expr(expr) => return Some(expr),
1124             Node::IntLiteral(&(s, _)) => aast::Expr_::Int(s),
1125             Node::FloatingLiteral(&(s, _)) => aast::Expr_::Float(s),
1126             Node::StringLiteral(&(s, _)) => aast::Expr_::String(s),
1127             Node::BooleanLiteral((s, _)) => {
1128                 if s.eq_ignore_ascii_case("true") {
1129                     aast::Expr_::True
1130                 } else {
1131                     aast::Expr_::False
1132                 }
1133             }
1134             Node::Token(t) if t.kind() == TokenKind::NullLiteral => aast::Expr_::Null,
1135             Node::Name(..) | Node::QualifiedName(..) => {
1136                 aast::Expr_::Id(self.alloc(self.elaborate_const_id(self.expect_name(node)?)))
1137             }
1138             _ => return None,
1139         };
1140         let pos = self.get_pos(node);
1141         Some(self.alloc(aast::Expr((), pos, expr_)))
1142     }
1144     fn node_to_non_ret_ty(&self, node: Node<'a>) -> Option<&'a Ty<'a>> {
1145         self.node_to_ty_(node, false)
1146     }
1148     fn node_to_ty(&self, node: Node<'a>) -> Option<&'a Ty<'a>> {
1149         self.node_to_ty_(node, true)
1150     }
1152     fn node_to_ty_(&self, node: Node<'a>, allow_non_ret_ty: bool) -> Option<&'a Ty<'a>> {
1153         match node {
1154             Node::Ty(Ty(reason, Ty_::Tprim(aast::Tprim::Tvoid))) if !allow_non_ret_ty => {
1155                 Some(self.alloc(Ty(reason, Ty_::Terr)))
1156             }
1157             Node::Ty(Ty(reason, Ty_::Tprim(aast::Tprim::Tnoreturn))) if !allow_non_ret_ty => {
1158                 Some(self.alloc(Ty(reason, Ty_::Terr)))
1159             }
1160             Node::Ty(ty) => Some(ty),
1161             Node::Expr(expr) => {
1162                 fn expr_to_ty<'a>(arena: &'a Bump, expr: &'a nast::Expr<'a>) -> Option<Ty_<'a>> {
1163                     use aast::Expr_::*;
1164                     match expr.2 {
1165                         Null => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tnull))),
1166                         This => Some(Ty_::Tthis),
1167                         True | False => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tbool))),
1168                         Int(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tint))),
1169                         Float(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tfloat))),
1170                         String(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1171                         String2(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1172                         PrefixedString(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1173                         Unop(&(_op, expr)) => expr_to_ty(arena, expr),
1174                         Hole(&(expr, _, _, _)) => expr_to_ty(arena, expr),
1176                         ArrayGet(_) | As(_) | Await(_) | Binop(_) | Call(_) | Cast(_)
1177                         | ClassConst(_) | ClassGet(_) | Clone(_) | Collection(_) | Darray(_)
1178                         | Dollardollar(_) | Efun(_) | Eif(_) | EnumClassLabel(_) | ETSplice(_)
1179                         | ExpressionTree(_) | FunctionPointer(_) | FunId(_) | Id(_) | Import(_)
1180                         | Is(_) | KeyValCollection(_) | Lfun(_) | List(_) | Lplaceholder(_)
1181                         | Lvar(_) | MethodCaller(_) | MethodId(_) | New(_) | ObjGet(_)
1182                         | Omitted | Pair(_) | Pipe(_) | ReadonlyExpr(_) | Record(_) | Shape(_)
1183                         | SmethodId(_) | Tuple(_) | Upcast(_) | ValCollection(_) | Varray(_)
1184                         | Xml(_) | Yield(_) => None,
1185                     }
1186                 }
1187                 Some(self.alloc(Ty(
1188                     self.alloc(Reason::witness_from_decl(expr.1)),
1189                     expr_to_ty(self.arena, expr)?,
1190                 )))
1191             }
1192             Node::IntLiteral((_, pos)) => Some(self.alloc(Ty(
1193                 self.alloc(Reason::witness_from_decl(pos)),
1194                 Ty_::Tprim(self.alloc(aast::Tprim::Tint)),
1195             ))),
1196             Node::FloatingLiteral((_, pos)) => Some(self.alloc(Ty(
1197                 self.alloc(Reason::witness_from_decl(pos)),
1198                 Ty_::Tprim(self.alloc(aast::Tprim::Tfloat)),
1199             ))),
1200             Node::StringLiteral((_, pos)) => Some(self.alloc(Ty(
1201                 self.alloc(Reason::witness_from_decl(pos)),
1202                 Ty_::Tprim(self.alloc(aast::Tprim::Tstring)),
1203             ))),
1204             Node::BooleanLiteral((_, pos)) => Some(self.alloc(Ty(
1205                 self.alloc(Reason::witness_from_decl(pos)),
1206                 Ty_::Tprim(self.alloc(aast::Tprim::Tbool)),
1207             ))),
1208             Node::Token(t) if t.kind() == TokenKind::Varray => {
1209                 let pos = self.token_pos(t);
1210                 let tany = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1211                 let ty_ = Ty_::Tapply(self.alloc((
1212                     (self.token_pos(t), naming_special_names::collections::VEC),
1213                     self.alloc([tany]),
1214                 )));
1215                 Some(self.alloc(Ty(self.alloc(Reason::hint(pos)), ty_)))
1216             }
1217             Node::Token(t) if t.kind() == TokenKind::Darray => {
1218                 let pos = self.token_pos(t);
1219                 let tany = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1220                 let ty_ = Ty_::Tapply(self.alloc((
1221                     (self.token_pos(t), naming_special_names::collections::DICT),
1222                     self.alloc([tany, tany]),
1223                 )));
1224                 Some(self.alloc(Ty(self.alloc(Reason::hint(pos)), ty_)))
1225             }
1226             Node::Token(t) if t.kind() == TokenKind::This => {
1227                 Some(self.alloc(Ty(self.alloc(Reason::hint(self.token_pos(t))), Ty_::Tthis)))
1228             }
1229             Node::Token(t) if t.kind() == TokenKind::NullLiteral => {
1230                 let pos = self.token_pos(t);
1231                 Some(self.alloc(Ty(
1232                     self.alloc(Reason::hint(pos)),
1233                     Ty_::Tprim(self.alloc(aast::Tprim::Tnull)),
1234                 )))
1235             }
1236             // In coeffects contexts, we get types like `ctx $f` or `$v::C`.
1237             // Node::Variable is used for the `$f` and `$v`, so that we don't
1238             // incorrectly attempt to elaborate them as names.
1239             Node::Variable(&(name, pos)) => Some(self.alloc(Ty(
1240                 self.alloc(Reason::hint(pos)),
1241                 Ty_::Tapply(self.alloc(((pos, name), &[][..]))),
1242             ))),
1243             node => {
1244                 let Id(pos, name) = self.expect_name(node)?;
1245                 let reason = self.alloc(Reason::hint(pos));
1246                 let ty_ = if self.is_type_param_in_scope(name) {
1247                     // TODO (T69662957) must fill type args of Tgeneric
1248                     Ty_::Tgeneric(self.alloc((name, &[])))
1249                 } else {
1250                     match name {
1251                         "nothing" => Ty_::Tunion(&[]),
1252                         "nonnull" => {
1253                             if self.opts.everything_sdt {
1254                                 Ty_::Tsupportdynamic
1255                             } else {
1256                                 Ty_::Tnonnull
1257                             }
1258                         }
1259                         "dynamic" => Ty_::Tdynamic,
1260                         "supportdynamic" => Ty_::Tsupportdynamic,
1261                         "varray_or_darray" | "vec_or_dict" => {
1262                             let key_type = self.vec_or_dict_key(pos);
1263                             let value_type = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1264                             Ty_::TvecOrDict(self.alloc((key_type, value_type)))
1265                         }
1266                         "_" => Ty_::Terr,
1267                         _ => {
1268                             let name = self.elaborate_raw_id(name);
1269                             Ty_::Tapply(self.alloc(((pos, name), &[][..])))
1270                         }
1271                     }
1272                 };
1273                 Some(self.alloc(Ty(reason, ty_)))
1274             }
1275         }
1276     }
1278     fn rewrite_ty_for_global_inference(
1279         &self,
1280         ty: Option<&'a Ty<'a>>,
1281         reason: Reason<'a>,
1282     ) -> Option<&'a Ty<'a>> {
1283         if !self.opts.global_inference {
1284             return ty;
1285         }
1286         let tvar = self.alloc(Ty(self.alloc(reason), Ty_::Tvar(0)));
1287         let ty = match ty {
1288             None => tvar,
1289             Some(ty) => {
1290                 fn cut_namespace<'a>(id: &'a str) -> &'a str {
1291                     id.rsplit_terminator('\\').next().unwrap()
1292                 }
1293                 fn reinfer_type_to_string_opt<'a>(arena: &'a Bump, ty: Ty_<'a>) -> Option<&'a str> {
1294                     match ty {
1295                         Ty_::Tmixed => Some("mixed"),
1296                         Ty_::Tnonnull => Some("nonnull"),
1297                         Ty_::Tdynamic => Some("dynamic"),
1298                         Ty_::Tunion([]) => Some("nothing"),
1299                         Ty_::Tthis => Some("this"),
1300                         Ty_::Tprim(prim) => Some(match prim {
1301                             aast::Tprim::Tnull => "null",
1302                             aast::Tprim::Tvoid => "void",
1303                             aast::Tprim::Tint => "int",
1304                             aast::Tprim::Tnum => "num",
1305                             aast::Tprim::Tfloat => "float",
1306                             aast::Tprim::Tstring => "string",
1307                             aast::Tprim::Tarraykey => "arraykey",
1308                             aast::Tprim::Tresource => "resource",
1309                             aast::Tprim::Tnoreturn => "noreturn",
1310                             aast::Tprim::Tbool => "bool",
1311                         }),
1312                         Ty_::Tapply(((_p, id), _tyl)) => Some(cut_namespace(id)),
1313                         Ty_::Taccess(TaccessType(ty, id)) => {
1314                             reinfer_type_to_string_opt(arena, ty.1).map(|s| {
1315                                 bumpalo::format!(in arena, "{}::{}", s, id.1).into_bump_str()
1316                             })
1317                         }
1318                         _ => None,
1319                     }
1320                 }
1321                 fn create_vars_for_reinfer_types<'a, 'text, S: SourceTextAllocator<'text, 'a>>(
1322                     this: &DirectDeclSmartConstructors<'a, 'text, S>,
1323                     ty: &'a Ty<'a>,
1324                     tvar: &'a Ty<'a>,
1325                 ) -> &'a Ty<'a> {
1326                     let mk = |r, ty_| this.alloc(Ty(r, ty_));
1327                     let must_reinfer_type = |ty| match reinfer_type_to_string_opt(this.arena, ty) {
1328                         None => false,
1329                         Some(ty_str) => this.opts.gi_reinfer_types.contains(&ty_str),
1330                     };
1331                     match *ty {
1332                         Ty(r, Ty_::Tapply(&(id, [ty1]))) if id.1 == "\\HH\\Awaitable" => {
1333                             let ty1 = this.alloc(create_vars_for_reinfer_types(this, *ty1, tvar));
1334                             mk(r, Ty_::Tapply(this.alloc((id, std::slice::from_ref(ty1)))))
1335                         }
1336                         Ty(r, Ty_::Toption(ty1)) => {
1337                             let ty1 = create_vars_for_reinfer_types(this, ty1, tvar);
1338                             mk(r, Ty_::Toption(ty1))
1339                         }
1340                         Ty(r, Ty_::Tapply(((_p, id), [])))
1341                             if cut_namespace(id) == "PHPism_FIXME_Array" =>
1342                         {
1343                             if must_reinfer_type(ty.1) {
1344                                 let tvar = mk(r, Ty_::Tvar(0));
1345                                 mk(r, Ty_::TvarrayOrDarray(this.alloc((tvar, tvar))))
1346                             } else {
1347                                 ty
1348                             }
1349                         }
1350                         Ty(r, Ty_::Tvarray(ty)) => {
1351                             let ty = create_vars_for_reinfer_types(this, ty, tvar);
1352                             mk(r, Ty_::Tvarray(ty))
1353                         }
1354                         Ty(r, Ty_::Tdarray((tyk, tyv))) => {
1355                             let tyk = create_vars_for_reinfer_types(this, tyk, tvar);
1356                             let tyv = create_vars_for_reinfer_types(this, tyv, tvar);
1357                             mk(r, Ty_::Tdarray(this.alloc((tyk, tyv))))
1358                         }
1359                         Ty(r, Ty_::TvarrayOrDarray((tyk, tyv))) => {
1360                             let tyk = create_vars_for_reinfer_types(this, tyk, tvar);
1361                             let tyv = create_vars_for_reinfer_types(this, tyv, tvar);
1362                             mk(r, Ty_::TvarrayOrDarray(this.alloc((tyk, tyv))))
1363                         }
1364                         Ty(_r, ty_) => {
1365                             if must_reinfer_type(ty_) {
1366                                 tvar
1367                             } else {
1368                                 ty
1369                             }
1370                         }
1371                     }
1372                 }
1373                 create_vars_for_reinfer_types(self, ty, tvar)
1374             }
1375         };
1376         Some(ty)
1377     }
1379     fn to_attributes(&self, node: Node<'a>) -> Attributes<'a> {
1380         let mut attributes = Attributes {
1381             deprecated: None,
1382             reifiable: None,
1383             late_init: false,
1384             const_: false,
1385             lsb: false,
1386             memoizelsb: false,
1387             override_: false,
1388             enforceable: None,
1389             accept_disposable: false,
1390             dynamically_callable: false,
1391             returns_disposable: false,
1392             php_std_lib: false,
1393             ifc_attribute: default_ifc_fun_decl(),
1394             external: false,
1395             can_call: false,
1396             via_label: false,
1397             soft: false,
1398             support_dynamic_type: false,
1399             module: None,
1400             internal: false,
1401         };
1403         let nodes = match node {
1404             Node::List(&nodes) | Node::BracketedList(&(_, nodes, _)) => nodes,
1405             _ => return attributes,
1406         };
1408         let mut ifc_already_policied = false;
1410         // Iterate in reverse, to match the behavior of OCaml decl in error conditions.
1411         for attribute in nodes.iter().rev() {
1412             if let Node::Attribute(attribute) = attribute {
1413                 match attribute.name.1.as_ref() {
1414                     "__Deprecated" => {
1415                         attributes.deprecated = attribute
1416                             .string_literal_params
1417                             .first()
1418                             .map(|&x| self.str_from_utf8_for_bytes_in_arena(x));
1419                     }
1420                     "__Reifiable" => attributes.reifiable = Some(attribute.name.0),
1421                     "__LateInit" => {
1422                         attributes.late_init = true;
1423                     }
1424                     "__Const" => {
1425                         attributes.const_ = true;
1426                     }
1427                     "__LSB" => {
1428                         attributes.lsb = true;
1429                     }
1430                     "__MemoizeLSB" => {
1431                         attributes.memoizelsb = true;
1432                     }
1433                     "__Override" => {
1434                         attributes.override_ = true;
1435                     }
1436                     "__Enforceable" => {
1437                         attributes.enforceable = Some(attribute.name.0);
1438                     }
1439                     "__AcceptDisposable" => {
1440                         attributes.accept_disposable = true;
1441                     }
1442                     "__DynamicallyCallable" => {
1443                         attributes.dynamically_callable = true;
1444                     }
1445                     "__ReturnDisposable" => {
1446                         attributes.returns_disposable = true;
1447                     }
1448                     "__PHPStdLib" => {
1449                         attributes.php_std_lib = true;
1450                     }
1451                     "__Policied" => {
1452                         let string_literal_params = || {
1453                             attribute
1454                                 .string_literal_params
1455                                 .first()
1456                                 .map(|&x| self.str_from_utf8_for_bytes_in_arena(x))
1457                         };
1458                         // Take the classname param by default
1459                         attributes.ifc_attribute =
1460                             IfcFunDecl::FDPolicied(attribute.classname_params.first().map_or_else(
1461                                 string_literal_params, // default
1462                                 |&x| Some(x.name.1),   // f
1463                             ));
1464                         ifc_already_policied = true;
1465                     }
1466                     "__InferFlows" => {
1467                         if !ifc_already_policied {
1468                             attributes.ifc_attribute = IfcFunDecl::FDInferFlows;
1469                         }
1470                     }
1471                     "__External" => {
1472                         attributes.external = true;
1473                     }
1474                     "__CanCall" => {
1475                         attributes.can_call = true;
1476                     }
1477                     naming_special_names::user_attributes::VIA_LABEL => {
1478                         attributes.via_label = true;
1479                     }
1480                     "__Soft" => {
1481                         attributes.soft = true;
1482                     }
1483                     "__SupportDynamicType" => {
1484                         attributes.support_dynamic_type = true;
1485                     }
1486                     "__Module" => {
1487                         attributes.module = attribute
1488                             .string_literal_params
1489                             .first()
1490                             .map(|&x| self.str_from_utf8_for_bytes_in_arena(x))
1491                             .and_then(|x| {
1492                                 let mut chars = x.split('.');
1493                                 match chars.next() {
1494                                     None => None,
1495                                     Some(s) => {
1496                                         let rest = chars.collect::<std::vec::Vec<_>>();
1497                                         Some(self.alloc(Module_(s, self.alloc(rest))))
1498                                     }
1499                                 }
1500                             });
1501                     }
1502                     "__Internal" => {
1503                         attributes.internal = true;
1504                     }
1505                     _ => {}
1506                 }
1507             }
1508         }
1510         attributes
1511     }
1513     // Limited version of node_to_ty that matches behavior of Decl_utils.infer_const
1514     fn infer_const(&self, name: Node<'a>, node: Node<'a>) -> Option<&'a Ty<'a>> {
1515         match node {
1516             Node::StringLiteral(_)
1517             | Node::BooleanLiteral(_)
1518             | Node::IntLiteral(_)
1519             | Node::FloatingLiteral(_)
1520             | Node::Expr(aast::Expr(_, _, aast::Expr_::Unop(&(Uop::Uminus, _))))
1521             | Node::Expr(aast::Expr(_, _, aast::Expr_::Unop(&(Uop::Uplus, _))))
1522             | Node::Expr(aast::Expr(_, _, aast::Expr_::String(..))) => self.node_to_ty(node),
1523             Node::Token(t) if t.kind() == TokenKind::NullLiteral => {
1524                 let pos = self.token_pos(t);
1525                 Some(self.alloc(Ty(
1526                     self.alloc(Reason::witness_from_decl(pos)),
1527                     Ty_::Tprim(self.alloc(aast::Tprim::Tnull)),
1528                 )))
1529             }
1530             _ => Some(self.tany_with_pos(self.get_pos(name))),
1531         }
1532     }
1534     fn pop_type_params(&mut self, node: Node<'a>) -> &'a [&'a Tparam<'a>] {
1535         match node {
1536             Node::TypeParameters(tparams) => {
1537                 Rc::make_mut(&mut self.type_parameters).pop().unwrap();
1538                 tparams
1539             }
1540             _ => &[],
1541         }
1542     }
1544     fn ret_from_fun_kind(&self, kind: FunKind, type_: &'a Ty<'a>) -> &'a Ty<'a> {
1545         let pos = type_.get_pos().unwrap_or_else(|| Pos::none());
1546         match kind {
1547             FunKind::FAsyncGenerator => self.alloc(Ty(
1548                 self.alloc(Reason::RretFunKindFromDecl(self.alloc((pos, kind)))),
1549                 Ty_::Tapply(self.alloc((
1550                     (pos, naming_special_names::classes::ASYNC_GENERATOR),
1551                     self.alloc([type_, type_, type_]),
1552                 ))),
1553             )),
1554             FunKind::FGenerator => self.alloc(Ty(
1555                 self.alloc(Reason::RretFunKindFromDecl(self.alloc((pos, kind)))),
1556                 Ty_::Tapply(self.alloc((
1557                     (pos, naming_special_names::classes::GENERATOR),
1558                     self.alloc([type_, type_, type_]),
1559                 ))),
1560             )),
1561             FunKind::FAsync => self.alloc(Ty(
1562                 self.alloc(Reason::RretFunKindFromDecl(self.alloc((pos, kind)))),
1563                 Ty_::Tapply(self.alloc((
1564                     (pos, naming_special_names::classes::AWAITABLE),
1565                     self.alloc([type_]),
1566                 ))),
1567             )),
1568             _ => type_,
1569         }
1570     }
1572     fn is_type_param_in_scope(&self, name: &str) -> bool {
1573         self.type_parameters.iter().any(|tps| tps.contains(name))
1574     }
1576     fn as_fun_implicit_params(
1577         &mut self,
1578         capability: Node<'a>,
1579         default_pos: &'a Pos<'a>,
1580     ) -> &'a FunImplicitParams<'a> {
1581         /* Note: do not simplify intersections, keep empty / singleton intersections
1582          * for coeffect contexts
1583          */
1584         let capability = match self.node_to_ty(capability) {
1585             Some(ty) => CapTy(ty),
1586             None => CapDefaults(default_pos),
1587         };
1588         self.alloc(FunImplicitParams { capability })
1589     }
1591     fn function_to_ty(
1592         &mut self,
1593         is_method: bool,
1594         attributes: Node<'a>,
1595         header: &'a FunctionHeader<'a>,
1596         body: Node<'_>,
1597     ) -> Option<(PosId<'a>, &'a Ty<'a>, &'a [ShallowProp<'a>])> {
1598         let id_opt = match (is_method, header.name) {
1599             // If the name is missing, we use the left paren here, just to get a
1600             // position to point to.
1601             (_, Node::Token(t)) if t.kind() == TokenKind::LeftParen => {
1602                 let pos = self.token_pos(t);
1603                 Some(Id(pos, ""))
1604             }
1605             (true, Node::Token(t)) if t.kind() == TokenKind::Construct => {
1606                 let pos = self.token_pos(t);
1607                 Some(Id(pos, naming_special_names::members::__CONSTRUCT))
1608             }
1609             (true, _) => self.expect_name(header.name),
1610             (false, _) => self.elaborate_defined_id(header.name),
1611         };
1612         let id = id_opt.unwrap_or(Id(self.get_pos(header.name), ""));
1613         let (params, properties, arity) = self.as_fun_params(header.param_list)?;
1614         let f_pos = self.get_pos(header.name);
1615         let implicit_params = self.as_fun_implicit_params(header.capability, f_pos);
1617         let type_ = match header.name {
1618             Node::Token(t) if t.kind() == TokenKind::Construct => {
1619                 let pos = self.token_pos(t);
1620                 self.alloc(Ty(
1621                     self.alloc(Reason::witness_from_decl(pos)),
1622                     Ty_::Tprim(self.alloc(aast::Tprim::Tvoid)),
1623                 ))
1624             }
1625             _ => self
1626                 .rewrite_ty_for_global_inference(
1627                     self.node_to_ty(header.ret_hint),
1628                     Reason::RglobalFunRet(f_pos),
1629                 )
1630                 .unwrap_or_else(|| self.tany_with_pos(f_pos)),
1631         };
1632         let async_ = header
1633             .modifiers
1634             .iter()
1635             .any(|n| n.is_token(TokenKind::Async));
1636         let readonly = header
1637             .modifiers
1638             .iter()
1639             .any(|n| n.is_token(TokenKind::Readonly));
1641         let fun_kind = if body.iter().any(|node| node.is_token(TokenKind::Yield)) {
1642             if async_ {
1643                 FunKind::FAsyncGenerator
1644             } else {
1645                 FunKind::FGenerator
1646             }
1647         } else {
1648             if async_ {
1649                 FunKind::FAsync
1650             } else {
1651                 FunKind::FSync
1652             }
1653         };
1654         let type_ = if !header.ret_hint.is_present() {
1655             self.ret_from_fun_kind(fun_kind, type_)
1656         } else {
1657             type_
1658         };
1659         let attributes = self.to_attributes(attributes);
1660         // TODO(hrust) Put this in a helper. Possibly do this for all flags.
1661         let mut flags = match fun_kind {
1662             FunKind::FSync => FunTypeFlags::empty(),
1663             FunKind::FAsync => FunTypeFlags::ASYNC,
1664             FunKind::FGenerator => FunTypeFlags::GENERATOR,
1665             FunKind::FAsyncGenerator => FunTypeFlags::ASYNC | FunTypeFlags::GENERATOR,
1666         };
1668         if attributes.returns_disposable {
1669             flags |= FunTypeFlags::RETURN_DISPOSABLE;
1670         }
1671         if attributes.support_dynamic_type {
1672             flags |= FunTypeFlags::SUPPORT_DYNAMIC_TYPE;
1673         }
1674         if header.readonly_return.is_token(TokenKind::Readonly) {
1675             flags |= FunTypeFlags::RETURNS_READONLY;
1676         }
1677         if readonly {
1678             flags |= FunTypeFlags::READONLY_THIS
1679         }
1681         let ifc_decl = attributes.ifc_attribute;
1683         // Pop the type params stack only after creating all inner types.
1684         let tparams = self.pop_type_params(header.type_params);
1686         let where_constraints =
1687             self.slice(header.where_constraints.iter().filter_map(|&x| match x {
1688                 Node::WhereConstraint(x) => Some(x),
1689                 _ => None,
1690             }));
1692         let (params, tparams, implicit_params, where_constraints) =
1693             self.rewrite_effect_polymorphism(params, tparams, implicit_params, where_constraints);
1695         let ft = self.alloc(FunType {
1696             arity,
1697             tparams,
1698             where_constraints,
1699             params,
1700             implicit_params,
1701             ret: self.alloc(PossiblyEnforcedTy {
1702                 enforced: Enforcement::Unenforced,
1703                 type_,
1704             }),
1705             flags,
1706             ifc_decl,
1707         });
1709         let ty = self.alloc(Ty(
1710             self.alloc(Reason::witness_from_decl(id.0)),
1711             Ty_::Tfun(ft),
1712         ));
1713         Some((id.into(), ty, properties))
1714     }
1716     fn as_fun_params(
1717         &self,
1718         list: Node<'a>,
1719     ) -> Option<(&'a FunParams<'a>, &'a [ShallowProp<'a>], FunArity<'a>)> {
1720         match list {
1721             Node::List(nodes) => {
1722                 let mut params = Vec::with_capacity_in(nodes.len(), self.arena);
1723                 let mut properties = Vec::new_in(self.arena);
1724                 let mut arity = FunArity::Fstandard;
1725                 for node in nodes.iter() {
1726                     match node {
1727                         Node::FunParam(&FunParamDecl {
1728                             attributes,
1729                             visibility,
1730                             kind,
1731                             readonly,
1732                             hint,
1733                             pos,
1734                             name,
1735                             variadic,
1736                             initializer,
1737                         }) => {
1738                             let attributes = self.to_attributes(attributes);
1740                             if let Some(visibility) = visibility.as_visibility() {
1741                                 let name = name.unwrap_or("");
1742                                 let name = strip_dollar_prefix(name);
1743                                 let mut flags = PropFlags::empty();
1744                                 flags.set(PropFlags::CONST, attributes.const_);
1745                                 flags.set(PropFlags::NEEDS_INIT, self.file_mode != Mode::Mhhi);
1746                                 flags.set(PropFlags::PHP_STD_LIB, attributes.php_std_lib);
1747                                 flags.set(PropFlags::READONLY, readonly);
1748                                 properties.push(ShallowProp {
1749                                     xhp_attr: None,
1750                                     name: (pos, name),
1751                                     type_: self.rewrite_ty_for_global_inference(
1752                                         self.node_to_ty(hint),
1753                                         Reason::RglobalFunParam(pos),
1754                                     ),
1755                                     visibility: if attributes.internal
1756                                         && visibility == aast::Visibility::Public
1757                                     {
1758                                         aast::Visibility::Internal
1759                                     } else {
1760                                         visibility
1761                                     },
1762                                     flags,
1763                                 });
1764                             }
1766                             let type_ = self
1767                                 .rewrite_ty_for_global_inference(
1768                                     self.node_to_ty(hint),
1769                                     Reason::RglobalFunParam(pos),
1770                                 )
1771                                 .unwrap_or_else(|| self.tany_with_pos(pos));
1772                             // These are illegal here--they can only be used on
1773                             // parameters in a function type hint (see
1774                             // make_closure_type_specifier and unwrap_mutability).
1775                             // Unwrap them here anyway for better error recovery.
1776                             let type_ = match type_ {
1777                                 Ty(_, Ty_::Tapply(((_, "\\Mutable"), [t]))) => t,
1778                                 Ty(_, Ty_::Tapply(((_, "\\OwnedMutable"), [t]))) => t,
1779                                 Ty(_, Ty_::Tapply(((_, "\\MaybeMutable"), [t]))) => t,
1780                                 _ => type_,
1781                             };
1782                             let mut flags = FunParamFlags::empty();
1783                             if attributes.accept_disposable {
1784                                 flags |= FunParamFlags::ACCEPT_DISPOSABLE
1785                             }
1786                             if attributes.external {
1787                                 flags |= FunParamFlags::IFC_EXTERNAL
1788                             }
1789                             if attributes.can_call {
1790                                 flags |= FunParamFlags::IFC_CAN_CALL
1791                             }
1792                             if attributes.via_label {
1793                                 flags |= FunParamFlags::VIA_LABEL
1794                             }
1795                             if readonly {
1796                                 flags |= FunParamFlags::READONLY
1797                             }
1798                             match kind {
1799                                 ParamMode::FPinout => {
1800                                     flags |= FunParamFlags::INOUT;
1801                                 }
1802                                 ParamMode::FPnormal => {}
1803                             };
1805                             if initializer.is_present() {
1806                                 flags |= FunParamFlags::HAS_DEFAULT;
1807                             }
1808                             let variadic = initializer.is_ignored() && variadic;
1809                             let type_ = if variadic {
1810                                 self.alloc(Ty(
1811                                     self.alloc(if name.is_some() {
1812                                         Reason::RvarParamFromDecl(pos)
1813                                     } else {
1814                                         Reason::witness_from_decl(pos)
1815                                     }),
1816                                     type_.1,
1817                                 ))
1818                             } else {
1819                                 type_
1820                             };
1821                             let param = self.alloc(FunParam {
1822                                 pos,
1823                                 name,
1824                                 type_: self.alloc(PossiblyEnforcedTy {
1825                                     enforced: Enforcement::Unenforced,
1826                                     type_,
1827                                 }),
1828                                 flags,
1829                             });
1830                             arity = match arity {
1831                                 FunArity::Fstandard if variadic => FunArity::Fvariadic(param),
1832                                 arity => {
1833                                     params.push(param);
1834                                     arity
1835                                 }
1836                             };
1837                         }
1838                         _ => {}
1839                     }
1840                 }
1841                 Some((
1842                     params.into_bump_slice(),
1843                     properties.into_bump_slice(),
1844                     arity,
1845                 ))
1846             }
1847             n if n.is_ignored() => Some((&[], &[], FunArity::Fstandard)),
1848             _ => None,
1849         }
1850     }
1852     fn make_shape_field_name(&self, name: Node<'a>) -> Option<ShapeFieldName<'a>> {
1853         Some(match name {
1854             Node::StringLiteral(&(s, pos)) => ShapeFieldName::SFlitStr(self.alloc((pos, s))),
1855             // TODO: OCaml decl produces SFlitStr here instead of SFlitInt, so
1856             // we must also. Looks like int literal keys have become a parse
1857             // error--perhaps that's why.
1858             Node::IntLiteral(&(s, pos)) => ShapeFieldName::SFlitStr(self.alloc((pos, s.into()))),
1859             Node::Expr(aast::Expr(
1860                 _,
1861                 _,
1862                 aast::Expr_::ClassConst(&(
1863                     aast::ClassId(_, _, aast::ClassId_::CI(&class_name)),
1864                     const_name,
1865                 )),
1866             )) => ShapeFieldName::SFclassConst(self.alloc((class_name, const_name))),
1867             Node::Expr(aast::Expr(
1868                 _,
1869                 _,
1870                 aast::Expr_::ClassConst(&(
1871                     aast::ClassId(_, pos, aast::ClassId_::CIself),
1872                     const_name,
1873                 )),
1874             )) => ShapeFieldName::SFclassConst(self.alloc((
1875                 Id(
1876                     pos,
1877                     self.classish_name_builder.get_current_classish_name()?.0,
1878                 ),
1879                 const_name,
1880             ))),
1881             _ => return None,
1882         })
1883     }
1887     fn make_t_shape_field_name(&mut self, ShapeField(field): &ShapeField<'a>) -> TShapeField<'a> {
1888         TShapeField(match field {
1889             ShapeFieldName::SFlitInt(&(pos, x)) => {
1890                 TshapeFieldName::TSFlitInt(self.alloc(PosString(pos, x)))
1891             }
1892             ShapeFieldName::SFlitStr(&(pos, x)) => {
1893                 TshapeFieldName::TSFlitStr(self.alloc(PosByteString(pos, x)))
1894             }
1895             ShapeFieldName::SFclassConst(&(id, &(pos, x))) => {
1896                 TshapeFieldName::TSFclassConst(self.alloc((id.into(), PosString(pos, x))))
1897             }
1898         })
1899     }
1901     fn make_apply(
1902         &self,
1903         base_ty: PosId<'a>,
1904         type_arguments: Node<'a>,
1905         pos_to_merge: &'a Pos<'a>,
1906     ) -> Node<'a> {
1907         let type_arguments = self.slice(
1908             type_arguments
1909                 .iter()
1910                 .filter_map(|&node| self.node_to_ty(node)),
1911         );
1913         let pos = self.merge(base_ty.0, pos_to_merge);
1915         // OCaml decl creates a capability with a hint pointing to the entire
1916         // type (i.e., pointing to `Rx<(function(): void)>` rather than just
1917         // `(function(): void)`), so we extend the hint position similarly here.
1918         let extend_capability_pos = |implicit_params: &'a FunImplicitParams<'_>| {
1919             let capability = match implicit_params.capability {
1920                 CapTy(ty) => {
1921                     let ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), ty.1));
1922                     CapTy(ty)
1923                 }
1924                 CapDefaults(_) => CapDefaults(pos),
1925             };
1926             self.alloc(FunImplicitParams {
1927                 capability,
1928                 ..*implicit_params
1929             })
1930         };
1932         let ty_ = match (base_ty, type_arguments) {
1933             ((_, name), &[&Ty(_, Ty_::Tfun(f))]) if name == "\\Pure" => {
1934                 Ty_::Tfun(self.alloc(FunType {
1935                     implicit_params: extend_capability_pos(f.implicit_params),
1936                     ..*f
1937                 }))
1938             }
1939             _ => Ty_::Tapply(self.alloc((base_ty, type_arguments))),
1940         };
1942         self.hint_ty(pos, ty_)
1943     }
1945     fn hint_ty(&self, pos: &'a Pos<'a>, ty_: Ty_<'a>) -> Node<'a> {
1946         Node::Ty(self.alloc(Ty(self.alloc(Reason::hint(pos)), ty_)))
1947     }
1949     fn prim_ty(&self, tprim: aast::Tprim, pos: &'a Pos<'a>) -> Node<'a> {
1950         self.hint_ty(pos, Ty_::Tprim(self.alloc(tprim)))
1951     }
1953     fn tany_with_pos(&self, pos: &'a Pos<'a>) -> &'a Ty<'a> {
1954         self.alloc(Ty(self.alloc(Reason::witness_from_decl(pos)), TANY_))
1955     }
1957     /// The type used when a `vec_or_dict` typehint is missing its key type argument.
1958     fn vec_or_dict_key(&self, pos: &'a Pos<'a>) -> &'a Ty<'a> {
1959         self.alloc(Ty(
1960             self.alloc(Reason::RvecOrDictKey(pos)),
1961             Ty_::Tprim(self.alloc(aast::Tprim::Tarraykey)),
1962         ))
1963     }
1965     fn source_text_at_pos(&self, pos: &'a Pos<'a>) -> &'text [u8] {
1966         let start = pos.start_cnum();
1967         let end = pos.end_cnum();
1968         self.source_text.source_text().sub(start, end - start)
1969     }
1971     // While we usually can tell whether to allocate a Tapply or Tgeneric based
1972     // on our type_parameters stack, *constraints* on type parameters may
1973     // reference type parameters which we have not parsed yet. When constructing
1974     // a type parameter list, we use this function to rewrite the type of each
1975     // constraint, considering the full list of type parameters to be in scope.
1976     fn convert_tapply_to_tgeneric(&self, ty: &'a Ty<'a>) -> &'a Ty<'a> {
1977         let ty_ = match ty.1 {
1978             Ty_::Tapply(&(id, targs)) => {
1979                 let converted_targs = self.slice(
1980                     targs
1981                         .iter()
1982                         .map(|&targ| self.convert_tapply_to_tgeneric(targ)),
1983                 );
1984                 match self.tapply_should_be_tgeneric(ty.0, id) {
1985                     Some(name) => Ty_::Tgeneric(self.alloc((name, converted_targs))),
1986                     None => Ty_::Tapply(self.alloc((id, converted_targs))),
1987                 }
1988             }
1989             Ty_::Tlike(ty) => Ty_::Tlike(self.convert_tapply_to_tgeneric(ty)),
1990             Ty_::Toption(ty) => Ty_::Toption(self.convert_tapply_to_tgeneric(ty)),
1991             Ty_::Tfun(fun_type) => {
1992                 let convert_param = |param: &'a FunParam<'a>| {
1993                     self.alloc(FunParam {
1994                         type_: self.alloc(PossiblyEnforcedTy {
1995                             enforced: param.type_.enforced,
1996                             type_: self.convert_tapply_to_tgeneric(param.type_.type_),
1997                         }),
1998                         ..*param
1999                     })
2000                 };
2001                 let arity = match fun_type.arity {
2002                     FunArity::Fstandard => FunArity::Fstandard,
2003                     FunArity::Fvariadic(param) => FunArity::Fvariadic(convert_param(param)),
2004                 };
2005                 let params = self.slice(fun_type.params.iter().copied().map(convert_param));
2006                 let implicit_params = fun_type.implicit_params;
2007                 let ret = self.alloc(PossiblyEnforcedTy {
2008                     enforced: fun_type.ret.enforced,
2009                     type_: self.convert_tapply_to_tgeneric(fun_type.ret.type_),
2010                 });
2011                 Ty_::Tfun(self.alloc(FunType {
2012                     arity,
2013                     params,
2014                     implicit_params,
2015                     ret,
2016                     ..*fun_type
2017                 }))
2018             }
2019             Ty_::Tshape(&(kind, fields)) => {
2020                 let mut converted_fields = AssocListMut::with_capacity_in(fields.len(), self.arena);
2021                 for (&name, ty) in fields.iter() {
2022                     converted_fields.insert(
2023                         name,
2024                         self.alloc(ShapeFieldType {
2025                             optional: ty.optional,
2026                             ty: self.convert_tapply_to_tgeneric(ty.ty),
2027                         }),
2028                     );
2029                 }
2030                 Ty_::Tshape(self.alloc((kind, converted_fields.into())))
2031             }
2032             Ty_::Tdarray(&(tk, tv)) => Ty_::Tdarray(self.alloc((
2033                 self.convert_tapply_to_tgeneric(tk),
2034                 self.convert_tapply_to_tgeneric(tv),
2035             ))),
2036             Ty_::Tvarray(ty) => Ty_::Tvarray(self.convert_tapply_to_tgeneric(ty)),
2037             Ty_::TvarrayOrDarray(&(tk, tv)) => Ty_::TvarrayOrDarray(self.alloc((
2038                 self.convert_tapply_to_tgeneric(tk),
2039                 self.convert_tapply_to_tgeneric(tv),
2040             ))),
2041             Ty_::TvecOrDict(&(tk, tv)) => Ty_::TvecOrDict(self.alloc((
2042                 self.convert_tapply_to_tgeneric(tk),
2043                 self.convert_tapply_to_tgeneric(tv),
2044             ))),
2045             Ty_::Ttuple(tys) => Ty_::Ttuple(
2046                 self.slice(
2047                     tys.iter()
2048                         .map(|&targ| self.convert_tapply_to_tgeneric(targ)),
2049                 ),
2050             ),
2051             _ => return ty,
2052         };
2053         self.alloc(Ty(ty.0, ty_))
2054     }
2056     // This is the logic for determining if convert_tapply_to_tgeneric should turn
2057     // a Tapply into a Tgeneric
2058     fn tapply_should_be_tgeneric(&self, reason: &'a Reason<'a>, id: PosId<'a>) -> Option<&'a str> {
2059         match reason.pos() {
2060             // If the name contained a namespace delimiter in the original
2061             // source text, then it can't have referred to a type parameter
2062             // (since type parameters cannot be namespaced).
2063             Some(pos) => {
2064                 if self.source_text_at_pos(pos).contains(&b'\\') {
2065                     return None;
2066                 }
2067             }
2068             None => return None,
2069         }
2070         // However, the direct decl parser will unconditionally prefix
2071         // the name with the current namespace (as it does for any
2072         // Tapply). We need to remove it.
2073         match id.1.rsplit('\\').next() {
2074             Some(name) if self.is_type_param_in_scope(name) => return Some(name),
2075             _ => return None,
2076         }
2077     }
2079     fn rewrite_taccess_reasons(&self, ty: &'a Ty<'a>, r: &'a Reason<'a>) -> &'a Ty<'a> {
2080         let ty_ = match ty.1 {
2081             Ty_::Taccess(&TaccessType(ty, id)) => {
2082                 Ty_::Taccess(self.alloc(TaccessType(self.rewrite_taccess_reasons(ty, r), id)))
2083             }
2084             ty_ => ty_,
2085         };
2086         self.alloc(Ty(r, ty_))
2087     }
2089     fn user_attribute_to_decl(
2090         &self,
2091         attr: &UserAttributeNode<'a>,
2092     ) -> &'a shallow_decl_defs::UserAttribute<'a> {
2093         self.alloc(shallow_decl_defs::UserAttribute {
2094             name: attr.name.into(),
2095             classname_params: self.slice(attr.classname_params.iter().map(|p| p.name.1)),
2096         })
2097     }
2099     fn namespace_use_kind(use_kind: &Node<'_>) -> Option<NamespaceUseKind> {
2100         match use_kind.token_kind() {
2101             Some(TokenKind::Const) => None,
2102             Some(TokenKind::Function) => None,
2103             Some(TokenKind::Type) => Some(NamespaceUseKind::Type),
2104             Some(TokenKind::Namespace) => Some(NamespaceUseKind::Namespace),
2105             _ if !use_kind.is_present() => Some(NamespaceUseKind::Mixed),
2106             _ => None,
2107         }
2108     }
2110     fn has_polymorphic_context(contexts: &[&Ty<'_>]) -> bool {
2111         contexts.iter().any(|&ty| match ty.1 {
2112             Ty_::Tapply((root, &[])) // Hfun_context in the AST
2113             | Ty_::Taccess(TaccessType(Ty(_, Ty_::Tapply((root, &[]))), _)) => root.1.contains('$'),
2114             | Ty_::Taccess(TaccessType(t, _)) => Self::taccess_root_is_generic(t),
2115             _ => false,
2116         })
2117     }
2119     fn ctx_generic_for_fun(&self, name: &str) -> &'a str {
2120         bumpalo::format!(in self.arena, "T/[ctx {}]", name).into_bump_str()
2121     }
2123     fn ctx_generic_for_dependent(&self, name: &str, cst: &str) -> &'a str {
2124         bumpalo::format!(in self.arena, "T/[{}::{}]", name, cst).into_bump_str()
2125     }
2127     // Note: the reason for the divergence between this and the lowerer is that
2128     // hint Haccess is a flat list, whereas decl ty Taccess is a tree.
2129     fn taccess_root_is_generic(ty: &Ty<'_>) -> bool {
2130         match ty {
2131             Ty(_, Ty_::Tgeneric((_, &[]))) => true,
2132             Ty(_, Ty_::Taccess(&TaccessType(t, _))) => Self::taccess_root_is_generic(t),
2133             _ => false,
2134         }
2135     }
2137     fn ctx_generic_for_generic_taccess_inner(&self, ty: &Ty<'_>, cst: &str) -> std::string::String {
2138         let left = match ty {
2139             Ty(_, Ty_::Tgeneric((name, &[]))) => name.to_string(),
2140             Ty(_, Ty_::Taccess(&TaccessType(ty, cst))) => {
2141                 self.ctx_generic_for_generic_taccess_inner(ty, cst.1)
2142             }
2143             _ => panic!("Unexpected element in Taccess"),
2144         };
2145         format!("{}::{}", left, cst)
2146     }
2147     fn ctx_generic_for_generic_taccess(&self, ty: &Ty<'_>, cst: &str) -> &'a str {
2148         bumpalo::format!(in self.arena, "T/[{}]", self.ctx_generic_for_generic_taccess_inner(ty, cst))
2149             .into_bump_str()
2150     }
2152     fn rewrite_effect_polymorphism(
2153         &self,
2154         params: &'a [&'a FunParam<'a>],
2155         tparams: &'a [&'a Tparam<'a>],
2156         implicit_params: &'a FunImplicitParams<'a>,
2157         where_constraints: &'a [&'a WhereConstraint<'a>],
2158     ) -> (
2159         &'a [&'a FunParam<'a>],
2160         &'a [&'a Tparam<'a>],
2161         &'a FunImplicitParams<'a>,
2162         &'a [&'a WhereConstraint<'a>],
2163     ) {
2164         let (cap_reason, context_tys) = match implicit_params.capability {
2165             CapTy(&Ty(r, Ty_::Tintersection(tys))) if Self::has_polymorphic_context(tys) => {
2166                 (r, tys)
2167             }
2168             CapTy(ty) if Self::has_polymorphic_context(&[ty]) => {
2169                 (ty.0, std::slice::from_ref(self.alloc(ty)))
2170             }
2171             _ => return (params, tparams, implicit_params, where_constraints),
2172         };
2173         let tp = |name, constraints| {
2174             self.alloc(Tparam {
2175                 variance: Variance::Invariant,
2176                 name,
2177                 tparams: &[],
2178                 constraints,
2179                 reified: aast::ReifyKind::Erased,
2180                 user_attributes: &[],
2181             })
2182         };
2184         // For a polymorphic context with form `ctx $f` (represented here as
2185         // `Tapply "$f"`), add a type parameter named `Tctx$f`, and rewrite the
2186         // parameter `(function (ts)[_]: t) $f` as `(function (ts)[Tctx$f]: t) $f`
2187         let rewrite_fun_ctx =
2188             |tparams: &mut Vec<'_, &'a Tparam<'a>>, ty: &Ty<'a>, param_name: &str| -> Ty<'a> {
2189                 let ft = match ty.1 {
2190                     Ty_::Tfun(ft) => ft,
2191                     _ => return ty.clone(),
2192                 };
2193                 let cap_ty = match ft.implicit_params.capability {
2194                     CapTy(&Ty(_, Ty_::Tintersection(&[ty]))) | CapTy(ty) => ty,
2195                     _ => return ty.clone(),
2196                 };
2197                 let pos = match cap_ty.1 {
2198                     Ty_::Tapply(((pos, "_"), _)) => pos,
2199                     _ => return ty.clone(),
2200                 };
2201                 let name = self.ctx_generic_for_fun(param_name);
2202                 let tparam = tp((pos, name), &[]);
2203                 tparams.push(tparam);
2204                 let cap_ty = self.alloc(Ty(cap_ty.0, Ty_::Tgeneric(self.alloc((name, &[])))));
2205                 let ft = self.alloc(FunType {
2206                     implicit_params: self.alloc(FunImplicitParams {
2207                         capability: CapTy(cap_ty),
2208                     }),
2209                     ..*ft
2210                 });
2211                 Ty(ty.0, Ty_::Tfun(ft))
2212             };
2214         // For a polymorphic context with form `$g::C`, if we have a function
2215         // parameter `$g` with type `G` (where `G` is not a type parameter),
2216         //   - add a type parameter constrained by $g's type: `T/$g as G`
2217         //   - replace $g's type hint (`G`) with the new type parameter `T/$g`
2218         // Then, for each polymorphic context with form `$g::C`,
2219         //   - add a type parameter `T/[$g::C]`
2220         //   - add a where constraint `T/[$g::C] = T$g :: C`
2221         let rewrite_arg_ctx = |
2222             tparams: &mut Vec<'_, &'a Tparam<'a>>,
2223             where_constraints: &mut Vec<'_, &'a WhereConstraint<'a>>,
2224             ty: &Ty<'a>,
2225             param_pos: &'a Pos<'a>,
2226             name: &str,
2227             context_reason: &'a Reason<'a>,
2228             cst: PosId<'a>,
2229         | -> Ty<'a> {
2230             let rewritten_ty = match ty.1 {
2231                 // If the type hint for this function parameter is a type
2232                 // parameter introduced in this function declaration, don't add
2233                 // a new type parameter.
2234                 Ty_::Tgeneric(&(type_name, _))
2235                     if tparams.iter().any(|tp| tp.name.1 == type_name) =>
2236                 {
2237                     ty.clone()
2238                 }
2239                 // Otherwise, if the parameter is `G $g`, create tparam
2240                 // `T$g as G` and replace $g's type hint
2241                 _ => {
2242                     let id = (param_pos, self.concat("T/", name));
2243                     tparams.push(tp(
2244                         id,
2245                         std::slice::from_ref(
2246                             self.alloc((ConstraintKind::ConstraintAs, self.alloc(ty.clone()))),
2247                         ),
2248                     ));
2249                     Ty(
2250                         self.alloc(Reason::hint(param_pos)),
2251                         Ty_::Tgeneric(self.alloc((id.1, &[]))),
2252                     )
2253                 }
2254             };
2255             let ty = self.alloc(Ty(context_reason, rewritten_ty.1));
2256             let right = self.alloc(Ty(
2257                 context_reason,
2258                 Ty_::Taccess(self.alloc(TaccessType(ty, cst))),
2259             ));
2260             let left_id = (
2261                 context_reason.pos().unwrap_or(Pos::none()),
2262                 self.ctx_generic_for_dependent(name, &cst.1),
2263             );
2264             tparams.push(tp(left_id, &[]));
2265             let left = self.alloc(Ty(
2266                 context_reason,
2267                 Ty_::Tgeneric(self.alloc((left_id.1, &[]))),
2268             ));
2269             where_constraints.push(self.alloc(WhereConstraint(
2270                 left,
2271                 ConstraintKind::ConstraintEq,
2272                 right,
2273             )));
2274             rewritten_ty
2275         };
2277         let mut tparams = Vec::from_iter_in(tparams.iter().copied(), self.arena);
2278         let mut where_constraints =
2279             Vec::from_iter_in(where_constraints.iter().copied(), self.arena);
2281         // The divergence here from the lowerer comes from using oxidized_by_ref instead of oxidized
2282         let mut ty_by_param: BTreeMap<&str, (Ty<'a>, &'a Pos<'a>)> = params
2283             .iter()
2284             .filter_map(|param| Some((param.name?, (param.type_.type_.clone(), param.pos))))
2285             .collect();
2287         for context_ty in context_tys {
2288             match context_ty.1 {
2289                 // Hfun_context in the AST.
2290                 Ty_::Tapply(((_, name), _)) if name.starts_with('$') => {
2291                     if let Some((param_ty, _)) = ty_by_param.get_mut(name) {
2292                         match param_ty.1 {
2293                             Ty_::Tlike(ref mut ty) => match ty {
2294                                 Ty(r, Ty_::Toption(tinner)) => {
2295                                     *ty = self.alloc(Ty(
2296                                         r,
2297                                         Ty_::Toption(self.alloc(rewrite_fun_ctx(
2298                                             &mut tparams,
2299                                             tinner,
2300                                             name,
2301                                         ))),
2302                                     ))
2303                                 }
2304                                 _ => {
2305                                     *ty = self.alloc(rewrite_fun_ctx(&mut tparams, ty, name));
2306                                 }
2307                             },
2308                             Ty_::Toption(ref mut ty) => {
2309                                 *ty = self.alloc(rewrite_fun_ctx(&mut tparams, ty, name));
2310                             }
2311                             _ => {
2312                                 *param_ty = rewrite_fun_ctx(&mut tparams, param_ty, name);
2313                             }
2314                         }
2315                     }
2316                 }
2317                 Ty_::Taccess(&TaccessType(Ty(_, Ty_::Tapply(((_, name), _))), cst)) => {
2318                     if let Some((param_ty, param_pos)) = ty_by_param.get_mut(name) {
2319                         let mut rewrite = |t| {
2320                             rewrite_arg_ctx(
2321                                 &mut tparams,
2322                                 &mut where_constraints,
2323                                 t,
2324                                 param_pos,
2325                                 name,
2326                                 context_ty.0,
2327                                 cst,
2328                             )
2329                         };
2330                         match param_ty.1 {
2331                             Ty_::Tlike(ref mut ty) => match ty {
2332                                 Ty(r, Ty_::Toption(tinner)) => {
2333                                     *ty =
2334                                         self.alloc(Ty(r, Ty_::Toption(self.alloc(rewrite(tinner)))))
2335                                 }
2336                                 _ => {
2337                                     *ty = self.alloc(rewrite(ty));
2338                                 }
2339                             },
2340                             Ty_::Toption(ref mut ty) => {
2341                                 *ty = self.alloc(rewrite(ty));
2342                             }
2343                             _ => {
2344                                 *param_ty = rewrite(param_ty);
2345                             }
2346                         }
2347                     }
2348                 }
2349                 Ty_::Taccess(&TaccessType(t, cst)) if Self::taccess_root_is_generic(t) => {
2350                     let left_id = (
2351                         context_ty.0.pos().unwrap_or(Pos::none()),
2352                         self.ctx_generic_for_generic_taccess(t, &cst.1),
2353                     );
2354                     tparams.push(tp(left_id, &[]));
2355                     let left = self.alloc(Ty(
2356                         context_ty.0,
2357                         Ty_::Tgeneric(self.alloc((left_id.1, &[]))),
2358                     ));
2359                     where_constraints.push(self.alloc(WhereConstraint(
2360                         left,
2361                         ConstraintKind::ConstraintEq,
2362                         context_ty,
2363                     )));
2364                 }
2365                 _ => {}
2366             }
2367         }
2369         let params = self.slice(params.iter().copied().map(|param| match param.name {
2370             None => param,
2371             Some(name) => match ty_by_param.get(name) {
2372                 Some((type_, _)) if param.type_.type_ != type_ => self.alloc(FunParam {
2373                     type_: self.alloc(PossiblyEnforcedTy {
2374                         type_: self.alloc(type_.clone()),
2375                         ..*param.type_
2376                     }),
2377                     ..*param
2378                 }),
2379                 _ => param,
2380             },
2381         }));
2383         let context_tys = self.slice(context_tys.iter().copied().map(|ty| {
2384             let ty_ = match ty.1 {
2385                 Ty_::Tapply(((_, name), &[])) if name.starts_with('$') => {
2386                     Ty_::Tgeneric(self.alloc((self.ctx_generic_for_fun(name), &[])))
2387                 }
2388                 Ty_::Taccess(&TaccessType(Ty(_, Ty_::Tapply(((_, name), &[]))), cst))
2389                     if name.starts_with('$') =>
2390                 {
2391                     let name = self.ctx_generic_for_dependent(name, &cst.1);
2392                     Ty_::Tgeneric(self.alloc((name, &[])))
2393                 }
2394                 Ty_::Taccess(&TaccessType(t, cst)) if Self::taccess_root_is_generic(t) => {
2395                     let name = self.ctx_generic_for_generic_taccess(t, &cst.1);
2396                     Ty_::Tgeneric(self.alloc((name, &[])))
2397                 }
2398                 _ => return ty,
2399             };
2400             self.alloc(Ty(ty.0, ty_))
2401         }));
2402         let cap_ty = match context_tys {
2403             [ty] => ty,
2404             _ => self.alloc(Ty(cap_reason, Ty_::Tintersection(context_tys))),
2405         };
2406         let implicit_params = self.alloc(FunImplicitParams {
2407             capability: CapTy(cap_ty),
2408         });
2410         (
2411             params,
2412             tparams.into_bump_slice(),
2413             implicit_params,
2414             where_constraints.into_bump_slice(),
2415         )
2416     }
2419 enum NodeIterHelper<'a, 'b> {
2420     Empty,
2421     Single(&'b Node<'a>),
2422     Vec(std::slice::Iter<'b, Node<'a>>),
2425 impl<'a, 'b> Iterator for NodeIterHelper<'a, 'b> {
2426     type Item = &'b Node<'a>;
2428     fn next(&mut self) -> Option<Self::Item> {
2429         match self {
2430             NodeIterHelper::Empty => None,
2431             NodeIterHelper::Single(node) => {
2432                 let node = *node;
2433                 *self = NodeIterHelper::Empty;
2434                 Some(node)
2435             }
2436             NodeIterHelper::Vec(ref mut iter) => iter.next(),
2437         }
2438     }
2440     // Must return the upper bound returned by Node::len.
2441     fn size_hint(&self) -> (usize, Option<usize>) {
2442         match self {
2443             NodeIterHelper::Empty => (0, Some(0)),
2444             NodeIterHelper::Single(_) => (1, Some(1)),
2445             NodeIterHelper::Vec(iter) => iter.size_hint(),
2446         }
2447     }
2450 impl<'a, 'b> DoubleEndedIterator for NodeIterHelper<'a, 'b> {
2451     fn next_back(&mut self) -> Option<Self::Item> {
2452         match self {
2453             NodeIterHelper::Empty => None,
2454             NodeIterHelper::Single(_) => self.next(),
2455             NodeIterHelper::Vec(ref mut iter) => iter.next_back(),
2456         }
2457     }
2460 impl<'a, 'text, S: SourceTextAllocator<'text, 'a>> FlattenOp
2461     for DirectDeclSmartConstructors<'a, 'text, S>
2463     type S = Node<'a>;
2465     fn flatten(&self, kind: SyntaxKind, lst: std::vec::Vec<Self::S>) -> Self::S {
2466         let size = lst
2467             .iter()
2468             .map(|s| match s {
2469                 Node::List(children) => children.len(),
2470                 x => {
2471                     if Self::is_zero(x) {
2472                         0
2473                     } else {
2474                         1
2475                     }
2476                 }
2477             })
2478             .sum();
2479         let mut r = Vec::with_capacity_in(size, self.arena);
2480         for s in lst.into_iter() {
2481             match s {
2482                 Node::List(children) => r.extend(children.iter().copied()),
2483                 x => {
2484                     if !Self::is_zero(&x) {
2485                         r.push(x)
2486                     }
2487                 }
2488             }
2489         }
2490         match r.into_bump_slice() {
2491             [] => Node::Ignored(kind),
2492             [node] => *node,
2493             slice => Node::List(self.alloc(slice)),
2494         }
2495     }
2497     fn zero(kind: SyntaxKind) -> Self::S {
2498         Node::Ignored(kind)
2499     }
2501     fn is_zero(s: &Self::S) -> bool {
2502         match s {
2503             Node::Token(token) => match token.kind() {
2504                 TokenKind::Yield | TokenKind::Required | TokenKind::Lateinit => false,
2505                 _ => true,
2506             },
2507             Node::List(inner) => inner.iter().all(Self::is_zero),
2508             _ => true,
2509         }
2510     }
2513 impl<'a, 'text, S: SourceTextAllocator<'text, 'a>>
2514     FlattenSmartConstructors<'a, DirectDeclSmartConstructors<'a, 'text, S>>
2515     for DirectDeclSmartConstructors<'a, 'text, S>
2517     fn make_token(&mut self, token: CompactToken) -> Self::R {
2518         let token_text = |this: &Self| this.str_from_utf8(this.token_bytes(&token));
2519         let token_pos = |this: &Self| {
2520             let start = this
2521                 .source_text
2522                 .offset_to_file_pos_triple(token.start_offset());
2523             let end = this
2524                 .source_text
2525                 .offset_to_file_pos_triple(token.end_offset());
2526             Pos::from_lnum_bol_cnum(this.arena, this.filename, start, end)
2527         };
2528         let kind = token.kind();
2530         let result = match kind {
2531             TokenKind::Name | TokenKind::XHPClassName => {
2532                 let text = token_text(self);
2533                 let pos = token_pos(self);
2535                 let name = if kind == TokenKind::XHPClassName {
2536                     Node::XhpName(self.alloc((text, pos)))
2537                 } else {
2538                     Node::Name(self.alloc((text, pos)))
2539                 };
2541                 if self.previous_token_kind == TokenKind::Class
2542                     || self.previous_token_kind == TokenKind::Trait
2543                     || self.previous_token_kind == TokenKind::Interface
2544                 {
2545                     if let Some(current_class_name) = self.elaborate_defined_id(name) {
2546                         self.classish_name_builder
2547                             .lexed_name_after_classish_keyword(
2548                                 self.arena,
2549                                 current_class_name.1,
2550                                 pos,
2551                                 self.previous_token_kind,
2552                             );
2553                     }
2554                 }
2555                 name
2556             }
2557             TokenKind::Class => Node::Name(self.alloc((token_text(self), token_pos(self)))),
2558             TokenKind::Variable => Node::Variable(self.alloc((token_text(self), token_pos(self)))),
2559             // There are a few types whose string representations we have to
2560             // grab anyway, so just go ahead and treat them as generic names.
2561             TokenKind::Vec
2562             | TokenKind::Dict
2563             | TokenKind::Keyset
2564             | TokenKind::Tuple
2565             | TokenKind::Classname
2566             | TokenKind::SelfToken => Node::Name(self.alloc((token_text(self), token_pos(self)))),
2567             TokenKind::XHPElementName => {
2568                 Node::XhpName(self.alloc((token_text(self), token_pos(self))))
2569             }
2570             TokenKind::SingleQuotedStringLiteral => match escaper::unescape_single_in(
2571                 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2572                 self.arena,
2573             ) {
2574                 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2575                 Err(_) => Node::Ignored(SK::Token(kind)),
2576             },
2577             TokenKind::DoubleQuotedStringLiteral => match escaper::unescape_double_in(
2578                 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2579                 self.arena,
2580             ) {
2581                 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2582                 Err(_) => Node::Ignored(SK::Token(kind)),
2583             },
2584             TokenKind::HeredocStringLiteral => match escaper::unescape_heredoc_in(
2585                 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2586                 self.arena,
2587             ) {
2588                 Ok(text) if !self.retain_or_omit_user_attributes_for_facts => {
2589                     Node::StringLiteral(self.alloc((text.into(), token_pos(self))))
2590                 }
2591                 _ => Node::Ignored(SK::Token(kind)),
2592             },
2593             TokenKind::NowdocStringLiteral => match escaper::unescape_nowdoc_in(
2594                 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2595                 self.arena,
2596             ) {
2597                 Ok(text) if !self.retain_or_omit_user_attributes_for_facts => {
2598                     Node::StringLiteral(self.alloc((text.into(), token_pos(self))))
2599                 }
2600                 _ => Node::Ignored(SK::Token(kind)),
2601             },
2602             TokenKind::DecimalLiteral
2603             | TokenKind::OctalLiteral
2604             | TokenKind::HexadecimalLiteral
2605             | TokenKind::BinaryLiteral => {
2606                 Node::IntLiteral(self.alloc((token_text(self), token_pos(self))))
2607             }
2608             TokenKind::FloatingLiteral => {
2609                 Node::FloatingLiteral(self.alloc((token_text(self), token_pos(self))))
2610             }
2611             TokenKind::BooleanLiteral => {
2612                 Node::BooleanLiteral(self.alloc((token_text(self), token_pos(self))))
2613             }
2614             TokenKind::String => self.prim_ty(aast::Tprim::Tstring, token_pos(self)),
2615             TokenKind::Int => self.prim_ty(aast::Tprim::Tint, token_pos(self)),
2616             TokenKind::Float => self.prim_ty(aast::Tprim::Tfloat, token_pos(self)),
2617             // "double" and "boolean" are parse errors--they should be written
2618             // "float" and "bool". The decl-parser treats the incorrect names as
2619             // type names rather than primitives.
2620             TokenKind::Double | TokenKind::Boolean => self.hint_ty(
2621                 token_pos(self),
2622                 Ty_::Tapply(self.alloc(((token_pos(self), token_text(self)), &[][..]))),
2623             ),
2624             TokenKind::Num => self.prim_ty(aast::Tprim::Tnum, token_pos(self)),
2625             TokenKind::Bool => self.prim_ty(aast::Tprim::Tbool, token_pos(self)),
2626             TokenKind::Mixed => {
2627                 if self.opts.everything_sdt {
2628                     Node::Ty(self.alloc(Ty(
2629                         self.alloc(Reason::hint(token_pos(self))),
2630                         Ty_::Toption(self.alloc(Ty(
2631                             self.alloc(Reason::hint(token_pos(self))),
2632                             Ty_::Tsupportdynamic,
2633                         ))),
2634                     )))
2635                 } else {
2636                     Node::Ty(self.alloc(Ty(self.alloc(Reason::hint(token_pos(self))), Ty_::Tmixed)))
2637                 }
2638             }
2639             TokenKind::Void => self.prim_ty(aast::Tprim::Tvoid, token_pos(self)),
2640             TokenKind::Arraykey => self.prim_ty(aast::Tprim::Tarraykey, token_pos(self)),
2641             TokenKind::Noreturn => self.prim_ty(aast::Tprim::Tnoreturn, token_pos(self)),
2642             TokenKind::Resource => self.prim_ty(aast::Tprim::Tresource, token_pos(self)),
2643             TokenKind::NullLiteral
2644             | TokenKind::Darray
2645             | TokenKind::Varray
2646             | TokenKind::Backslash
2647             | TokenKind::Construct
2648             | TokenKind::LeftParen
2649             | TokenKind::RightParen
2650             | TokenKind::LeftBracket
2651             | TokenKind::RightBracket
2652             | TokenKind::Shape
2653             | TokenKind::Question
2654             | TokenKind::This
2655             | TokenKind::Tilde
2656             | TokenKind::Exclamation
2657             | TokenKind::Plus
2658             | TokenKind::Minus
2659             | TokenKind::PlusPlus
2660             | TokenKind::MinusMinus
2661             | TokenKind::At
2662             | TokenKind::Star
2663             | TokenKind::Slash
2664             | TokenKind::EqualEqual
2665             | TokenKind::EqualEqualEqual
2666             | TokenKind::StarStar
2667             | TokenKind::AmpersandAmpersand
2668             | TokenKind::BarBar
2669             | TokenKind::LessThan
2670             | TokenKind::LessThanEqual
2671             | TokenKind::GreaterThan
2672             | TokenKind::GreaterThanEqual
2673             | TokenKind::Dot
2674             | TokenKind::Ampersand
2675             | TokenKind::Bar
2676             | TokenKind::LessThanLessThan
2677             | TokenKind::GreaterThanGreaterThan
2678             | TokenKind::Percent
2679             | TokenKind::QuestionQuestion
2680             | TokenKind::Equal
2681             | TokenKind::Abstract
2682             | TokenKind::As
2683             | TokenKind::Super
2684             | TokenKind::Async
2685             | TokenKind::DotDotDot
2686             | TokenKind::Extends
2687             | TokenKind::Final
2688             | TokenKind::Implements
2689             | TokenKind::Inout
2690             | TokenKind::Interface
2691             | TokenKind::Newctx
2692             | TokenKind::Newtype
2693             | TokenKind::Type
2694             | TokenKind::Yield
2695             | TokenKind::Semicolon
2696             | TokenKind::Private
2697             | TokenKind::Protected
2698             | TokenKind::Public
2699             | TokenKind::Reify
2700             | TokenKind::Static
2701             | TokenKind::Trait
2702             | TokenKind::Lateinit
2703             | TokenKind::RecordDec
2704             | TokenKind::RightBrace
2705             | TokenKind::Enum
2706             | TokenKind::Const
2707             | TokenKind::Function
2708             | TokenKind::Namespace
2709             | TokenKind::XHP
2710             | TokenKind::Required
2711             | TokenKind::Ctx
2712             | TokenKind::Readonly => Node::Token(FixedWidthToken::new(kind, token.start_offset())),
2713             _ if kind.fixed_width().is_some() => {
2714                 Node::IgnoredToken(FixedWidthToken::new(kind, token.start_offset()))
2715             }
2716             _ => Node::Ignored(SK::Token(kind)),
2717         };
2718         self.previous_token_kind = kind;
2719         result
2720     }
2722     fn make_error(&mut self, error: Self::R) -> Self::R {
2723         // If it's a Token or IgnoredToken, we can use it for error recovery.
2724         // For instance, in `function using() {}`, the `using` keyword will be a
2725         // token wrapped in an error CST node, since the keyword isn't legal in
2726         // that position.
2727         error
2728     }
2730     fn make_missing(&mut self, _: usize) -> Self::R {
2731         Node::Ignored(SK::Missing)
2732     }
2734     fn make_list(&mut self, items: std::vec::Vec<Self::R>, _: usize) -> Self::R {
2735         if let Some(&yield_) = items
2736             .iter()
2737             .flat_map(|node| node.iter())
2738             .find(|node| node.is_token(TokenKind::Yield))
2739         {
2740             yield_
2741         } else {
2742             let size = items.iter().filter(|node| node.is_present()).count();
2743             let items_iter = items.into_iter();
2744             let mut items = Vec::with_capacity_in(size, self.arena);
2745             for node in items_iter {
2746                 if node.is_present() {
2747                     items.push(node);
2748                 }
2749             }
2750             let items = items.into_bump_slice();
2751             if items.is_empty() {
2752                 Node::Ignored(SK::SyntaxList)
2753             } else {
2754                 Node::List(self.alloc(items))
2755             }
2756         }
2757     }
2759     fn make_qualified_name(&mut self, parts: Self::R) -> Self::R {
2760         let pos = self.get_pos(parts);
2761         match parts {
2762             Node::List(nodes) => Node::QualifiedName(self.alloc((nodes, pos))),
2763             node if node.is_ignored() => Node::Ignored(SK::QualifiedName),
2764             node => Node::QualifiedName(
2765                 self.alloc((bumpalo::vec![in self.arena; node].into_bump_slice(), pos)),
2766             ),
2767         }
2768     }
2770     fn make_simple_type_specifier(&mut self, specifier: Self::R) -> Self::R {
2771         // Return this explicitly because flatten filters out zero nodes, and
2772         // we treat most non-error nodes as zeroes.
2773         specifier
2774     }
2776     fn make_literal_expression(&mut self, expression: Self::R) -> Self::R {
2777         expression
2778     }
2780     fn make_simple_initializer(&mut self, equals: Self::R, expr: Self::R) -> Self::R {
2781         // If the expr is Ignored, bubble up the assignment operator so that we
2782         // can tell that *some* initializer was here. Useful for class
2783         // properties, where we need to enforce that properties without default
2784         // values are initialized in the constructor.
2785         if expr.is_ignored() { equals } else { expr }
2786     }
2788     fn make_anonymous_function(
2789         &mut self,
2790         _attribute_spec: Self::R,
2791         _async_keyword: Self::R,
2792         _function_keyword: Self::R,
2793         _left_paren: Self::R,
2794         _parameters: Self::R,
2795         _right_paren: Self::R,
2796         _ctx_list: Self::R,
2797         _colon: Self::R,
2798         _readonly_return: Self::R,
2799         _type_: Self::R,
2800         _use_: Self::R,
2801         _body: Self::R,
2802     ) -> Self::R {
2803         // do not allow Yield to bubble up
2804         Node::Ignored(SK::AnonymousFunction)
2805     }
2807     fn make_lambda_expression(
2808         &mut self,
2809         _attribute_spec: Self::R,
2810         _async_: Self::R,
2811         _signature: Self::R,
2812         _arrow: Self::R,
2813         _body: Self::R,
2814     ) -> Self::R {
2815         // do not allow Yield to bubble up
2816         Node::Ignored(SK::LambdaExpression)
2817     }
2819     fn make_awaitable_creation_expression(
2820         &mut self,
2821         _attribute_spec: Self::R,
2822         _async_: Self::R,
2823         _compound_statement: Self::R,
2824     ) -> Self::R {
2825         // do not allow Yield to bubble up
2826         Node::Ignored(SK::AwaitableCreationExpression)
2827     }
2829     fn make_element_initializer(
2830         &mut self,
2831         key: Self::R,
2832         _arrow: Self::R,
2833         value: Self::R,
2834     ) -> Self::R {
2835         Node::ListItem(self.alloc((key, value)))
2836     }
2838     fn make_prefix_unary_expression(&mut self, op: Self::R, value: Self::R) -> Self::R {
2839         let pos = self.merge_positions(op, value);
2840         let op = match op.token_kind() {
2841             Some(TokenKind::Tilde) => Uop::Utild,
2842             Some(TokenKind::Exclamation) => Uop::Unot,
2843             Some(TokenKind::Plus) => Uop::Uplus,
2844             Some(TokenKind::Minus) => Uop::Uminus,
2845             Some(TokenKind::PlusPlus) => Uop::Uincr,
2846             Some(TokenKind::MinusMinus) => Uop::Udecr,
2847             Some(TokenKind::At) => Uop::Usilence,
2848             _ => return Node::Ignored(SK::PrefixUnaryExpression),
2849         };
2850         let value = match self.node_to_expr(value) {
2851             Some(value) => value,
2852             None => return Node::Ignored(SK::PrefixUnaryExpression),
2853         };
2854         Node::Expr(self.alloc(aast::Expr(
2855             (),
2856             pos,
2857             aast::Expr_::Unop(self.alloc((op, value))),
2858         )))
2859     }
2861     fn make_postfix_unary_expression(&mut self, value: Self::R, op: Self::R) -> Self::R {
2862         let pos = self.merge_positions(value, op);
2863         let op = match op.token_kind() {
2864             Some(TokenKind::PlusPlus) => Uop::Upincr,
2865             Some(TokenKind::MinusMinus) => Uop::Updecr,
2866             _ => return Node::Ignored(SK::PostfixUnaryExpression),
2867         };
2868         let value = match self.node_to_expr(value) {
2869             Some(value) => value,
2870             None => return Node::Ignored(SK::PostfixUnaryExpression),
2871         };
2872         Node::Expr(self.alloc(aast::Expr(
2873             (),
2874             pos,
2875             aast::Expr_::Unop(self.alloc((op, value))),
2876         )))
2877     }
2879     fn make_binary_expression(&mut self, lhs: Self::R, op_node: Self::R, rhs: Self::R) -> Self::R {
2880         let op = match op_node.token_kind() {
2881             Some(TokenKind::Plus) => Bop::Plus,
2882             Some(TokenKind::Minus) => Bop::Minus,
2883             Some(TokenKind::Star) => Bop::Star,
2884             Some(TokenKind::Slash) => Bop::Slash,
2885             Some(TokenKind::Equal) => Bop::Eq(None),
2886             Some(TokenKind::EqualEqual) => Bop::Eqeq,
2887             Some(TokenKind::EqualEqualEqual) => Bop::Eqeqeq,
2888             Some(TokenKind::StarStar) => Bop::Starstar,
2889             Some(TokenKind::AmpersandAmpersand) => Bop::Ampamp,
2890             Some(TokenKind::BarBar) => Bop::Barbar,
2891             Some(TokenKind::LessThan) => Bop::Lt,
2892             Some(TokenKind::LessThanEqual) => Bop::Lte,
2893             Some(TokenKind::LessThanLessThan) => Bop::Ltlt,
2894             Some(TokenKind::GreaterThan) => Bop::Gt,
2895             Some(TokenKind::GreaterThanEqual) => Bop::Gte,
2896             Some(TokenKind::GreaterThanGreaterThan) => Bop::Gtgt,
2897             Some(TokenKind::Dot) => Bop::Dot,
2898             Some(TokenKind::Ampersand) => Bop::Amp,
2899             Some(TokenKind::Bar) => Bop::Bar,
2900             Some(TokenKind::Percent) => Bop::Percent,
2901             Some(TokenKind::QuestionQuestion) => Bop::QuestionQuestion,
2902             _ => return Node::Ignored(SK::BinaryExpression),
2903         };
2905         match (&op, rhs.is_token(TokenKind::Yield)) {
2906             (Bop::Eq(_), true) => return rhs,
2907             _ => {}
2908         }
2910         let pos = self.merge(self.merge_positions(lhs, op_node), self.get_pos(rhs));
2912         let lhs = match self.node_to_expr(lhs) {
2913             Some(lhs) => lhs,
2914             None => return Node::Ignored(SK::BinaryExpression),
2915         };
2916         let rhs = match self.node_to_expr(rhs) {
2917             Some(rhs) => rhs,
2918             None => return Node::Ignored(SK::BinaryExpression),
2919         };
2921         Node::Expr(self.alloc(aast::Expr(
2922             (),
2923             pos,
2924             aast::Expr_::Binop(self.alloc((op, lhs, rhs))),
2925         )))
2926     }
2928     fn make_parenthesized_expression(
2929         &mut self,
2930         _lparen: Self::R,
2931         expr: Self::R,
2932         _rparen: Self::R,
2933     ) -> Self::R {
2934         if self.retain_or_omit_user_attributes_for_facts {
2935             Node::Ignored(SK::ParenthesizedExpression)
2936         } else {
2937             expr
2938         }
2939     }
2941     fn make_keyset_intrinsic_expression(
2942         &mut self,
2943         _keyset_intrinsic_keyword: Self::R,
2944         _type: Self::R,
2945         _left_bracket: Self::R,
2946         expr: Self::R,
2947         _right_bracket: Self::R,
2948     ) -> Self::R {
2949         if !self.retain_or_omit_user_attributes_for_facts {
2950             Node::Ignored(SK::KeysetIntrinsicExpression)
2951         } else if let Node::List([node]) = expr {
2952             *node
2953         } else {
2954             expr
2955         }
2956     }
2958     fn make_varray_intrinsic_expression(
2959         &mut self,
2960         _varray_intrinsic_keyword: Self::R,
2961         _type: Self::R,
2962         _left_bracket: Self::R,
2963         expr: Self::R,
2964         _right_bracket: Self::R,
2965     ) -> Self::R {
2966         if !self.retain_or_omit_user_attributes_for_facts {
2967             Node::Ignored(SK::VarrayIntrinsicExpression)
2968         } else if let Node::List([node]) = expr {
2969             *node
2970         } else {
2971             expr
2972         }
2973     }
2975     fn make_darray_intrinsic_expression(
2976         &mut self,
2977         _varray_intrinsic_keyword: Self::R,
2978         _type: Self::R,
2979         _left_bracket: Self::R,
2980         expr: Self::R,
2981         _right_bracket: Self::R,
2982     ) -> Self::R {
2983         if !self.retain_or_omit_user_attributes_for_facts {
2984             Node::Ignored(SK::DarrayIntrinsicExpression)
2985         } else if let Node::List([node]) = expr {
2986             *node
2987         } else {
2988             expr
2989         }
2990     }
2992     fn make_vector_intrinsic_expression(
2993         &mut self,
2994         _vector_intrinsic_keyword: Self::R,
2995         _type: Self::R,
2996         _left_bracket: Self::R,
2997         expr: Self::R,
2998         _right_bracket: Self::R,
2999     ) -> Self::R {
3000         if !self.retain_or_omit_user_attributes_for_facts {
3001             Node::Ignored(SK::VectorIntrinsicExpression)
3002         } else if let Node::List([node]) = expr {
3003             *node
3004         } else {
3005             expr
3006         }
3007     }
3009     fn make_list_item(&mut self, item: Self::R, sep: Self::R) -> Self::R {
3010         match (item.is_ignored(), sep.is_ignored()) {
3011             (true, true) => Node::Ignored(SK::ListItem),
3012             (false, true) => item,
3013             (true, false) => sep,
3014             (false, false) => Node::ListItem(self.alloc((item, sep))),
3015         }
3016     }
3018     fn make_type_arguments(
3019         &mut self,
3020         less_than: Self::R,
3021         arguments: Self::R,
3022         greater_than: Self::R,
3023     ) -> Self::R {
3024         Node::BracketedList(self.alloc((
3025             self.get_pos(less_than),
3026             arguments.as_slice(self.arena),
3027             self.get_pos(greater_than),
3028         )))
3029     }
3031     fn make_generic_type_specifier(
3032         &mut self,
3033         class_type: Self::R,
3034         type_arguments: Self::R,
3035     ) -> Self::R {
3036         let class_id = match self.expect_name(class_type) {
3037             Some(id) => id,
3038             None => return Node::Ignored(SK::GenericTypeSpecifier),
3039         };
3040         match class_id.1.trim_start_matches("\\") {
3041             "varray_or_darray" | "vec_or_dict" => {
3042                 let id_pos = class_id.0;
3043                 let pos = self.merge(id_pos, self.get_pos(type_arguments));
3044                 let type_arguments = type_arguments.as_slice(self.arena);
3045                 let ty_ = match type_arguments {
3046                     [tk, tv] => Ty_::TvecOrDict(
3047                         self.alloc((
3048                             self.node_to_ty(*tk)
3049                                 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
3050                             self.node_to_ty(*tv)
3051                                 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
3052                         )),
3053                     ),
3054                     [tv] => Ty_::TvecOrDict(
3055                         self.alloc((
3056                             self.vec_or_dict_key(pos),
3057                             self.node_to_ty(*tv)
3058                                 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
3059                         )),
3060                     ),
3061                     _ => TANY_,
3062                 };
3063                 self.hint_ty(pos, ty_)
3064             }
3065             _ => {
3066                 let Id(pos, class_type) = class_id;
3067                 match class_type.rsplit('\\').next() {
3068                     Some(name) if self.is_type_param_in_scope(name) => {
3069                         let pos = self.merge(pos, self.get_pos(type_arguments));
3070                         let type_arguments = self.slice(
3071                             type_arguments
3072                                 .iter()
3073                                 .filter_map(|&node| self.node_to_ty(node)),
3074                         );
3075                         let ty_ = if self.simplify_naming_for_facts {
3076                             Ty_::Tgeneric(self.alloc((class_type, type_arguments)))
3077                         } else {
3078                             Ty_::Tgeneric(self.alloc((name, type_arguments)))
3079                         };
3080                         self.hint_ty(pos, ty_)
3081                     }
3082                     _ => {
3083                         let class_type = self.elaborate_raw_id(class_type);
3084                         self.make_apply(
3085                             (pos, class_type),
3086                             type_arguments,
3087                             self.get_pos(type_arguments),
3088                         )
3089                     }
3090                 }
3091             }
3092         }
3093     }
3095     fn make_record_declaration(
3096         &mut self,
3097         attribute_spec: Self::R,
3098         modifier: Self::R,
3099         record_keyword: Self::R,
3100         name: Self::R,
3101         _extends_keyword: Self::R,
3102         extends_opt: Self::R,
3103         _left_brace: Self::R,
3104         fields: Self::R,
3105         right_brace: Self::R,
3106     ) -> Self::R {
3107         let name = match self.elaborate_defined_id(name) {
3108             Some(name) => name,
3109             None => return Node::Ignored(SK::RecordDeclaration),
3110         };
3111         let parsed_attributes = self.to_attributes(attribute_spec);
3112         self.add_record(
3113             name.1,
3114             self.alloc(typing_defs::RecordDefType {
3115                 module: self.alloc(parsed_attributes.module),
3116                 name: name.into(),
3117                 extends: self
3118                     .expect_name(extends_opt)
3119                     .map(|id| self.elaborate_id(id).into()),
3120                 fields: self.slice(fields.iter().filter_map(|node| match node {
3121                     Node::RecordField(&(id, req)) => Some((id.into(), req)),
3122                     _ => None,
3123                 })),
3124                 abstract_: modifier.is_token(TokenKind::Abstract),
3125                 pos: self.pos_from_slice(&[attribute_spec, modifier, record_keyword, right_brace]),
3126             }),
3127         );
3128         Node::Ignored(SK::RecordDeclaration)
3129     }
3131     fn make_record_field(
3132         &mut self,
3133         _type_: Self::R,
3134         name: Self::R,
3135         initializer: Self::R,
3136         _semicolon: Self::R,
3137     ) -> Self::R {
3138         let name = match self.expect_name(name) {
3139             Some(name) => name,
3140             None => return Node::Ignored(SK::RecordField),
3141         };
3142         let field_req = if initializer.is_ignored() {
3143             RecordFieldReq::ValueRequired
3144         } else {
3145             RecordFieldReq::HasDefaultValue
3146         };
3147         Node::RecordField(self.alloc((name, field_req)))
3148     }
3150     fn make_alias_declaration(
3151         &mut self,
3152         attributes: Self::R,
3153         keyword: Self::R,
3154         name: Self::R,
3155         generic_params: Self::R,
3156         constraint: Self::R,
3157         _equal: Self::R,
3158         aliased_type: Self::R,
3159         _semicolon: Self::R,
3160     ) -> Self::R {
3161         if name.is_ignored() {
3162             return Node::Ignored(SK::AliasDeclaration);
3163         }
3164         let Id(pos, name) = match self.elaborate_defined_id(name) {
3165             Some(id) => id,
3166             None => return Node::Ignored(SK::AliasDeclaration),
3167         };
3168         let ty = match self.node_to_ty(aliased_type) {
3169             Some(ty) => ty,
3170             None => return Node::Ignored(SK::AliasDeclaration),
3171         };
3172         let constraint = match constraint {
3173             Node::TypeConstraint(&(_kind, hint)) => self.node_to_ty(hint),
3174             _ => None,
3175         };
3177         // Pop the type params stack only after creating all inner types.
3178         let tparams = self.pop_type_params(generic_params);
3179         let parsed_attributes = self.to_attributes(attributes);
3180         let user_attributes = if self.retain_or_omit_user_attributes_for_facts {
3181             self.slice(attributes.iter().rev().filter_map(|attribute| {
3182                 if let Node::Attribute(attr) = attribute {
3183                     Some(self.user_attribute_to_decl(attr))
3184                 } else {
3185                     None
3186                 }
3187             }))
3188         } else {
3189             &[][..]
3190         };
3191         let typedef = self.alloc(TypedefType {
3192             module: self.alloc(parsed_attributes.module),
3193             pos,
3194             vis: if parsed_attributes.internal {
3195                 aast::TypedefVisibility::Tinternal
3196             } else {
3197                 match keyword.token_kind() {
3198                     Some(TokenKind::Type) => aast::TypedefVisibility::Transparent,
3199                     Some(TokenKind::Newtype) => aast::TypedefVisibility::Opaque,
3200                     _ => aast::TypedefVisibility::Transparent,
3201                 }
3202             },
3203             tparams,
3204             constraint,
3205             type_: ty,
3206             is_ctx: false,
3207             attributes: user_attributes,
3208         });
3210         self.add_typedef(name, typedef);
3212         Node::Ignored(SK::AliasDeclaration)
3213     }
3215     fn make_context_alias_declaration(
3216         &mut self,
3217         attributes: Self::R,
3218         _keyword: Self::R,
3219         name: Self::R,
3220         generic_params: Self::R,
3221         constraint: Self::R,
3222         _equal: Self::R,
3223         ctx_list: Self::R,
3224         _semicolon: Self::R,
3225     ) -> Self::R {
3226         if name.is_ignored() {
3227             return Node::Ignored(SK::ContextAliasDeclaration);
3228         }
3229         let Id(pos, name) = match self.elaborate_defined_id(name) {
3230             Some(id) => id,
3231             None => return Node::Ignored(SK::ContextAliasDeclaration),
3232         };
3233         let ty = match self.node_to_ty(ctx_list) {
3234             Some(ty) => ty,
3235             None => self.alloc(Ty(
3236                 self.alloc(Reason::hint(pos)),
3237                 Ty_::Tapply(self.alloc(((pos, "\\HH\\Contexts\\defaults"), &[]))),
3238             )),
3239         };
3241         // lowerer ensures there is only one as constraint
3242         let mut as_constraint = None;
3243         for c in constraint.iter() {
3244             if let Node::ContextConstraint(&(kind, hint)) = c {
3245                 let ty = self.node_to_ty(hint);
3246                 match kind {
3247                     ConstraintKind::ConstraintAs => as_constraint = ty,
3248                     _ => {}
3249                 }
3250             }
3251         }
3252         // Pop the type params stack only after creating all inner types.
3253         let tparams = self.pop_type_params(generic_params);
3254         let parsed_attributes = self.to_attributes(attributes);
3255         let user_attributes = if self.retain_or_omit_user_attributes_for_facts {
3256             self.slice(attributes.iter().rev().filter_map(|attribute| {
3257                 if let Node::Attribute(attr) = attribute {
3258                     Some(self.user_attribute_to_decl(attr))
3259                 } else {
3260                     None
3261                 }
3262             }))
3263         } else {
3264             &[][..]
3265         };
3266         let typedef = self.alloc(TypedefType {
3267             module: self.alloc(parsed_attributes.module),
3268             pos,
3269             vis: if parsed_attributes.internal {
3270                 aast::TypedefVisibility::Tinternal
3271             } else {
3272                 aast::TypedefVisibility::Opaque
3273             },
3274             tparams,
3275             constraint: as_constraint,
3276             type_: ty,
3277             is_ctx: true,
3278             attributes: user_attributes,
3279         });
3281         self.add_typedef(name, typedef);
3283         Node::Ignored(SK::ContextAliasDeclaration)
3284     }
3286     fn make_type_constraint(&mut self, kind: Self::R, value: Self::R) -> Self::R {
3287         let kind = match kind.token_kind() {
3288             Some(TokenKind::As) => ConstraintKind::ConstraintAs,
3289             Some(TokenKind::Super) => ConstraintKind::ConstraintSuper,
3290             _ => return Node::Ignored(SK::TypeConstraint),
3291         };
3292         Node::TypeConstraint(self.alloc((kind, value)))
3293     }
3295     fn make_context_constraint(&mut self, kind: Self::R, value: Self::R) -> Self::R {
3296         let kind = match kind.token_kind() {
3297             Some(TokenKind::As) => ConstraintKind::ConstraintAs,
3298             Some(TokenKind::Super) => ConstraintKind::ConstraintSuper,
3299             _ => return Node::Ignored(SK::ContextConstraint),
3300         };
3301         Node::ContextConstraint(self.alloc((kind, value)))
3302     }
3304     fn make_type_parameter(
3305         &mut self,
3306         user_attributes: Self::R,
3307         reify: Self::R,
3308         variance: Self::R,
3309         name: Self::R,
3310         tparam_params: Self::R,
3311         constraints: Self::R,
3312     ) -> Self::R {
3313         let user_attributes = match user_attributes {
3314             Node::BracketedList((_, attributes, _)) => {
3315                 self.slice(attributes.into_iter().filter_map(|x| match x {
3316                     Node::Attribute(a) => Some(*a),
3317                     _ => None,
3318                 }))
3319             }
3320             _ => &[][..],
3321         };
3323         let constraints = self.slice(constraints.iter().filter_map(|node| match node {
3324             Node::TypeConstraint(&constraint) => Some(constraint),
3325             _ => None,
3326         }));
3328         // TODO(T70068435) Once we add support for constraints on higher-kinded types
3329         // (in particular, constraints on nested type parameters), we need to ensure
3330         // that we correctly handle the scoping of nested type parameters.
3331         // This includes making sure that the call to convert_type_appl_to_generic
3332         // in make_type_parameters handles nested constraints.
3333         // For now, we just make sure that the nested type parameters that make_type_parameters
3334         // added to the global list of in-scope type parameters are removed immediately:
3335         self.pop_type_params(tparam_params);
3337         let tparam_params = match tparam_params {
3338             Node::TypeParameters(&params) => params,
3339             _ => &[],
3340         };
3342         Node::TypeParameter(self.alloc(TypeParameterDecl {
3343             name,
3344             variance: match variance.token_kind() {
3345                 Some(TokenKind::Minus) => Variance::Contravariant,
3346                 Some(TokenKind::Plus) => Variance::Covariant,
3347                 _ => Variance::Invariant,
3348             },
3349             reified: if reify.is_token(TokenKind::Reify) {
3350                 if user_attributes.iter().any(|node| node.name.1 == "__Soft") {
3351                     aast::ReifyKind::SoftReified
3352                 } else {
3353                     aast::ReifyKind::Reified
3354                 }
3355             } else {
3356                 aast::ReifyKind::Erased
3357             },
3358             constraints,
3359             tparam_params,
3360             user_attributes,
3361         }))
3362     }
3364     fn make_type_parameters(&mut self, _lt: Self::R, tparams: Self::R, _gt: Self::R) -> Self::R {
3365         let size = tparams.len();
3366         let mut tparams_with_name = Vec::with_capacity_in(size, self.arena);
3367         let mut tparam_names = MultiSetMut::with_capacity_in(size, self.arena);
3368         for node in tparams.iter() {
3369             match node {
3370                 &Node::TypeParameter(decl) => {
3371                     let name = match decl.name.as_id() {
3372                         Some(name) => name,
3373                         None => return Node::Ignored(SK::TypeParameters),
3374                     };
3375                     tparam_names.insert(name.1);
3376                     tparams_with_name.push((decl, name));
3377                 }
3378                 _ => {}
3379             }
3380         }
3381         Rc::make_mut(&mut self.type_parameters).push(tparam_names.into());
3382         let mut tparams = Vec::with_capacity_in(tparams_with_name.len(), self.arena);
3383         for (decl, name) in tparams_with_name.into_iter() {
3384             let &TypeParameterDecl {
3385                 name: _,
3386                 variance,
3387                 reified,
3388                 constraints,
3389                 tparam_params,
3390                 user_attributes,
3391             } = decl;
3392             let constraints = self.slice(constraints.iter().filter_map(|constraint| {
3393                 let &(kind, ty) = constraint;
3394                 let ty = self.node_to_ty(ty)?;
3395                 let ty = self.convert_tapply_to_tgeneric(ty);
3396                 Some((kind, ty))
3397             }));
3399             let user_attributes = self.slice(
3400                 user_attributes
3401                     .iter()
3402                     .rev()
3403                     .map(|x| self.user_attribute_to_decl(x)),
3404             );
3405             tparams.push(self.alloc(Tparam {
3406                 variance,
3407                 name: name.into(),
3408                 constraints,
3409                 reified,
3410                 user_attributes,
3411                 tparams: tparam_params,
3412             }));
3413         }
3414         Node::TypeParameters(self.alloc(tparams.into_bump_slice()))
3415     }
3417     fn make_parameter_declaration(
3418         &mut self,
3419         attributes: Self::R,
3420         visibility: Self::R,
3421         inout: Self::R,
3422         readonly: Self::R,
3423         hint: Self::R,
3424         name: Self::R,
3425         initializer: Self::R,
3426     ) -> Self::R {
3427         let (variadic, pos, name) = match name {
3428             Node::ListItem(&(ellipsis, id)) => {
3429                 let Id(pos, name) = match id.as_variable() {
3430                     Some(id) => id,
3431                     None => return Node::Ignored(SK::ParameterDeclaration),
3432                 };
3433                 let variadic = ellipsis.is_token(TokenKind::DotDotDot);
3434                 (variadic, pos, Some(name))
3435             }
3436             name => {
3437                 let Id(pos, name) = match name.as_variable() {
3438                     Some(id) => id,
3439                     None => return Node::Ignored(SK::ParameterDeclaration),
3440                 };
3441                 (false, pos, Some(name))
3442             }
3443         };
3444         let kind = if inout.is_token(TokenKind::Inout) {
3445             ParamMode::FPinout
3446         } else {
3447             ParamMode::FPnormal
3448         };
3449         let is_readonly = readonly.is_token(TokenKind::Readonly);
3450         let hint = if self.opts.interpret_soft_types_as_like_types {
3451             let attributes = self.to_attributes(attributes);
3452             if attributes.soft {
3453                 match hint {
3454                     Node::Ty(ty) => self.hint_ty(self.get_pos(hint), Ty_::Tlike(ty)),
3455                     _ => hint,
3456                 }
3457             } else {
3458                 hint
3459             }
3460         } else {
3461             hint
3462         };
3463         Node::FunParam(self.alloc(FunParamDecl {
3464             attributes,
3465             visibility,
3466             kind,
3467             readonly: is_readonly,
3468             hint,
3469             pos,
3470             name,
3471             variadic,
3472             initializer,
3473         }))
3474     }
3476     fn make_variadic_parameter(&mut self, _: Self::R, hint: Self::R, ellipsis: Self::R) -> Self::R {
3477         Node::FunParam(
3478             self.alloc(FunParamDecl {
3479                 attributes: Node::Ignored(SK::Missing),
3480                 visibility: Node::Ignored(SK::Missing),
3481                 kind: ParamMode::FPnormal,
3482                 readonly: false,
3483                 hint,
3484                 pos: self
3485                     .get_pos_opt(hint)
3486                     .unwrap_or_else(|| self.get_pos(ellipsis)),
3487                 name: None,
3488                 variadic: true,
3489                 initializer: Node::Ignored(SK::Missing),
3490             }),
3491         )
3492     }
3494     fn make_function_declaration(
3495         &mut self,
3496         attributes: Self::R,
3497         header: Self::R,
3498         body: Self::R,
3499     ) -> Self::R {
3500         let parsed_attributes = self.to_attributes(attributes);
3501         match header {
3502             Node::FunctionHeader(header) => {
3503                 let is_method = false;
3504                 let ((pos, name), type_, _) =
3505                     match self.function_to_ty(is_method, attributes, header, body) {
3506                         Some(x) => x,
3507                         None => return Node::Ignored(SK::FunctionDeclaration),
3508                     };
3509                 let deprecated = parsed_attributes.deprecated.map(|msg| {
3510                     let mut s = String::new_in(self.arena);
3511                     s.push_str("The function ");
3512                     s.push_str(name.trim_start_matches("\\"));
3513                     s.push_str(" is deprecated: ");
3514                     s.push_str(msg);
3515                     s.into_bump_str()
3516                 });
3517                 let fun_elt = self.alloc(FunElt {
3518                     module: self.alloc(parsed_attributes.module),
3519                     internal: parsed_attributes.internal,
3520                     deprecated,
3521                     type_,
3522                     pos,
3523                     php_std_lib: parsed_attributes.php_std_lib,
3524                     support_dynamic_type: self.opts.everything_sdt
3525                         || parsed_attributes.support_dynamic_type,
3526                 });
3527                 self.add_fun(name, fun_elt);
3528                 Node::Ignored(SK::FunctionDeclaration)
3529             }
3530             _ => Node::Ignored(SK::FunctionDeclaration),
3531         }
3532     }
3534     fn make_contexts(
3535         &mut self,
3536         left_bracket: Self::R,
3537         tys: Self::R,
3538         right_bracket: Self::R,
3539     ) -> Self::R {
3540         let tys = self.slice(tys.iter().filter_map(|ty| match ty {
3541             Node::ListItem(&(ty, _)) | &ty => {
3542                 // A wildcard is used for the context of a closure type on a
3543                 // parameter of a function with a function context (e.g.,
3544                 // `function f((function ()[_]: void) $f)[ctx $f]: void {}`).
3545                 if let Some(Id(pos, "_")) = self.expect_name(ty) {
3546                     return Some(self.alloc(Ty(
3547                         self.alloc(Reason::hint(pos)),
3548                         Ty_::Tapply(self.alloc(((pos, "_"), &[]))),
3549                     )));
3550                 }
3551                 let ty = self.node_to_ty(ty)?;
3552                 match ty.1 {
3553                     // Only three forms of type can appear here in a valid program:
3554                     //   - function contexts (`ctx $f`)
3555                     //   - value-dependent paths (`$v::C`)
3556                     //   - built-in contexts (`rx`, `cipp_of<EntFoo>`)
3557                     // The first and last will be represented with `Tapply`,
3558                     // but function contexts will use a variable name
3559                     // (containing a `$`). Built-in contexts are always in the
3560                     // \HH\Contexts namespace, so we rewrite those names here.
3561                     Ty_::Tapply(&((pos, name), targs)) if !name.starts_with('$') => {
3562                         // The name will have been elaborated in the current
3563                         // namespace, but we actually want it to be in the
3564                         // \HH\Contexts namespace. Grab the last component of
3565                         // the name, and rewrite it in the correct namespace.
3566                         // Note that this makes it impossible to express names
3567                         // in any sub-namespace of \HH\Contexts (e.g.,
3568                         // "Unsafe\\cipp" will be rewritten as
3569                         // "\\HH\\Contexts\\cipp" rather than
3570                         // "\\HH\\Contexts\\Unsafe\\cipp").
3571                         let name = match name.trim_end_matches('\\').split('\\').next_back() {
3572                             Some(ctxname) => {
3573                                 if let Some(first_char) = ctxname.chars().nth(0) {
3574                                     if first_char.is_lowercase() {
3575                                         self.concat("\\HH\\Contexts\\", ctxname)
3576                                     } else {
3577                                         name
3578                                     }
3579                                 } else {
3580                                     name
3581                                 }
3582                             }
3583                             None => name,
3584                         };
3585                         Some(self.alloc(Ty(ty.0, Ty_::Tapply(self.alloc(((pos, name), targs))))))
3586                     }
3587                     _ => Some(ty),
3588                 }
3589             }
3590         }));
3591         /* Like in as_fun_implicit_params, we keep the intersection as is: we do not simplify
3592          * empty or singleton intersections.
3593          */
3594         let pos = self.merge_positions(left_bracket, right_bracket);
3595         self.hint_ty(pos, Ty_::Tintersection(tys))
3596     }
3598     fn make_function_ctx_type_specifier(
3599         &mut self,
3600         ctx_keyword: Self::R,
3601         variable: Self::R,
3602     ) -> Self::R {
3603         match variable.as_variable() {
3604             Some(Id(pos, name)) => {
3605                 Node::Variable(self.alloc((name, self.merge(pos, self.get_pos(ctx_keyword)))))
3606             }
3607             None => Node::Ignored(SK::FunctionCtxTypeSpecifier),
3608         }
3609     }
3611     fn make_function_declaration_header(
3612         &mut self,
3613         modifiers: Self::R,
3614         _keyword: Self::R,
3615         name: Self::R,
3616         type_params: Self::R,
3617         left_paren: Self::R,
3618         param_list: Self::R,
3619         _right_paren: Self::R,
3620         capability: Self::R,
3621         _colon: Self::R,
3622         readonly_return: Self::R,
3623         ret_hint: Self::R,
3624         where_constraints: Self::R,
3625     ) -> Self::R {
3626         // Use the position of the left paren if the name is missing.
3627         // Keep the name if it's an IgnoredToken rather than an Ignored. An
3628         // IgnoredToken here should always be an error, but it's better to treat
3629         // a keyword as a name than to claim the function has no name at all.
3630         let name = if matches!(name, Node::Ignored(..)) {
3631             left_paren
3632         } else {
3633             name
3634         };
3635         Node::FunctionHeader(self.alloc(FunctionHeader {
3636             name,
3637             modifiers,
3638             type_params,
3639             param_list,
3640             capability,
3641             ret_hint,
3642             readonly_return,
3643             where_constraints,
3644         }))
3645     }
3647     fn make_yield_expression(&mut self, keyword: Self::R, _operand: Self::R) -> Self::R {
3648         assert!(keyword.token_kind() == Some(TokenKind::Yield));
3649         keyword
3650     }
3652     fn make_const_declaration(
3653         &mut self,
3654         modifiers: Self::R,
3655         const_keyword: Self::R,
3656         hint: Self::R,
3657         decls: Self::R,
3658         semicolon: Self::R,
3659     ) -> Self::R {
3660         match decls {
3661             // Class consts.
3662             Node::List(consts)
3663                 if self
3664                     .classish_name_builder
3665                     .get_current_classish_name()
3666                     .is_some() =>
3667             {
3668                 let ty = self.node_to_ty(hint);
3669                 Node::List(
3670                     self.alloc(self.slice(consts.iter().filter_map(|cst| match cst {
3671                         Node::ConstInitializer(&(name, initializer, refs)) => {
3672                             let id = name.as_id()?;
3673                             let modifiers = read_member_modifiers(modifiers.iter());
3674                             let abstract_ = if modifiers.is_abstract {
3675                                 ClassConstKind::CCAbstract(!initializer.is_ignored())
3676                             } else {
3677                                 ClassConstKind::CCConcrete
3678                             };
3679                             let ty = ty
3680                                 .or_else(|| self.infer_const(name, initializer))
3681                                 .unwrap_or_else(|| tany());
3682                             Some(Node::Const(self.alloc(
3683                                 shallow_decl_defs::ShallowClassConst {
3684                                     abstract_,
3685                                     name: id.into(),
3686                                     type_: ty,
3687                                     refs,
3688                                 },
3689                             )))
3690                         }
3691                         _ => None,
3692                     }))),
3693                 )
3694             }
3695             // Global consts.
3696             Node::List(consts) => {
3697                 // This case always returns Node::Ignored,
3698                 // but has the side effect of calling self.add_const
3700                 // Note: given "const int X=1,Y=2;", the legacy decl-parser
3701                 // allows both decls, and it gives them both an identical text-span -
3702                 // from start of "const" to end of semicolon. This is a bug but
3703                 // the code here preserves it.
3704                 let pos = self.merge_positions(const_keyword, semicolon);
3705                 for cst in consts.iter() {
3706                     match cst {
3707                         Node::ConstInitializer(&(name, initializer, _refs)) => {
3708                             if let Some(Id(id_pos, id)) = self.elaborate_defined_id(name) {
3709                                 let ty = self
3710                                     .node_to_ty(hint)
3711                                     .or_else(|| self.infer_const(name, initializer))
3712                                     .unwrap_or_else(|| self.tany_with_pos(id_pos));
3713                                 self.add_const(id, self.alloc(ConstDecl { pos, type_: ty }));
3714                             }
3715                         }
3716                         _ => {}
3717                     }
3718                 }
3719                 Node::Ignored(SK::ConstDeclaration)
3720             }
3721             _ => Node::Ignored(SK::ConstDeclaration),
3722         }
3723     }
3725     fn begin_constant_declarator(&mut self) {
3726         self.start_accumulating_const_refs();
3727     }
3729     fn make_constant_declarator(&mut self, name: Self::R, initializer: Self::R) -> Self::R {
3730         // The "X=1" part of either a member const "class C {const int X=1;}" or a top-level const "const int X=1;"
3731         // Note: the the declarator itself doesn't yet know whether a type was provided by the user;
3732         // that's only known in the parent, make_const_declaration
3733         let refs = self.stop_accumulating_const_refs();
3734         if name.is_ignored() {
3735             Node::Ignored(SK::ConstantDeclarator)
3736         } else {
3737             Node::ConstInitializer(self.alloc((name, initializer, refs)))
3738         }
3739     }
3741     fn make_namespace_declaration(&mut self, _name: Self::R, body: Self::R) -> Self::R {
3742         if let Node::Ignored(SK::NamespaceBody) = body {
3743             Rc::make_mut(&mut self.namespace_builder).pop_namespace();
3744         }
3745         Node::Ignored(SK::NamespaceDeclaration)
3746     }
3748     fn make_namespace_declaration_header(&mut self, _keyword: Self::R, name: Self::R) -> Self::R {
3749         let name = self.expect_name(name).map(|Id(_, name)| name);
3750         // if this is header of semicolon-style (one with NamespaceEmptyBody) namespace, we should pop
3751         // the previous namespace first, but we don't have the body yet. We'll fix it retroactively in
3752         // make_namespace_empty_body
3753         Rc::make_mut(&mut self.namespace_builder).push_namespace(name);
3754         Node::Ignored(SK::NamespaceDeclarationHeader)
3755     }
3757     fn make_namespace_body(
3758         &mut self,
3759         _left_brace: Self::R,
3760         _declarations: Self::R,
3761         _right_brace: Self::R,
3762     ) -> Self::R {
3763         Node::Ignored(SK::NamespaceBody)
3764     }
3766     fn make_namespace_empty_body(&mut self, _semicolon: Self::R) -> Self::R {
3767         Rc::make_mut(&mut self.namespace_builder).pop_previous_namespace();
3768         Node::Ignored(SK::NamespaceEmptyBody)
3769     }
3771     fn make_namespace_use_declaration(
3772         &mut self,
3773         _keyword: Self::R,
3774         namespace_use_kind: Self::R,
3775         clauses: Self::R,
3776         _semicolon: Self::R,
3777     ) -> Self::R {
3778         if let Some(import_kind) = Self::namespace_use_kind(&namespace_use_kind) {
3779             for clause in clauses.iter() {
3780                 if let Node::NamespaceUseClause(nuc) = clause {
3781                     Rc::make_mut(&mut self.namespace_builder).add_import(
3782                         import_kind,
3783                         nuc.id.1,
3784                         nuc.as_,
3785                     );
3786                 }
3787             }
3788         }
3789         Node::Ignored(SK::NamespaceUseDeclaration)
3790     }
3792     fn make_namespace_group_use_declaration(
3793         &mut self,
3794         _keyword: Self::R,
3795         _kind: Self::R,
3796         prefix: Self::R,
3797         _left_brace: Self::R,
3798         clauses: Self::R,
3799         _right_brace: Self::R,
3800         _semicolon: Self::R,
3801     ) -> Self::R {
3802         let Id(_, prefix) = match self.expect_name(prefix) {
3803             Some(id) => id,
3804             None => return Node::Ignored(SK::NamespaceGroupUseDeclaration),
3805         };
3806         for clause in clauses.iter() {
3807             if let Node::NamespaceUseClause(nuc) = clause {
3808                 let mut id = String::new_in(self.arena);
3809                 id.push_str(prefix);
3810                 id.push_str(nuc.id.1);
3811                 Rc::make_mut(&mut self.namespace_builder).add_import(
3812                     nuc.kind,
3813                     id.into_bump_str(),
3814                     nuc.as_,
3815                 );
3816             }
3817         }
3818         Node::Ignored(SK::NamespaceGroupUseDeclaration)
3819     }
3821     fn make_namespace_use_clause(
3822         &mut self,
3823         clause_kind: Self::R,
3824         name: Self::R,
3825         as_: Self::R,
3826         aliased_name: Self::R,
3827     ) -> Self::R {
3828         let id = match self.expect_name(name) {
3829             Some(id) => id,
3830             None => return Node::Ignored(SK::NamespaceUseClause),
3831         };
3832         let as_ = if as_.is_token(TokenKind::As) {
3833             match aliased_name.as_id() {
3834                 Some(name) => Some(name.1),
3835                 None => return Node::Ignored(SK::NamespaceUseClause),
3836             }
3837         } else {
3838             None
3839         };
3840         if let Some(kind) = Self::namespace_use_kind(&clause_kind) {
3841             Node::NamespaceUseClause(self.alloc(NamespaceUseClause { kind, id, as_ }))
3842         } else {
3843             Node::Ignored(SK::NamespaceUseClause)
3844         }
3845     }
3847     fn make_where_clause(&mut self, _: Self::R, where_constraints: Self::R) -> Self::R {
3848         where_constraints
3849     }
3851     fn make_where_constraint(
3852         &mut self,
3853         left_type: Self::R,
3854         operator: Self::R,
3855         right_type: Self::R,
3856     ) -> Self::R {
3857         Node::WhereConstraint(self.alloc(WhereConstraint(
3858             self.node_to_ty(left_type).unwrap_or_else(|| tany()),
3859             match operator.token_kind() {
3860                 Some(TokenKind::Equal) => ConstraintKind::ConstraintEq,
3861                 Some(TokenKind::Super) => ConstraintKind::ConstraintSuper,
3862                 _ => ConstraintKind::ConstraintAs,
3863             },
3864             self.node_to_ty(right_type).unwrap_or_else(|| tany()),
3865         )))
3866     }
3868     fn make_classish_declaration(
3869         &mut self,
3870         attributes: Self::R,
3871         modifiers: Self::R,
3872         xhp_keyword: Self::R,
3873         class_keyword: Self::R,
3874         name: Self::R,
3875         tparams: Self::R,
3876         _extends_keyword: Self::R,
3877         extends: Self::R,
3878         _implements_keyword: Self::R,
3879         implements: Self::R,
3880         where_clause: Self::R,
3881         body: Self::R,
3882     ) -> Self::R {
3883         let raw_name = match self.expect_name(name) {
3884             Some(Id(_, name)) => name,
3885             None => return Node::Ignored(SK::ClassishDeclaration),
3886         };
3887         let Id(pos, name) = match self.elaborate_defined_id(name) {
3888             Some(id) => id,
3889             None => return Node::Ignored(SK::ClassishDeclaration),
3890         };
3891         let is_xhp = raw_name.starts_with(':') || xhp_keyword.is_present();
3893         let mut final_ = false;
3894         let mut abstract_ = false;
3896         for modifier in modifiers.iter() {
3897             match modifier.token_kind() {
3898                 Some(TokenKind::Abstract) => {
3899                     abstract_ = true;
3900                 }
3901                 Some(TokenKind::Final) => final_ = true,
3902                 _ => {}
3903             }
3904         }
3905         let class_kind = match class_keyword.token_kind() {
3906             Some(TokenKind::Interface) => ClassishKind::Cinterface,
3907             Some(TokenKind::Trait) => ClassishKind::Ctrait,
3908             _ => ClassishKind::Cclass(if abstract_ {
3909                 &Abstraction::Abstract
3910             } else {
3911                 &Abstraction::Concrete
3912             }),
3913         };
3915         let where_constraints = self.slice(where_clause.iter().filter_map(|&x| match x {
3916             Node::WhereConstraint(x) => Some(x),
3917             _ => None,
3918         }));
3920         let body = match body {
3921             Node::ClassishBody(body) => body,
3922             _ => return Node::Ignored(SK::ClassishDeclaration),
3923         };
3925         let mut uses_len = 0;
3926         let mut xhp_attr_uses_len = 0;
3927         let mut xhp_enum_values = SMap::empty();
3928         let mut req_extends_len = 0;
3929         let mut req_implements_len = 0;
3930         let mut consts_len = 0;
3931         let mut typeconsts_len = 0;
3932         let mut props_len = 0;
3933         let mut sprops_len = 0;
3934         let mut static_methods_len = 0;
3935         let mut methods_len = 0;
3937         let mut user_attributes_len = 0;
3938         for attribute in attributes.iter() {
3939             match attribute {
3940                 &Node::Attribute(..) => user_attributes_len += 1,
3941                 _ => {}
3942             }
3943         }
3945         for element in body.iter().copied() {
3946             match element {
3947                 Node::TraitUse(names) => uses_len += names.len(),
3948                 Node::XhpClassAttributeDeclaration(&XhpClassAttributeDeclarationNode {
3949                     xhp_attr_decls,
3950                     xhp_attr_uses_decls,
3951                     xhp_attr_enum_values,
3952                 }) => {
3953                     props_len += xhp_attr_decls.len();
3954                     xhp_attr_uses_len += xhp_attr_uses_decls.len();
3956                     for (name, values) in xhp_attr_enum_values {
3957                         xhp_enum_values = xhp_enum_values.add(self.arena, name, *values);
3958                     }
3959                 }
3960                 Node::TypeConstant(..) => typeconsts_len += 1,
3961                 Node::RequireClause(require) => match require.require_type.token_kind() {
3962                     Some(TokenKind::Extends) => req_extends_len += 1,
3963                     Some(TokenKind::Implements) => req_implements_len += 1,
3964                     _ => {}
3965                 },
3966                 Node::List(consts @ [Node::Const(..), ..]) => consts_len += consts.len(),
3967                 Node::Property(&PropertyNode { decls, is_static }) => {
3968                     if is_static {
3969                         sprops_len += decls.len()
3970                     } else {
3971                         props_len += decls.len()
3972                     }
3973                 }
3974                 Node::Constructor(&ConstructorNode { properties, .. }) => {
3975                     props_len += properties.len()
3976                 }
3977                 Node::Method(&MethodNode { is_static, .. }) => {
3978                     if is_static {
3979                         static_methods_len += 1
3980                     } else {
3981                         methods_len += 1
3982                     }
3983                 }
3984                 _ => {}
3985             }
3986         }
3988         let mut constructor = None;
3990         let mut uses = Vec::with_capacity_in(uses_len, self.arena);
3991         let mut xhp_attr_uses = Vec::with_capacity_in(xhp_attr_uses_len, self.arena);
3992         let mut req_extends = Vec::with_capacity_in(req_extends_len, self.arena);
3993         let mut req_implements = Vec::with_capacity_in(req_implements_len, self.arena);
3994         let mut consts = Vec::with_capacity_in(consts_len, self.arena);
3995         let mut typeconsts = Vec::with_capacity_in(typeconsts_len, self.arena);
3996         let mut props = Vec::with_capacity_in(props_len, self.arena);
3997         let mut sprops = Vec::with_capacity_in(sprops_len, self.arena);
3998         let mut static_methods = Vec::with_capacity_in(static_methods_len, self.arena);
3999         let mut methods = Vec::with_capacity_in(methods_len, self.arena);
4001         let mut user_attributes = Vec::with_capacity_in(user_attributes_len, self.arena);
4002         for attribute in attributes.iter() {
4003             match attribute {
4004                 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(&attr)),
4005                 _ => {}
4006             }
4007         }
4008         // Match ordering of attributes produced by the OCaml decl parser (even
4009         // though it's the reverse of the syntactic ordering).
4010         user_attributes.reverse();
4012         let class_attributes = self.to_attributes(attributes);
4014         // xhp props go after regular props, regardless of their order in file
4015         let mut xhp_props = vec![];
4017         for element in body.iter().copied() {
4018             match element {
4019                 Node::TraitUse(names) => {
4020                     uses.extend(names.iter().filter_map(|&name| self.node_to_ty(name)))
4021                 }
4022                 Node::XhpClassAttributeDeclaration(&XhpClassAttributeDeclarationNode {
4023                     xhp_attr_decls,
4024                     xhp_attr_uses_decls,
4025                     ..
4026                 }) => {
4027                     xhp_props.extend(xhp_attr_decls);
4028                     xhp_attr_uses.extend(
4029                         xhp_attr_uses_decls
4030                             .iter()
4031                             .filter_map(|&node| self.node_to_ty(node)),
4032                     )
4033                 }
4034                 Node::TypeConstant(constant) => typeconsts.push(constant),
4035                 Node::RequireClause(require) => match require.require_type.token_kind() {
4036                     Some(TokenKind::Extends) => {
4037                         req_extends.extend(self.node_to_ty(require.name).iter())
4038                     }
4039                     Some(TokenKind::Implements) => {
4040                         req_implements.extend(self.node_to_ty(require.name).iter())
4041                     }
4042                     _ => {}
4043                 },
4044                 Node::List(&const_nodes @ [Node::Const(..), ..]) => {
4045                     for node in const_nodes {
4046                         if let &Node::Const(decl) = node {
4047                             consts.push(decl)
4048                         }
4049                     }
4050                 }
4051                 Node::Property(&PropertyNode { decls, is_static }) => {
4052                     for property in decls {
4053                         if is_static {
4054                             sprops.push(property)
4055                         } else {
4056                             props.push(property)
4057                         }
4058                     }
4059                 }
4060                 Node::Constructor(&ConstructorNode { method, properties }) => {
4061                     constructor = Some(method);
4062                     for property in properties {
4063                         props.push(property)
4064                     }
4065                 }
4066                 Node::Method(&MethodNode { method, is_static }) => {
4067                     // Annoyingly, the <<__SupportDynamicType>> annotation on a
4068                     // class implicitly changes the decls of every method inside
4069                     // it, so we have to reallocate them here.
4070                     let method = if class_attributes.support_dynamic_type
4071                         && !method.flags.contains(MethodFlags::SUPPORT_DYNAMIC_TYPE)
4072                     {
4073                         let type_ = match method.type_.1 {
4074                             Ty_::Tfun(ft) => {
4075                                 let flags = ft.flags | FunTypeFlags::SUPPORT_DYNAMIC_TYPE;
4076                                 let ft = self.alloc(FunType { flags, ..*ft });
4077                                 self.alloc(Ty(method.type_.0, Ty_::Tfun(ft)))
4078                             }
4079                             _ => method.type_,
4080                         };
4081                         let flags = method.flags | MethodFlags::SUPPORT_DYNAMIC_TYPE;
4082                         self.alloc(ShallowMethod {
4083                             type_,
4084                             flags,
4085                             ..*method
4086                         })
4087                     } else {
4088                         method
4089                     };
4090                     if is_static {
4091                         static_methods.push(method);
4092                     } else {
4093                         methods.push(method);
4094                     }
4095                 }
4096                 _ => {} // It's not our job to report errors here.
4097             }
4098         }
4100         props.extend(xhp_props.into_iter());
4102         if class_attributes.const_ {
4103             for prop in props.iter_mut() {
4104                 if !prop.flags.contains(PropFlags::CONST) {
4105                     *prop = self.alloc(ShallowProp {
4106                         flags: prop.flags | PropFlags::CONST,
4107                         ..**prop
4108                     })
4109                 }
4110             }
4111         }
4113         let uses = uses.into_bump_slice();
4114         let xhp_attr_uses = xhp_attr_uses.into_bump_slice();
4115         let req_extends = req_extends.into_bump_slice();
4116         let req_implements = req_implements.into_bump_slice();
4117         let consts = consts.into_bump_slice();
4118         let typeconsts = typeconsts.into_bump_slice();
4119         let props = props.into_bump_slice();
4120         let sprops = sprops.into_bump_slice();
4121         let static_methods = static_methods.into_bump_slice();
4122         let methods = methods.into_bump_slice();
4123         let user_attributes = user_attributes.into_bump_slice();
4124         let extends = self.slice(extends.iter().filter_map(|&node| self.node_to_ty(node)));
4125         let implements = self.slice(implements.iter().filter_map(|&node| self.node_to_ty(node)));
4126         let support_dynamic_type =
4127             self.opts.everything_sdt || class_attributes.support_dynamic_type;
4128         // Pop the type params stack only after creating all inner types.
4129         let tparams = self.pop_type_params(tparams);
4130         let module = class_attributes.module;
4132         let cls = self.alloc(shallow_decl_defs::ShallowClass {
4133             mode: self.file_mode,
4134             final_,
4135             abstract_,
4136             is_xhp,
4137             has_xhp_keyword: xhp_keyword.is_token(TokenKind::XHP),
4138             kind: class_kind,
4139             module: self.alloc(module),
4140             name: (pos, name),
4141             tparams,
4142             where_constraints,
4143             extends,
4144             uses,
4145             xhp_attr_uses,
4146             xhp_enum_values,
4147             req_extends,
4148             req_implements,
4149             implements,
4150             support_dynamic_type,
4151             consts,
4152             typeconsts,
4153             props,
4154             sprops,
4155             constructor,
4156             static_methods,
4157             methods,
4158             user_attributes,
4159             enum_type: None,
4160         });
4161         self.add_class(name, cls);
4163         self.classish_name_builder.parsed_classish_declaration();
4165         Node::Ignored(SK::ClassishDeclaration)
4166     }
4168     fn make_property_declaration(
4169         &mut self,
4170         attrs: Self::R,
4171         modifiers: Self::R,
4172         hint: Self::R,
4173         declarators: Self::R,
4174         _semicolon: Self::R,
4175     ) -> Self::R {
4176         let (attrs, modifiers, hint) = (attrs, modifiers, hint);
4177         let modifiers = read_member_modifiers(modifiers.iter());
4178         let declarators = self.slice(declarators.iter().filter_map(
4179             |declarator| match declarator {
4180                 Node::ListItem(&(name, initializer)) => {
4181                     let attributes = self.to_attributes(attrs);
4182                     let Id(pos, name) = name.as_variable()?;
4183                     let name = if modifiers.is_static {
4184                         name
4185                     } else {
4186                         strip_dollar_prefix(name)
4187                     };
4188                     let ty = self.rewrite_ty_for_global_inference(
4189                         self.node_to_non_ret_ty(hint),
4190                         Reason::RglobalClassProp(pos),
4191                     );
4192                     let ty = if self.opts.interpret_soft_types_as_like_types {
4193                         if attributes.soft {
4194                             ty.map(|t| {
4195                                 self.alloc(Ty(
4196                                     self.alloc(Reason::hint(self.get_pos(hint))),
4197                                     Ty_::Tlike(t),
4198                                 ))
4199                             })
4200                         } else {
4201                             ty
4202                         }
4203                     } else {
4204                         ty
4205                     };
4206                     let needs_init = if self.file_mode == Mode::Mhhi {
4207                         false
4208                     } else {
4209                         initializer.is_ignored()
4210                     };
4211                     let mut flags = PropFlags::empty();
4212                     flags.set(PropFlags::CONST, attributes.const_);
4213                     flags.set(PropFlags::LATEINIT, attributes.late_init);
4214                     flags.set(PropFlags::LSB, attributes.lsb);
4215                     flags.set(PropFlags::NEEDS_INIT, needs_init);
4216                     flags.set(PropFlags::ABSTRACT, modifiers.is_abstract);
4217                     flags.set(PropFlags::READONLY, modifiers.is_readonly);
4218                     flags.set(PropFlags::PHP_STD_LIB, attributes.php_std_lib);
4219                     Some(ShallowProp {
4220                         xhp_attr: None,
4221                         name: (pos, name),
4222                         type_: ty,
4223                         visibility: if attributes.internal
4224                             && modifiers.visibility == aast::Visibility::Public
4225                         {
4226                             aast::Visibility::Internal
4227                         } else {
4228                             modifiers.visibility
4229                         },
4230                         flags,
4231                     })
4232                 }
4233                 _ => None,
4234             },
4235         ));
4236         Node::Property(self.alloc(PropertyNode {
4237             decls: declarators,
4238             is_static: modifiers.is_static,
4239         }))
4240     }
4242     fn make_xhp_class_attribute_declaration(
4243         &mut self,
4244         _keyword: Self::R,
4245         attributes: Self::R,
4246         _semicolon: Self::R,
4247     ) -> Self::R {
4248         let mut xhp_attr_enum_values = Vec::new_in(self.arena);
4250         let xhp_attr_decls = self.slice(attributes.iter().filter_map(|node| {
4251             let node = match node {
4252                 Node::XhpClassAttribute(x) => x,
4253                 _ => return None,
4254             };
4255             let Id(pos, name) = node.name;
4256             let name = prefix_colon(self.arena, name);
4258             let (type_, enum_values) = match node.hint {
4259                 Node::XhpEnumTy((ty, values)) => (Some(*ty), Some(values)),
4260                 _ => (self.node_to_ty(node.hint), None),
4261             };
4262             if let Some(enum_values) = enum_values {
4263                 xhp_attr_enum_values.push((name, *enum_values));
4264             };
4266             let type_ = if node.nullable && node.tag.is_none() {
4267                 type_.and_then(|x| match x {
4268                     // already nullable
4269                     Ty(_, Ty_::Toption(_)) | Ty(_, Ty_::Tmixed) => type_,
4270                     // make nullable
4271                     _ => self.node_to_ty(self.hint_ty(x.get_pos()?, Ty_::Toption(x))),
4272                 })
4273             } else {
4274                 type_
4275             };
4277             let mut flags = PropFlags::empty();
4278             flags.set(PropFlags::NEEDS_INIT, node.needs_init);
4279             Some(ShallowProp {
4280                 name: (pos, name),
4281                 visibility: aast::Visibility::Public,
4282                 type_,
4283                 xhp_attr: Some(shallow_decl_defs::XhpAttr {
4284                     tag: node.tag,
4285                     has_default: !node.needs_init,
4286                 }),
4287                 flags,
4288             })
4289         }));
4291         let xhp_attr_uses_decls = self.slice(attributes.iter().filter_map(|x| match x {
4292             Node::XhpAttributeUse(&name) => Some(name),
4293             _ => None,
4294         }));
4296         Node::XhpClassAttributeDeclaration(self.alloc(XhpClassAttributeDeclarationNode {
4297             xhp_attr_enum_values: xhp_attr_enum_values.into_bump_slice(),
4298             xhp_attr_decls,
4299             xhp_attr_uses_decls,
4300         }))
4301     }
4303     /// Handle XHP attribute enum declarations.
4304     ///
4305     ///   class :foo implements XHPChild {
4306     ///     attribute
4307     ///       enum {'big', 'small'} size; // this line
4308     ///   }
4309     fn make_xhp_enum_type(
4310         &mut self,
4311         enum_keyword: Self::R,
4312         _left_brace: Self::R,
4313         xhp_enum_values: Self::R,
4314         right_brace: Self::R,
4315     ) -> Self::R {
4316         // Infer the type hint from the first value.
4317         // TODO: T88207956 consider all the values.
4318         let ty = xhp_enum_values
4319             .iter()
4320             .next()
4321             .and_then(|node| self.node_to_ty(*node))
4322             .and_then(|node_ty| {
4323                 let pos = self.merge_positions(enum_keyword, right_brace);
4324                 let ty_ = node_ty.1;
4325                 Some(self.alloc(Ty(self.alloc(Reason::hint(pos)), ty_)))
4326             });
4328         let mut values = Vec::new_in(self.arena);
4329         for node in xhp_enum_values.iter() {
4330             // XHP enum values may only be string or int literals.
4331             match node {
4332                 Node::IntLiteral(&(s, _)) => {
4333                     let i = s.parse::<isize>().unwrap_or(0);
4334                     values.push(XhpEnumValue::XEVInt(i));
4335                 }
4336                 Node::StringLiteral(&(s, _)) => {
4337                     let owned_str = std::string::String::from_utf8_lossy(s);
4338                     values.push(XhpEnumValue::XEVString(self.arena.alloc_str(&owned_str)));
4339                 }
4340                 _ => {}
4341             };
4342         }
4344         match ty {
4345             Some(ty) => Node::XhpEnumTy(self.alloc((&ty, values.into_bump_slice()))),
4346             None => Node::Ignored(SK::XHPEnumType),
4347         }
4348     }
4350     fn make_xhp_class_attribute(
4351         &mut self,
4352         type_: Self::R,
4353         name: Self::R,
4354         initializer: Self::R,
4355         tag: Self::R,
4356     ) -> Self::R {
4357         let name = match name.as_id() {
4358             Some(name) => name,
4359             None => return Node::Ignored(SK::XHPClassAttribute),
4360         };
4361         Node::XhpClassAttribute(self.alloc(XhpClassAttributeNode {
4362             name,
4363             hint: type_,
4364             needs_init: !initializer.is_present(),
4365             tag: match tag.token_kind() {
4366                 Some(TokenKind::Required) => Some(XhpAttrTag::Required),
4367                 Some(TokenKind::Lateinit) => Some(XhpAttrTag::Lateinit),
4368                 _ => None,
4369             },
4370             nullable: initializer.is_token(TokenKind::NullLiteral) || !initializer.is_present(),
4371         }))
4372     }
4374     fn make_xhp_simple_class_attribute(&mut self, name: Self::R) -> Self::R {
4375         Node::XhpAttributeUse(self.alloc(name))
4376     }
4378     fn make_property_declarator(&mut self, name: Self::R, initializer: Self::R) -> Self::R {
4379         Node::ListItem(self.alloc((name, initializer)))
4380     }
4382     fn make_methodish_declaration(
4383         &mut self,
4384         attrs: Self::R,
4385         header: Self::R,
4386         body: Self::R,
4387         closer: Self::R,
4388     ) -> Self::R {
4389         let header = match header {
4390             Node::FunctionHeader(header) => header,
4391             _ => return Node::Ignored(SK::MethodishDeclaration),
4392         };
4393         // If we don't have a body, use the closing token. A closing token of
4394         // '}' indicates a regular function, while a closing token of ';'
4395         // indicates an abstract function.
4396         let body = if body.is_ignored() { closer } else { body };
4397         let modifiers = read_member_modifiers(header.modifiers.iter());
4398         let is_constructor = header.name.is_token(TokenKind::Construct);
4399         let is_method = true;
4400         let (id, ty, properties) = match self.function_to_ty(is_method, attrs, header, body) {
4401             Some(tuple) => tuple,
4402             None => return Node::Ignored(SK::MethodishDeclaration),
4403         };
4404         let attributes = self.to_attributes(attrs);
4405         let deprecated = attributes.deprecated.map(|msg| {
4406             let mut s = String::new_in(self.arena);
4407             s.push_str("The method ");
4408             s.push_str(id.1);
4409             s.push_str(" is deprecated: ");
4410             s.push_str(msg);
4411             s.into_bump_str()
4412         });
4413         let mut flags = MethodFlags::empty();
4414         flags.set(
4415             MethodFlags::ABSTRACT,
4416             self.classish_name_builder.in_interface() || modifiers.is_abstract,
4417         );
4418         flags.set(MethodFlags::FINAL, modifiers.is_final);
4419         flags.set(MethodFlags::OVERRIDE, attributes.override_);
4420         flags.set(
4421             MethodFlags::DYNAMICALLYCALLABLE,
4422             attributes.dynamically_callable,
4423         );
4424         flags.set(MethodFlags::PHP_STD_LIB, attributes.php_std_lib);
4425         flags.set(
4426             MethodFlags::SUPPORT_DYNAMIC_TYPE,
4427             !is_constructor && attributes.support_dynamic_type,
4428         );
4429         let visibility = match modifiers.visibility {
4430             aast::Visibility::Public => {
4431                 if attributes.internal {
4432                     aast::Visibility::Internal
4433                 } else {
4434                     aast::Visibility::Public
4435                 }
4436             }
4437             _ => modifiers.visibility,
4438         };
4440         let mut user_attributes = Vec::new_in(self.arena);
4441         if self.retain_or_omit_user_attributes_for_facts {
4442             for attribute in attrs.iter() {
4443                 match attribute {
4444                     Node::Attribute(attr) => {
4445                         user_attributes.push(self.user_attribute_to_decl(attr))
4446                     }
4447                     _ => {}
4448                 }
4449             }
4450             // Match ordering of attributes produced by the OCaml decl parser (even
4451             // though it's the reverse of the syntactic ordering).
4452             user_attributes.reverse();
4453         }
4454         let user_attributes = user_attributes.into_bump_slice();
4456         let method = self.alloc(ShallowMethod {
4457             name: id,
4458             type_: ty,
4459             visibility,
4460             deprecated,
4461             flags,
4462             attributes: user_attributes,
4463         });
4464         if is_constructor {
4465             Node::Constructor(self.alloc(ConstructorNode { method, properties }))
4466         } else {
4467             Node::Method(self.alloc(MethodNode {
4468                 method,
4469                 is_static: modifiers.is_static,
4470             }))
4471         }
4472     }
4474     fn make_classish_body(
4475         &mut self,
4476         _left_brace: Self::R,
4477         elements: Self::R,
4478         _right_brace: Self::R,
4479     ) -> Self::R {
4480         Node::ClassishBody(self.alloc(elements.as_slice(self.arena)))
4481     }
4483     fn make_enum_declaration(
4484         &mut self,
4485         attributes: Self::R,
4486         _keyword: Self::R,
4487         name: Self::R,
4488         _colon: Self::R,
4489         extends: Self::R,
4490         constraint: Self::R,
4491         _left_brace: Self::R,
4492         use_clauses: Self::R,
4493         enumerators: Self::R,
4494         _right_brace: Self::R,
4495     ) -> Self::R {
4496         let id = match self.elaborate_defined_id(name) {
4497             Some(id) => id,
4498             None => return Node::Ignored(SK::EnumDeclaration),
4499         };
4500         let hint = match self.node_to_ty(extends) {
4501             Some(ty) => ty,
4502             None => return Node::Ignored(SK::EnumDeclaration),
4503         };
4504         let extends = match self.node_to_ty(self.make_apply(
4505             (self.get_pos(name), "\\HH\\BuiltinEnum"),
4506             name,
4507             Pos::none(),
4508         )) {
4509             Some(ty) => ty,
4510             None => return Node::Ignored(SK::EnumDeclaration),
4511         };
4512         let key = id.1;
4513         let consts = self.slice(enumerators.iter().filter_map(|node| match node {
4514             &Node::Const(const_) => Some(const_),
4515             _ => None,
4516         }));
4517         let mut user_attributes = Vec::with_capacity_in(attributes.len(), self.arena);
4518         for attribute in attributes.iter() {
4519             match attribute {
4520                 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(attr)),
4521                 _ => {}
4522             }
4523         }
4524         // Match ordering of attributes produced by the OCaml decl parser (even
4525         // though it's the reverse of the syntactic ordering).
4526         user_attributes.reverse();
4527         let user_attributes = user_attributes.into_bump_slice();
4529         let constraint = match constraint {
4530             Node::TypeConstraint(&(_kind, ty)) => self.node_to_ty(ty),
4531             _ => None,
4532         };
4534         let mut includes_len = 0;
4535         for element in use_clauses.iter() {
4536             match element {
4537                 Node::EnumUse(names) => includes_len += names.len(),
4538                 _ => {}
4539             }
4540         }
4541         let mut includes = Vec::with_capacity_in(includes_len, self.arena);
4542         for element in use_clauses.iter() {
4543             match element {
4544                 Node::EnumUse(names) => {
4545                     includes.extend(names.iter().filter_map(|&name| self.node_to_ty(name)))
4546                 }
4547                 _ => {}
4548             }
4549         }
4550         let includes = includes.into_bump_slice();
4552         let parsed_attributes = self.to_attributes(attributes);
4554         let cls = self.alloc(shallow_decl_defs::ShallowClass {
4555             mode: self.file_mode,
4556             final_: false,
4557             abstract_: false,
4558             is_xhp: false,
4559             has_xhp_keyword: false,
4560             kind: ClassishKind::Cenum,
4561             module: self.alloc(parsed_attributes.module),
4562             name: id.into(),
4563             tparams: &[],
4564             where_constraints: &[],
4565             extends: bumpalo::vec![in self.arena; extends].into_bump_slice(),
4566             uses: &[],
4567             xhp_attr_uses: &[],
4568             xhp_enum_values: SMap::empty(),
4569             req_extends: &[],
4570             req_implements: &[],
4571             implements: &[],
4572             support_dynamic_type: parsed_attributes.support_dynamic_type,
4573             consts,
4574             typeconsts: &[],
4575             props: &[],
4576             sprops: &[],
4577             constructor: None,
4578             static_methods: &[],
4579             methods: &[],
4580             user_attributes,
4581             enum_type: Some(self.alloc(EnumType {
4582                 base: hint,
4583                 constraint,
4584                 includes,
4585             })),
4586         });
4587         self.add_class(key, cls);
4589         self.classish_name_builder.parsed_classish_declaration();
4591         Node::Ignored(SK::EnumDeclaration)
4592     }
4594     fn make_enum_use(&mut self, _keyword: Self::R, names: Self::R, _semicolon: Self::R) -> Self::R {
4595         Node::EnumUse(self.alloc(names))
4596     }
4598     fn begin_enumerator(&mut self) {
4599         self.start_accumulating_const_refs();
4600     }
4602     fn make_enumerator(
4603         &mut self,
4604         name: Self::R,
4605         _equal: Self::R,
4606         value: Self::R,
4607         _semicolon: Self::R,
4608     ) -> Self::R {
4609         let refs = self.stop_accumulating_const_refs();
4610         let id = match self.expect_name(name) {
4611             Some(id) => id,
4612             None => return Node::Ignored(SyntaxKind::Enumerator),
4613         };
4615         Node::Const(
4616             self.alloc(ShallowClassConst {
4617                 abstract_: ClassConstKind::CCConcrete,
4618                 name: id.into(),
4619                 type_: self
4620                     .infer_const(name, value)
4621                     .unwrap_or_else(|| self.tany_with_pos(id.0)),
4622                 refs,
4623             }),
4624         )
4625     }
4627     fn make_enum_class_declaration(
4628         &mut self,
4629         attributes: Self::R,
4630         modifiers: Self::R,
4631         _enum_keyword: Self::R,
4632         _class_keyword: Self::R,
4633         name: Self::R,
4634         _colon: Self::R,
4635         base: Self::R,
4636         _extends_keyword: Self::R,
4637         extends_list: Self::R,
4638         _left_brace: Self::R,
4639         elements: Self::R,
4640         _right_brace: Self::R,
4641     ) -> Self::R {
4642         let name = match self.elaborate_defined_id(name) {
4643             Some(name) => name,
4644             None => return Node::Ignored(SyntaxKind::EnumClassDeclaration),
4645         };
4646         let base = self
4647             .node_to_ty(base)
4648             .unwrap_or_else(|| self.tany_with_pos(name.0));
4650         let mut is_abstract = false;
4651         let mut is_final = false;
4652         for modifier in modifiers.iter() {
4653             match modifier.token_kind() {
4654                 Some(TokenKind::Abstract) => is_abstract = true,
4655                 Some(TokenKind::Final) => is_final = true,
4656                 _ => {}
4657             }
4658         }
4660         let class_kind = if is_abstract {
4661             ClassishKind::CenumClass(&Abstraction::Abstract)
4662         } else {
4663             ClassishKind::CenumClass(&Abstraction::Concrete)
4664         };
4666         let builtin_enum_class_ty = {
4667             let pos = name.0;
4668             let enum_class_ty_ = Ty_::Tapply(self.alloc((name.into(), &[])));
4669             let enum_class_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), enum_class_ty_));
4670             let elt_ty_ = Ty_::Tapply(self.alloc((
4671                 (pos, "\\HH\\MemberOf"),
4672                 bumpalo::vec![in self.arena; enum_class_ty, base].into_bump_slice(),
4673             )));
4674             let elt_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), elt_ty_));
4675             let builtin_enum_ty_ = if is_abstract {
4676                 Ty_::Tapply(self.alloc(((pos, "\\HH\\BuiltinAbstractEnumClass"), &[])))
4677             } else {
4678                 Ty_::Tapply(self.alloc((
4679                     (pos, "\\HH\\BuiltinEnumClass"),
4680                     std::slice::from_ref(self.alloc(elt_ty)),
4681                 )))
4682             };
4683             self.alloc(Ty(self.alloc(Reason::hint(pos)), builtin_enum_ty_))
4684         };
4686         let consts = self.slice(elements.iter().filter_map(|node| match node {
4687             &Node::Const(const_) => Some(const_),
4688             _ => None,
4689         }));
4691         let mut extends = Vec::with_capacity_in(extends_list.len() + 1, self.arena);
4692         extends.push(builtin_enum_class_ty);
4693         extends.extend(extends_list.iter().filter_map(|&n| self.node_to_ty(n)));
4694         let extends = extends.into_bump_slice();
4695         let includes = &extends[1..];
4697         let mut user_attributes = Vec::with_capacity_in(attributes.len() + 1, self.arena);
4698         for attribute in attributes.iter() {
4699             match attribute {
4700                 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(attr)),
4701                 _ => {}
4702             }
4703         }
4704         user_attributes.push(self.alloc(shallow_decl_defs::UserAttribute {
4705             name: (name.0, "__EnumClass"),
4706             classname_params: &[],
4707         }));
4708         // Match ordering of attributes produced by the OCaml decl parser (even
4709         // though it's the reverse of the syntactic ordering).
4710         user_attributes.reverse();
4711         let user_attributes = user_attributes.into_bump_slice();
4713         let parsed_attributes = self.to_attributes(attributes);
4715         let cls = self.alloc(shallow_decl_defs::ShallowClass {
4716             mode: self.file_mode,
4717             final_: is_final,
4718             abstract_: is_abstract,
4719             is_xhp: false,
4720             has_xhp_keyword: false,
4721             kind: class_kind,
4722             module: &None, // TODO: grab module from attributes
4723             name: name.into(),
4724             tparams: &[],
4725             where_constraints: &[],
4726             extends,
4727             uses: &[],
4728             xhp_attr_uses: &[],
4729             xhp_enum_values: SMap::empty(),
4730             req_extends: &[],
4731             req_implements: &[],
4732             implements: &[],
4733             support_dynamic_type: parsed_attributes.support_dynamic_type,
4734             consts,
4735             typeconsts: &[],
4736             props: &[],
4737             sprops: &[],
4738             constructor: None,
4739             static_methods: &[],
4740             methods: &[],
4741             user_attributes,
4742             enum_type: Some(self.alloc(EnumType {
4743                 base,
4744                 constraint: None,
4745                 includes,
4746             })),
4747         });
4748         self.add_class(name.1, cls);
4750         self.classish_name_builder.parsed_classish_declaration();
4752         Node::Ignored(SyntaxKind::EnumClassDeclaration)
4753     }
4755     fn begin_enum_class_enumerator(&mut self) {
4756         self.start_accumulating_const_refs();
4757     }
4759     fn make_enum_class_enumerator(
4760         &mut self,
4761         modifiers: Self::R,
4762         type_: Self::R,
4763         name: Self::R,
4764         _initializer: Self::R,
4765         _semicolon: Self::R,
4766     ) -> Self::R {
4767         let refs = self.stop_accumulating_const_refs();
4768         let name = match self.expect_name(name) {
4769             Some(name) => name,
4770             None => return Node::Ignored(SyntaxKind::EnumClassEnumerator),
4771         };
4772         let pos = name.0;
4773         let has_abstract_keyword = modifiers
4774             .iter()
4775             .any(|node| node.is_token(TokenKind::Abstract));
4776         let abstract_ = if has_abstract_keyword {
4777             /* default values not allowed atm */
4778             ClassConstKind::CCAbstract(false)
4779         } else {
4780             ClassConstKind::CCConcrete
4781         };
4782         let type_ = self
4783             .node_to_ty(type_)
4784             .unwrap_or_else(|| self.tany_with_pos(name.0));
4785         let class_name = match self.classish_name_builder.get_current_classish_name() {
4786             Some(name) => name,
4787             None => return Node::Ignored(SyntaxKind::EnumClassEnumerator),
4788         };
4789         let enum_class_ty_ = Ty_::Tapply(self.alloc(((pos, class_name.0), &[])));
4790         let enum_class_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), enum_class_ty_));
4791         let type_ = Ty_::Tapply(self.alloc((
4792             (pos, "\\HH\\MemberOf"),
4793             bumpalo::vec![in self.arena; enum_class_ty, type_].into_bump_slice(),
4794         )));
4795         let type_ = self.alloc(Ty(self.alloc(Reason::hint(pos)), type_));
4796         Node::Const(self.alloc(ShallowClassConst {
4797             abstract_,
4798             name: name.into(),
4799             type_,
4800             refs,
4801         }))
4802     }
4804     fn make_tuple_type_specifier(
4805         &mut self,
4806         left_paren: Self::R,
4807         tys: Self::R,
4808         right_paren: Self::R,
4809     ) -> Self::R {
4810         // We don't need to include the tys list in this position merging
4811         // because by definition it's already contained by the two brackets.
4812         let pos = self.merge_positions(left_paren, right_paren);
4813         let tys = self.slice(tys.iter().filter_map(|&node| self.node_to_ty(node)));
4814         self.hint_ty(pos, Ty_::Ttuple(tys))
4815     }
4817     fn make_tuple_type_explicit_specifier(
4818         &mut self,
4819         keyword: Self::R,
4820         _left_angle: Self::R,
4821         types: Self::R,
4822         right_angle: Self::R,
4823     ) -> Self::R {
4824         let id = (self.get_pos(keyword), "\\tuple");
4825         // This is an error--tuple syntax is (A, B), not tuple<A, B>.
4826         // OCaml decl makes a Tapply rather than a Ttuple here.
4827         self.make_apply(id, types, self.get_pos(right_angle))
4828     }
4830     fn make_intersection_type_specifier(
4831         &mut self,
4832         left_paren: Self::R,
4833         tys: Self::R,
4834         right_paren: Self::R,
4835     ) -> Self::R {
4836         let pos = self.merge_positions(left_paren, right_paren);
4837         let tys = self.slice(tys.iter().filter_map(|x| match x {
4838             Node::ListItem(&(ty, _ampersand)) => self.node_to_ty(ty),
4839             &x => self.node_to_ty(x),
4840         }));
4841         self.hint_ty(pos, Ty_::Tintersection(tys))
4842     }
4844     fn make_union_type_specifier(
4845         &mut self,
4846         left_paren: Self::R,
4847         tys: Self::R,
4848         right_paren: Self::R,
4849     ) -> Self::R {
4850         let pos = self.merge_positions(left_paren, right_paren);
4851         let tys = self.slice(tys.iter().filter_map(|x| match x {
4852             Node::ListItem(&(ty, _bar)) => self.node_to_ty(ty),
4853             &x => self.node_to_ty(x),
4854         }));
4855         self.hint_ty(pos, Ty_::Tunion(tys))
4856     }
4858     fn make_shape_type_specifier(
4859         &mut self,
4860         shape: Self::R,
4861         _lparen: Self::R,
4862         fields: Self::R,
4863         open: Self::R,
4864         rparen: Self::R,
4865     ) -> Self::R {
4866         let fields = fields;
4867         let fields_iter = fields.iter();
4868         let mut fields = AssocListMut::new_in(self.arena);
4869         for node in fields_iter {
4870             if let &Node::ShapeFieldSpecifier(&ShapeFieldNode { name, type_ }) = node {
4871                 fields.insert(self.make_t_shape_field_name(name), type_)
4872             }
4873         }
4874         let kind = match open.token_kind() {
4875             Some(TokenKind::DotDotDot) => ShapeKind::OpenShape,
4876             _ => ShapeKind::ClosedShape,
4877         };
4878         let pos = self.merge_positions(shape, rparen);
4879         self.hint_ty(pos, Ty_::Tshape(self.alloc((kind, fields.into()))))
4880     }
4882     fn make_classname_type_specifier(
4883         &mut self,
4884         classname: Self::R,
4885         _lt: Self::R,
4886         targ: Self::R,
4887         _trailing_comma: Self::R,
4888         gt: Self::R,
4889     ) -> Self::R {
4890         let id = match classname.as_id() {
4891             Some(id) => id,
4892             None => return Node::Ignored(SK::ClassnameTypeSpecifier),
4893         };
4894         if gt.is_ignored() {
4895             self.prim_ty(aast::Tprim::Tstring, id.0)
4896         } else {
4897             self.make_apply(
4898                 (id.0, self.elaborate_raw_id(id.1)),
4899                 targ,
4900                 self.merge_positions(classname, gt),
4901             )
4902         }
4903     }
4905     fn make_scope_resolution_expression(
4906         &mut self,
4907         class_name: Self::R,
4908         _operator: Self::R,
4909         value: Self::R,
4910     ) -> Self::R {
4911         let pos = self.merge_positions(class_name, value);
4912         let Id(class_name_pos, class_name_str) = match self.expect_name(class_name) {
4913             Some(id) => self.elaborate_id(id),
4914             None => return Node::Ignored(SK::ScopeResolutionExpression),
4915         };
4916         let class_id = self.alloc(aast::ClassId(
4917             (),
4918             class_name_pos,
4919             match class_name {
4920                 Node::Name(("self", _)) => aast::ClassId_::CIself,
4921                 _ => aast::ClassId_::CI(self.alloc(Id(class_name_pos, class_name_str))),
4922             },
4923         ));
4924         let value_id = match self.expect_name(value) {
4925             Some(id) => id,
4926             None => return Node::Ignored(SK::ScopeResolutionExpression),
4927         };
4928         self.accumulate_const_ref(class_id, &value_id);
4929         Node::Expr(self.alloc(aast::Expr(
4930             (),
4931             pos,
4932             nast::Expr_::ClassConst(self.alloc((class_id, self.alloc((value_id.0, value_id.1))))),
4933         )))
4934     }
4936     fn make_field_specifier(
4937         &mut self,
4938         question_token: Self::R,
4939         name: Self::R,
4940         _arrow: Self::R,
4941         type_: Self::R,
4942     ) -> Self::R {
4943         let optional = question_token.is_present();
4944         let ty = match self.node_to_ty(type_) {
4945             Some(ty) => ty,
4946             None => return Node::Ignored(SK::FieldSpecifier),
4947         };
4948         let name = match self.make_shape_field_name(name) {
4949             Some(name) => name,
4950             None => return Node::Ignored(SK::FieldSpecifier),
4951         };
4952         Node::ShapeFieldSpecifier(self.alloc(ShapeFieldNode {
4953             name: self.alloc(ShapeField(name)),
4954             type_: self.alloc(ShapeFieldType { optional, ty }),
4955         }))
4956     }
4958     fn make_field_initializer(&mut self, key: Self::R, _arrow: Self::R, value: Self::R) -> Self::R {
4959         Node::ListItem(self.alloc((key, value)))
4960     }
4962     fn make_varray_type_specifier(
4963         &mut self,
4964         varray_keyword: Self::R,
4965         _less_than: Self::R,
4966         tparam: Self::R,
4967         _trailing_comma: Self::R,
4968         greater_than: Self::R,
4969     ) -> Self::R {
4970         let tparam = match self.node_to_ty(tparam) {
4971             Some(ty) => ty,
4972             None => self.tany_with_pos(self.get_pos(varray_keyword)),
4973         };
4974         self.hint_ty(
4975             self.merge_positions(varray_keyword, greater_than),
4976             Ty_::Tapply(self.alloc((
4977                 (
4978                     self.get_pos(varray_keyword),
4979                     naming_special_names::collections::VEC,
4980                 ),
4981                 self.alloc([tparam]),
4982             ))),
4983         )
4984     }
4986     fn make_darray_type_specifier(
4987         &mut self,
4988         darray: Self::R,
4989         _less_than: Self::R,
4990         key_type: Self::R,
4991         _comma: Self::R,
4992         value_type: Self::R,
4993         _trailing_comma: Self::R,
4994         greater_than: Self::R,
4995     ) -> Self::R {
4996         let pos = self.merge_positions(darray, greater_than);
4997         let key_type = self.node_to_ty(key_type).unwrap_or(TANY);
4998         let value_type = self.node_to_ty(value_type).unwrap_or(TANY);
4999         self.hint_ty(
5000             pos,
5001             Ty_::Tapply(self.alloc((
5002                 (
5003                     self.get_pos(darray),
5004                     naming_special_names::collections::DICT,
5005                 ),
5006                 self.alloc([key_type, value_type]),
5007             ))),
5008         )
5009     }
5011     fn make_old_attribute_specification(
5012         &mut self,
5013         ltlt: Self::R,
5014         attrs: Self::R,
5015         gtgt: Self::R,
5016     ) -> Self::R {
5017         match attrs {
5018             Node::List(nodes) => {
5019                 Node::BracketedList(self.alloc((self.get_pos(ltlt), nodes, self.get_pos(gtgt))))
5020             }
5021             _ => Node::Ignored(SK::OldAttributeSpecification),
5022         }
5023     }
5025     fn make_constructor_call(
5026         &mut self,
5027         name: Self::R,
5028         _left_paren: Self::R,
5029         args: Self::R,
5030         _right_paren: Self::R,
5031     ) -> Self::R {
5032         let unqualified_name = match self.expect_name(name) {
5033             Some(name) => name,
5034             None => return Node::Ignored(SK::ConstructorCall),
5035         };
5036         let name = if unqualified_name.1.starts_with("__") {
5037             if self.simplify_naming_for_facts
5038                 && !naming_special_names::user_attributes::AS_SET.contains(unqualified_name.1)
5039             {
5040                 // only elaborate non-builtins
5041                 self.elaborate_id(unqualified_name)
5042             } else {
5043                 unqualified_name
5044             }
5045         } else {
5046             match self.expect_name(name) {
5047                 Some(name) => self.elaborate_id(name),
5048                 None => return Node::Ignored(SK::ConstructorCall),
5049             }
5050         };
5051         let classname_params = self.slice(args.iter().filter_map(|node| match node {
5052             Node::Expr(aast::Expr(
5053                 _,
5054                 full_pos,
5055                 aast::Expr_::ClassConst(&(
5056                     aast::ClassId(_, _, aast::ClassId_::CI(&Id(pos, class_name))),
5057                     (_, "class"),
5058                 )),
5059             )) => {
5060                 let name = self.elaborate_id(Id(pos, class_name));
5061                 Some(ClassNameParam { name, full_pos })
5062             }
5063             Node::StringLiteral((name, full_pos))
5064                 if self.retain_or_omit_user_attributes_for_facts =>
5065             {
5066                 Some(ClassNameParam {
5067                     name: Id(Pos::none(), self.str_from_utf8_for_bytes_in_arena(*name)),
5068                     full_pos,
5069                 })
5070             }
5071             Node::IntLiteral((name, full_pos)) if self.retain_or_omit_user_attributes_for_facts => {
5072                 Some(ClassNameParam {
5073                     name: Id(Pos::none(), name),
5074                     full_pos,
5075                 })
5076             }
5077             _ => None,
5078         }));
5080         let string_literal_params = if match name.1 {
5081             "__Deprecated" | "__Cipp" | "__CippLocal" | "__Policied" | "__Module" => true,
5082             _ => false,
5083         } {
5084             fn fold_string_concat<'a>(expr: &nast::Expr<'a>, acc: &mut Vec<'a, u8>) {
5085                 match expr {
5086                     &aast::Expr(_, _, aast::Expr_::String(val)) => acc.extend_from_slice(val),
5087                     &aast::Expr(_, _, aast::Expr_::Binop(&(Bop::Dot, e1, e2))) => {
5088                         fold_string_concat(&e1, acc);
5089                         fold_string_concat(&e2, acc);
5090                     }
5091                     _ => {}
5092                 }
5093             }
5095             self.slice(args.iter().filter_map(|expr| match expr {
5096                 Node::StringLiteral((x, _)) => Some(*x),
5097                 Node::Expr(e @ aast::Expr(_, _, aast::Expr_::Binop(_))) => {
5098                     let mut acc = Vec::new_in(self.arena);
5099                     fold_string_concat(e, &mut acc);
5100                     Some(acc.into_bump_slice().into())
5101                 }
5102                 _ => None,
5103             }))
5104         } else {
5105             &[]
5106         };
5108         Node::Attribute(self.alloc(UserAttributeNode {
5109             name,
5110             classname_params,
5111             string_literal_params,
5112         }))
5113     }
5115     fn make_trait_use(
5116         &mut self,
5117         _keyword: Self::R,
5118         names: Self::R,
5119         _semicolon: Self::R,
5120     ) -> Self::R {
5121         Node::TraitUse(self.alloc(names))
5122     }
5124     fn make_trait_use_conflict_resolution(
5125         &mut self,
5126         _keyword: Self::R,
5127         names: Self::R,
5128         _left_brace: Self::R,
5129         _clauses: Self::R,
5130         _right_brace: Self::R,
5131     ) -> Self::R {
5132         Node::TraitUse(self.alloc(names))
5133     }
5135     fn make_require_clause(
5136         &mut self,
5137         _keyword: Self::R,
5138         require_type: Self::R,
5139         name: Self::R,
5140         _semicolon: Self::R,
5141     ) -> Self::R {
5142         Node::RequireClause(self.alloc(RequireClause { require_type, name }))
5143     }
5145     fn make_nullable_type_specifier(&mut self, question_mark: Self::R, hint: Self::R) -> Self::R {
5146         let pos = self.merge_positions(question_mark, hint);
5147         let ty = match self.node_to_ty(hint) {
5148             Some(ty) => ty,
5149             None => return Node::Ignored(SK::NullableTypeSpecifier),
5150         };
5151         self.hint_ty(pos, Ty_::Toption(ty))
5152     }
5154     fn make_like_type_specifier(&mut self, tilde: Self::R, hint: Self::R) -> Self::R {
5155         let pos = self.merge_positions(tilde, hint);
5156         let ty = match self.node_to_ty(hint) {
5157             Some(ty) => ty,
5158             None => return Node::Ignored(SK::LikeTypeSpecifier),
5159         };
5160         self.hint_ty(pos, Ty_::Tlike(ty))
5161     }
5163     fn make_closure_type_specifier(
5164         &mut self,
5165         outer_left_paren: Self::R,
5166         readonly_keyword: Self::R,
5167         _function_keyword: Self::R,
5168         _inner_left_paren: Self::R,
5169         parameter_list: Self::R,
5170         _inner_right_paren: Self::R,
5171         capability: Self::R,
5172         _colon: Self::R,
5173         readonly_ret: Self::R,
5174         return_type: Self::R,
5175         outer_right_paren: Self::R,
5176     ) -> Self::R {
5177         let make_param = |fp: &'a FunParamDecl<'a>| -> &'a FunParam<'a> {
5178             let mut flags = FunParamFlags::empty();
5180             match fp.kind {
5181                 ParamMode::FPinout => {
5182                     flags |= FunParamFlags::INOUT;
5183                 }
5184                 ParamMode::FPnormal => {}
5185             };
5187             if fp.readonly {
5188                 flags |= FunParamFlags::READONLY;
5189             }
5191             self.alloc(FunParam {
5192                 pos: self.get_pos(fp.hint),
5193                 name: None,
5194                 type_: self.alloc(PossiblyEnforcedTy {
5195                     enforced: Enforcement::Unenforced,
5196                     type_: self.node_to_ty(fp.hint).unwrap_or_else(|| tany()),
5197                 }),
5198                 flags,
5199             })
5200         };
5202         let arity = parameter_list
5203             .iter()
5204             .find_map(|&node| match node {
5205                 Node::FunParam(fp) if fp.variadic => Some(FunArity::Fvariadic(make_param(fp))),
5206                 _ => None,
5207             })
5208             .unwrap_or(FunArity::Fstandard);
5210         let params = self.slice(parameter_list.iter().filter_map(|&node| match node {
5211             Node::FunParam(fp) if !fp.variadic => Some(make_param(fp)),
5212             _ => None,
5213         }));
5215         let ret = match self.node_to_ty(return_type) {
5216             Some(ty) => ty,
5217             None => return Node::Ignored(SK::ClosureTypeSpecifier),
5218         };
5219         let pos = self.merge_positions(outer_left_paren, outer_right_paren);
5220         let implicit_params = self.as_fun_implicit_params(capability, pos);
5222         let mut flags = FunTypeFlags::empty();
5223         if readonly_ret.is_token(TokenKind::Readonly) {
5224             flags |= FunTypeFlags::RETURNS_READONLY;
5225         }
5226         if readonly_keyword.is_token(TokenKind::Readonly) {
5227             flags |= FunTypeFlags::READONLY_THIS;
5228         }
5230         self.hint_ty(
5231             pos,
5232             Ty_::Tfun(self.alloc(FunType {
5233                 arity,
5234                 tparams: &[],
5235                 where_constraints: &[],
5236                 params,
5237                 implicit_params,
5238                 ret: self.alloc(PossiblyEnforcedTy {
5239                     enforced: Enforcement::Unenforced,
5240                     type_: ret,
5241                 }),
5242                 flags,
5243                 ifc_decl: default_ifc_fun_decl(),
5244             })),
5245         )
5246     }
5248     fn make_closure_parameter_type_specifier(
5249         &mut self,
5250         inout: Self::R,
5251         readonly: Self::R,
5252         hint: Self::R,
5253     ) -> Self::R {
5254         let kind = if inout.is_token(TokenKind::Inout) {
5255             ParamMode::FPinout
5256         } else {
5257             ParamMode::FPnormal
5258         };
5259         Node::FunParam(self.alloc(FunParamDecl {
5260             attributes: Node::Ignored(SK::Missing),
5261             visibility: Node::Ignored(SK::Missing),
5262             kind,
5263             hint,
5264             readonly: readonly.is_token(TokenKind::Readonly),
5265             pos: self.get_pos(hint),
5266             name: Some(""),
5267             variadic: false,
5268             initializer: Node::Ignored(SK::Missing),
5269         }))
5270     }
5272     fn make_type_const_declaration(
5273         &mut self,
5274         attributes: Self::R,
5275         modifiers: Self::R,
5276         _const_keyword: Self::R,
5277         _type_keyword: Self::R,
5278         name: Self::R,
5279         _type_parameters: Self::R,
5280         as_constraint: Self::R,
5281         _equal: Self::R,
5282         type_: Self::R,
5283         _semicolon: Self::R,
5284     ) -> Self::R {
5285         let attributes = self.to_attributes(attributes);
5286         let has_abstract_keyword = modifiers
5287             .iter()
5288             .any(|node| node.is_token(TokenKind::Abstract));
5289         let as_constraint = match as_constraint {
5290             Node::TypeConstraint(innards) => self.node_to_ty(innards.1),
5291             _ => None,
5292         };
5293         let type_ = self.node_to_ty(type_);
5294         let kind = if has_abstract_keyword {
5295             // Abstract type constant:
5296             //     abstract const type T [as X] [super Y] [= Z];
5297             Typeconst::TCAbstract(self.alloc(AbstractTypeconst {
5298                 as_constraint,
5299                 super_constraint: None,
5300                 default: type_,
5301             }))
5302         } else {
5303             if let Some(t) = type_ {
5304                 // Concrete type constant:
5305                 //     const type T = Z;
5306                 Typeconst::TCConcrete(self.alloc(ConcreteTypeconst { tc_type: t }))
5307             } else {
5308                 // concrete or type constant requires a value
5309                 return Node::Ignored(SK::TypeConstDeclaration);
5310             }
5311         };
5312         let name = match name.as_id() {
5313             Some(name) => name,
5314             None => return Node::Ignored(SK::TypeConstDeclaration),
5315         };
5316         Node::TypeConstant(self.alloc(ShallowTypeconst {
5317             name: name.into(),
5318             kind,
5319             enforceable: match attributes.enforceable {
5320                 Some(pos) => (pos, true),
5321                 None => (Pos::none(), false),
5322             },
5323             reifiable: attributes.reifiable,
5324             is_ctx: false,
5325         }))
5326     }
5328     fn make_context_const_declaration(
5329         &mut self,
5330         modifiers: Self::R,
5331         _const_keyword: Self::R,
5332         _ctx_keyword: Self::R,
5333         name: Self::R,
5334         _type_parameters: Self::R,
5335         constraints: Self::R,
5336         _equal: Self::R,
5337         ctx_list: Self::R,
5338         _semicolon: Self::R,
5339     ) -> Self::R {
5340         let name = match name.as_id() {
5341             Some(name) => name,
5342             None => return Node::Ignored(SK::TypeConstDeclaration),
5343         };
5344         let has_abstract_keyword = modifiers
5345             .iter()
5346             .any(|node| node.is_token(TokenKind::Abstract));
5347         let context = self.node_to_ty(ctx_list);
5349         // note: lowerer ensures that there's at most 1 constraint of each kind
5350         let mut as_constraint = None;
5351         let mut super_constraint = None;
5352         for c in constraints.iter() {
5353             if let Node::ContextConstraint(&(kind, hint)) = c {
5354                 let ty = self.node_to_ty(hint);
5355                 match kind {
5356                     ConstraintKind::ConstraintSuper => super_constraint = ty,
5357                     ConstraintKind::ConstraintAs => as_constraint = ty,
5358                     _ => {}
5359                 }
5360             }
5361         }
5362         let kind = if has_abstract_keyword {
5363             Typeconst::TCAbstract(self.alloc(AbstractTypeconst {
5364                 as_constraint,
5365                 super_constraint,
5366                 default: context,
5367             }))
5368         } else {
5369             if let Some(tc_type) = context {
5370                 Typeconst::TCConcrete(self.alloc(ConcreteTypeconst { tc_type }))
5371             } else {
5372                 /* Concrete type const must have a value */
5373                 return Node::Ignored(SK::TypeConstDeclaration);
5374             }
5375         };
5376         Node::TypeConstant(self.alloc(ShallowTypeconst {
5377             name: name.into(),
5378             kind,
5379             enforceable: (Pos::none(), false),
5380             reifiable: None,
5381             is_ctx: true,
5382         }))
5383     }
5385     fn make_decorated_expression(&mut self, decorator: Self::R, expr: Self::R) -> Self::R {
5386         Node::ListItem(self.alloc((decorator, expr)))
5387     }
5389     fn make_type_constant(
5390         &mut self,
5391         ty: Self::R,
5392         _coloncolon: Self::R,
5393         constant_name: Self::R,
5394     ) -> Self::R {
5395         let id = match self.expect_name(constant_name) {
5396             Some(id) => id,
5397             None => return Node::Ignored(SK::TypeConstant),
5398         };
5399         let pos = self.merge_positions(ty, constant_name);
5400         let ty = match (ty, self.classish_name_builder.get_current_classish_name()) {
5401             (Node::Name(("self", self_pos)), Some((name, class_name_pos))) => {
5402                 // In classes, we modify the position when rewriting the
5403                 // `self` keyword to point to the class name. In traits,
5404                 // we don't (because traits are not types). We indicate
5405                 // that the position shouldn't be rewritten with the
5406                 // none Pos.
5407                 let id_pos = if class_name_pos.is_none() {
5408                     self_pos
5409                 } else {
5410                     class_name_pos
5411                 };
5412                 let reason = self.alloc(Reason::hint(self_pos));
5413                 let ty_ = Ty_::Tapply(self.alloc(((id_pos, name), &[][..])));
5414                 self.alloc(Ty(reason, ty_))
5415             }
5416             _ => match self.node_to_ty(ty) {
5417                 Some(ty) => ty,
5418                 None => return Node::Ignored(SK::TypeConstant),
5419             },
5420         };
5421         let reason = self.alloc(Reason::hint(pos));
5422         // The reason-rewriting here is only necessary to match the
5423         // behavior of OCaml decl (which flattens and then unflattens
5424         // Haccess hints, losing some position information).
5425         let ty = self.rewrite_taccess_reasons(ty, reason);
5426         Node::Ty(self.alloc(Ty(
5427             reason,
5428             Ty_::Taccess(self.alloc(TaccessType(ty, id.into()))),
5429         )))
5430     }
5432     fn make_soft_type_specifier(&mut self, at_token: Self::R, hint: Self::R) -> Self::R {
5433         let pos = self.merge_positions(at_token, hint);
5434         let hint = match self.node_to_ty(hint) {
5435             Some(ty) => ty,
5436             None => return Node::Ignored(SK::SoftTypeSpecifier),
5437         };
5438         // Use the type of the hint as-is (i.e., throw away the knowledge that
5439         // we had a soft type specifier here--the typechecker does not use it).
5440         // Replace its Reason with one including the position of the `@` token.
5441         self.hint_ty(
5442             pos,
5443             if self.opts.interpret_soft_types_as_like_types {
5444                 Ty_::Tlike(hint)
5445             } else {
5446                 hint.1
5447             },
5448         )
5449     }
5451     fn make_attribute_specification(&mut self, attributes: Self::R) -> Self::R {
5452         if self.retain_or_omit_user_attributes_for_facts {
5453             attributes
5454         } else {
5455             Node::Ignored(SK::AttributeSpecification)
5456         }
5457     }
5459     fn make_attribute(&mut self, _at: Self::R, attribute: Self::R) -> Self::R {
5460         if self.retain_or_omit_user_attributes_for_facts {
5461             attribute
5462         } else {
5463             Node::Ignored(SK::Attribute)
5464         }
5465     }
5467     // A type specifier preceded by an attribute list. At the time of writing,
5468     // only the <<__Soft>> attribute is permitted here.
5469     fn make_attributized_specifier(&mut self, attributes: Self::R, hint: Self::R) -> Self::R {
5470         match attributes {
5471             Node::BracketedList((
5472                 ltlt_pos,
5473                 [Node::Attribute(UserAttributeNode {
5474                     name: Id(_, "__Soft"),
5475                     ..
5476                 })],
5477                 gtgt_pos,
5478             )) => {
5479                 let attributes_pos = self.merge(*ltlt_pos, *gtgt_pos);
5480                 let hint_pos = self.get_pos(hint);
5481                 // Use the type of the hint as-is (i.e., throw away the
5482                 // knowledge that we had a soft type specifier here--the
5483                 // typechecker does not use it). Replace its Reason with one
5484                 // including the position of the attribute list.
5485                 let hint = match self.node_to_ty(hint) {
5486                     Some(ty) => ty,
5487                     None => return Node::Ignored(SK::AttributizedSpecifier),
5488                 };
5490                 self.hint_ty(
5491                     self.merge(attributes_pos, hint_pos),
5492                     if self.opts.interpret_soft_types_as_like_types {
5493                         Ty_::Tlike(hint)
5494                     } else {
5495                         hint.1
5496                     },
5497                 )
5498             }
5499             _ => hint,
5500         }
5501     }
5503     fn make_vector_type_specifier(
5504         &mut self,
5505         vec: Self::R,
5506         _left_angle: Self::R,
5507         hint: Self::R,
5508         _trailing_comma: Self::R,
5509         right_angle: Self::R,
5510     ) -> Self::R {
5511         let id = match self.expect_name(vec) {
5512             Some(id) => id,
5513             None => return Node::Ignored(SK::VectorTypeSpecifier),
5514         };
5515         let id = (id.0, self.elaborate_raw_id(id.1));
5516         self.make_apply(id, hint, self.get_pos(right_angle))
5517     }
5519     fn make_dictionary_type_specifier(
5520         &mut self,
5521         dict: Self::R,
5522         _left_angle: Self::R,
5523         type_arguments: Self::R,
5524         right_angle: Self::R,
5525     ) -> Self::R {
5526         let id = match self.expect_name(dict) {
5527             Some(id) => id,
5528             None => return Node::Ignored(SK::DictionaryTypeSpecifier),
5529         };
5530         let id = (id.0, self.elaborate_raw_id(id.1));
5531         self.make_apply(id, type_arguments, self.get_pos(right_angle))
5532     }
5534     fn make_keyset_type_specifier(
5535         &mut self,
5536         keyset: Self::R,
5537         _left_angle: Self::R,
5538         hint: Self::R,
5539         _trailing_comma: Self::R,
5540         right_angle: Self::R,
5541     ) -> Self::R {
5542         let id = match self.expect_name(keyset) {
5543             Some(id) => id,
5544             None => return Node::Ignored(SK::KeysetTypeSpecifier),
5545         };
5546         let id = (id.0, self.elaborate_raw_id(id.1));
5547         self.make_apply(id, hint, self.get_pos(right_angle))
5548     }
5550     fn make_variable_expression(&mut self, _expression: Self::R) -> Self::R {
5551         Node::Ignored(SK::VariableExpression)
5552     }
5554     fn make_file_attribute_specification(
5555         &mut self,
5556         _left_double_angle: Self::R,
5557         _keyword: Self::R,
5558         _colon: Self::R,
5559         attributes: Self::R,
5560         _right_double_angle: Self::R,
5561     ) -> Self::R {
5562         if self.retain_or_omit_user_attributes_for_facts {
5563             self.file_attributes = List::empty();
5564             for attr in attributes.iter() {
5565                 match attr {
5566                     Node::Attribute(attr) => self
5567                         .file_attributes
5568                         .push_front(self.user_attribute_to_decl(attr), self.arena),
5569                     _ => {}
5570                 }
5571             }
5572         }
5573         Node::Ignored(SK::FileAttributeSpecification)
5574     }
5576     fn make_subscript_expression(
5577         &mut self,
5578         _receiver: Self::R,
5579         _left_bracket: Self::R,
5580         _index: Self::R,
5581         _right_bracket: Self::R,
5582     ) -> Self::R {
5583         Node::Ignored(SK::SubscriptExpression)
5584     }
5586     fn make_member_selection_expression(
5587         &mut self,
5588         _object: Self::R,
5589         _operator: Self::R,
5590         _name: Self::R,
5591     ) -> Self::R {
5592         Node::Ignored(SK::MemberSelectionExpression)
5593     }
5595     fn make_object_creation_expression(
5596         &mut self,
5597         _new_keyword: Self::R,
5598         _object: Self::R,
5599     ) -> Self::R {
5600         Node::Ignored(SK::ObjectCreationExpression)
5601     }
5603     fn make_safe_member_selection_expression(
5604         &mut self,
5605         _object: Self::R,
5606         _operator: Self::R,
5607         _name: Self::R,
5608     ) -> Self::R {
5609         Node::Ignored(SK::SafeMemberSelectionExpression)
5610     }
5612     fn make_function_call_expression(
5613         &mut self,
5614         _receiver: Self::R,
5615         _type_args: Self::R,
5616         _enum_class_label: Self::R,
5617         _left_paren: Self::R,
5618         _argument_list: Self::R,
5619         _right_paren: Self::R,
5620     ) -> Self::R {
5621         Node::Ignored(SK::FunctionCallExpression)
5622     }
5624     fn make_list_expression(
5625         &mut self,
5626         _keyword: Self::R,
5627         _left_paren: Self::R,
5628         _members: Self::R,
5629         _right_paren: Self::R,
5630     ) -> Self::R {
5631         Node::Ignored(SK::ListExpression)
5632     }