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