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