1 // Copyright (c) Facebook, Inc. and its affiliates.
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;
11 collections::{String, Vec},
15 use hh_autoimport_rust as hh_autoimport;
16 use naming_special_names_rust as naming_special_names;
18 use arena_collections::{AssocListMut, MultiSetMut};
19 use flatten_smart_constructors::{FlattenOp, FlattenSmartConstructors};
20 use namespaces::ElaborateKind;
21 use namespaces_rust as namespaces;
22 use oxidized_by_ref::{
24 ast_defs::{Bop, ClassKind, ConstraintKind, FunKind, Id, ShapeFieldName, Uop, Variance},
25 decl_defs::MethodReactivity,
26 direct_decl_parser::Decls,
28 method_flags::MethodFlags,
29 namespace_env::Env as NamespaceEnv,
32 prop_flags::PropFlags,
33 relative_path::RelativePath,
36 self, Decl, ShallowClassConst, ShallowMethod, ShallowProp, ShallowTypeconst,
38 shape_map::ShapeField,
40 self, Capability::*, ConstDecl, EnumType, FunArity, FunElt, FunImplicitParams, FunParam,
41 FunParams, FunType, IfcFunDecl, ParamMode, ParamMutability, ParamRxAnnotation,
42 PossiblyEnforcedTy, Reactivity, RecordFieldReq, ShapeFieldType, ShapeKind, TaccessType,
43 Tparam, Ty, Ty_, TypeconstAbstractKind, TypedefType, WhereConstraint, XhpAttrTag,
45 typing_defs_flags::{FunParamFlags, FunTypeFlags},
46 typing_reason::Reason,
48 use parser_core_types::{
49 compact_token::CompactToken, indexed_source_text::IndexedSourceText, source_text::SourceText,
50 syntax_kind::SyntaxKind, token_factory::SimpleTokenFactoryImpl, token_kind::TokenKind,
53 mod direct_decl_smart_constructors_generated;
57 type SSet<'a> = arena_collections::SortedSet<'a, &'a str>;
59 type NamespaceMap = BTreeMap<std::string::String, std::string::String>;
62 pub struct DirectDeclSmartConstructors<'a> {
63 pub token_factory: SimpleTokenFactoryImpl<CompactToken>,
65 pub source_text: IndexedSourceText<'a>,
66 pub arena: &'a bumpalo::Bump,
68 pub disable_xhp_element_mangling: bool,
69 pub array_unification: bool,
70 filename: &'a RelativePath<'a>,
72 namespace_builder: Rc<NamespaceBuilder<'a>>,
73 classish_name_builder: ClassishNameBuilder<'a>,
74 type_parameters: Rc<Vec<'a, SSet<'a>>>,
76 previous_token_kind: TokenKind,
79 impl<'a> DirectDeclSmartConstructors<'a> {
83 disable_xhp_element_mangling: bool,
84 array_unification: bool,
85 auto_namespace_map: &'a NamespaceMap,
88 let source_text = IndexedSourceText::new(src.clone());
89 let path = source_text.source_text().file_path();
90 let prefix = path.prefix();
91 let path = String::from_str_in(path.path_str(), arena).into_bump_str();
92 let filename = RelativePath::make(prefix, path);
94 token_factory: SimpleTokenFactoryImpl::new(),
98 filename: arena.alloc(filename),
100 disable_xhp_element_mangling,
102 decls: Decls::empty(),
103 namespace_builder: Rc::new(NamespaceBuilder::new_in(
105 disable_xhp_element_mangling,
108 classish_name_builder: ClassishNameBuilder::new(),
109 type_parameters: Rc::new(Vec::new_in(arena)),
110 // EndOfFile is used here as a None value (signifying "beginning of
111 // file") to save space. There is no legitimate circumstance where
112 // we would parse a token and the previous token kind would be
114 previous_token_kind: TokenKind::EndOfFile,
119 pub fn alloc<T>(&self, val: T) -> &'a T {
120 self.arena.alloc(val)
123 fn qualified_name_from_parts(&self, parts: &'a [Node<'a>], pos: &'a Pos<'a>) -> Id<'a> {
124 // Count the length of the qualified name, so that we can allocate
125 // exactly the right amount of space for it in our arena.
129 Node::Name(&(name, _)) => len += name.len(),
130 Node::Token(t) if t.kind() == TokenKind::Backslash => len += 1,
131 Node::ListItem(&(Node::Name(&(name, _)), _backslash)) => len += name.len() + 1,
132 Node::ListItem(&(Node::Token(t), _backslash))
133 if t.kind() == TokenKind::Namespace =>
135 len += t.width() + 1;
140 // If there's no internal trivia, then we can just reference the
141 // qualified name in the original source text instead of copying it.
142 let source_len = pos.end_cnum() - pos.start_cnum();
143 if source_len == len {
144 let qualified_name = self.str_from_utf8(self.source_text_at_pos(pos));
145 return Id(pos, qualified_name);
147 // Allocate `len` bytes and fill them with the fully qualified name.
148 let mut qualified_name = String::with_capacity_in(len, self.arena);
151 Node::Name(&(name, _pos)) => qualified_name.push_str(&name),
152 Node::Token(t) if t.kind() == TokenKind::Backslash => qualified_name.push('\\'),
153 &Node::ListItem(&(Node::Name(&(name, _)), _backslash)) => {
154 qualified_name.push_str(&name);
155 qualified_name.push_str("\\");
157 &Node::ListItem(&(Node::Token(t), _backslash))
158 if t.kind() == TokenKind::Namespace =>
160 qualified_name.push_str("namespace\\");
162 Node::ListItem(listitem) => {
164 "Expected ListItem with name and backslash, but got {:?}",
169 panic!("Expected a name, backslash, or list item, but got {:?}", n);
173 debug_assert_eq!(len, qualified_name.len());
174 debug_assert_eq!(len, qualified_name.capacity());
175 Id(pos, qualified_name.into_bump_str())
178 /// If the given node is an identifier, XHP name, or qualified name,
179 /// elaborate it in the current namespace and return Some. To be used for
180 /// the name of a decl in its definition (e.g., "C" in `class C {}` or "f"
181 /// in `function f() {}`).
182 fn elaborate_defined_id(&self, name: Node<'a>) -> Option<Id<'a>> {
183 let id = match name {
184 Node::Name(&(name, pos)) => Id(pos, name),
185 Node::XhpName(&(name, pos)) => Id(pos, name),
186 Node::QualifiedName(&(parts, pos)) => self.qualified_name_from_parts(parts, pos),
189 Some(self.namespace_builder.elaborate_defined_id(id))
192 /// If the given node is a name (i.e., an identifier or a qualified name),
193 /// return Some. No namespace elaboration is performed.
194 fn expect_name(&self, name: Node<'a>) -> Option<Id<'a>> {
195 // If it's a simple identifier, return it.
196 if let id @ Some(_) = name.as_id() {
200 Node::QualifiedName(&(parts, pos)) => Some(self.qualified_name_from_parts(parts, pos)),
201 Node::Token(t) if t.kind() == TokenKind::XHP => {
202 let pos = self.token_pos(t);
203 let text = self.str_from_utf8(self.source_text_at_pos(pos));
210 /// Fully qualify the given identifier as a type name (with consideration
211 /// to `use` statements in scope).
212 fn elaborate_id(&self, id: Id<'a>) -> Id<'a> {
213 let Id(pos, name) = id;
214 Id(pos, self.elaborate_raw_id(name))
217 /// Fully qualify the given identifier as a type name (with consideration
218 /// to `use` statements in scope).
219 fn elaborate_raw_id(&self, id: &'a str) -> &'a str {
220 self.namespace_builder
221 .elaborate_raw_id(ElaborateKind::Class, id)
224 /// Fully qualify the given identifier as a constant name (with
225 /// consideration to `use` statements in scope).
226 fn elaborate_const_id(&self, id: Id<'a>) -> Id<'a> {
227 let Id(pos, name) = id;
230 self.namespace_builder
231 .elaborate_raw_id(ElaborateKind::Const, name),
235 fn slice<T>(&self, iter: impl Iterator<Item = T>) -> &'a [T] {
236 let mut result = match iter.size_hint().1 {
237 Some(upper_bound) => Vec::with_capacity_in(upper_bound, self.arena),
238 None => Vec::new_in(self.arena),
243 result.into_bump_slice()
246 fn unwrap_mutability(hint: Node<'a>) -> (Node<'a>, Option<ParamMutability>) {
248 Node::Ty(Ty(_, Ty_::Tapply((hn, [t])))) if hn.1 == "\\Mutable" => {
249 (Node::Ty(t), Some(ParamMutability::ParamBorrowedMutable))
251 Node::Ty(Ty(_, Ty_::Tapply((hn, [t])))) if hn.1 == "\\OwnedMutable" => {
252 (Node::Ty(t), Some(ParamMutability::ParamOwnedMutable))
254 Node::Ty(Ty(_, Ty_::Tapply((hn, [t])))) if hn.1 == "\\MaybeMutable" => {
255 (Node::Ty(t), Some(ParamMutability::ParamMaybeMutable))
262 fn prefix_slash<'a>(arena: &'a Bump, name: &str) -> &'a str {
263 let mut s = String::with_capacity_in(1 + name.len(), arena);
269 fn prefix_colon<'a>(arena: &'a Bump, name: &str) -> &'a str {
270 let mut s = String::with_capacity_in(1 + name.len(), arena);
276 fn concat<'a>(arena: &'a Bump, str1: &str, str2: &str) -> &'a str {
277 let mut result = String::with_capacity_in(str1.len() + str2.len(), arena);
278 result.push_str(str1);
279 result.push_str(str2);
280 result.into_bump_str()
283 fn str_from_utf8<'a>(arena: &'a Bump, slice: &'a [u8]) -> &'a str {
284 if let Ok(s) = std::str::from_utf8(slice) {
287 String::from_utf8_lossy_in(slice, arena).into_bump_str()
291 fn strip_dollar_prefix<'a>(name: &'a str) -> &'a str {
292 name.trim_start_matches("$")
295 const TANY_: Ty_<'_> = Ty_::Tany(oxidized_by_ref::tany_sentinel::TanySentinel);
296 const TANY: &Ty<'_> = &Ty(Reason::none(), TANY_);
298 fn tany() -> &'static Ty<'static> {
302 fn default_ifc_fun_decl<'a>() -> IfcFunDecl<'a> {
303 IfcFunDecl::FDPolicied(Some("PUBLIC"))
309 visibility: aast::Visibility,
314 fn read_member_modifiers<'a: 'b, 'b>(modifiers: impl Iterator<Item = &'b Node<'a>>) -> Modifiers {
315 let mut ret = Modifiers {
317 visibility: aast::Visibility::Public,
321 for modifier in modifiers {
322 if let Some(vis) = modifier.as_visibility() {
323 ret.visibility = vis;
325 match modifier.token_kind() {
326 Some(TokenKind::Static) => ret.is_static = true,
327 Some(TokenKind::Abstract) => ret.is_abstract = true,
328 Some(TokenKind::Final) => ret.is_final = true,
335 #[derive(Clone, Debug)]
336 struct NamespaceBuilder<'a> {
338 stack: Vec<'a, NamespaceEnv<'a>>,
339 auto_ns_map: &'a [(&'a str, &'a str)],
342 impl<'a> NamespaceBuilder<'a> {
344 auto_ns_map: &'a NamespaceMap,
345 disable_xhp_element_mangling: bool,
348 let mut arena_ns_map = Vec::with_capacity_in(auto_ns_map.len(), arena);
349 for (k, v) in auto_ns_map.iter() {
350 arena_ns_map.push((k.as_str(), v.as_str()));
352 let auto_ns_map = arena_ns_map.into_bump_slice();
354 let mut ns_uses = SMap::empty();
355 for &alias in hh_autoimport::NAMESPACES {
356 ns_uses = ns_uses.add(arena, alias, concat(arena, "HH\\", alias));
358 for (alias, ns) in auto_ns_map.iter() {
359 ns_uses = ns_uses.add(arena, alias, ns);
362 let mut class_uses = SMap::empty();
363 for &alias in hh_autoimport::TYPES {
364 class_uses = class_uses.add(arena, alias, concat(arena, "HH\\", alias));
369 stack: bumpalo::vec![in arena; NamespaceEnv {
372 fun_uses: SMap::empty(),
373 const_uses: SMap::empty(),
374 record_def_uses: SMap::empty(),
378 disable_xhp_element_mangling,
384 fn empty_with_ns_in(ns: &'a str, arena: &'a Bump) -> Self {
387 stack: bumpalo::vec![in arena; NamespaceEnv {
388 ns_uses: SMap::empty(),
389 class_uses: SMap::empty(),
390 fun_uses: SMap::empty(),
391 const_uses: SMap::empty(),
392 record_def_uses: SMap::empty(),
396 disable_xhp_element_mangling: false,
402 fn push_namespace(&mut self, name: Option<&str>) {
403 let current = self.current_namespace();
404 let nsenv = self.stack.last().unwrap().clone(); // shallow clone
405 if let Some(name) = name {
406 let mut fully_qualified = match current {
407 None => String::with_capacity_in(name.len(), self.arena),
409 let mut fully_qualified =
410 String::with_capacity_in(current.len() + name.len() + 1, self.arena);
411 fully_qualified.push_str(current);
412 fully_qualified.push('\\');
416 fully_qualified.push_str(name);
417 self.stack.push(NamespaceEnv {
418 name: Some(fully_qualified.into_bump_str()),
422 self.stack.push(NamespaceEnv {
429 fn pop_namespace(&mut self) {
430 // We'll never push a namespace for a declaration of items in the global
431 // namespace (e.g., `namespace { ... }`), so only pop if we are in some
432 // namespace other than the global one.
433 if self.stack.len() > 1 {
434 self.stack.pop().unwrap();
438 // push_namespace(Y) + pop_namespace() + push_namespace(X) should be equivalent to
439 // push_namespace(Y) + push_namespace(X) + pop_previous_namespace()
440 fn pop_previous_namespace(&mut self) {
441 if self.stack.len() > 2 {
442 let last = self.stack.pop().unwrap().name.unwrap_or("\\");
443 let previous = self.stack.pop().unwrap().name.unwrap_or("\\");
444 assert!(last.starts_with(previous));
445 let name = &last[previous.len() + 1..last.len()];
446 self.push_namespace(Some(name));
450 fn current_namespace(&self) -> Option<&'a str> {
451 self.stack.last().and_then(|nsenv| nsenv.name)
454 fn add_import(&mut self, kind: TokenKind, name: &'a str, aliased_name: Option<&'a str>) {
455 let stack_top = &mut self
458 .expect("Attempted to get the current import map, but namespace stack was empty");
459 let aliased_name = aliased_name.unwrap_or_else(|| {
460 name.rsplit_terminator('\\')
462 .expect("Expected at least one entry in import name")
464 let name = name.trim_end_matches('\\');
465 let name = if name.starts_with('\\') {
468 prefix_slash(self.arena, name)
472 stack_top.class_uses = stack_top.class_uses.add(self.arena, aliased_name, name);
474 TokenKind::Namespace => {
475 stack_top.ns_uses = stack_top.ns_uses.add(self.arena, aliased_name, name);
477 TokenKind::Mixed => {
478 stack_top.class_uses = stack_top.class_uses.add(self.arena, aliased_name, name);
479 stack_top.ns_uses = stack_top.ns_uses.add(self.arena, aliased_name, name);
481 _ => panic!("Unexpected import kind: {:?}", kind),
485 fn elaborate_raw_id(&self, kind: ElaborateKind, name: &'a str) -> &'a str {
486 if name.starts_with('\\') {
489 let env = self.stack.last().unwrap();
490 namespaces::elaborate_raw_id_in(self.arena, env, kind, name)
493 fn elaborate_defined_id(&self, id: Id<'a>) -> Id<'a> {
494 let Id(pos, name) = id;
495 let env = self.stack.last().unwrap();
496 let name = if env.disable_xhp_element_mangling && name.contains(':') {
497 let xhp_name_opt = namespaces::elaborate_xhp_namespace(name);
498 let name = xhp_name_opt.map_or(name, |s| self.arena.alloc_str(&s));
499 if !name.starts_with('\\') {
500 namespaces::elaborate_into_current_ns_in(self.arena, env, name)
505 namespaces::elaborate_into_current_ns_in(self.arena, env, name)
511 #[derive(Clone, Debug)]
512 enum ClassishNameBuilder<'a> {
513 /// We are not in a classish declaration.
516 /// We saw a classish keyword token followed by a Name, so we make it
517 /// available as the name of the containing class declaration.
518 InClassish(&'a (&'a str, &'a Pos<'a>, TokenKind)),
521 impl<'a> ClassishNameBuilder<'a> {
523 ClassishNameBuilder::NotInClassish
526 fn lexed_name_after_classish_keyword(
531 token_kind: TokenKind,
533 use ClassishNameBuilder::*;
536 let name = if name.starts_with(':') {
537 prefix_slash(arena, name)
541 *self = InClassish(arena.alloc((name, pos, token_kind)))
547 fn parsed_classish_declaration(&mut self) {
548 *self = ClassishNameBuilder::NotInClassish;
551 fn get_current_classish_name(&self) -> Option<(&'a str, &'a Pos<'a>)> {
552 use ClassishNameBuilder::*;
554 NotInClassish => None,
555 InClassish((name, pos, _)) => Some((name, pos)),
559 fn in_interface(&self) -> bool {
560 use ClassishNameBuilder::*;
562 InClassish((_, _, TokenKind::Interface)) => true,
563 InClassish((_, _, _)) | NotInClassish => false,
569 pub struct FunParamDecl<'a> {
570 attributes: Node<'a>,
571 visibility: Node<'a>,
575 name: Option<&'a str>,
577 initializer: Node<'a>,
581 pub struct FunctionHeader<'a> {
584 type_params: Node<'a>,
585 param_list: Node<'a>,
586 capability: Node<'a>,
588 where_constraints: Node<'a>,
592 pub struct RequireClause<'a> {
593 require_type: Node<'a>,
598 pub struct TypeParameterDecl<'a> {
600 reified: aast::ReifyKind,
602 constraints: &'a [(ConstraintKind, Node<'a>)],
603 tparam_params: &'a [&'a Tparam<'a>],
604 user_attributes: &'a [&'a UserAttributeNode<'a>],
608 pub struct ClosureTypeHint<'a> {
614 pub struct NamespaceUseClause<'a> {
617 as_: Option<&'a str>,
621 pub struct ConstructorNode<'a> {
622 method: &'a ShallowMethod<'a>,
623 properties: &'a [ShallowProp<'a>],
627 pub struct MethodNode<'a> {
628 method: &'a ShallowMethod<'a>,
633 pub struct PropertyNode<'a> {
634 decls: &'a [ShallowProp<'a>],
639 pub struct XhpClassAttributeDeclarationNode<'a> {
640 xhp_attr_decls: &'a [ShallowProp<'a>],
641 xhp_attr_uses_decls: &'a [Node<'a>],
645 pub struct XhpClassAttributeNode<'a> {
647 tag: Option<XhpAttrTag>,
654 pub struct ShapeFieldNode<'a> {
655 name: &'a ShapeField<'a>,
656 type_: &'a ShapeFieldType<'a>,
659 #[derive(Copy, Clone, Debug)]
660 struct ClassNameParam<'a> {
662 full_pos: &'a Pos<'a>, // Position of the full expression `Foo::class`
666 pub struct UserAttributeNode<'a> {
668 classname_params: &'a [ClassNameParam<'a>],
669 string_literal_params: &'a [&'a BStr], // this is only used for __Deprecated attribute message and Cipp parameters
672 mod fixed_width_token {
673 use parser_core_types::token_kind::TokenKind;
674 use std::convert::TryInto;
676 #[derive(Copy, Clone)]
677 pub struct FixedWidthToken(u64); // { offset: u56, kind: TokenKind }
679 const KIND_BITS: u8 = 8;
680 const KIND_MASK: u64 = u8::MAX as u64;
681 const MAX_OFFSET: u64 = !(KIND_MASK << (64 - KIND_BITS));
683 impl FixedWidthToken {
684 pub fn new(kind: TokenKind, offset: usize) -> Self {
685 // We don't want to spend bits tracking the width of fixed-width
686 // tokens. Since we don't track width, verify that this token kind
687 // is in fact a fixed-width kind.
688 debug_assert!(kind.fixed_width().is_some());
690 let offset: u64 = offset.try_into().unwrap();
691 if offset > MAX_OFFSET {
692 panic!("FixedWidthToken: offset too large");
694 Self(offset << KIND_BITS | kind as u8 as u64)
697 pub fn offset(self) -> usize {
698 (self.0 >> KIND_BITS).try_into().unwrap()
701 pub fn kind(self) -> TokenKind {
702 TokenKind::try_from_u8(self.0 as u8).unwrap()
705 pub fn width(self) -> usize {
706 self.kind().fixed_width().unwrap().get()
710 impl std::fmt::Debug for FixedWidthToken {
711 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
712 fmt.debug_struct("FixedWidthToken")
713 .field("kind", &self.kind())
714 .field("offset", &self.offset())
719 use fixed_width_token::FixedWidthToken;
721 #[derive(Copy, Clone, Debug)]
723 // Nodes which are not useful in constructing a decl are ignored. We keep
724 // track of the SyntaxKind for two reasons.
726 // One is that the parser needs to know the SyntaxKind of a parsed node in
727 // some circumstances (this information is exposed to the parser via an
728 // implementation of `smart_constructors::NodeType`). An adapter called
729 // WithKind exists to provide a `NodeType` implementation for arbitrary
730 // nodes by pairing each node with a SyntaxKind, but in the direct decl
731 // parser, we want to avoid the extra 8 bytes of overhead on each node.
733 // The second reason is that debugging is difficult when nodes are silently
734 // ignored, and providing at least the SyntaxKind of an ignored node helps
735 // in tracking down the reason it was ignored.
738 List(&'a &'a [Node<'a>]),
739 BracketedList(&'a (&'a Pos<'a>, &'a [Node<'a>], &'a Pos<'a>)),
740 Name(&'a (&'a str, &'a Pos<'a>)),
741 XhpName(&'a (&'a str, &'a Pos<'a>)),
742 QualifiedName(&'a (&'a [Node<'a>], &'a Pos<'a>)),
743 StringLiteral(&'a (&'a BStr, &'a Pos<'a>)), // For shape keys and const expressions.
744 IntLiteral(&'a (&'a str, &'a Pos<'a>)), // For const expressions.
745 FloatingLiteral(&'a (&'a str, &'a Pos<'a>)), // For const expressions.
746 BooleanLiteral(&'a (&'a str, &'a Pos<'a>)), // For const expressions.
748 ListItem(&'a (Node<'a>, Node<'a>)),
749 Const(&'a ShallowClassConst<'a>),
750 ConstInitializer(&'a (Node<'a>, Node<'a>)), // Name, initializer expression
751 FunParam(&'a FunParamDecl<'a>),
752 Attribute(&'a UserAttributeNode<'a>),
753 FunctionHeader(&'a FunctionHeader<'a>),
754 Constructor(&'a ConstructorNode<'a>),
755 Method(&'a MethodNode<'a>),
756 Property(&'a PropertyNode<'a>),
757 TraitUse(&'a Node<'a>),
758 XhpClassAttributeDeclaration(&'a XhpClassAttributeDeclarationNode<'a>),
759 XhpClassAttribute(&'a XhpClassAttributeNode<'a>),
760 XhpAttributeUse(&'a Node<'a>),
761 TypeConstant(&'a ShallowTypeconst<'a>),
762 RequireClause(&'a RequireClause<'a>),
763 ClassishBody(&'a &'a [Node<'a>]),
764 TypeParameter(&'a TypeParameterDecl<'a>),
765 TypeConstraint(&'a (ConstraintKind, Node<'a>)),
766 ShapeFieldSpecifier(&'a ShapeFieldNode<'a>),
767 NamespaceUseClause(&'a NamespaceUseClause<'a>),
768 Expr(&'a nast::Expr<'a>),
769 TypeParameters(&'a &'a [&'a Tparam<'a>]),
770 WhereConstraint(&'a WhereConstraint<'a>),
771 RecordField(&'a (Id<'a>, RecordFieldReq)),
773 // Non-ignored, fixed-width tokens (e.g., keywords, operators, braces, etc.).
774 Token(FixedWidthToken),
777 impl<'a> smart_constructors::NodeType for Node<'a> {
780 fn extract(self) -> Self::R {
784 fn is_abstract(&self) -> bool {
785 self.is_token(TokenKind::Abstract)
786 || matches!(self, Node::Ignored(SK::Token(TokenKind::Abstract)))
788 fn is_name(&self) -> bool {
789 matches!(self, Node::Name(..)) || matches!(self, Node::Ignored(SK::Token(TokenKind::Name)))
791 fn is_qualified_name(&self) -> bool {
792 matches!(self, Node::QualifiedName(..)) || matches!(self, Node::Ignored(SK::QualifiedName))
794 fn is_prefix_unary_expression(&self) -> bool {
795 matches!(self, Node::Expr(aast::Expr(_, aast::Expr_::Unop(..))))
796 || matches!(self, Node::Ignored(SK::PrefixUnaryExpression))
798 fn is_scope_resolution_expression(&self) -> bool {
799 matches!(self, Node::Expr(aast::Expr(_, aast::Expr_::ClassConst(..))))
800 || matches!(self, Node::Ignored(SK::ScopeResolutionExpression))
802 fn is_missing(&self) -> bool {
803 matches!(self, Node::Ignored(SK::Missing))
805 fn is_variable_expression(&self) -> bool {
806 matches!(self, Node::Ignored(SK::VariableExpression))
808 fn is_subscript_expression(&self) -> bool {
809 matches!(self, Node::Ignored(SK::SubscriptExpression))
811 fn is_member_selection_expression(&self) -> bool {
812 matches!(self, Node::Ignored(SK::MemberSelectionExpression))
814 fn is_object_creation_expression(&self) -> bool {
815 matches!(self, Node::Ignored(SK::ObjectCreationExpression))
817 fn is_safe_member_selection_expression(&self) -> bool {
818 matches!(self, Node::Ignored(SK::SafeMemberSelectionExpression))
820 fn is_function_call_expression(&self) -> bool {
821 matches!(self, Node::Ignored(SK::FunctionCallExpression))
823 fn is_list_expression(&self) -> bool {
824 matches!(self, Node::Ignored(SK::ListExpression))
829 fn is_token(self, kind: TokenKind) -> bool {
830 self.token_kind() == Some(kind)
833 fn token_kind(self) -> Option<TokenKind> {
835 Node::Token(token) => Some(token.kind()),
840 fn as_slice(self, b: &'a Bump) -> &'a [Self] {
842 Node::List(&items) | Node::BracketedList(&(_, items, _)) => items,
843 n if n.is_ignored() => &[],
844 n => std::slice::from_ref(b.alloc(n)),
848 fn iter<'b>(&'b self) -> NodeIterHelper<'a, 'b>
853 &Node::List(&items) | Node::BracketedList(&(_, items, _)) => {
854 NodeIterHelper::Vec(items.iter())
856 n if n.is_ignored() => NodeIterHelper::Empty,
857 n => NodeIterHelper::Single(n),
861 // The number of elements which would be yielded by `self.iter()`.
862 // Must return the upper bound returned by NodeIterHelper::size_hint.
863 fn len(&self) -> usize {
865 &Node::List(&items) | Node::BracketedList(&(_, items, _)) => items.len(),
866 n if n.is_ignored() => 0,
871 fn as_visibility(&self) -> Option<aast::Visibility> {
872 match self.token_kind() {
873 Some(TokenKind::Private) => Some(aast::Visibility::Private),
874 Some(TokenKind::Protected) => Some(aast::Visibility::Protected),
875 Some(TokenKind::Public) => Some(aast::Visibility::Public),
880 // If this node is a simple unqualified identifier, return its position and text.
881 fn as_id(&self) -> Option<Id<'a>> {
883 Node::Name(&(name, pos)) | Node::XhpName(&(name, pos)) => Some(Id(pos, name)),
888 fn is_ignored(&self) -> bool {
889 matches!(self, Node::Ignored(..))
892 fn is_present(&self) -> bool {
897 struct Attributes<'a> {
898 reactivity: Reactivity<'a>,
899 reactivity_condition_type: Option<&'a Ty<'a>>,
900 param_mutability: Option<ParamMutability>,
901 deprecated: Option<&'a str>,
902 reifiable: Option<&'a Pos<'a>>,
903 returns_mutable: bool,
909 at_most_rx_as_func: bool,
910 enforceable: Option<&'a Pos<'a>>,
911 returns_void_to_rx: bool,
912 accept_disposable: bool,
913 dynamically_callable: bool,
914 returns_disposable: bool,
916 ifc_attribute: IfcFunDecl<'a>,
922 impl<'a> DirectDeclSmartConstructors<'a> {
923 fn add_class(&mut self, name: &'a str, decl: &'a shallow_decl_defs::ShallowClass<'a>) {
924 self.decls.add(name, Decl::Class(decl), self.arena);
926 fn add_fun(&mut self, name: &'a str, decl: &'a typing_defs::FunElt<'a>) {
927 self.decls.add(name, Decl::Fun(decl), self.arena);
929 fn add_typedef(&mut self, name: &'a str, decl: &'a typing_defs::TypedefType<'a>) {
930 self.decls.add(name, Decl::Typedef(decl), self.arena);
932 fn add_const(&mut self, name: &'a str, decl: &'a typing_defs::ConstDecl<'a>) {
933 self.decls.add(name, Decl::Const(decl), self.arena);
935 fn add_record(&mut self, name: &'a str, decl: &'a typing_defs::RecordDefType<'a>) {
936 self.decls.add(name, Decl::Record(decl), self.arena);
939 fn token_bytes(&self, token: &CompactToken) -> &'a [u8] {
942 .sub(token.start_offset(), token.width())
945 // Check that the slice is valid UTF-8. If it is, return a &str referencing
946 // the same data. Otherwise, copy the slice into our arena using
947 // String::from_utf8_lossy_in, and return a reference to the arena str.
948 fn str_from_utf8(&self, slice: &'a [u8]) -> &'a str {
949 str_from_utf8(self.arena, slice)
954 pos1: impl Into<Option<&'a Pos<'a>>>,
955 pos2: impl Into<Option<&'a Pos<'a>>>,
957 match (pos1.into(), pos2.into()) {
958 (None, None) => Pos::none(),
959 (Some(pos), None) | (None, Some(pos)) => pos,
960 (Some(pos1), Some(pos2)) => match (pos1.is_none(), pos2.is_none()) {
961 (true, true) => Pos::none(),
962 (true, false) => pos2,
963 (false, true) => pos1,
964 (false, false) => Pos::merge_without_checking_filename(self.arena, pos1, pos2),
969 fn merge_positions(&self, node1: Node<'a>, node2: Node<'a>) -> &'a Pos<'a> {
970 self.merge(self.get_pos(node1), self.get_pos(node2))
973 fn pos_from_slice(&self, nodes: &[Node<'a>]) -> &'a Pos<'a> {
974 nodes.iter().fold(Pos::none(), |acc, &node| {
975 self.merge(acc, self.get_pos(node))
979 fn get_pos(&self, node: Node<'a>) -> &'a Pos<'a> {
980 self.get_pos_opt(node).unwrap_or(Pos::none())
983 fn get_pos_opt(&self, node: Node<'a>) -> Option<&'a Pos<'a>> {
984 let pos = match node {
985 Node::Name(&(_, pos)) => pos,
986 Node::Ty(ty) => return ty.get_pos(),
987 Node::XhpName(&(_, pos)) => pos,
988 Node::QualifiedName(&(_, pos)) => pos,
989 Node::IntLiteral(&(_, pos))
990 | Node::FloatingLiteral(&(_, pos))
991 | Node::StringLiteral(&(_, pos))
992 | Node::BooleanLiteral(&(_, pos)) => pos,
993 Node::ListItem(&(fst, snd)) => self.merge_positions(fst, snd),
994 Node::List(items) => self.pos_from_slice(&items),
995 Node::BracketedList(&(first_pos, inner_list, second_pos)) => self.merge(
997 self.merge(self.pos_from_slice(inner_list), second_pos),
999 Node::Expr(&aast::Expr(pos, _)) => pos,
1000 Node::Token(token) => self.token_pos(token),
1003 if pos.is_none() { None } else { Some(pos) }
1006 fn token_pos(&self, token: FixedWidthToken) -> &'a Pos<'a> {
1007 let start = token.offset();
1008 let end = start + token.width();
1009 let start = self.source_text.offset_to_file_pos_triple(start);
1010 let end = self.source_text.offset_to_file_pos_triple(end);
1011 Pos::from_lnum_bol_cnum(self.arena, self.filename, start, end)
1014 fn node_to_expr(&self, node: Node<'a>) -> Option<&'a nast::Expr<'a>> {
1015 let expr_ = match node {
1016 Node::Expr(expr) => return Some(expr),
1017 Node::IntLiteral(&(s, _)) => aast::Expr_::Int(s),
1018 Node::FloatingLiteral(&(s, _)) => aast::Expr_::Float(s),
1019 Node::StringLiteral(&(s, _)) => aast::Expr_::String(s),
1020 Node::BooleanLiteral((s, _)) => {
1021 if s.eq_ignore_ascii_case("true") {
1027 Node::Token(t) if t.kind() == TokenKind::NullLiteral => aast::Expr_::Null,
1028 Node::Name(..) | Node::QualifiedName(..) => {
1029 aast::Expr_::Id(self.alloc(self.elaborate_const_id(self.expect_name(node)?)))
1033 let pos = self.get_pos(node);
1034 Some(self.alloc(aast::Expr(pos, expr_)))
1037 fn node_to_non_ret_ty(&self, node: Node<'a>) -> Option<&'a Ty<'a>> {
1038 self.node_to_ty_(node, false)
1041 fn node_to_ty(&self, node: Node<'a>) -> Option<&'a Ty<'a>> {
1042 self.node_to_ty_(node, true)
1045 fn node_to_ty_(&self, node: Node<'a>, allow_non_ret_ty: bool) -> Option<&'a Ty<'a>> {
1047 Node::Ty(Ty(reason, Ty_::Tprim(aast::Tprim::Tvoid))) if !allow_non_ret_ty => {
1048 Some(self.alloc(Ty(reason, Ty_::Terr)))
1050 Node::Ty(Ty(reason, Ty_::Tprim(aast::Tprim::Tnoreturn))) if !allow_non_ret_ty => {
1051 Some(self.alloc(Ty(reason, Ty_::Terr)))
1053 Node::Ty(ty) => Some(ty),
1054 Node::Expr(expr) => {
1055 fn expr_to_ty<'a>(arena: &'a Bump, expr: &'a nast::Expr<'a>) -> Option<Ty_<'a>> {
1058 Null => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tnull))),
1059 This => Some(Ty_::Tthis),
1060 True | False => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tbool))),
1061 Int(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tint))),
1062 Float(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tfloat))),
1063 String(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1064 String2(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1065 PrefixedString(_) => Some(Ty_::Tprim(arena.alloc(aast::Tprim::Tstring))),
1066 Unop(&(_op, expr)) => expr_to_ty(arena, expr),
1069 ArrayGet(_) | As(_) | Await(_) | Binop(_) | Call(_) | Callconv(_)
1070 | Cast(_) | ClassConst(_) | ClassGet(_) | Clone(_) | Collection(_)
1071 | Darray(_) | Dollardollar(_) | Efun(_) | Eif(_) | EnumAtom(_)
1072 | ETSplice(_) | ExpressionTree(_) | FunctionPointer(_) | FunId(_)
1073 | Id(_) | Import(_) | Is(_) | KeyValCollection(_) | Lfun(_) | List(_)
1074 | Lplaceholder(_) | Lvar(_) | MethodCaller(_) | MethodId(_) | New(_)
1075 | ObjGet(_) | Omitted | Pair(_) | Pipe(_) | Record(_) | Shape(_)
1076 | SmethodId(_) | ValCollection(_) | Varray(_) | Xml(_) | Yield(_) => None,
1081 self.alloc(Reason::witness(expr.0)),
1082 expr_to_ty(self.arena, expr)?,
1085 Node::IntLiteral((_, pos)) => Some(self.alloc(Ty(
1086 self.alloc(Reason::witness(pos)),
1087 Ty_::Tprim(self.alloc(aast::Tprim::Tint)),
1089 Node::FloatingLiteral((_, pos)) => Some(self.alloc(Ty(
1090 self.alloc(Reason::witness(pos)),
1091 Ty_::Tprim(self.alloc(aast::Tprim::Tfloat)),
1093 Node::StringLiteral((_, pos)) => Some(self.alloc(Ty(
1094 self.alloc(Reason::witness(pos)),
1095 Ty_::Tprim(self.alloc(aast::Tprim::Tstring)),
1097 Node::BooleanLiteral((_, pos)) => Some(self.alloc(Ty(
1098 self.alloc(Reason::witness(pos)),
1099 Ty_::Tprim(self.alloc(aast::Tprim::Tbool)),
1101 Node::Token(t) if t.kind() == TokenKind::Varray => {
1102 let pos = self.token_pos(t);
1103 let tany = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1104 Some(self.alloc(Ty(self.alloc(Reason::hint(pos)), Ty_::Tvarray(tany))))
1106 Node::Token(t) if t.kind() == TokenKind::Darray => {
1107 let pos = self.token_pos(t);
1108 let tany = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1110 self.alloc(Reason::hint(pos)),
1111 Ty_::Tdarray(self.alloc((tany, tany))),
1114 Node::Token(t) if t.kind() == TokenKind::This => {
1115 Some(self.alloc(Ty(self.alloc(Reason::hint(self.token_pos(t))), Ty_::Tthis)))
1117 Node::Token(t) if t.kind() == TokenKind::NullLiteral => {
1118 let pos = self.token_pos(t);
1120 self.alloc(Reason::hint(pos)),
1121 Ty_::Tprim(self.alloc(aast::Tprim::Tnull)),
1125 let Id(pos, name) = self.expect_name(node)?;
1126 let reason = self.alloc(Reason::hint(pos));
1127 let ty_ = if self.is_type_param_in_scope(name) {
1128 // TODO (T69662957) must fill type args of Tgeneric
1129 Ty_::Tgeneric(self.alloc((name, &[])))
1131 match name.as_ref() {
1132 "nothing" => Ty_::Tunion(&[]),
1133 "nonnull" => Ty_::Tnonnull,
1134 "dynamic" => Ty_::Tdynamic,
1135 "varray_or_darray" => {
1136 let key_type = self.varray_or_darray_key(pos);
1137 let value_type = self.alloc(Ty(self.alloc(Reason::hint(pos)), TANY_));
1138 Ty_::TvarrayOrDarray(self.alloc((key_type, value_type)))
1142 let name = self.elaborate_raw_id(name);
1143 Ty_::Tapply(self.alloc((Id(pos, name), &[][..])))
1147 Some(self.alloc(Ty(reason, ty_)))
1152 fn to_attributes(&self, node: Node<'a>) -> Attributes<'a> {
1153 let mut attributes = Attributes {
1154 reactivity: Reactivity::Nonreactive,
1155 reactivity_condition_type: None,
1156 param_mutability: None,
1159 returns_mutable: false,
1165 at_most_rx_as_func: false,
1167 returns_void_to_rx: false,
1168 accept_disposable: false,
1169 dynamically_callable: false,
1170 returns_disposable: false,
1172 ifc_attribute: default_ifc_fun_decl(),
1178 let nodes = match node {
1179 Node::List(&nodes) | Node::BracketedList(&(_, nodes, _)) => nodes,
1180 _ => return attributes,
1183 // If we see the attribute `__OnlyRxIfImpl(Foo::class)`, set
1184 // `reactivity_condition_type` to `Foo`.
1185 attributes.reactivity_condition_type = nodes.iter().find_map(|attr| match attr {
1186 Node::Attribute(UserAttributeNode {
1187 name: Id(_, "__OnlyRxIfImpl"),
1188 classname_params: &[param],
1190 }) => Some(self.alloc(Ty(
1191 self.alloc(Reason::hint(param.full_pos)),
1192 Ty_::Tapply(self.alloc((param.name, &[][..]))),
1197 let string_or_classname_arg = |attribute: &'a UserAttributeNode| {
1199 .string_literal_params
1201 .map(|&x| self.str_from_utf8(x))
1202 .or_else(|| attribute.classname_params.first().map(|x| x.name.1))
1204 let mut ifc_already_policied = false;
1206 // Iterate in reverse, to match the behavior of OCaml decl in error conditions.
1207 for attribute in nodes.iter().rev() {
1208 if let Node::Attribute(attribute) = attribute {
1209 match attribute.name.1.as_ref() {
1210 // NB: It is an error to specify more than one of __Rx,
1211 // __RxShallow, and __RxLocal, so to avoid cloning the
1212 // condition type, we use Option::take here.
1214 attributes.reactivity =
1215 Reactivity::Reactive(attributes.reactivity_condition_type)
1218 attributes.reactivity =
1219 Reactivity::Shallow(attributes.reactivity_condition_type)
1222 attributes.reactivity =
1223 Reactivity::Local(attributes.reactivity_condition_type)
1226 attributes.reactivity =
1227 Reactivity::Pure(attributes.reactivity_condition_type);
1230 attributes.reactivity = Reactivity::Cipp(string_or_classname_arg(attribute))
1233 attributes.reactivity = Reactivity::CippGlobal;
1236 attributes.reactivity =
1237 Reactivity::CippLocal(string_or_classname_arg(attribute))
1240 attributes.reactivity = Reactivity::CippRx;
1243 attributes.param_mutability = Some(ParamMutability::ParamBorrowedMutable)
1245 "__MaybeMutable" => {
1246 attributes.param_mutability = Some(ParamMutability::ParamMaybeMutable)
1248 "__OwnedMutable" => {
1249 attributes.param_mutability = Some(ParamMutability::ParamOwnedMutable)
1251 "__MutableReturn" => attributes.returns_mutable = true,
1252 "__ReturnsVoidToRx" => attributes.returns_void_to_rx = true,
1254 attributes.deprecated = attribute
1255 .string_literal_params
1257 .map(|&x| self.str_from_utf8(x));
1259 "__Reifiable" => attributes.reifiable = Some(attribute.name.0),
1261 attributes.late_init = true;
1264 attributes.const_ = true;
1267 attributes.lsb = true;
1270 attributes.memoizelsb = true;
1273 attributes.override_ = true;
1275 "__AtMostRxAsFunc" => {
1276 attributes.at_most_rx_as_func = true;
1278 "__Enforceable" => {
1279 attributes.enforceable = Some(attribute.name.0);
1281 "__AcceptDisposable" => {
1282 attributes.accept_disposable = true;
1284 "__DynamicallyCallable" => {
1285 attributes.dynamically_callable = true;
1287 "__ReturnDisposable" => {
1288 attributes.returns_disposable = true;
1291 attributes.php_std_lib = true;
1294 let string_literal_params = || {
1296 .string_literal_params
1298 .map(|&x| self.str_from_utf8(x))
1300 // Take the classname param by default
1301 attributes.ifc_attribute =
1302 IfcFunDecl::FDPolicied(attribute.classname_params.first().map_or_else(
1303 string_literal_params, // default
1304 |&x| Some(x.name.1), // f
1306 ifc_already_policied = true;
1309 if !ifc_already_policied {
1310 attributes.ifc_attribute = IfcFunDecl::FDInferFlows;
1314 attributes.external = true;
1317 attributes.can_call = true;
1320 attributes.atom = true;
1325 panic!("Expected an attribute, but was {:?}", node);
1332 // Limited version of node_to_ty that matches behavior of Decl_utils.infer_const
1333 fn infer_const(&self, name: Node<'a>, node: Node<'a>) -> Option<&'a Ty<'a>> {
1335 Node::StringLiteral(_)
1336 | Node::BooleanLiteral(_)
1337 | Node::IntLiteral(_)
1338 | Node::FloatingLiteral(_)
1339 | Node::Expr(aast::Expr(_, aast::Expr_::Unop(&(Uop::Uminus, _))))
1340 | Node::Expr(aast::Expr(_, aast::Expr_::Unop(&(Uop::Uplus, _))))
1341 | Node::Expr(aast::Expr(_, aast::Expr_::String(..))) => self.node_to_ty(node),
1342 Node::Token(t) if t.kind() == TokenKind::NullLiteral => {
1343 let pos = self.token_pos(t);
1345 self.alloc(Reason::witness(pos)),
1346 Ty_::Tprim(self.alloc(aast::Tprim::Tnull)),
1349 _ => Some(self.tany_with_pos(self.get_pos(name))),
1353 fn pop_type_params(&mut self, node: Node<'a>) -> &'a [&'a Tparam<'a>] {
1355 Node::TypeParameters(tparams) => {
1356 Rc::make_mut(&mut self.type_parameters).pop().unwrap();
1363 fn ret_from_fun_kind(&self, kind: FunKind, type_: &'a Ty<'a>) -> &'a Ty<'a> {
1364 let pos = type_.get_pos().unwrap_or_else(|| Pos::none());
1366 FunKind::FAsyncGenerator => self.alloc(Ty(
1367 self.alloc(Reason::RretFunKind(self.alloc((pos, kind)))),
1368 Ty_::Tapply(self.alloc((
1369 Id(pos, naming_special_names::classes::ASYNC_GENERATOR),
1370 self.alloc([type_, type_, type_]),
1373 FunKind::FGenerator => self.alloc(Ty(
1374 self.alloc(Reason::RretFunKind(self.alloc((pos, kind)))),
1375 Ty_::Tapply(self.alloc((
1376 Id(pos, naming_special_names::classes::GENERATOR),
1377 self.alloc([type_, type_, type_]),
1380 FunKind::FAsync => self.alloc(Ty(
1381 self.alloc(Reason::RretFunKind(self.alloc((pos, kind)))),
1382 Ty_::Tapply(self.alloc((
1383 Id(pos, naming_special_names::classes::AWAITABLE),
1384 self.alloc([type_]),
1391 fn is_type_param_in_scope(&self, name: &str) -> bool {
1392 self.type_parameters.iter().any(|tps| tps.contains(name))
1395 fn param_mutability_to_fun_type_flags(
1396 param_mutability: Option<ParamMutability>,
1398 match param_mutability {
1399 Some(ParamMutability::ParamBorrowedMutable) => FunTypeFlags::MUTABLE_FLAGS_BORROWED,
1400 Some(ParamMutability::ParamOwnedMutable) => FunTypeFlags::MUTABLE_FLAGS_OWNED,
1401 Some(ParamMutability::ParamMaybeMutable) => FunTypeFlags::MUTABLE_FLAGS_MAYBE,
1402 None => FunTypeFlags::empty(),
1406 fn param_mutability_to_fun_param_flags(
1407 param_mutability: Option<ParamMutability>,
1408 ) -> FunParamFlags {
1409 match param_mutability {
1410 Some(ParamMutability::ParamBorrowedMutable) => FunParamFlags::MUTABLE_FLAGS_BORROWED,
1411 Some(ParamMutability::ParamOwnedMutable) => FunParamFlags::MUTABLE_FLAGS_OWNED,
1412 Some(ParamMutability::ParamMaybeMutable) => FunParamFlags::MUTABLE_FLAGS_MAYBE,
1413 None => FunParamFlags::empty(),
1417 fn as_fun_implicit_params(
1419 capability: Node<'a>,
1420 default_pos: &'a Pos<'a>,
1421 ) -> &'a FunImplicitParams<'a> {
1422 let capability = match self.node_to_ty(capability) {
1423 Some(ty) => CapTy(ty),
1424 None => CapDefaults(default_pos),
1426 self.alloc(FunImplicitParams { capability })
1432 attributes: Node<'a>,
1433 header: &'a FunctionHeader<'a>,
1435 ) -> Option<(Id<'a>, &'a Ty<'a>, &'a [ShallowProp<'a>])> {
1436 let id_opt = match (is_method, header.name) {
1437 (true, Node::Token(t)) if t.kind() == TokenKind::Construct => {
1438 let pos = self.token_pos(t);
1439 Some(Id(pos, naming_special_names::members::__CONSTRUCT))
1441 (true, _) => self.expect_name(header.name),
1442 (false, _) => self.elaborate_defined_id(header.name),
1444 let id = id_opt.unwrap_or(Id(self.get_pos(header.name), ""));
1445 let (params, properties, arity) = self.as_fun_params(header.param_list)?;
1446 let f_pos = self.get_pos(header.name);
1447 let implicit_params = self.as_fun_implicit_params(header.capability, f_pos);
1449 let type_ = match header.name {
1450 Node::Token(t) if t.kind() == TokenKind::Construct => {
1451 let pos = self.token_pos(t);
1453 self.alloc(Reason::witness(pos)),
1454 Ty_::Tprim(self.alloc(aast::Tprim::Tvoid)),
1458 .node_to_ty(header.ret_hint)
1459 .unwrap_or_else(|| self.tany_with_pos(f_pos)),
1464 .any(|n| n.is_token(TokenKind::Async));
1465 let fun_kind = if body.iter().any(|node| node.is_token(TokenKind::Yield)) {
1467 FunKind::FAsyncGenerator
1478 let type_ = if !header.ret_hint.is_present() {
1479 self.ret_from_fun_kind(fun_kind, type_)
1483 let attributes = self.to_attributes(attributes);
1484 // TODO(hrust) Put this in a helper. Possibly do this for all flags.
1485 let mut flags = match fun_kind {
1486 FunKind::FSync => FunTypeFlags::empty(),
1487 FunKind::FAsync => FunTypeFlags::ASYNC,
1488 FunKind::FGenerator => FunTypeFlags::GENERATOR,
1489 FunKind::FAsyncGenerator => FunTypeFlags::ASYNC | FunTypeFlags::GENERATOR,
1491 if attributes.returns_mutable {
1492 flags |= FunTypeFlags::RETURNS_MUTABLE;
1494 if attributes.returns_disposable {
1495 flags |= FunTypeFlags::RETURN_DISPOSABLE;
1497 if attributes.returns_void_to_rx {
1498 flags |= FunTypeFlags::RETURNS_VOID_TO_RX;
1500 let ifc_decl = attributes.ifc_attribute;
1502 flags |= Self::param_mutability_to_fun_type_flags(attributes.param_mutability);
1503 // Pop the type params stack only after creating all inner types.
1504 let tparams = self.pop_type_params(header.type_params);
1506 let where_constraints =
1507 self.slice(header.where_constraints.iter().filter_map(|&x| match x {
1508 Node::WhereConstraint(x) => Some(x),
1512 let ft = self.alloc(FunType {
1518 ret: self.alloc(PossiblyEnforcedTy {
1522 reactive: attributes.reactivity,
1527 let ty = self.alloc(Ty(self.alloc(Reason::witness(id.0)), Ty_::Tfun(ft)));
1528 Some((id, ty, properties))
1534 ) -> Option<(&'a FunParams<'a>, &'a [ShallowProp<'a>], FunArity<'a>)> {
1536 Node::List(nodes) => {
1537 let mut params = Vec::with_capacity_in(nodes.len(), self.arena);
1538 let mut properties = Vec::new_in(self.arena);
1539 let mut arity = FunArity::Fstandard;
1540 for node in nodes.iter() {
1542 Node::FunParam(&FunParamDecl {
1552 let attributes = self.to_attributes(attributes);
1554 if let Some(visibility) = visibility.as_visibility() {
1555 let name = name.unwrap_or("");
1556 let name = strip_dollar_prefix(name);
1557 let mut flags = PropFlags::empty();
1558 flags.set(PropFlags::CONST, attributes.const_);
1559 flags.set(PropFlags::NEEDS_INIT, self.file_mode != Mode::Mdecl);
1560 flags.set(PropFlags::PHP_STD_LIB, attributes.php_std_lib);
1561 properties.push(ShallowProp {
1563 name: Id(pos, name),
1564 type_: self.node_to_ty(hint),
1570 let type_ = if hint.is_ignored() {
1571 self.tany_with_pos(pos)
1573 self.node_to_ty(hint).map(|ty| match ty {
1574 &Ty(r, Ty_::Tfun(fun_type))
1575 if attributes.at_most_rx_as_func =>
1577 let fun_type = self.alloc(FunType {
1578 reactive: Reactivity::RxVar(None),
1581 self.alloc(Ty(r, Ty_::Tfun(fun_type)))
1583 &Ty(r, Ty_::Toption(&Ty(r1, Ty_::Tfun(fun_type))))
1584 if attributes.at_most_rx_as_func =>
1586 let fun_type = self.alloc(FunType {
1587 reactive: Reactivity::RxVar(None),
1592 Ty_::Toption(self.alloc(Ty(r1, Ty_::Tfun(fun_type)))),
1598 // These are illegal here--they can only be used on
1599 // parameters in a function type hint (see
1600 // make_closure_type_specifier and unwrap_mutability).
1601 // Unwrap them here anyway for better error recovery.
1602 let type_ = match type_ {
1603 Ty(_, Ty_::Tapply((Id(_, "\\Mutable"), [t]))) => t,
1604 Ty(_, Ty_::Tapply((Id(_, "\\OwnedMutable"), [t]))) => t,
1605 Ty(_, Ty_::Tapply((Id(_, "\\MaybeMutable"), [t]))) => t,
1608 let mut flags = match attributes.param_mutability {
1609 Some(ParamMutability::ParamBorrowedMutable) => {
1610 FunParamFlags::MUTABLE_FLAGS_BORROWED
1612 Some(ParamMutability::ParamOwnedMutable) => {
1613 FunParamFlags::MUTABLE_FLAGS_OWNED
1615 Some(ParamMutability::ParamMaybeMutable) => {
1616 FunParamFlags::MUTABLE_FLAGS_MAYBE
1618 None => FunParamFlags::empty(),
1620 if attributes.accept_disposable {
1621 flags |= FunParamFlags::ACCEPT_DISPOSABLE
1623 if attributes.external {
1624 flags |= FunParamFlags::IFC_EXTERNAL
1626 if attributes.can_call {
1627 flags |= FunParamFlags::IFC_CAN_CALL
1629 if attributes.atom {
1630 flags |= FunParamFlags::ATOM
1633 ParamMode::FPinout => {
1634 flags |= FunParamFlags::INOUT;
1636 ParamMode::FPnormal => {}
1638 if initializer.is_present() {
1639 flags |= FunParamFlags::HAS_DEFAULT;
1641 let variadic = initializer.is_ignored() && variadic;
1642 let type_ = if variadic {
1644 self.alloc(if name.is_some() {
1645 Reason::RvarParam(pos)
1647 Reason::witness(pos)
1654 let rx_annotation = if attributes.at_most_rx_as_func {
1655 Some(ParamRxAnnotation::ParamRxVar)
1658 .reactivity_condition_type
1659 .map(|ty| ParamRxAnnotation::ParamRxIfImpl(ty))
1661 let param = self.alloc(FunParam {
1664 type_: self.alloc(PossiblyEnforcedTy {
1671 arity = match arity {
1672 FunArity::Fstandard if variadic => FunArity::Fvariadic(param),
1679 n => panic!("Expected a function parameter, but got {:?}", n),
1683 params.into_bump_slice(),
1684 properties.into_bump_slice(),
1688 n if n.is_ignored() => Some((&[], &[], FunArity::Fstandard)),
1689 n => panic!("Expected a list of function parameters, but got {:?}", n),
1693 fn make_shape_field_name(&self, name: Node<'a>) -> Option<ShapeFieldName<'a>> {
1695 Node::StringLiteral(&(s, pos)) => ShapeFieldName::SFlitStr(self.alloc((pos, s))),
1696 // TODO: OCaml decl produces SFlitStr here instead of SFlitInt, so
1697 // we must also. Looks like int literal keys have become a parse
1698 // error--perhaps that's why.
1699 Node::IntLiteral(&(s, pos)) => ShapeFieldName::SFlitStr(self.alloc((pos, s.into()))),
1700 Node::Expr(aast::Expr(
1702 aast::Expr_::ClassConst(&(
1703 aast::ClassId(_, aast::ClassId_::CI(&class_name)),
1706 )) => ShapeFieldName::SFclassConst(self.alloc((class_name, const_name))),
1707 Node::Expr(aast::Expr(
1709 aast::Expr_::ClassConst(&(aast::ClassId(pos, aast::ClassId_::CIself), const_name)),
1710 )) => ShapeFieldName::SFclassConst(self.alloc((
1713 self.classish_name_builder.get_current_classish_name()?.0,
1724 type_arguments: Node<'a>,
1725 pos_to_merge: &'a Pos<'a>,
1727 let type_arguments = self.slice(
1730 .filter_map(|&node| self.node_to_ty(node)),
1733 let pos = self.merge(base_ty.0, pos_to_merge);
1735 // OCaml decl creates a capability with a hint pointing to the entire
1736 // type (i.e., pointing to `Rx<(function(): void)>` rather than just
1737 // `(function(): void)`), so we extend the hint position similarly here.
1738 let extend_capability_pos = |implicit_params: &'a FunImplicitParams| {
1739 let capability = match implicit_params.capability {
1741 let ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), ty.1));
1744 CapDefaults(_) => CapDefaults(pos),
1746 self.alloc(FunImplicitParams {
1752 let ty_ = match (base_ty, type_arguments) {
1753 (Id(_, name), &[&Ty(_, Ty_::Tfun(f))]) if name == "\\Pure" => {
1754 Ty_::Tfun(self.alloc(FunType {
1755 reactive: Reactivity::Pure(None),
1756 implicit_params: extend_capability_pos(f.implicit_params),
1760 (Id(_, name), &[&Ty(_, Ty_::Tfun(f))]) if name == "\\Rx" => {
1761 Ty_::Tfun(self.alloc(FunType {
1762 reactive: Reactivity::Reactive(None),
1763 implicit_params: extend_capability_pos(f.implicit_params),
1767 (Id(_, name), &[&Ty(_, Ty_::Tfun(f))]) if name == "\\RxShallow" => {
1768 Ty_::Tfun(self.alloc(FunType {
1769 reactive: Reactivity::Shallow(None),
1770 implicit_params: extend_capability_pos(f.implicit_params),
1774 (Id(_, name), &[&Ty(_, Ty_::Tfun(f))]) if name == "\\RxLocal" => {
1775 Ty_::Tfun(self.alloc(FunType {
1776 reactive: Reactivity::Local(None),
1777 implicit_params: extend_capability_pos(f.implicit_params),
1781 _ => Ty_::Tapply(self.alloc((base_ty, type_arguments))),
1784 self.hint_ty(pos, ty_)
1787 fn hint_ty(&self, pos: &'a Pos<'a>, ty_: Ty_<'a>) -> Node<'a> {
1788 Node::Ty(self.alloc(Ty(self.alloc(Reason::hint(pos)), ty_)))
1791 fn prim_ty(&self, tprim: aast::Tprim, pos: &'a Pos<'a>) -> Node<'a> {
1792 self.hint_ty(pos, Ty_::Tprim(self.alloc(tprim)))
1795 fn tany_with_pos(&self, pos: &'a Pos<'a>) -> &'a Ty<'a> {
1796 self.alloc(Ty(self.alloc(Reason::witness(pos)), TANY_))
1799 /// The type used when a `varray_or_darray` typehint is missing its key type argument.
1800 fn varray_or_darray_key(&self, pos: &'a Pos<'a>) -> &'a Ty<'a> {
1802 self.alloc(Reason::RvarrayOrDarrayKey(pos)),
1803 Ty_::Tprim(self.alloc(aast::Tprim::Tarraykey)),
1807 fn source_text_at_pos(&self, pos: &'a Pos<'a>) -> &'a [u8] {
1808 let start = pos.start_cnum();
1809 let end = pos.end_cnum();
1810 self.source_text.source_text().sub(start, end - start)
1813 // While we usually can tell whether to allocate a Tapply or Tgeneric based
1814 // on our type_parameters stack, *constraints* on type parameters may
1815 // reference type parameters which we have not parsed yet. When constructing
1816 // a type parameter list, we use this function to rewrite the type of each
1817 // constraint, considering the full list of type parameters to be in scope.
1818 fn convert_tapply_to_tgeneric(&self, ty: &'a Ty<'a>) -> &'a Ty<'a> {
1819 let ty_ = match ty.1 {
1820 Ty_::Tapply(&(id, targs)) => {
1821 let converted_targs = self.slice(
1824 .map(|&targ| self.convert_tapply_to_tgeneric(targ)),
1826 match self.tapply_should_be_tgeneric(ty.0, id) {
1827 Some(name) => Ty_::Tgeneric(self.alloc((name, converted_targs))),
1828 None => Ty_::Tapply(self.alloc((id, converted_targs))),
1831 Ty_::Tlike(ty) => Ty_::Tlike(self.convert_tapply_to_tgeneric(ty)),
1832 Ty_::Toption(ty) => Ty_::Toption(self.convert_tapply_to_tgeneric(ty)),
1833 Ty_::Tfun(fun_type) => {
1834 let convert_param = |param: &'a FunParam<'a>| {
1835 self.alloc(FunParam {
1836 type_: self.alloc(PossiblyEnforcedTy {
1837 enforced: param.type_.enforced,
1838 type_: self.convert_tapply_to_tgeneric(param.type_.type_),
1843 let arity = match fun_type.arity {
1844 FunArity::Fstandard => FunArity::Fstandard,
1845 FunArity::Fvariadic(param) => FunArity::Fvariadic(convert_param(param)),
1847 let params = self.slice(fun_type.params.iter().copied().map(convert_param));
1848 let implicit_params = fun_type.implicit_params;
1849 let ret = self.alloc(PossiblyEnforcedTy {
1850 enforced: fun_type.ret.enforced,
1851 type_: self.convert_tapply_to_tgeneric(fun_type.ret.type_),
1853 Ty_::Tfun(self.alloc(FunType {
1861 Ty_::Tshape(&(kind, fields)) => {
1862 let mut converted_fields = AssocListMut::with_capacity_in(fields.len(), self.arena);
1863 for (&name, ty) in fields.iter() {
1864 converted_fields.insert(
1866 self.alloc(ShapeFieldType {
1867 optional: ty.optional,
1868 ty: self.convert_tapply_to_tgeneric(ty.ty),
1872 Ty_::Tshape(self.alloc((kind, converted_fields.into())))
1874 Ty_::Tdarray(&(tk, tv)) => Ty_::Tdarray(self.alloc((
1875 self.convert_tapply_to_tgeneric(tk),
1876 self.convert_tapply_to_tgeneric(tv),
1878 Ty_::Tvarray(ty) => Ty_::Tvarray(self.convert_tapply_to_tgeneric(ty)),
1879 Ty_::TvarrayOrDarray(&(tk, tv)) => Ty_::TvarrayOrDarray(self.alloc((
1880 self.convert_tapply_to_tgeneric(tk),
1881 self.convert_tapply_to_tgeneric(tv),
1883 Ty_::Ttuple(tys) => Ty_::Ttuple(
1886 .map(|&targ| self.convert_tapply_to_tgeneric(targ)),
1891 self.alloc(Ty(ty.0, ty_))
1894 // This is the logic for determining if convert_tapply_to_tgeneric should turn
1895 // a Tapply into a Tgeneric
1896 fn tapply_should_be_tgeneric(
1898 reason: &'a Reason<'a>,
1900 ) -> Option<&'a str> {
1901 match reason.pos() {
1902 // If the name contained a namespace delimiter in the original
1903 // source text, then it can't have referred to a type parameter
1904 // (since type parameters cannot be namespaced).
1906 if self.source_text_at_pos(pos).contains(&b'\\') {
1910 None => return None,
1912 // However, the direct decl parser will unconditionally prefix
1913 // the name with the current namespace (as it does for any
1914 // Tapply). We need to remove it.
1915 match id.1.rsplit('\\').next() {
1916 Some(name) if self.is_type_param_in_scope(name) => return Some(name),
1921 fn rewrite_taccess_reasons(&self, ty: &'a Ty<'a>, r: &'a Reason<'a>) -> &'a Ty<'a> {
1922 let ty_ = match ty.1 {
1923 Ty_::Taccess(&TaccessType(ty, id)) => {
1924 Ty_::Taccess(self.alloc(TaccessType(self.rewrite_taccess_reasons(ty, r), id)))
1928 self.alloc(Ty(r, ty_))
1931 fn user_attribute_to_decl(
1933 attr: &UserAttributeNode<'a>,
1934 ) -> &'a shallow_decl_defs::UserAttribute<'a> {
1935 self.alloc(shallow_decl_defs::UserAttribute {
1937 classname_params: self.slice(attr.classname_params.iter().map(|p| p.name.1)),
1941 fn namespace_use_kind(use_kind: &Node) -> Option<TokenKind> {
1942 match use_kind.token_kind() {
1943 Some(TokenKind::Const) => None,
1944 Some(TokenKind::Function) => None,
1945 Some(TokenKind::Type) => Some(TokenKind::Type),
1946 Some(TokenKind::Namespace) => Some(TokenKind::Namespace),
1947 _ if !use_kind.is_present() => Some(TokenKind::Mixed),
1948 x => panic!("Unexpected namespace use kind: {:?}", x),
1953 enum NodeIterHelper<'a: 'b, 'b> {
1955 Single(&'b Node<'a>),
1956 Vec(std::slice::Iter<'b, Node<'a>>),
1959 impl<'a, 'b> Iterator for NodeIterHelper<'a, 'b> {
1960 type Item = &'b Node<'a>;
1962 fn next(&mut self) -> Option<Self::Item> {
1964 NodeIterHelper::Empty => None,
1965 NodeIterHelper::Single(node) => {
1967 *self = NodeIterHelper::Empty;
1970 NodeIterHelper::Vec(ref mut iter) => iter.next(),
1974 // Must return the upper bound returned by Node::len.
1975 fn size_hint(&self) -> (usize, Option<usize>) {
1977 NodeIterHelper::Empty => (0, Some(0)),
1978 NodeIterHelper::Single(_) => (1, Some(1)),
1979 NodeIterHelper::Vec(iter) => iter.size_hint(),
1984 impl<'a, 'b> DoubleEndedIterator for NodeIterHelper<'a, 'b> {
1985 fn next_back(&mut self) -> Option<Self::Item> {
1987 NodeIterHelper::Empty => None,
1988 NodeIterHelper::Single(_) => self.next(),
1989 NodeIterHelper::Vec(ref mut iter) => iter.next_back(),
1994 impl<'a> FlattenOp for DirectDeclSmartConstructors<'a> {
1997 fn flatten(&self, kind: SyntaxKind, lst: std::vec::Vec<Self::S>) -> Self::S {
2001 Node::List(children) => children.len(),
2003 if Self::is_zero(x) {
2011 let mut r = Vec::with_capacity_in(size, self.arena);
2012 for s in lst.into_iter() {
2014 Node::List(children) => r.extend(children.iter().copied()),
2016 if !Self::is_zero(&x) {
2022 match r.into_bump_slice() {
2023 [] => Node::Ignored(kind),
2025 slice => Node::List(self.alloc(slice)),
2029 fn zero(kind: SyntaxKind) -> Self::S {
2033 fn is_zero(s: &Self::S) -> bool {
2035 Node::Token(token) => match token.kind() {
2036 TokenKind::Yield | TokenKind::Required | TokenKind::Lateinit => false,
2039 Node::List(inner) => inner.iter().all(Self::is_zero),
2045 impl<'a> FlattenSmartConstructors<'a, DirectDeclSmartConstructors<'a>>
2046 for DirectDeclSmartConstructors<'a>
2048 fn make_token(&mut self, token: CompactToken) -> Self::R {
2049 let token_text = |this: &Self| this.str_from_utf8(this.token_bytes(&token));
2050 let token_pos = |this: &Self| {
2053 .offset_to_file_pos_triple(token.start_offset());
2056 .offset_to_file_pos_triple(token.end_offset());
2057 Pos::from_lnum_bol_cnum(this.arena, this.filename, start, end)
2059 let kind = token.kind();
2061 let result = match kind {
2062 TokenKind::Name | TokenKind::XHPClassName => {
2063 let text = token_text(self);
2064 let pos = token_pos(self);
2066 let name = if kind == TokenKind::XHPClassName {
2067 Node::XhpName(self.alloc((text, pos)))
2069 Node::Name(self.alloc((text, pos)))
2072 if self.previous_token_kind == TokenKind::Class
2073 || self.previous_token_kind == TokenKind::Trait
2074 || self.previous_token_kind == TokenKind::Interface
2076 if let Some(current_class_name) = self.elaborate_defined_id(name) {
2077 self.classish_name_builder
2078 .lexed_name_after_classish_keyword(
2080 current_class_name.1,
2082 self.previous_token_kind,
2088 TokenKind::Class => Node::Name(self.alloc((token_text(self), token_pos(self)))),
2089 // There are a few types whose string representations we have to
2090 // grab anyway, so just go ahead and treat them as generic names.
2096 | TokenKind::Classname
2097 | TokenKind::SelfToken => Node::Name(self.alloc((token_text(self), token_pos(self)))),
2098 TokenKind::XHPElementName => {
2099 Node::XhpName(self.alloc((token_text(self), token_pos(self))))
2101 TokenKind::SingleQuotedStringLiteral => match escaper::unescape_single_in(
2102 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2105 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2106 Err(_) => Node::Ignored(SK::Token(kind)),
2108 TokenKind::DoubleQuotedStringLiteral => match escaper::unescape_double_in(
2109 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2112 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2113 Err(_) => Node::Ignored(SK::Token(kind)),
2115 TokenKind::HeredocStringLiteral => match escaper::unescape_heredoc_in(
2116 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2119 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2120 Err(_) => Node::Ignored(SK::Token(kind)),
2122 TokenKind::NowdocStringLiteral => match escaper::unescape_nowdoc_in(
2123 self.str_from_utf8(escaper::unquote_slice(self.token_bytes(&token))),
2126 Ok(text) => Node::StringLiteral(self.alloc((text.into(), token_pos(self)))),
2127 Err(_) => Node::Ignored(SK::Token(kind)),
2129 TokenKind::DecimalLiteral
2130 | TokenKind::OctalLiteral
2131 | TokenKind::HexadecimalLiteral
2132 | TokenKind::BinaryLiteral => {
2133 Node::IntLiteral(self.alloc((token_text(self), token_pos(self))))
2135 TokenKind::FloatingLiteral => {
2136 Node::FloatingLiteral(self.alloc((token_text(self), token_pos(self))))
2138 TokenKind::BooleanLiteral => {
2139 Node::BooleanLiteral(self.alloc((token_text(self), token_pos(self))))
2141 TokenKind::String => self.prim_ty(aast::Tprim::Tstring, token_pos(self)),
2142 TokenKind::Int => self.prim_ty(aast::Tprim::Tint, token_pos(self)),
2143 TokenKind::Float => self.prim_ty(aast::Tprim::Tfloat, token_pos(self)),
2144 // "double" and "boolean" are parse errors--they should be written
2145 // "float" and "bool". The decl-parser treats the incorrect names as
2146 // type names rather than primitives.
2147 TokenKind::Double | TokenKind::Boolean => self.hint_ty(
2149 Ty_::Tapply(self.alloc((Id(token_pos(self), token_text(self)), &[][..]))),
2151 TokenKind::Num => self.prim_ty(aast::Tprim::Tnum, token_pos(self)),
2152 TokenKind::Bool => self.prim_ty(aast::Tprim::Tbool, token_pos(self)),
2153 TokenKind::Mixed => {
2154 Node::Ty(self.alloc(Ty(self.alloc(Reason::hint(token_pos(self))), Ty_::Tmixed)))
2156 TokenKind::Void => self.prim_ty(aast::Tprim::Tvoid, token_pos(self)),
2157 TokenKind::Arraykey => self.prim_ty(aast::Tprim::Tarraykey, token_pos(self)),
2158 TokenKind::Noreturn => self.prim_ty(aast::Tprim::Tnoreturn, token_pos(self)),
2159 TokenKind::Resource => self.prim_ty(aast::Tprim::Tresource, token_pos(self)),
2160 TokenKind::NullLiteral
2163 | TokenKind::Backslash
2164 | TokenKind::Construct
2165 | TokenKind::LeftParen
2166 | TokenKind::RightParen
2167 | TokenKind::LeftBracket
2168 | TokenKind::RightBracket
2170 | TokenKind::Question
2173 | TokenKind::Exclamation
2176 | TokenKind::PlusPlus
2177 | TokenKind::MinusMinus
2181 | TokenKind::EqualEqual
2182 | TokenKind::EqualEqualEqual
2183 | TokenKind::StarStar
2184 | TokenKind::AmpersandAmpersand
2186 | TokenKind::LessThan
2187 | TokenKind::LessThanEqual
2188 | TokenKind::GreaterThan
2189 | TokenKind::GreaterThanEqual
2191 | TokenKind::Ampersand
2193 | TokenKind::LessThanLessThan
2194 | TokenKind::GreaterThanGreaterThan
2195 | TokenKind::Percent
2196 | TokenKind::QuestionQuestion
2198 | TokenKind::Abstract
2202 | TokenKind::DotDotDot
2203 | TokenKind::Extends
2205 | TokenKind::Implements
2207 | TokenKind::Interface
2208 | TokenKind::Newtype
2211 | TokenKind::Semicolon
2212 | TokenKind::Private
2213 | TokenKind::Protected
2218 | TokenKind::Lateinit
2219 | TokenKind::RecordDec
2220 | TokenKind::RightBrace
2223 | TokenKind::Function
2224 | TokenKind::Namespace
2226 | TokenKind::Required
2227 | TokenKind::Ctx => Node::Token(FixedWidthToken::new(kind, token.start_offset())),
2228 TokenKind::EndOfFile
2229 | TokenKind::Attribute
2235 | TokenKind::Category
2236 | TokenKind::Children
2238 | TokenKind::Continue
2239 | TokenKind::Default
2247 | TokenKind::Endforeach
2249 | TokenKind::Endswitch
2250 | TokenKind::Endwhile
2252 | TokenKind::Fallthrough
2254 | TokenKind::Finally
2256 | TokenKind::Foreach
2259 | TokenKind::Concurrent
2261 | TokenKind::Include
2262 | TokenKind::Include_once
2263 | TokenKind::Instanceof
2264 | TokenKind::Insteadof
2265 | TokenKind::Integer
2275 | TokenKind::Require
2276 | TokenKind::Require_once
2287 | TokenKind::LeftBrace
2288 | TokenKind::MinusGreaterThan
2290 | TokenKind::LessThanEqualGreaterThan
2291 | TokenKind::ExclamationEqual
2292 | TokenKind::ExclamationEqualEqual
2294 | TokenKind::QuestionAs
2295 | TokenKind::QuestionColon
2296 | TokenKind::QuestionQuestionEqual
2298 | TokenKind::StarStarEqual
2299 | TokenKind::StarEqual
2300 | TokenKind::SlashEqual
2301 | TokenKind::PercentEqual
2302 | TokenKind::PlusEqual
2303 | TokenKind::MinusEqual
2304 | TokenKind::DotEqual
2305 | TokenKind::LessThanLessThanEqual
2306 | TokenKind::GreaterThanGreaterThanEqual
2307 | TokenKind::AmpersandEqual
2308 | TokenKind::CaratEqual
2309 | TokenKind::BarEqual
2311 | TokenKind::ColonColon
2312 | TokenKind::EqualGreaterThan
2313 | TokenKind::EqualEqualGreaterThan
2314 | TokenKind::QuestionMinusGreaterThan
2315 | TokenKind::DollarDollar
2316 | TokenKind::BarGreaterThan
2317 | TokenKind::SlashGreaterThan
2318 | TokenKind::LessThanSlash
2319 | TokenKind::LessThanQuestion
2320 | TokenKind::Backtick
2321 | TokenKind::ErrorToken
2322 | TokenKind::DoubleQuotedStringLiteralHead
2323 | TokenKind::StringLiteralBody
2324 | TokenKind::DoubleQuotedStringLiteralTail
2325 | TokenKind::HeredocStringLiteralHead
2326 | TokenKind::HeredocStringLiteralTail
2327 | TokenKind::XHPCategoryName
2328 | TokenKind::XHPStringLiteral
2329 | TokenKind::XHPBody
2330 | TokenKind::XHPComment
2332 | TokenKind::Hashbang => Node::Ignored(SK::Token(kind)),
2334 self.previous_token_kind = kind;
2338 fn make_missing(&mut self, _: usize) -> Self::R {
2339 Node::Ignored(SK::Missing)
2342 fn make_list(&mut self, items: std::vec::Vec<Self::R>, _: usize) -> Self::R {
2343 if let Some(&yield_) = items
2345 .flat_map(|node| node.iter())
2346 .find(|node| node.is_token(TokenKind::Yield))
2350 let size = items.iter().filter(|node| node.is_present()).count();
2351 let items_iter = items.into_iter();
2352 let mut items = Vec::with_capacity_in(size, self.arena);
2353 for node in items_iter {
2354 if node.is_present() {
2358 let items = items.into_bump_slice();
2359 if items.is_empty() {
2360 Node::Ignored(SK::SyntaxList)
2362 Node::List(self.alloc(items))
2367 fn make_qualified_name(&mut self, parts: Self::R) -> Self::R {
2368 let pos = self.get_pos(parts);
2370 Node::List(nodes) => Node::QualifiedName(self.alloc((nodes, pos))),
2371 node if node.is_ignored() => Node::Ignored(SK::QualifiedName),
2372 node => Node::QualifiedName(
2373 self.alloc((bumpalo::vec![in self.arena; node].into_bump_slice(), pos)),
2378 fn make_simple_type_specifier(&mut self, specifier: Self::R) -> Self::R {
2379 // Return this explicitly because flatten filters out zero nodes, and
2380 // we treat most non-error nodes as zeroes.
2384 fn make_literal_expression(&mut self, expression: Self::R) -> Self::R {
2388 fn make_simple_initializer(&mut self, equals: Self::R, expr: Self::R) -> Self::R {
2389 // If the expr is Ignored, bubble up the assignment operator so that we
2390 // can tell that *some* initializer was here. Useful for class
2391 // properties, where we need to enforce that properties without default
2392 // values are initialized in the constructor.
2393 if expr.is_ignored() { equals } else { expr }
2396 fn make_anonymous_function(
2398 _attribute_spec: Self::R,
2399 _static_keyword: Self::R,
2400 _async_keyword: Self::R,
2401 _function_keyword: Self::R,
2402 _left_paren: Self::R,
2403 _parameters: Self::R,
2404 _right_paren: Self::R,
2411 // do not allow Yield to bubble up
2412 Node::Ignored(SK::AnonymousFunction)
2415 fn make_lambda_expression(
2417 _attribute_spec: Self::R,
2419 _signature: Self::R,
2423 // do not allow Yield to bubble up
2424 Node::Ignored(SK::LambdaExpression)
2427 fn make_awaitable_creation_expression(
2429 _attribute_spec: Self::R,
2431 _compound_statement: Self::R,
2433 // do not allow Yield to bubble up
2434 Node::Ignored(SK::AwaitableCreationExpression)
2437 fn make_darray_intrinsic_expression(
2440 _explicit_type: Self::R,
2441 _left_bracket: Self::R,
2443 right_bracket: Self::R,
2445 let fields = self.slice(fields.iter().filter_map(|node| match node {
2446 Node::ListItem(&(key, value)) => {
2447 let key = self.node_to_expr(key)?;
2448 let value = self.node_to_expr(value)?;
2451 n => panic!("Expected a ListItem but was {:?}", n),
2453 Node::Expr(self.alloc(aast::Expr(
2454 self.merge_positions(darray, right_bracket),
2455 nast::Expr_::Darray(self.alloc((None, fields))),
2459 fn make_dictionary_intrinsic_expression(
2462 _explicit_type: Self::R,
2463 _left_bracket: Self::R,
2465 right_bracket: Self::R,
2467 let fields = self.slice(fields.iter().filter_map(|node| match node {
2468 Node::ListItem(&(key, value)) => {
2469 let key = self.node_to_expr(key)?;
2470 let value = self.node_to_expr(value)?;
2471 Some(self.alloc(aast::Field(key, value)))
2473 n => panic!("Expected a ListItem but was {:?}", n),
2475 Node::Expr(self.alloc(aast::Expr(
2476 self.merge_positions(dict, right_bracket),
2477 nast::Expr_::KeyValCollection(self.alloc((aast_defs::KvcKind::Dict, None, fields))),
2481 fn make_keyset_intrinsic_expression(
2484 _explicit_type: Self::R,
2485 _left_bracket: Self::R,
2487 right_bracket: Self::R,
2489 let fields = self.slice(fields.iter().filter_map(|&node| self.node_to_expr(node)));
2490 Node::Expr(self.alloc(aast::Expr(
2491 self.merge_positions(keyset, right_bracket),
2492 nast::Expr_::ValCollection(self.alloc((aast_defs::VcKind::Keyset, None, fields))),
2496 fn make_varray_intrinsic_expression(
2499 _explicit_type: Self::R,
2500 _left_bracket: Self::R,
2502 right_bracket: Self::R,
2504 let fields = self.slice(fields.iter().filter_map(|&node| self.node_to_expr(node)));
2505 Node::Expr(self.alloc(aast::Expr(
2506 self.merge_positions(varray, right_bracket),
2507 nast::Expr_::Varray(self.alloc((None, fields))),
2511 fn make_vector_intrinsic_expression(
2514 _explicit_type: Self::R,
2515 _left_bracket: Self::R,
2517 right_bracket: Self::R,
2519 let fields = self.slice(fields.iter().filter_map(|&node| self.node_to_expr(node)));
2520 Node::Expr(self.alloc(aast::Expr(
2521 self.merge_positions(vec, right_bracket),
2522 nast::Expr_::ValCollection(self.alloc((aast_defs::VcKind::Vec, None, fields))),
2526 fn make_element_initializer(
2532 Node::ListItem(self.alloc((key, value)))
2535 fn make_prefix_unary_expression(&mut self, op: Self::R, value: Self::R) -> Self::R {
2536 let pos = self.merge_positions(op, value);
2537 let op = match op.token_kind() {
2538 Some(TokenKind::Tilde) => Uop::Utild,
2539 Some(TokenKind::Exclamation) => Uop::Unot,
2540 Some(TokenKind::Plus) => Uop::Uplus,
2541 Some(TokenKind::Minus) => Uop::Uminus,
2542 Some(TokenKind::PlusPlus) => Uop::Uincr,
2543 Some(TokenKind::MinusMinus) => Uop::Udecr,
2544 Some(TokenKind::At) => Uop::Usilence,
2545 _ => return Node::Ignored(SK::PrefixUnaryExpression),
2547 let value = match self.node_to_expr(value) {
2548 Some(value) => value,
2549 None => return Node::Ignored(SK::PrefixUnaryExpression),
2551 Node::Expr(self.alloc(aast::Expr(pos, aast::Expr_::Unop(self.alloc((op, value))))))
2554 fn make_postfix_unary_expression(&mut self, value: Self::R, op: Self::R) -> Self::R {
2555 let pos = self.merge_positions(value, op);
2556 let op = match op.token_kind() {
2557 Some(TokenKind::PlusPlus) => Uop::Upincr,
2558 Some(TokenKind::MinusMinus) => Uop::Updecr,
2559 _ => return Node::Ignored(SK::PostfixUnaryExpression),
2561 let value = match self.node_to_expr(value) {
2562 Some(value) => value,
2563 None => return Node::Ignored(SK::PostfixUnaryExpression),
2565 Node::Expr(self.alloc(aast::Expr(pos, aast::Expr_::Unop(self.alloc((op, value))))))
2568 fn make_binary_expression(&mut self, lhs: Self::R, op_node: Self::R, rhs: Self::R) -> Self::R {
2569 let op = match op_node.token_kind() {
2570 Some(TokenKind::Plus) => Bop::Plus,
2571 Some(TokenKind::Minus) => Bop::Minus,
2572 Some(TokenKind::Star) => Bop::Star,
2573 Some(TokenKind::Slash) => Bop::Slash,
2574 Some(TokenKind::Equal) => Bop::Eq(None),
2575 Some(TokenKind::EqualEqual) => Bop::Eqeq,
2576 Some(TokenKind::EqualEqualEqual) => Bop::Eqeqeq,
2577 Some(TokenKind::StarStar) => Bop::Starstar,
2578 Some(TokenKind::AmpersandAmpersand) => Bop::Ampamp,
2579 Some(TokenKind::BarBar) => Bop::Barbar,
2580 Some(TokenKind::LessThan) => Bop::Lt,
2581 Some(TokenKind::LessThanEqual) => Bop::Lte,
2582 Some(TokenKind::LessThanLessThan) => Bop::Ltlt,
2583 Some(TokenKind::GreaterThan) => Bop::Gt,
2584 Some(TokenKind::GreaterThanEqual) => Bop::Gte,
2585 Some(TokenKind::GreaterThanGreaterThan) => Bop::Gtgt,
2586 Some(TokenKind::Dot) => Bop::Dot,
2587 Some(TokenKind::Ampersand) => Bop::Amp,
2588 Some(TokenKind::Bar) => Bop::Bar,
2589 Some(TokenKind::Percent) => Bop::Percent,
2590 Some(TokenKind::QuestionQuestion) => Bop::QuestionQuestion,
2591 _ => return Node::Ignored(SK::BinaryExpression),
2594 match (&op, rhs.is_token(TokenKind::Yield)) {
2595 (Bop::Eq(_), true) => return rhs,
2599 let pos = self.merge(self.merge_positions(lhs, op_node), self.get_pos(rhs));
2601 let lhs = match self.node_to_expr(lhs) {
2603 None => return Node::Ignored(SK::BinaryExpression),
2605 let rhs = match self.node_to_expr(rhs) {
2607 None => return Node::Ignored(SK::BinaryExpression),
2610 Node::Expr(self.alloc(aast::Expr(
2612 aast::Expr_::Binop(self.alloc((op, lhs, rhs))),
2616 fn make_parenthesized_expression(
2625 fn make_list_item(&mut self, item: Self::R, sep: Self::R) -> Self::R {
2626 match (item.is_ignored(), sep.is_ignored()) {
2627 (true, true) => Node::Ignored(SK::ListItem),
2628 (false, true) => item,
2629 (true, false) => sep,
2630 (false, false) => Node::ListItem(self.alloc((item, sep))),
2634 fn make_type_arguments(
2638 greater_than: Self::R,
2640 Node::BracketedList(self.alloc((
2641 self.get_pos(less_than),
2642 arguments.as_slice(self.arena),
2643 self.get_pos(greater_than),
2647 fn make_generic_type_specifier(
2649 class_type: Self::R,
2650 type_arguments: Self::R,
2652 let class_id = match self.expect_name(class_type) {
2654 None => return Node::Ignored(SK::GenericTypeSpecifier),
2656 if class_id.1.trim_start_matches("\\") == "varray_or_darray" {
2657 let id_pos = class_id.0;
2658 let pos = self.merge(id_pos, self.get_pos(type_arguments));
2659 let type_arguments = type_arguments.as_slice(self.arena);
2660 let ty_ = match type_arguments {
2661 [tk, tv] => Ty_::TvarrayOrDarray(
2663 self.node_to_ty(*tk)
2664 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
2665 self.node_to_ty(*tv)
2666 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
2669 [tv] => Ty_::TvarrayOrDarray(
2671 self.varray_or_darray_key(pos),
2672 self.node_to_ty(*tv)
2673 .unwrap_or_else(|| self.tany_with_pos(id_pos)),
2678 self.hint_ty(pos, ty_)
2680 let Id(pos, class_type) = class_id;
2681 match class_type.rsplit('\\').next() {
2682 Some(name) if self.is_type_param_in_scope(name) => {
2683 let pos = self.merge(pos, self.get_pos(type_arguments));
2684 let type_arguments = self.slice(
2687 .filter_map(|&node| self.node_to_ty(node)),
2689 let ty_ = Ty_::Tgeneric(self.alloc((name, type_arguments)));
2690 self.hint_ty(pos, ty_)
2693 let class_type = self.elaborate_raw_id(class_type);
2695 Id(pos, class_type),
2697 self.get_pos(type_arguments),
2704 fn make_record_declaration(
2706 attribute_spec: Self::R,
2708 record_keyword: Self::R,
2710 _extends_keyword: Self::R,
2711 extends_opt: Self::R,
2712 _left_brace: Self::R,
2714 right_brace: Self::R,
2716 let name = match self.elaborate_defined_id(name) {
2718 None => return Node::Ignored(SK::RecordDeclaration),
2722 self.alloc(typing_defs::RecordDefType {
2725 .expect_name(extends_opt)
2726 .map(|id| self.elaborate_id(id)),
2727 fields: self.slice(fields.iter().filter_map(|node| match node {
2728 Node::RecordField(&field) => Some(field),
2731 abstract_: modifier.is_token(TokenKind::Abstract),
2732 pos: self.pos_from_slice(&[attribute_spec, modifier, record_keyword, right_brace]),
2735 Node::Ignored(SK::RecordDeclaration)
2738 fn make_record_field(
2742 initializer: Self::R,
2743 _semicolon: Self::R,
2745 let name = match self.expect_name(name) {
2747 None => return Node::Ignored(SK::RecordField),
2749 let field_req = if initializer.is_ignored() {
2750 RecordFieldReq::ValueRequired
2752 RecordFieldReq::HasDefaultValue
2754 Node::RecordField(self.alloc((name, field_req)))
2757 fn make_alias_declaration(
2759 _attributes: Self::R,
2762 generic_params: Self::R,
2763 constraint: Self::R,
2765 aliased_type: Self::R,
2766 _semicolon: Self::R,
2768 if name.is_ignored() {
2769 return Node::Ignored(SK::AliasDeclaration);
2771 let Id(pos, name) = match self.elaborate_defined_id(name) {
2773 None => return Node::Ignored(SK::AliasDeclaration),
2775 let ty = match self.node_to_ty(aliased_type) {
2777 None => return Node::Ignored(SK::AliasDeclaration),
2779 let constraint = match constraint {
2780 Node::TypeConstraint(&(_kind, hint)) => self.node_to_ty(hint),
2783 // Pop the type params stack only after creating all inner types.
2784 let tparams = self.pop_type_params(generic_params);
2785 let typedef = self.alloc(TypedefType {
2787 vis: match keyword.token_kind() {
2788 Some(TokenKind::Type) => aast::TypedefVisibility::Transparent,
2789 Some(TokenKind::Newtype) => aast::TypedefVisibility::Opaque,
2790 _ => aast::TypedefVisibility::Transparent,
2797 self.add_typedef(name, typedef);
2799 Node::Ignored(SK::AliasDeclaration)
2802 fn make_type_constraint(&mut self, kind: Self::R, value: Self::R) -> Self::R {
2803 let kind = match kind.token_kind() {
2804 Some(TokenKind::As) => ConstraintKind::ConstraintAs,
2805 Some(TokenKind::Super) => ConstraintKind::ConstraintSuper,
2806 n => panic!("Expected either As or Super, but was {:?}", n),
2808 Node::TypeConstraint(self.alloc((kind, value)))
2811 fn make_type_parameter(
2813 user_attributes: Self::R,
2817 tparam_params: Self::R,
2818 constraints: Self::R,
2820 let user_attributes = match user_attributes {
2821 Node::BracketedList((_, attributes, _)) => {
2822 self.slice(attributes.into_iter().filter_map(|x| match x {
2823 Node::Attribute(a) => Some(*a),
2830 let constraints = self.slice(constraints.iter().filter_map(|node| match node {
2831 Node::TypeConstraint(&constraint) => Some(constraint),
2832 n if n.is_ignored() => None,
2833 n => panic!("Expected a type constraint, but was {:?}", n),
2836 // TODO(T70068435) Once we add support for constraints on higher-kinded types
2837 // (in particular, constraints on nested type parameters), we need to ensure
2838 // that we correctly handle the scoping of nested type parameters.
2839 // This includes making sure that the call to convert_type_appl_to_generic
2840 // in make_type_parameters handles nested constraints.
2841 // For now, we just make sure that the nested type parameters that make_type_parameters
2842 // added to the global list of in-scope type parameters are removed immediately:
2843 self.pop_type_params(tparam_params);
2845 let tparam_params = match tparam_params {
2846 Node::TypeParameters(¶ms) => params,
2850 Node::TypeParameter(self.alloc(TypeParameterDecl {
2852 variance: match variance.token_kind() {
2853 Some(TokenKind::Minus) => Variance::Contravariant,
2854 Some(TokenKind::Plus) => Variance::Covariant,
2855 _ => Variance::Invariant,
2857 reified: if reify.is_token(TokenKind::Reify) {
2858 if user_attributes.iter().any(|node| node.name.1 == "__Soft") {
2859 aast::ReifyKind::SoftReified
2861 aast::ReifyKind::Reified
2864 aast::ReifyKind::Erased
2872 fn make_type_parameters(&mut self, _lt: Self::R, tparams: Self::R, _gt: Self::R) -> Self::R {
2873 let size = tparams.len();
2874 let mut tparams_with_name = Vec::with_capacity_in(size, self.arena);
2875 let mut tparam_names = MultiSetMut::with_capacity_in(size, self.arena);
2876 for node in tparams.iter() {
2878 &Node::TypeParameter(decl) => {
2879 let name = match decl.name.as_id() {
2881 None => return Node::Ignored(SK::TypeParameters),
2883 tparam_names.insert(name.1);
2884 tparams_with_name.push((decl, name));
2886 n => panic!("Expected a type parameter, but got {:?}", n),
2889 Rc::make_mut(&mut self.type_parameters).push(tparam_names.into());
2890 let mut tparams = Vec::with_capacity_in(tparams_with_name.len(), self.arena);
2891 for (decl, name) in tparams_with_name.into_iter() {
2892 let &TypeParameterDecl {
2900 let constraints = self.slice(constraints.iter().filter_map(|constraint| {
2901 let &(kind, ty) = constraint;
2902 let ty = self.node_to_ty(ty)?;
2903 let ty = self.convert_tapply_to_tgeneric(ty);
2907 let user_attributes = self.slice(
2911 .map(|x| self.user_attribute_to_decl(x)),
2913 tparams.push(self.alloc(Tparam {
2919 tparams: tparam_params,
2922 Node::TypeParameters(self.alloc(tparams.into_bump_slice()))
2925 fn make_parameter_declaration(
2927 attributes: Self::R,
2928 visibility: Self::R,
2932 initializer: Self::R,
2934 let (variadic, pos, name) = match name {
2935 Node::ListItem(&(ellipsis, id)) => {
2936 let Id(pos, name) = match id.as_id() {
2938 None => return Node::Ignored(SK::ParameterDeclaration),
2940 let variadic = ellipsis.is_token(TokenKind::DotDotDot);
2941 (variadic, pos, Some(name))
2944 let Id(pos, name) = match name.as_id() {
2946 None => return Node::Ignored(SK::ParameterDeclaration),
2948 (false, pos, Some(name))
2951 let kind = if inout.is_token(TokenKind::Inout) {
2956 Node::FunParam(self.alloc(FunParamDecl {
2968 fn make_variadic_parameter(&mut self, _: Self::R, hint: Self::R, ellipsis: Self::R) -> Self::R {
2970 self.alloc(FunParamDecl {
2971 attributes: Node::Ignored(SK::Missing),
2972 visibility: Node::Ignored(SK::Missing),
2973 kind: ParamMode::FPnormal,
2977 .unwrap_or_else(|| self.get_pos(ellipsis)),
2980 initializer: Node::Ignored(SK::Missing),
2985 fn make_function_declaration(
2987 attributes: Self::R,
2991 let parsed_attributes = self.to_attributes(attributes);
2993 Node::FunctionHeader(header) => {
2994 let is_method = false;
2995 let (Id(pos, name), type_, _) =
2996 match self.function_to_ty(is_method, attributes, header, body) {
2998 None => return Node::Ignored(SK::FunctionDeclaration),
3000 let deprecated = parsed_attributes.deprecated.map(|msg| {
3001 let mut s = String::new_in(self.arena);
3002 s.push_str("The function ");
3003 s.push_str(name.trim_start_matches("\\"));
3004 s.push_str(" is deprecated: ");
3008 let fun_elt = self.alloc(FunElt {
3012 php_std_lib: parsed_attributes.php_std_lib,
3014 self.add_fun(name, fun_elt);
3015 Node::Ignored(SK::FunctionDeclaration)
3017 _ => Node::Ignored(SK::FunctionDeclaration),
3021 fn make_contexts(&mut self, lb: Self::R, tys: Self::R, rb: Self::R) -> Self::R {
3022 let mut namespace_builder = NamespaceBuilder::empty_with_ns_in("HH\\Contexts", self.arena);
3024 &mut namespace_builder,
3025 Rc::make_mut(&mut self.namespace_builder),
3027 // Simulating Typing_make_type.intersection here
3028 let make_mixed = || {
3029 let pos = Reason::hint(self.merge_positions(lb, rb));
3030 Node::Ty(self.alloc(Ty(
3032 Ty_::Toption(self.alloc(Ty(self.alloc(pos), Ty_::Tnonnull))),
3035 let cap = match tys {
3036 Node::Ignored(_) => make_mixed(),
3037 Node::List(tys_list) => {
3038 if tys_list.is_empty() {
3040 } else if tys_list.len() == 1 {
3041 Node::Ty(self.node_to_ty(tys_list[0]).unwrap())
3043 self.make_intersection_type_specifier(lb, tys, rb)
3046 _ => self.make_intersection_type_specifier(lb, tys, rb),
3049 &mut namespace_builder,
3050 Rc::make_mut(&mut self.namespace_builder),
3055 fn make_function_declaration_header(
3060 type_params: Self::R,
3061 left_paren: Self::R,
3062 param_list: Self::R,
3063 _right_paren: Self::R,
3064 capability: Self::R,
3067 where_constraints: Self::R,
3069 // Use the position of the left paren if the name is missing.
3070 let name = if name.is_ignored() { left_paren } else { name };
3071 Node::FunctionHeader(self.alloc(FunctionHeader {
3082 fn make_yield_expression(&mut self, keyword: Self::R, _operand: Self::R) -> Self::R {
3083 assert!(keyword.token_kind() == Some(TokenKind::Yield));
3087 fn make_const_declaration(
3090 _const_keyword: Self::R,
3093 _semicolon: Self::R,
3099 .classish_name_builder
3100 .get_current_classish_name()
3103 let ty = self.node_to_ty(hint);
3105 self.alloc(self.slice(consts.iter().filter_map(|cst| match cst {
3106 Node::ConstInitializer(&(name, initializer)) => {
3107 let id = name.as_id()?;
3109 .or_else(|| self.infer_const(name, initializer))
3110 .unwrap_or_else(|| tany());
3111 let modifiers = read_member_modifiers(modifiers.iter());
3112 Some(Node::Const(self.alloc(
3113 shallow_decl_defs::ShallowClassConst {
3114 abstract_: modifiers.is_abstract,
3125 Node::List([Node::ConstInitializer(&(name, initializer))]) => {
3126 let Id(pos, id) = match self.elaborate_defined_id(name) {
3128 None => return Node::Ignored(SK::ConstDeclaration),
3132 .or_else(|| self.infer_const(name, initializer))
3133 .unwrap_or_else(|| self.tany_with_pos(pos));
3134 self.add_const(id, self.alloc(ConstDecl { pos, type_: ty }));
3135 Node::Ignored(SK::ConstDeclaration)
3137 _ => Node::Ignored(SK::ConstDeclaration),
3141 fn make_constant_declarator(&mut self, name: Self::R, initializer: Self::R) -> Self::R {
3142 if name.is_ignored() {
3143 Node::Ignored(SK::ConstantDeclarator)
3145 Node::ConstInitializer(self.alloc((name, initializer)))
3149 fn make_namespace_declaration(&mut self, _name: Self::R, body: Self::R) -> Self::R {
3150 if let Node::Ignored(SK::NamespaceBody) = body {
3151 Rc::make_mut(&mut self.namespace_builder).pop_namespace();
3153 Node::Ignored(SK::NamespaceDeclaration)
3156 fn make_namespace_declaration_header(&mut self, _keyword: Self::R, name: Self::R) -> Self::R {
3157 let name = self.expect_name(name).map(|Id(_, name)| name);
3158 // if this is header of semicolon-style (one with NamespaceEmptyBody) namespace, we should pop
3159 // the previous namespace first, but we don't have the body yet. We'll fix it retroactively in
3160 // make_namespace_empty_body
3161 Rc::make_mut(&mut self.namespace_builder).push_namespace(name);
3162 Node::Ignored(SK::NamespaceDeclarationHeader)
3165 fn make_namespace_body(
3167 _left_brace: Self::R,
3168 _declarations: Self::R,
3169 _right_brace: Self::R,
3171 Node::Ignored(SK::NamespaceBody)
3174 fn make_namespace_empty_body(&mut self, _semicolon: Self::R) -> Self::R {
3175 Rc::make_mut(&mut self.namespace_builder).pop_previous_namespace();
3176 Node::Ignored(SK::NamespaceEmptyBody)
3179 fn make_namespace_use_declaration(
3182 namespace_use_kind: Self::R,
3184 _semicolon: Self::R,
3186 if let Some(import_kind) = Self::namespace_use_kind(&namespace_use_kind) {
3187 for clause in clauses.iter() {
3188 if let Node::NamespaceUseClause(nuc) = clause {
3189 Rc::make_mut(&mut self.namespace_builder).add_import(
3197 Node::Ignored(SK::NamespaceUseDeclaration)
3200 fn make_namespace_group_use_declaration(
3205 _left_brace: Self::R,
3207 _right_brace: Self::R,
3208 _semicolon: Self::R,
3210 let Id(_, prefix) = match self.expect_name(prefix) {
3212 None => return Node::Ignored(SK::NamespaceGroupUseDeclaration),
3214 for clause in clauses.iter() {
3215 if let Node::NamespaceUseClause(nuc) = clause {
3216 let mut id = String::new_in(self.arena);
3217 id.push_str(prefix);
3218 id.push_str(nuc.id.1);
3219 Rc::make_mut(&mut self.namespace_builder).add_import(
3226 Node::Ignored(SK::NamespaceGroupUseDeclaration)
3229 fn make_namespace_use_clause(
3231 clause_kind: Self::R,
3234 aliased_name: Self::R,
3236 let id = match self.expect_name(name) {
3238 None => return Node::Ignored(SK::NamespaceUseClause),
3240 let as_ = if as_.is_token(TokenKind::As) {
3241 match aliased_name.as_id() {
3242 Some(name) => Some(name.1),
3243 None => return Node::Ignored(SK::NamespaceUseClause),
3248 if let Some(kind) = Self::namespace_use_kind(&clause_kind) {
3249 Node::NamespaceUseClause(self.alloc(NamespaceUseClause { kind, id, as_ }))
3251 Node::Ignored(SK::NamespaceUseClause)
3255 fn make_where_clause(&mut self, _: Self::R, where_constraints: Self::R) -> Self::R {
3259 fn make_where_constraint(
3263 right_type: Self::R,
3265 Node::WhereConstraint(self.alloc(WhereConstraint(
3266 self.node_to_ty(left_type).unwrap_or_else(|| tany()),
3267 match operator.token_kind() {
3268 Some(TokenKind::Equal) => ConstraintKind::ConstraintEq,
3269 Some(TokenKind::Super) => ConstraintKind::ConstraintSuper,
3270 _ => ConstraintKind::ConstraintAs,
3272 self.node_to_ty(right_type).unwrap_or_else(|| tany()),
3276 fn make_classish_declaration(
3278 attributes: Self::R,
3280 xhp_keyword: Self::R,
3281 class_keyword: Self::R,
3284 _extends_keyword: Self::R,
3286 _implements_keyword: Self::R,
3287 implements: Self::R,
3288 where_clause: Self::R,
3291 let raw_name = match self.expect_name(name) {
3292 Some(Id(_, name)) => name,
3293 None => return Node::Ignored(SK::ClassishDeclaration),
3295 let Id(pos, name) = match self.elaborate_defined_id(name) {
3297 None => return Node::Ignored(SK::ClassishDeclaration),
3299 let is_xhp = raw_name.starts_with(':') || xhp_keyword.is_present();
3301 let mut class_kind = match class_keyword.token_kind() {
3302 Some(TokenKind::Interface) => ClassKind::Cinterface,
3303 Some(TokenKind::Trait) => ClassKind::Ctrait,
3304 _ => ClassKind::Cnormal,
3306 let mut final_ = false;
3308 for modifier in modifiers.iter() {
3309 match modifier.token_kind() {
3310 Some(TokenKind::Abstract) => class_kind = ClassKind::Cabstract,
3311 Some(TokenKind::Final) => final_ = true,
3316 let where_constraints = self.slice(where_clause.iter().filter_map(|&x| match x {
3317 Node::WhereConstraint(x) => Some(x),
3321 let body = match body {
3322 Node::ClassishBody(body) => body,
3323 body => panic!("Expected a classish body, but was {:?}", body),
3326 let mut uses_len = 0;
3327 let mut xhp_attr_uses_len = 0;
3328 let mut req_extends_len = 0;
3329 let mut req_implements_len = 0;
3330 let mut consts_len = 0;
3331 let mut typeconsts_len = 0;
3332 let mut props_len = 0;
3333 let mut sprops_len = 0;
3334 let mut static_methods_len = 0;
3335 let mut methods_len = 0;
3337 let mut user_attributes_len = 0;
3338 for attribute in attributes.iter() {
3340 &Node::Attribute(..) => user_attributes_len += 1,
3345 for element in body.iter().copied() {
3347 Node::TraitUse(names) => uses_len += names.len(),
3348 Node::XhpClassAttributeDeclaration(&XhpClassAttributeDeclarationNode {
3350 xhp_attr_uses_decls,
3352 props_len += xhp_attr_decls.len();
3353 xhp_attr_uses_len += xhp_attr_uses_decls.len();
3355 Node::TypeConstant(..) => typeconsts_len += 1,
3356 Node::RequireClause(require) => match require.require_type.token_kind() {
3357 Some(TokenKind::Extends) => req_extends_len += 1,
3358 Some(TokenKind::Implements) => req_implements_len += 1,
3361 Node::List(consts @ [Node::Const(..), ..]) => consts_len += consts.len(),
3362 Node::Property(&PropertyNode { decls, is_static }) => {
3364 sprops_len += decls.len()
3366 props_len += decls.len()
3369 Node::Constructor(&ConstructorNode { properties, .. }) => {
3370 props_len += properties.len()
3372 Node::Method(&MethodNode { is_static, .. }) => {
3374 static_methods_len += 1
3383 let mut constructor = None;
3385 let mut uses = Vec::with_capacity_in(uses_len, self.arena);
3386 let mut xhp_attr_uses = Vec::with_capacity_in(xhp_attr_uses_len, self.arena);
3387 let mut req_extends = Vec::with_capacity_in(req_extends_len, self.arena);
3388 let mut req_implements = Vec::with_capacity_in(req_implements_len, self.arena);
3389 let mut consts = Vec::with_capacity_in(consts_len, self.arena);
3390 let mut typeconsts = Vec::with_capacity_in(typeconsts_len, self.arena);
3391 let mut props = Vec::with_capacity_in(props_len, self.arena);
3392 let mut sprops = Vec::with_capacity_in(sprops_len, self.arena);
3393 let mut static_methods = Vec::with_capacity_in(static_methods_len, self.arena);
3394 let mut methods = Vec::with_capacity_in(methods_len, self.arena);
3396 let mut user_attributes = Vec::with_capacity_in(user_attributes_len, self.arena);
3397 for attribute in attributes.iter() {
3399 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(&attr)),
3403 // Match ordering of attributes produced by the OCaml decl parser (even
3404 // though it's the reverse of the syntactic ordering).
3405 user_attributes.reverse();
3407 // xhp props go after regular props, regardless of their order in file
3408 let mut xhp_props = vec![];
3410 for element in body.iter().copied() {
3412 Node::TraitUse(names) => {
3413 uses.extend(names.iter().filter_map(|&name| self.node_to_ty(name)))
3415 Node::XhpClassAttributeDeclaration(&XhpClassAttributeDeclarationNode {
3417 xhp_attr_uses_decls,
3419 xhp_props.extend(xhp_attr_decls);
3420 xhp_attr_uses.extend(
3423 .filter_map(|&node| self.node_to_ty(node)),
3426 Node::TypeConstant(constant) => typeconsts.push(constant),
3427 Node::RequireClause(require) => match require.require_type.token_kind() {
3428 Some(TokenKind::Extends) => {
3429 req_extends.extend(self.node_to_ty(require.name).iter())
3431 Some(TokenKind::Implements) => {
3432 req_implements.extend(self.node_to_ty(require.name).iter())
3436 Node::List(&const_nodes @ [Node::Const(..), ..]) => {
3437 for node in const_nodes {
3438 if let &Node::Const(decl) = node {
3443 Node::Property(&PropertyNode { decls, is_static }) => {
3444 for property in decls {
3446 sprops.push(property)
3448 props.push(property)
3452 Node::Constructor(&ConstructorNode { method, properties }) => {
3453 constructor = Some(method);
3454 for property in properties {
3455 props.push(property)
3458 Node::Method(&MethodNode { method, is_static }) => {
3460 static_methods.push(method);
3462 methods.push(method);
3465 _ => {} // It's not our job to report errors here.
3469 props.extend(xhp_props.into_iter());
3471 let class_attributes = self.to_attributes(attributes);
3472 if class_attributes.const_ {
3473 for prop in props.iter_mut() {
3474 if !prop.flags.contains(PropFlags::CONST) {
3475 *prop = self.alloc(ShallowProp {
3476 flags: prop.flags | PropFlags::CONST,
3483 let uses = uses.into_bump_slice();
3484 let xhp_attr_uses = xhp_attr_uses.into_bump_slice();
3485 let req_extends = req_extends.into_bump_slice();
3486 let req_implements = req_implements.into_bump_slice();
3487 let consts = consts.into_bump_slice();
3488 let typeconsts = typeconsts.into_bump_slice();
3489 let props = props.into_bump_slice();
3490 let sprops = sprops.into_bump_slice();
3491 let static_methods = static_methods.into_bump_slice();
3492 let methods = methods.into_bump_slice();
3493 let user_attributes = user_attributes.into_bump_slice();
3495 let extends = self.slice(extends.iter().filter_map(|&node| self.node_to_ty(node)));
3497 let mut implements_dynamic = false;
3498 let implements = self.slice(implements.iter().filter_map(
3499 |&node| match self.node_to_ty(node) {
3500 Some(Ty(_, Ty_::Tdynamic)) => {
3501 implements_dynamic = true;
3508 // Pop the type params stack only after creating all inner types.
3509 let tparams = self.pop_type_params(tparams);
3511 let cls = self.alloc(shallow_decl_defs::ShallowClass {
3512 mode: self.file_mode,
3515 has_xhp_keyword: xhp_keyword.is_token(TokenKind::XHP),
3517 name: Id(pos, name),
3537 self.add_class(name, cls);
3539 self.classish_name_builder.parsed_classish_declaration();
3541 Node::Ignored(SK::ClassishDeclaration)
3544 fn make_property_declaration(
3549 declarators: Self::R,
3550 _semicolon: Self::R,
3552 let (attrs, modifiers, hint) = (attrs, modifiers, hint);
3553 let modifiers = read_member_modifiers(modifiers.iter());
3554 let declarators = self.slice(declarators.iter().filter_map(
3555 |declarator| match declarator {
3556 Node::ListItem(&(name, initializer)) => {
3557 let attributes = self.to_attributes(attrs);
3558 let Id(pos, name) = name.as_id()?;
3559 let name = if modifiers.is_static {
3562 strip_dollar_prefix(name)
3564 let ty = self.node_to_non_ret_ty(hint);
3565 let needs_init = if self.file_mode == Mode::Mdecl {
3568 initializer.is_ignored()
3570 let mut flags = PropFlags::empty();
3571 flags.set(PropFlags::CONST, attributes.const_);
3572 flags.set(PropFlags::LATEINIT, attributes.late_init);
3573 flags.set(PropFlags::LSB, attributes.lsb);
3574 flags.set(PropFlags::NEEDS_INIT, needs_init);
3575 flags.set(PropFlags::ABSTRACT, modifiers.is_abstract);
3576 flags.set(PropFlags::PHP_STD_LIB, attributes.php_std_lib);
3579 name: Id(pos, name),
3581 visibility: modifiers.visibility,
3585 n => panic!("Expected a ListItem, but was {:?}", n),
3588 Node::Property(self.alloc(PropertyNode {
3590 is_static: modifiers.is_static,
3594 fn make_xhp_class_attribute_declaration(
3597 attributes: Self::R,
3598 _semicolon: Self::R,
3600 let xhp_attr_decls = self.slice(attributes.iter().filter_map(|node| {
3601 let node = match node {
3602 Node::XhpClassAttribute(x) => x,
3605 let Id(pos, name) = node.name;
3606 let name = prefix_colon(self.arena, name);
3608 let type_ = self.node_to_ty(node.hint);
3609 let type_ = if node.nullable && node.tag.is_none() {
3610 type_.and_then(|x| match x {
3612 Ty(_, Ty_::Toption(_)) | Ty(_, Ty_::Tmixed) => type_,
3614 _ => self.node_to_ty(self.hint_ty(x.get_pos()?, Ty_::Toption(x))),
3619 let mut flags = PropFlags::empty();
3620 flags.set(PropFlags::NEEDS_INIT, node.needs_init);
3622 name: Id(pos, name),
3623 visibility: aast::Visibility::Public,
3625 xhp_attr: Some(shallow_decl_defs::XhpAttr {
3627 has_default: !node.needs_init,
3633 let xhp_attr_uses_decls = self.slice(attributes.iter().filter_map(|x| match x {
3634 Node::XhpAttributeUse(&name) => Some(name),
3638 Node::XhpClassAttributeDeclaration(self.alloc(XhpClassAttributeDeclarationNode {
3640 xhp_attr_uses_decls,
3644 fn make_xhp_enum_type(
3646 enum_keyword: Self::R,
3647 _left_brace: Self::R,
3648 xhp_enum_values: Self::R,
3649 right_brace: Self::R,
3651 let ty_opt = xhp_enum_values
3654 .and_then(|x| self.node_to_ty(*x));
3656 Some(ty) => self.hint_ty(self.merge_positions(enum_keyword, right_brace), ty.1),
3657 None => Node::Ignored(SK::XHPEnumType),
3661 fn make_xhp_class_attribute(
3665 initializer: Self::R,
3668 let name = match name.as_id() {
3670 None => return Node::Ignored(SK::XHPClassAttribute),
3672 Node::XhpClassAttribute(self.alloc(XhpClassAttributeNode {
3675 needs_init: !initializer.is_present(),
3676 tag: match tag.token_kind() {
3677 Some(TokenKind::Required) => Some(XhpAttrTag::Required),
3678 Some(TokenKind::Lateinit) => Some(XhpAttrTag::Lateinit),
3681 nullable: initializer.is_token(TokenKind::NullLiteral) || !initializer.is_present(),
3685 fn make_xhp_simple_class_attribute(&mut self, name: Self::R) -> Self::R {
3686 Node::XhpAttributeUse(self.alloc(name))
3689 fn make_property_declarator(&mut self, name: Self::R, initializer: Self::R) -> Self::R {
3690 Node::ListItem(self.alloc((name, initializer)))
3693 fn make_methodish_declaration(
3695 attributes: Self::R,
3700 let header = match header {
3701 Node::FunctionHeader(header) => header,
3702 n => panic!("Expected a FunctionDecl header, but was {:?}", n),
3704 // If we don't have a body, use the closing token. A closing token of
3705 // '}' indicates a regular function, while a closing token of ';'
3706 // indicates an abstract function.
3707 let body = if body.is_ignored() { closer } else { body };
3708 let modifiers = read_member_modifiers(header.modifiers.iter());
3709 let is_constructor = header.name.is_token(TokenKind::Construct);
3710 let is_method = true;
3711 let (id, ty, properties) = match self.function_to_ty(is_method, attributes, header, body) {
3712 Some(tuple) => tuple,
3713 None => return Node::Ignored(SK::MethodishDeclaration),
3715 let attributes = self.to_attributes(attributes);
3716 let deprecated = attributes.deprecated.map(|msg| {
3717 let mut s = String::new_in(self.arena);
3718 s.push_str("The method ");
3720 s.push_str(" is deprecated: ");
3724 fn get_condition_type_name<'a>(ty_opt: Option<&'a Ty<'a>>) -> Option<&'a str> {
3725 ty_opt.and_then(|ty| {
3726 let Ty(_, ty_) = ty;
3728 Ty_::Tapply(&(Id(_, class_name), _)) => Some(class_name),
3733 let mut flags = MethodFlags::empty();
3735 MethodFlags::ABSTRACT,
3736 self.classish_name_builder.in_interface() || modifiers.is_abstract,
3738 flags.set(MethodFlags::FINAL, modifiers.is_final);
3739 flags.set(MethodFlags::OVERRIDE, attributes.override_);
3741 MethodFlags::DYNAMICALLYCALLABLE,
3742 attributes.dynamically_callable,
3744 flags.set(MethodFlags::PHP_STD_LIB, attributes.php_std_lib);
3745 let method = self.alloc(ShallowMethod {
3747 reactivity: match attributes.reactivity {
3748 Reactivity::Local(condition_type) => Some(MethodReactivity::MethodLocal(
3749 get_condition_type_name(condition_type),
3751 Reactivity::Shallow(condition_type) => Some(MethodReactivity::MethodShallow(
3752 get_condition_type_name(condition_type),
3754 Reactivity::Reactive(condition_type) => Some(MethodReactivity::MethodReactive(
3755 get_condition_type_name(condition_type),
3757 Reactivity::Pure(condition_type) => Some(MethodReactivity::MethodPure(
3758 get_condition_type_name(condition_type),
3760 Reactivity::Nonreactive
3761 | Reactivity::MaybeReactive(_)
3762 | Reactivity::RxVar(_)
3763 | Reactivity::Cipp(_)
3764 | Reactivity::CippLocal(_)
3765 | Reactivity::CippGlobal
3766 | Reactivity::CippRx => None,
3769 visibility: modifiers.visibility,
3774 Node::Constructor(self.alloc(ConstructorNode { method, properties }))
3776 Node::Method(self.alloc(MethodNode {
3778 is_static: modifiers.is_static,
3783 fn make_classish_body(
3785 _left_brace: Self::R,
3787 _right_brace: Self::R,
3789 Node::ClassishBody(self.alloc(elements.as_slice(self.arena)))
3792 fn make_enum_declaration(
3794 attributes: Self::R,
3799 constraint: Self::R,
3800 _left_brace: Self::R,
3801 use_clauses: Self::R,
3802 enumerators: Self::R,
3803 _right_brace: Self::R,
3805 let id = match self.elaborate_defined_id(name) {
3807 None => return Node::Ignored(SK::EnumDeclaration),
3809 let hint = match self.node_to_ty(extends) {
3811 None => return Node::Ignored(SK::EnumDeclaration),
3813 let extends = match self.node_to_ty(self.make_apply(
3814 Id(self.get_pos(name), "\\HH\\BuiltinEnum"),
3819 None => return Node::Ignored(SK::EnumDeclaration),
3822 let consts = self.slice(enumerators.iter().filter_map(|node| match node {
3823 Node::ListItem(&(name, value)) => {
3824 let id = name.as_id()?;
3826 self.alloc(shallow_decl_defs::ShallowClassConst {
3830 .infer_const(name, value)
3831 .unwrap_or_else(|| self.tany_with_pos(id.0)),
3835 n => panic!("Expected an enum case, got {:?}", n),
3838 let mut user_attributes = Vec::with_capacity_in(attributes.len(), self.arena);
3839 for attribute in attributes.iter() {
3841 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(attr)),
3845 // Match ordering of attributes produced by the OCaml decl parser (even
3846 // though it's the reverse of the syntactic ordering).
3847 user_attributes.reverse();
3848 let user_attributes = user_attributes.into_bump_slice();
3850 let constraint = match constraint {
3851 Node::TypeConstraint(&(_kind, ty)) => self.node_to_ty(ty),
3855 let includes = self.slice(use_clauses.iter().filter_map(|&node| self.node_to_ty(node)));
3857 let cls = self.alloc(shallow_decl_defs::ShallowClass {
3858 mode: self.file_mode,
3861 has_xhp_keyword: false,
3862 kind: ClassKind::Cenum,
3865 where_constraints: &[],
3866 extends: bumpalo::vec![in self.arena; extends].into_bump_slice(),
3870 req_implements: &[],
3872 implements_dynamic: false,
3878 static_methods: &[],
3881 enum_type: Some(self.alloc(EnumType {
3888 self.add_class(key, cls);
3890 self.classish_name_builder.parsed_classish_declaration();
3892 Node::Ignored(SK::EnumDeclaration)
3900 _semicolon: Self::R,
3902 Node::ListItem(self.alloc((name, value)))
3905 fn make_enum_class_declaration(
3907 attributes: Self::R,
3908 _enum_keyword: Self::R,
3909 _class_keyword: Self::R,
3913 _extends_keyword: Self::R,
3914 extends_list: Self::R,
3915 _left_brace: Self::R,
3917 _right_brace: Self::R,
3919 let name = match self.elaborate_defined_id(name) {
3921 None => return Node::Ignored(SyntaxKind::EnumClassDeclaration),
3925 .unwrap_or_else(|| self.tany_with_pos(name.0));
3927 let builtin_enum_class_ty = {
3929 let enum_class_ty_ = Ty_::Tapply(self.alloc((name, &[])));
3930 let enum_class_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), enum_class_ty_));
3931 let elt_ty_ = Ty_::Tapply(self.alloc((
3932 Id(pos, "\\HH\\MemberOf"),
3933 bumpalo::vec![in self.arena; enum_class_ty, base].into_bump_slice(),
3935 let elt_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), elt_ty_));
3936 let builtin_enum_ty_ = Ty_::Tapply(self.alloc((
3937 Id(pos, "\\HH\\BuiltinEnumClass"),
3938 std::slice::from_ref(self.alloc(elt_ty)),
3940 self.alloc(Ty(self.alloc(Reason::hint(pos)), builtin_enum_ty_))
3943 let consts = self.slice(elements.iter().filter_map(|node| match node {
3944 &Node::Const(const_) => Some(const_),
3948 let mut extends = Vec::with_capacity_in(extends_list.len() + 1, self.arena);
3949 extends.push(builtin_enum_class_ty);
3950 extends.extend(extends_list.iter().filter_map(|&n| self.node_to_ty(n)));
3951 let extends = extends.into_bump_slice();
3952 let includes = &extends[1..];
3954 let mut user_attributes = Vec::with_capacity_in(attributes.len() + 1, self.arena);
3955 user_attributes.push(self.alloc(shallow_decl_defs::UserAttribute {
3956 name: Id(name.0, "__EnumClass"),
3957 classname_params: &[],
3959 for attribute in attributes.iter() {
3961 Node::Attribute(attr) => user_attributes.push(self.user_attribute_to_decl(attr)),
3965 // Match ordering of attributes produced by the OCaml decl parser (even
3966 // though it's the reverse of the syntactic ordering).
3967 user_attributes.reverse();
3968 let user_attributes = user_attributes.into_bump_slice();
3970 let cls = self.alloc(shallow_decl_defs::ShallowClass {
3971 mode: self.file_mode,
3974 has_xhp_keyword: false,
3975 kind: ClassKind::Cenum,
3978 where_constraints: &[],
3983 req_implements: &[],
3985 implements_dynamic: false,
3991 static_methods: &[],
3994 enum_type: Some(self.alloc(EnumType {
4001 self.add_class(name.1, cls);
4003 self.classish_name_builder.parsed_classish_declaration();
4005 Node::Ignored(SyntaxKind::EnumClassDeclaration)
4008 fn make_enum_class_enumerator(
4013 _initial_value: Self::R,
4014 _semicolon: Self::R,
4016 let name = match self.expect_name(name) {
4018 None => return Node::Ignored(SyntaxKind::EnumClassEnumerator),
4023 .unwrap_or_else(|| self.tany_with_pos(name.0));
4024 let class_name = match self.classish_name_builder.get_current_classish_name() {
4026 None => return Node::Ignored(SyntaxKind::EnumClassEnumerator),
4028 let enum_class_ty_ = Ty_::Tapply(self.alloc((Id(pos, class_name.0), &[])));
4029 let enum_class_ty = self.alloc(Ty(self.alloc(Reason::hint(pos)), enum_class_ty_));
4030 let type_ = Ty_::Tapply(self.alloc((
4031 Id(pos, "\\HH\\MemberOf"),
4032 bumpalo::vec![in self.arena; enum_class_ty, type_].into_bump_slice(),
4034 let type_ = self.alloc(Ty(self.alloc(Reason::hint(pos)), type_));
4035 Node::Const(self.alloc(ShallowClassConst {
4042 fn make_tuple_type_specifier(
4044 left_paren: Self::R,
4046 right_paren: Self::R,
4048 // We don't need to include the tys list in this position merging
4049 // because by definition it's already contained by the two brackets.
4050 let pos = self.merge_positions(left_paren, right_paren);
4051 let tys = self.slice(tys.iter().filter_map(|&node| self.node_to_ty(node)));
4052 self.hint_ty(pos, Ty_::Ttuple(tys))
4055 fn make_tuple_type_explicit_specifier(
4058 _left_angle: Self::R,
4060 right_angle: Self::R,
4062 let id = Id(self.get_pos(keyword), "\\tuple");
4063 // This is an error--tuple syntax is (A, B), not tuple<A, B>.
4064 // OCaml decl makes a Tapply rather than a Ttuple here.
4065 self.make_apply(id, types, self.get_pos(right_angle))
4068 fn make_intersection_type_specifier(
4070 left_paren: Self::R,
4072 right_paren: Self::R,
4074 let pos = self.merge_positions(left_paren, right_paren);
4075 let tys = self.slice(tys.iter().filter_map(|x| match x {
4076 Node::ListItem(&(ty, _ampersand)) => self.node_to_ty(ty),
4077 &x => self.node_to_ty(x),
4079 self.hint_ty(pos, Ty_::Tintersection(tys))
4082 fn make_union_type_specifier(
4084 left_paren: Self::R,
4086 right_paren: Self::R,
4088 let pos = self.merge_positions(left_paren, right_paren);
4089 let tys = self.slice(tys.iter().filter_map(|x| match x {
4090 Node::ListItem(&(ty, _bar)) => self.node_to_ty(ty),
4091 &x => self.node_to_ty(x),
4093 self.hint_ty(pos, Ty_::Tunion(tys))
4096 fn make_shape_type_specifier(
4104 let fields = fields;
4105 let fields_iter = fields.iter();
4106 let mut fields = AssocListMut::new_in(self.arena);
4107 for node in fields_iter {
4109 &Node::ShapeFieldSpecifier(&ShapeFieldNode { name, type_ }) => {
4110 fields.insert(*name, type_)
4112 n => panic!("Expected a shape field specifier, but was {:?}", n),
4115 let kind = match open.token_kind() {
4116 Some(TokenKind::DotDotDot) => ShapeKind::OpenShape,
4117 _ => ShapeKind::ClosedShape,
4119 let pos = self.merge_positions(shape, rparen);
4120 self.hint_ty(pos, Ty_::Tshape(self.alloc((kind, fields.into()))))
4123 fn make_shape_expression(
4126 _left_paren: Self::R,
4128 right_paren: Self::R,
4130 let fields = self.slice(fields.iter().filter_map(|node| match node {
4131 Node::ListItem(&(key, value)) => {
4132 let key = self.make_shape_field_name(key)?;
4133 let value = self.node_to_expr(value)?;
4136 n => panic!("Expected a ListItem but was {:?}", n),
4138 Node::Expr(self.alloc(aast::Expr(
4139 self.merge_positions(shape, right_paren),
4140 nast::Expr_::Shape(fields),
4144 fn make_tuple_expression(
4147 _left_paren: Self::R,
4149 right_paren: Self::R,
4151 let fields = self.slice(fields.iter().filter_map(|&field| self.node_to_expr(field)));
4152 Node::Expr(self.alloc(aast::Expr(
4153 self.merge_positions(tuple, right_paren),
4154 nast::Expr_::List(fields),
4158 fn make_classname_type_specifier(
4163 _trailing_comma: Self::R,
4166 let id = match classname.as_id() {
4168 None => return Node::Ignored(SK::ClassnameTypeSpecifier),
4170 if gt.is_ignored() {
4171 self.prim_ty(aast::Tprim::Tstring, id.0)
4174 Id(id.0, self.elaborate_raw_id(id.1)),
4176 self.merge_positions(classname, gt),
4181 fn make_scope_resolution_expression(
4183 class_name: Self::R,
4187 let pos = self.merge_positions(class_name, value);
4188 let Id(class_name_pos, class_name_str) = match self.expect_name(class_name) {
4189 Some(id) => self.elaborate_id(id),
4190 None => return Node::Ignored(SK::ScopeResolutionExpression),
4192 let class_id = self.alloc(aast::ClassId(
4195 Node::Name(("self", _)) => aast::ClassId_::CIself,
4196 _ => aast::ClassId_::CI(self.alloc(Id(class_name_pos, class_name_str))),
4199 let value_id = match self.expect_name(value) {
4201 None => return Node::Ignored(SK::ScopeResolutionExpression),
4203 Node::Expr(self.alloc(aast::Expr(
4205 nast::Expr_::ClassConst(self.alloc((class_id, self.alloc((value_id.0, value_id.1))))),
4209 fn make_field_specifier(
4211 question_token: Self::R,
4216 let optional = question_token.is_present();
4217 let ty = match self.node_to_ty(type_) {
4219 None => return Node::Ignored(SK::FieldSpecifier),
4221 let name = match self.make_shape_field_name(name) {
4223 None => return Node::Ignored(SK::FieldSpecifier),
4225 Node::ShapeFieldSpecifier(self.alloc(ShapeFieldNode {
4226 name: self.alloc(ShapeField(name)),
4227 type_: self.alloc(ShapeFieldType { optional, ty }),
4231 fn make_field_initializer(&mut self, key: Self::R, _arrow: Self::R, value: Self::R) -> Self::R {
4232 Node::ListItem(self.alloc((key, value)))
4235 fn make_varray_type_specifier(
4237 varray_keyword: Self::R,
4238 _less_than: Self::R,
4240 _trailing_comma: Self::R,
4241 greater_than: Self::R,
4243 let tparam = match self.node_to_ty(tparam) {
4245 None => self.tany_with_pos(self.get_pos(varray_keyword)),
4248 self.merge_positions(varray_keyword, greater_than),
4249 Ty_::Tvarray(tparam),
4253 fn make_darray_type_specifier(
4256 _less_than: Self::R,
4259 value_type: Self::R,
4260 _trailing_comma: Self::R,
4261 greater_than: Self::R,
4263 let pos = self.merge_positions(darray, greater_than);
4264 let key_type = self.node_to_ty(key_type).unwrap_or(TANY);
4265 let value_type = self.node_to_ty(value_type).unwrap_or(TANY);
4266 self.hint_ty(pos, Ty_::Tdarray(self.alloc((key_type, value_type))))
4269 fn make_old_attribute_specification(
4276 Node::List(nodes) => {
4277 Node::BracketedList(self.alloc((self.get_pos(ltlt), nodes, self.get_pos(gtgt))))
4280 "Expected List in old_attribute_specification, but got {:?}",
4286 fn make_constructor_call(
4289 _left_paren: Self::R,
4291 _right_paren: Self::R,
4293 let unqualified_name = match self.expect_name(name) {
4295 None => return Node::Ignored(SK::ConstructorCall),
4297 let name = if unqualified_name.1.starts_with("__") {
4300 match self.expect_name(name) {
4301 Some(name) => self.elaborate_id(name),
4302 None => return Node::Ignored(SK::ConstructorCall),
4305 let classname_params = self.slice(args.iter().filter_map(|node| match node {
4306 Node::Expr(aast::Expr(
4308 aast::Expr_::ClassConst(&(
4309 aast::ClassId(_, aast::ClassId_::CI(&Id(pos, class_name))),
4313 let name = self.elaborate_id(Id(pos, class_name));
4314 Some(ClassNameParam { name, full_pos })
4319 let string_literal_params = if match name.1 {
4320 "__Deprecated" | "__Cipp" | "__CippLocal" | "__Policied" => true,
4323 fn fold_string_concat<'a>(expr: &nast::Expr<'a>, acc: &mut Vec<'a, u8>) {
4325 &aast::Expr(_, aast::Expr_::String(val)) => acc.extend_from_slice(val),
4326 &aast::Expr(_, aast::Expr_::Binop(&(Bop::Dot, e1, e2))) => {
4327 fold_string_concat(&e1, acc);
4328 fold_string_concat(&e2, acc);
4334 self.slice(args.iter().filter_map(|expr| match expr {
4335 Node::StringLiteral((x, _)) => Some(*x),
4336 Node::Expr(e @ aast::Expr(_, aast::Expr_::Binop(_))) => {
4337 let mut acc = Vec::new_in(self.arena);
4338 fold_string_concat(e, &mut acc);
4339 Some(acc.into_bump_slice().into())
4347 Node::Attribute(self.alloc(UserAttributeNode {
4350 string_literal_params,
4358 _semicolon: Self::R,
4360 Node::TraitUse(self.alloc(names))
4363 fn make_trait_use_conflict_resolution(
4367 _left_brace: Self::R,
4369 _right_brace: Self::R,
4371 Node::TraitUse(self.alloc(names))
4374 fn make_require_clause(
4377 require_type: Self::R,
4379 _semicolon: Self::R,
4381 Node::RequireClause(self.alloc(RequireClause { require_type, name }))
4384 fn make_nullable_type_specifier(&mut self, question_mark: Self::R, hint: Self::R) -> Self::R {
4385 let pos = self.merge_positions(question_mark, hint);
4386 let ty = match self.node_to_ty(hint) {
4388 None => return Node::Ignored(SK::NullableTypeSpecifier),
4390 self.hint_ty(pos, Ty_::Toption(ty))
4393 fn make_like_type_specifier(&mut self, tilde: Self::R, hint: Self::R) -> Self::R {
4394 let pos = self.merge_positions(tilde, hint);
4395 let ty = match self.node_to_ty(hint) {
4397 None => return Node::Ignored(SK::LikeTypeSpecifier),
4399 self.hint_ty(pos, Ty_::Tlike(ty))
4402 fn make_closure_type_specifier(
4404 outer_left_paren: Self::R,
4405 _function_keyword: Self::R,
4406 _inner_left_paren: Self::R,
4407 parameter_list: Self::R,
4408 _inner_right_paren: Self::R,
4409 capability: Self::R,
4411 return_type: Self::R,
4412 outer_right_paren: Self::R,
4414 let make_param = |fp: &'a FunParamDecl<'a>| -> &'a FunParam<'a> {
4415 let mut flags = FunParamFlags::empty();
4416 let (hint, mutability) = Self::unwrap_mutability(fp.hint);
4417 flags |= Self::param_mutability_to_fun_param_flags(mutability);
4420 ParamMode::FPinout => {
4421 flags |= FunParamFlags::INOUT;
4423 ParamMode::FPnormal => {}
4426 self.alloc(FunParam {
4427 pos: self.get_pos(hint),
4429 type_: self.alloc(PossiblyEnforcedTy {
4431 type_: self.node_to_ty(hint).unwrap_or_else(|| tany()),
4434 rx_annotation: None,
4438 let arity = parameter_list
4440 .find_map(|&node| match node {
4441 Node::FunParam(fp) if fp.variadic => Some(FunArity::Fvariadic(make_param(fp))),
4444 .unwrap_or(FunArity::Fstandard);
4446 let params = self.slice(parameter_list.iter().filter_map(|&node| match node {
4447 Node::FunParam(fp) if !fp.variadic => Some(make_param(fp)),
4451 let (hint, mutability) = Self::unwrap_mutability(return_type);
4452 let ret = match self.node_to_ty(hint) {
4454 None => return Node::Ignored(SK::ClosureTypeSpecifier),
4456 let pos = self.merge_positions(outer_left_paren, outer_right_paren);
4457 let implicit_params = self.as_fun_implicit_params(capability, pos);
4459 let mut flags = FunTypeFlags::empty();
4460 if mutability.is_some() {
4461 flags |= FunTypeFlags::RETURNS_MUTABLE;
4466 Ty_::Tfun(self.alloc(FunType {
4469 where_constraints: &[],
4472 ret: self.alloc(PossiblyEnforcedTy {
4476 reactive: Reactivity::Nonreactive,
4478 ifc_decl: default_ifc_fun_decl(),
4483 fn make_closure_parameter_type_specifier(&mut self, inout: Self::R, hint: Self::R) -> Self::R {
4484 let kind = if inout.is_token(TokenKind::Inout) {
4489 Node::FunParam(self.alloc(FunParamDecl {
4490 attributes: Node::Ignored(SK::Missing),
4491 visibility: Node::Ignored(SK::Missing),
4494 pos: self.get_pos(hint),
4497 initializer: Node::Ignored(SK::Missing),
4501 fn make_type_const_declaration(
4503 attributes: Self::R,
4505 _const_keyword: Self::R,
4506 _type_keyword: Self::R,
4508 _type_parameters: Self::R,
4509 constraint: Self::R,
4512 _semicolon: Self::R,
4514 let attributes = self.to_attributes(attributes);
4515 let has_abstract_keyword = modifiers
4517 .any(|node| node.is_token(TokenKind::Abstract));
4518 let constraint = match constraint {
4519 Node::TypeConstraint(innards) => self.node_to_ty(innards.1),
4522 let type_ = self.node_to_ty(type_);
4523 let has_constraint = constraint.is_some();
4524 let has_type = type_.is_some();
4525 let (type_, abstract_) = match (has_abstract_keyword, has_constraint, has_type) {
4526 // Has no assigned type. Technically illegal, so if the constraint
4527 // is present, proceed as if the constraint was the assigned type.
4529 // const type TFoo as OtherType;
4530 (false, _, false) => (constraint, TypeconstAbstractKind::TCConcrete),
4531 // Has no constraint, but does have an assigned type.
4532 // const type TFoo = SomeType;
4533 (false, false, true) => (type_, TypeconstAbstractKind::TCConcrete),
4534 // Has both a constraint and an assigned type.
4535 // const type TFoo as OtherType = SomeType;
4536 (false, true, true) => (type_, TypeconstAbstractKind::TCPartiallyAbstract),
4537 // Has no default type.
4538 // abstract const type TFoo;
4539 // abstract const type TFoo as OtherType;
4540 (true, _, false) => (type_, TypeconstAbstractKind::TCAbstract(None)),
4541 // Has a default type.
4542 // abstract const Type TFoo = SomeType;
4543 // abstract const Type TFoo as OtherType = SomeType;
4544 (true, _, true) => (None, TypeconstAbstractKind::TCAbstract(type_)),
4546 let name = match name.as_id() {
4548 None => return Node::Ignored(SK::TypeConstDeclaration),
4550 Node::TypeConstant(self.alloc(ShallowTypeconst {
4555 enforceable: match attributes.enforceable {
4556 Some(pos) => (pos, true),
4557 None => (Pos::none(), false),
4559 reifiable: attributes.reifiable,
4563 fn make_decorated_expression(&mut self, decorator: Self::R, expr: Self::R) -> Self::R {
4564 Node::ListItem(self.alloc((decorator, expr)))
4567 fn make_type_constant(
4570 _coloncolon: Self::R,
4571 constant_name: Self::R,
4573 let id = match self.expect_name(constant_name) {
4575 None => return Node::Ignored(SK::TypeConstant),
4577 let pos = self.merge_positions(ty, constant_name);
4578 let ty = match (ty, self.classish_name_builder.get_current_classish_name()) {
4579 (Node::Name(("self", self_pos)), Some((name, class_name_pos))) => {
4580 // In classes, we modify the position when rewriting the
4581 // `self` keyword to point to the class name. In traits,
4582 // we don't (because traits are not types). We indicate
4583 // that the position shouldn't be rewritten with the
4585 let id_pos = if class_name_pos.is_none() {
4590 let reason = self.alloc(Reason::hint(self_pos));
4591 let ty_ = Ty_::Tapply(self.alloc((Id(id_pos, name), &[][..])));
4592 self.alloc(Ty(reason, ty_))
4594 _ => match self.node_to_ty(ty) {
4596 None => return Node::Ignored(SK::TypeConstant),
4599 let reason = self.alloc(Reason::hint(pos));
4600 // The reason-rewriting here is only necessary to match the
4601 // behavior of OCaml decl (which flattens and then unflattens
4602 // Haccess hints, losing some position information).
4603 let ty = self.rewrite_taccess_reasons(ty, reason);
4604 Node::Ty(self.alloc(Ty(reason, Ty_::Taccess(self.alloc(TaccessType(ty, id))))))
4607 fn make_soft_type_specifier(&mut self, at_token: Self::R, hint: Self::R) -> Self::R {
4608 let pos = self.merge_positions(at_token, hint);
4609 let hint = match self.node_to_ty(hint) {
4611 None => return Node::Ignored(SK::SoftTypeSpecifier),
4613 // Use the type of the hint as-is (i.e., throw away the knowledge that
4614 // we had a soft type specifier here--the typechecker does not use it).
4615 // Replace its Reason with one including the position of the `@` token.
4616 self.hint_ty(pos, hint.1)
4619 // A type specifier preceded by an attribute list. At the time of writing,
4620 // only the <<__Soft>> attribute is permitted here.
4621 fn make_attributized_specifier(&mut self, attributes: Self::R, hint: Self::R) -> Self::R {
4623 Node::BracketedList((
4625 [Node::Attribute(UserAttributeNode {
4626 name: Id(_, "__Soft"),
4631 let attributes_pos = self.merge(*ltlt_pos, *gtgt_pos);
4632 let hint_pos = self.get_pos(hint);
4633 // Use the type of the hint as-is (i.e., throw away the
4634 // knowledge that we had a soft type specifier here--the
4635 // typechecker does not use it). Replace its Reason with one
4636 // including the position of the attribute list.
4637 let hint = match self.node_to_ty(hint) {
4639 None => return Node::Ignored(SK::AttributizedSpecifier),
4641 self.hint_ty(self.merge(attributes_pos, hint_pos), hint.1)
4647 fn make_vector_type_specifier(
4650 _left_angle: Self::R,
4652 _trailing_comma: Self::R,
4653 right_angle: Self::R,
4655 let id = match self.expect_name(vec) {
4657 None => return Node::Ignored(SK::VectorTypeSpecifier),
4659 let id = Id(id.0, self.elaborate_raw_id(id.1));
4660 self.make_apply(id, hint, self.get_pos(right_angle))
4663 fn make_dictionary_type_specifier(
4666 _left_angle: Self::R,
4667 type_arguments: Self::R,
4668 right_angle: Self::R,
4670 let id = match self.expect_name(dict) {
4672 None => return Node::Ignored(SK::DictionaryTypeSpecifier),
4674 let id = Id(id.0, self.elaborate_raw_id(id.1));
4675 self.make_apply(id, type_arguments, self.get_pos(right_angle))
4678 fn make_keyset_type_specifier(
4681 _left_angle: Self::R,
4683 _trailing_comma: Self::R,
4684 right_angle: Self::R,
4686 let id = match self.expect_name(keyset) {
4688 None => return Node::Ignored(SK::KeysetTypeSpecifier),
4690 let id = Id(id.0, self.elaborate_raw_id(id.1));
4691 self.make_apply(id, hint, self.get_pos(right_angle))
4694 fn make_variable_expression(&mut self, _expression: Self::R) -> Self::R {
4695 Node::Ignored(SK::VariableExpression)
4698 fn make_subscript_expression(
4701 _left_bracket: Self::R,
4703 _right_bracket: Self::R,
4705 Node::Ignored(SK::SubscriptExpression)
4708 fn make_member_selection_expression(
4714 Node::Ignored(SK::MemberSelectionExpression)
4717 fn make_object_creation_expression(
4719 _new_keyword: Self::R,
4722 Node::Ignored(SK::ObjectCreationExpression)
4725 fn make_safe_member_selection_expression(
4731 Node::Ignored(SK::SafeMemberSelectionExpression)
4734 fn make_function_call_expression(
4737 _type_args: Self::R,
4738 _left_paren: Self::R,
4739 _argument_list: Self::R,
4740 _right_paren: Self::R,
4742 Node::Ignored(SK::FunctionCallExpression)
4745 fn make_list_expression(
4748 _left_paren: Self::R,
4750 _right_paren: Self::R,
4752 Node::Ignored(SK::ListExpression)