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