Remove positive is_typechecker guards
[hiphop-php.git] / hphp / hack / src / hhbc / emitter / instruction_sequence.rs
blob1c90bd045ee8da24218f5720f28e303aabbc82ba
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use ffi::{
7     BumpSliceMut,
8     Maybe::{self, Just, Nothing},
9     Pair, Slice, Str,
11 use hhbc_ast::*;
12 use iterator::Id as IterId;
13 use label::Label;
14 use local::Local;
15 use oxidized::ast_defs::Pos;
16 use runtime::TypedValue;
17 use thiserror::Error;
19 pub type Result<T> = std::result::Result<T, Error>;
21 #[derive(Error, Debug)]
22 pub enum Error {
23     #[error("IncludeTimeFatalException: FatalOp={0:?}, {1}")]
24     IncludeTimeFatalException(FatalOp, Pos, std::string::String),
26     #[error("Unrecoverable: {0}")]
27     Unrecoverable(std::string::String),
30 pub fn unrecoverable(msg: impl std::convert::Into<std::string::String>) -> Error {
31     Error::Unrecoverable(msg.into())
34 /// The various from_X functions below take some kind of AST
35 /// (expression, statement, etc.) and produce what is logically a
36 /// sequence of instructions. This could be represented by a list, but
37 /// we wish to avoid the quadratic complexity associated with repeated
38 /// appending. So, we build a tree of instructions which can be
39 /// flattened when complete.
40 #[derive(Debug)]
41 #[repr(C)]
42 pub enum InstrSeq<'a> {
43     List(BumpSliceMut<'a, Instruct<'a>>),
44     Concat(BumpSliceMut<'a, InstrSeq<'a>>),
46 // The slices are mutable because of `rewrite_user_labels`. This means
47 // we can't derive `Clone` (because you can't have multiple mutable
48 // references referring to the same resource). It is possible to implement
49 // deep copy functionality though: see `InstrSeq::clone()` below.
51 impl<'a> std::convert::From<(&'a bumpalo::Bump, (InstrSeq<'a>, InstrSeq<'a>))> for InstrSeq<'a> {
52     fn from((alloc, (i1, i2)): (&'a bumpalo::Bump, (InstrSeq<'a>, InstrSeq<'a>))) -> InstrSeq<'a> {
53         InstrSeq::gather(alloc, vec![i1, i2])
54     }
57 #[derive(Debug)]
58 pub struct CompactIter<'i, 'a, I>
59 where
60     I: Iterator<Item = &'i Instruct<'a>>,
62     iter: I,
63     next: Option<&'i Instruct<'a>>,
66 impl<'i, 'a, I> CompactIter<'i, 'a, I>
67 where
68     I: Iterator<Item = &'i Instruct<'a>>,
70     pub fn new(i: I) -> Self {
71         Self {
72             iter: i,
73             next: None,
74         }
75     }
78 impl<'i, 'a, I> Iterator for CompactIter<'i, 'a, I>
79 where
80     I: Iterator<Item = &'i Instruct<'a>>,
82     type Item = &'i Instruct<'a>;
83     fn next(&mut self) -> Option<Self::Item> {
84         if self.next.is_some() {
85             std::mem::replace(&mut self.next, None)
86         } else {
87             let mut cur = self.iter.next();
88             match cur {
89                 Some(i) if InstrSeq::is_srcloc(i) => {
90                     self.next = self.iter.next();
91                     while self.next.map_or(false, InstrSeq::is_srcloc) {
92                         cur = self.next;
93                         self.next = self.iter.next();
94                     }
95                     cur
96                 }
97                 _ => cur,
98             }
99         }
100     }
103 #[derive(Debug)]
104 pub struct InstrIter<'i, 'a> {
105     instr_seq: &'i InstrSeq<'a>,
106     index: usize,
107     concat_stack: std::vec::Vec<
108         itertools::Either<
109             (&'i BumpSliceMut<'a, Instruct<'a>>, usize),
110             (&'i BumpSliceMut<'a, InstrSeq<'a>>, usize),
111         >,
112     >,
115 impl<'i, 'a> InstrIter<'i, 'a> {
116     pub fn new(instr_seq: &'i InstrSeq<'a>) -> Self {
117         Self {
118             instr_seq,
119             index: 0,
120             concat_stack: std::vec::Vec::new(),
121         }
122     }
125 impl<'i, 'a> Iterator for InstrIter<'i, 'a> {
126     type Item = &'i Instruct<'a>;
127     fn next(&mut self) -> Option<Self::Item> {
128         //self: & mut InstrIter<'i, 'a>
129         //self.instr_seq: &'i InstrSeq<'a>
130         match self.instr_seq {
131             InstrSeq::List(s) if s.is_empty() => None,
132             InstrSeq::List(s) if s.len() == 1 && self.index > 0 => None,
133             InstrSeq::List(s) if s.len() == 1 => {
134                 self.index += 1;
135                 s.get(0)
136             }
137             InstrSeq::List(s) if s.len() > 1 && self.index >= s.len() => None,
138             InstrSeq::List(s) => {
139                 let r = s.get(self.index);
140                 self.index += 1;
141                 r
142             }
143             InstrSeq::Concat(s) => {
144                 if self.concat_stack.is_empty() {
145                     if self.index == 0 {
146                         self.index += 1;
147                         self.concat_stack.push(itertools::Either::Right((s, 0)));
148                     } else {
149                         return None;
150                     }
151                 }
153                 while !self.concat_stack.is_empty() {
154                     let top: &mut itertools::Either<_, _> = self.concat_stack.last_mut().unwrap();
155                     match top {
156                         itertools::Either::Left((list, size)) if *size >= list.len() => {
157                             self.concat_stack.pop();
158                         }
159                         itertools::Either::Left((list, size)) => {
160                             let r: Option<&'i Instruct<'a>> = list.get(*size);
161                             *size += 1;
162                             return r;
163                         }
164                         itertools::Either::Right((concat, size)) if *size >= concat.len() => {
165                             self.concat_stack.pop();
166                         }
167                         itertools::Either::Right((concat, size)) => {
168                             let i: &'i InstrSeq<'a> = &(concat[*size]);
169                             *size += 1;
170                             match i {
171                                 InstrSeq::List(s) if s.is_empty() => {}
172                                 InstrSeq::List(s) if s.len() == 1 => {
173                                     return s.get(0);
174                                 }
175                                 InstrSeq::List(s) => {
176                                     self.concat_stack.push(itertools::Either::Left((s, 0)));
177                                 }
178                                 InstrSeq::Concat(s) => {
179                                     self.concat_stack.push(itertools::Either::Right((s, 0)));
180                                 }
181                             }
182                         }
183                     }
184                 }
185                 None
186             }
187         }
188     }
191 #[allow(clippy::needless_lifetimes)]
192 pub mod instr {
193     use crate::*;
195     pub fn empty<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
196         InstrSeq::new_empty(alloc)
197     }
199     pub fn instr<'a>(alloc: &'a bumpalo::Bump, i: Instruct<'a>) -> InstrSeq<'a> {
200         InstrSeq::new_singleton(alloc, i)
201     }
203     pub fn instrs<'a>(alloc: &'a bumpalo::Bump, is: &'a mut [Instruct<'a>]) -> InstrSeq<'a> {
204         InstrSeq::new_list(alloc, is)
205     }
207     pub fn lit_const<'a>(alloc: &'a bumpalo::Bump, l: InstructLitConst<'a>) -> InstrSeq<'a> {
208         instr(alloc, Instruct::ILitConst(l))
209     }
211     pub fn iterinit<'a>(
212         alloc: &'a bumpalo::Bump,
213         args: IterArgs<'a>,
214         label: Label,
215     ) -> InstrSeq<'a> {
216         instr(
217             alloc,
218             Instruct::IIterator(InstructIterator::IterInit(args, label)),
219         )
220     }
222     pub fn iternext<'a>(
223         alloc: &'a bumpalo::Bump,
224         args: IterArgs<'a>,
225         label: Label,
226     ) -> InstrSeq<'a> {
227         instr(
228             alloc,
229             Instruct::IIterator(InstructIterator::IterNext(args, label)),
230         )
231     }
233     pub fn iternextk<'a>(
234         alloc: &'a bumpalo::Bump,
235         id: IterId,
236         label: Label,
237         value: Local<'a>,
238         key: Local<'a>,
239     ) -> InstrSeq<'a> {
240         let args = IterArgs {
241             iter_id: id,
242             key_id: Just(key),
243             val_id: value,
244         };
245         instr(
246             alloc,
247             Instruct::IIterator(InstructIterator::IterNext(args, label)),
248         )
249     }
251     pub fn iterfree<'a>(alloc: &'a bumpalo::Bump, id: IterId) -> InstrSeq<'a> {
252         instr(alloc, Instruct::IIterator(InstructIterator::IterFree(id)))
253     }
255     pub fn whresult<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
256         instr(alloc, Instruct::IAsync(AsyncFunctions::WHResult))
257     }
259     pub fn jmp<'a>(alloc: &'a bumpalo::Bump, label: Label) -> InstrSeq<'a> {
260         instr(alloc, Instruct::IContFlow(InstructControlFlow::Jmp(label)))
261     }
263     pub fn jmpz<'a>(alloc: &'a bumpalo::Bump, label: Label) -> InstrSeq<'a> {
264         instr(alloc, Instruct::IContFlow(InstructControlFlow::JmpZ(label)))
265     }
267     pub fn jmpnz<'a>(alloc: &'a bumpalo::Bump, label: Label) -> InstrSeq<'a> {
268         instr(
269             alloc,
270             Instruct::IContFlow(InstructControlFlow::JmpNZ(label)),
271         )
272     }
274     pub fn jmpns<'a>(alloc: &'a bumpalo::Bump, label: Label) -> InstrSeq<'a> {
275         instr(
276             alloc,
277             Instruct::IContFlow(InstructControlFlow::JmpNS(label)),
278         )
279     }
281     pub fn continue_<'a>(alloc: &'a bumpalo::Bump, level: isize) -> InstrSeq<'a> {
282         instr(
283             alloc,
284             Instruct::ISpecialFlow(InstructSpecialFlow::Continue(level)),
285         )
286     }
288     pub fn break_<'a>(alloc: &'a bumpalo::Bump, level: isize) -> InstrSeq<'a> {
289         instr(
290             alloc,
291             Instruct::ISpecialFlow(InstructSpecialFlow::Break(level)),
292         )
293     }
295     pub fn goto<'a>(alloc: &'a bumpalo::Bump, label: std::string::String) -> InstrSeq<'_> {
296         instr(
297             alloc,
298             Instruct::ISpecialFlow(InstructSpecialFlow::Goto(Str::new_str(alloc, &label))),
299         )
300     }
302     pub fn iter_break<'a>(
303         alloc: &'a bumpalo::Bump,
304         label: Label,
305         itrs: std::vec::Vec<IterId>,
306     ) -> InstrSeq<'a> {
307         let mut vec = bumpalo::collections::Vec::from_iter_in(
308             itrs.into_iter()
309                 .map(|id| Instruct::IIterator(InstructIterator::IterFree(id))),
310             alloc,
311         );
312         vec.push(Instruct::IContFlow(InstructControlFlow::Jmp(label)));
313         instrs(alloc, vec.into_bump_slice_mut())
314     }
316     pub fn false_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
317         instr(alloc, Instruct::ILitConst(InstructLitConst::False))
318     }
320     pub fn true_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
321         instr(alloc, Instruct::ILitConst(InstructLitConst::True))
322     }
324     pub fn clscnsd<'a>(
325         alloc: &'a bumpalo::Bump,
326         const_id: ConstId<'a>,
327         cid: ClassId<'a>,
328     ) -> InstrSeq<'a> {
329         instr(
330             alloc,
331             Instruct::ILitConst(InstructLitConst::ClsCnsD(const_id, cid)),
332         )
333     }
335     pub fn clscns<'a>(alloc: &'a bumpalo::Bump, const_id: ConstId<'a>) -> InstrSeq<'a> {
336         instr(
337             alloc,
338             Instruct::ILitConst(InstructLitConst::ClsCns(const_id)),
339         )
340     }
342     pub fn clscnsl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
343         instr(alloc, Instruct::ILitConst(InstructLitConst::ClsCnsL(local)))
344     }
346     pub fn eq<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
347         instr(alloc, Instruct::IOp(InstructOperator::Eq))
348     }
350     pub fn neq<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
351         instr(alloc, Instruct::IOp(InstructOperator::Neq))
352     }
354     pub fn gt<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
355         instr(alloc, Instruct::IOp(InstructOperator::Gt))
356     }
358     pub fn gte<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
359         instr(alloc, Instruct::IOp(InstructOperator::Gte))
360     }
362     pub fn lt<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
363         instr(alloc, Instruct::IOp(InstructOperator::Lt))
364     }
366     pub fn lte<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
367         instr(alloc, Instruct::IOp(InstructOperator::Lte))
368     }
370     pub fn concat<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
371         instr(alloc, Instruct::IOp(InstructOperator::Concat))
372     }
374     pub fn concatn<'a>(alloc: &'a bumpalo::Bump, n: isize) -> InstrSeq<'a> {
375         instr(alloc, Instruct::IOp(InstructOperator::ConcatN(n)))
376     }
378     pub fn print<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
379         instr(alloc, Instruct::IOp(InstructOperator::Print))
380     }
382     pub fn cast_dict<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
383         instr(alloc, Instruct::IOp(InstructOperator::CastDict))
384     }
386     pub fn cast_string<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
387         instr(alloc, Instruct::IOp(InstructOperator::CastString))
388     }
390     pub fn cast_int<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
391         instr(alloc, Instruct::IOp(InstructOperator::CastInt))
392     }
394     pub fn cast_bool<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
395         instr(alloc, Instruct::IOp(InstructOperator::CastBool))
396     }
398     pub fn cast_double<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
399         instr(alloc, Instruct::IOp(InstructOperator::CastDouble))
400     }
402     pub fn retc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
403         instr(alloc, Instruct::IContFlow(InstructControlFlow::RetC))
404     }
406     pub fn retc_suspended<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
407         instr(
408             alloc,
409             Instruct::IContFlow(InstructControlFlow::RetCSuspended),
410         )
411     }
413     pub fn retm<'a>(alloc: &'a bumpalo::Bump, p: NumParams) -> InstrSeq<'a> {
414         instr(alloc, Instruct::IContFlow(InstructControlFlow::RetM(p)))
415     }
417     pub fn null<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
418         instr(alloc, Instruct::ILitConst(InstructLitConst::Null))
419     }
421     pub fn nulluninit<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
422         instr(alloc, Instruct::ILitConst(InstructLitConst::NullUninit))
423     }
425     pub fn chain_faults<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
426         instr(alloc, Instruct::IMisc(InstructMisc::ChainFaults))
427     }
429     pub fn dup<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
430         instr(alloc, Instruct::IBasic(InstructBasic::Dup))
431     }
433     pub fn nop<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
434         instr(alloc, Instruct::IBasic(InstructBasic::Nop))
435     }
437     pub fn instanceofd<'a>(alloc: &'a bumpalo::Bump, s: ClassId<'a>) -> InstrSeq<'a> {
438         instr(alloc, Instruct::IOp(InstructOperator::InstanceOfD(s)))
439     }
441     pub fn instanceof<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
442         instr(alloc, Instruct::IOp(InstructOperator::InstanceOf))
443     }
445     pub fn islateboundcls<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
446         instr(alloc, Instruct::IOp(InstructOperator::IsLateBoundCls))
447     }
449     pub fn istypestructc<'a>(alloc: &'a bumpalo::Bump, mode: TypestructResolveOp) -> InstrSeq<'a> {
450         instr(alloc, Instruct::IOp(InstructOperator::IsTypeStructC(mode)))
451     }
453     pub fn throwastypestructexception<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
454         instr(
455             alloc,
456             Instruct::IOp(InstructOperator::ThrowAsTypeStructException),
457         )
458     }
460     pub fn throw_non_exhaustive_switch<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
461         instr(
462             alloc,
463             Instruct::IMisc(InstructMisc::ThrowNonExhaustiveSwitch),
464         )
465     }
467     pub fn raise_class_string_conversion_warning<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
468         instr(
469             alloc,
470             Instruct::IMisc(InstructMisc::RaiseClassStringConversionWarning),
471         )
472     }
474     pub fn combine_and_resolve_type_struct<'a>(alloc: &'a bumpalo::Bump, i: isize) -> InstrSeq<'a> {
475         instr(
476             alloc,
477             Instruct::IOp(InstructOperator::CombineAndResolveTypeStruct(i)),
478         )
479     }
481     pub fn record_reified_generic<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
482         instr(alloc, Instruct::IMisc(InstructMisc::RecordReifiedGeneric))
483     }
485     pub fn check_reified_generic_mismatch<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
486         instr(
487             alloc,
488             Instruct::IMisc(InstructMisc::CheckReifiedGenericMismatch),
489         )
490     }
492     pub fn int<'a>(alloc: &'a bumpalo::Bump, i: isize) -> InstrSeq<'a> {
493         instr(
494             alloc,
495             Instruct::ILitConst(InstructLitConst::Int(i.try_into().unwrap())),
496         )
497     }
499     pub fn int64<'a>(alloc: &'a bumpalo::Bump, i: i64) -> InstrSeq<'a> {
500         instr(alloc, Instruct::ILitConst(InstructLitConst::Int(i)))
501     }
503     pub fn int_of_string<'a>(alloc: &'a bumpalo::Bump, litstr: &str) -> InstrSeq<'a> {
504         instr(
505             alloc,
506             Instruct::ILitConst(InstructLitConst::Int(litstr.parse::<i64>().unwrap())),
507         )
508     }
510     pub fn double<'a>(alloc: &'a bumpalo::Bump, litstr: &str) -> InstrSeq<'a> {
511         instr(
512             alloc,
513             Instruct::ILitConst(InstructLitConst::Double(Str::from(
514                 bumpalo::collections::String::from_str_in(litstr, alloc).into_bump_str(),
515             ))),
516         )
517     }
519     pub fn string<'a>(alloc: &'a bumpalo::Bump, litstr: impl Into<String>) -> InstrSeq<'a> {
520         instr(
521             alloc,
522             Instruct::ILitConst(InstructLitConst::String(Str::from(
523                 bumpalo::collections::String::from_str_in(litstr.into().as_str(), alloc)
524                     .into_bump_str(),
525             ))),
526         )
527     }
529     pub fn this<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
530         instr(alloc, Instruct::IMisc(InstructMisc::This))
531     }
533     pub fn istypec<'a>(alloc: &'a bumpalo::Bump, op: IstypeOp) -> InstrSeq<'a> {
534         instr(alloc, Instruct::IIsset(InstructIsset::IsTypeC(op)))
535     }
537     pub fn istypel<'a>(alloc: &'a bumpalo::Bump, id: Local<'a>, op: IstypeOp) -> InstrSeq<'a> {
538         instr(alloc, Instruct::IIsset(InstructIsset::IsTypeL(id, op)))
539     }
541     pub fn add<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
542         instr(alloc, Instruct::IOp(InstructOperator::Add))
543     }
545     pub fn addo<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
546         instr(alloc, Instruct::IOp(InstructOperator::AddO))
547     }
549     pub fn sub<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
550         instr(alloc, Instruct::IOp(InstructOperator::Sub))
551     }
553     pub fn subo<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
554         instr(alloc, Instruct::IOp(InstructOperator::SubO))
555     }
557     pub fn mul<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
558         instr(alloc, Instruct::IOp(InstructOperator::Mul))
559     }
561     pub fn mulo<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
562         instr(alloc, Instruct::IOp(InstructOperator::MulO))
563     }
565     pub fn shl<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
566         instr(alloc, Instruct::IOp(InstructOperator::Shl))
567     }
569     pub fn shr<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
570         instr(alloc, Instruct::IOp(InstructOperator::Shr))
571     }
573     pub fn cmp<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
574         instr(alloc, Instruct::IOp(InstructOperator::Cmp))
575     }
577     pub fn mod_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
578         instr(alloc, Instruct::IOp(InstructOperator::Mod))
579     }
581     pub fn div<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
582         instr(alloc, Instruct::IOp(InstructOperator::Div))
583     }
585     pub fn same<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
586         instr(alloc, Instruct::IOp(InstructOperator::Same))
587     }
589     pub fn pow<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
590         instr(alloc, Instruct::IOp(InstructOperator::Pow))
591     }
593     pub fn nsame<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
594         instr(alloc, Instruct::IOp(InstructOperator::NSame))
595     }
597     pub fn not<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
598         instr(alloc, Instruct::IOp(InstructOperator::Not))
599     }
601     pub fn bitnot<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
602         instr(alloc, Instruct::IOp(InstructOperator::BitNot))
603     }
605     pub fn bitand<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
606         instr(alloc, Instruct::IOp(InstructOperator::BitAnd))
607     }
609     pub fn bitor<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
610         instr(alloc, Instruct::IOp(InstructOperator::BitOr))
611     }
613     pub fn bitxor<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
614         instr(alloc, Instruct::IOp(InstructOperator::BitXor))
615     }
617     pub fn sets<'a>(alloc: &'a bumpalo::Bump, readonly_op: ReadonlyOp) -> InstrSeq<'a> {
618         instr(
619             alloc,
620             Instruct::IMutator(InstructMutator::SetS(readonly_op)),
621         )
622     }
624     pub fn setl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
625         instr(alloc, Instruct::IMutator(InstructMutator::SetL(local)))
626     }
628     pub fn setg<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
629         instr(alloc, Instruct::IMutator(InstructMutator::SetG))
630     }
632     pub fn unsetl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
633         instr(alloc, Instruct::IMutator(InstructMutator::UnsetL(local)))
634     }
636     pub fn unsetg<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
637         instr(alloc, Instruct::IMutator(InstructMutator::UnsetG))
638     }
640     pub fn incdecl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>, op: IncdecOp) -> InstrSeq<'a> {
641         instr(
642             alloc,
643             Instruct::IMutator(InstructMutator::IncDecL(local, op)),
644         )
645     }
647     pub fn incdecg<'a>(alloc: &'a bumpalo::Bump, op: IncdecOp) -> InstrSeq<'a> {
648         instr(alloc, Instruct::IMutator(InstructMutator::IncDecG(op)))
649     }
651     pub fn incdecs<'a>(alloc: &'a bumpalo::Bump, op: IncdecOp) -> InstrSeq<'a> {
652         instr(alloc, Instruct::IMutator(InstructMutator::IncDecS(op)))
653     }
655     pub fn setopg<'a>(alloc: &'a bumpalo::Bump, op: EqOp) -> InstrSeq<'a> {
656         instr(alloc, Instruct::IMutator(InstructMutator::SetOpG(op)))
657     }
659     pub fn setopl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>, op: EqOp) -> InstrSeq<'a> {
660         instr(
661             alloc,
662             Instruct::IMutator(InstructMutator::SetOpL(local, op)),
663         )
664     }
666     pub fn setops<'a>(alloc: &'a bumpalo::Bump, op: EqOp) -> InstrSeq<'a> {
667         instr(alloc, Instruct::IMutator(InstructMutator::SetOpS(op)))
668     }
670     pub fn issetl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
671         instr(alloc, Instruct::IIsset(InstructIsset::IssetL(local)))
672     }
674     pub fn issetg<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
675         instr(alloc, Instruct::IIsset(InstructIsset::IssetG))
676     }
678     pub fn issets<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
679         instr(alloc, Instruct::IIsset(InstructIsset::IssetS))
680     }
682     pub fn isunsetl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
683         instr(alloc, Instruct::IIsset(InstructIsset::IsUnsetL(local)))
684     }
686     pub fn cgets<'a>(alloc: &'a bumpalo::Bump, readonly_op: ReadonlyOp) -> InstrSeq<'a> {
687         instr(alloc, Instruct::IGet(InstructGet::CGetS(readonly_op)))
688     }
690     pub fn cgetg<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
691         instr(alloc, Instruct::IGet(InstructGet::CGetG))
692     }
694     pub fn cgetl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
695         instr(alloc, Instruct::IGet(InstructGet::CGetL(local)))
696     }
698     pub fn cugetl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
699         instr(alloc, Instruct::IGet(InstructGet::CUGetL(local)))
700     }
702     pub fn cgetl2<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
703         instr(alloc, Instruct::IGet(InstructGet::CGetL2(local)))
704     }
706     pub fn cgetquietl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
707         instr(alloc, Instruct::IGet(InstructGet::CGetQuietL(local)))
708     }
710     pub fn classgetc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
711         instr(alloc, Instruct::IGet(InstructGet::ClassGetC))
712     }
714     pub fn classgetts<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
715         instr(alloc, Instruct::IGet(InstructGet::ClassGetTS))
716     }
718     pub fn classname<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
719         instr(alloc, Instruct::IMisc(InstructMisc::ClassName))
720     }
722     pub fn lazyclassfromclass<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
723         instr(alloc, Instruct::IMisc(InstructMisc::LazyClassFromClass))
724     }
726     pub fn self_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
727         instr(alloc, Instruct::IMisc(InstructMisc::Self_))
728     }
730     pub fn lateboundcls<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
731         instr(alloc, Instruct::IMisc(InstructMisc::LateBoundCls))
732     }
734     pub fn parent<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
735         instr(alloc, Instruct::IMisc(InstructMisc::Parent))
736     }
738     pub fn popu<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
739         instr(alloc, Instruct::IBasic(InstructBasic::PopU))
740     }
742     pub fn popc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
743         instr(alloc, Instruct::IBasic(InstructBasic::PopC))
744     }
746     pub fn popl<'a>(alloc: &'a bumpalo::Bump, l: Local<'a>) -> InstrSeq<'a> {
747         instr(alloc, Instruct::IMutator(InstructMutator::PopL(l)))
748     }
750     pub fn initprop<'a>(alloc: &'a bumpalo::Bump, pid: PropId<'a>, op: InitpropOp) -> InstrSeq<'a> {
751         instr(
752             alloc,
753             Instruct::IMutator(InstructMutator::InitProp(pid, op)),
754         )
755     }
757     pub fn checkprop<'a>(alloc: &'a bumpalo::Bump, pid: PropId<'a>) -> InstrSeq<'a> {
758         instr(alloc, Instruct::IMutator(InstructMutator::CheckProp(pid)))
759     }
761     pub fn pushl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
762         instr(alloc, Instruct::IGet(InstructGet::PushL(local)))
763     }
765     pub fn throw<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
766         instr(alloc, Instruct::IContFlow(InstructControlFlow::Throw))
767     }
769     pub fn new_vec_array<'a>(alloc: &'a bumpalo::Bump, i: isize) -> InstrSeq<'a> {
770         instr(alloc, Instruct::ILitConst(InstructLitConst::NewVec(i)))
771     }
773     pub fn new_pair<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
774         instr(alloc, Instruct::ILitConst(InstructLitConst::NewPair))
775     }
777     pub fn add_elemc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
778         instr(alloc, Instruct::ILitConst(InstructLitConst::AddElemC))
779     }
781     pub fn add_new_elemc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
782         instr(alloc, Instruct::ILitConst(InstructLitConst::AddNewElemC))
783     }
785     pub fn switch<'a>(
786         alloc: &'a bumpalo::Bump,
787         labels: bumpalo::collections::Vec<'a, Label>,
788     ) -> InstrSeq<'a> {
789         instr(
790             alloc,
791             Instruct::IContFlow(InstructControlFlow::Switch(
792                 Switchkind::Unbounded,
793                 0,
794                 BumpSliceMut::new(alloc, labels.into_bump_slice_mut()),
795             )),
796         )
797     }
799     pub fn newobj<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
800         instr(alloc, Instruct::ICall(InstructCall::NewObj))
801     }
803     pub fn sswitch<'a>(
804         alloc: &'a bumpalo::Bump,
805         cases: bumpalo::collections::Vec<'a, (&'a str, Label)>,
806     ) -> InstrSeq<'a> {
807         let cases_ = BumpSliceMut::new(
808             alloc,
809             alloc.alloc_slice_fill_iter(cases.into_iter().map(|p| Pair(Str::from(p.0), p.1))),
810         );
811         instr(
812             alloc,
813             Instruct::IContFlow(InstructControlFlow::SSwitch(cases_)),
814         )
815     }
817     pub fn newobjr<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
818         instr(alloc, Instruct::ICall(InstructCall::NewObjR))
819     }
821     pub fn newobjd<'a>(alloc: &'a bumpalo::Bump, id: ClassId<'a>) -> InstrSeq<'a> {
822         instr(alloc, Instruct::ICall(InstructCall::NewObjD(id)))
823     }
825     pub fn newobjrd<'a>(alloc: &'a bumpalo::Bump, id: ClassId<'a>) -> InstrSeq<'a> {
826         instr(alloc, Instruct::ICall(InstructCall::NewObjRD(id)))
827     }
829     pub fn newobjs<'a>(alloc: &'a bumpalo::Bump, scref: SpecialClsRef) -> InstrSeq<'a> {
830         instr(alloc, Instruct::ICall(InstructCall::NewObjS(scref)))
831     }
833     pub fn lockobj<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
834         instr(alloc, Instruct::IMisc(InstructMisc::LockObj))
835     }
837     pub fn clone<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
838         instr(alloc, Instruct::IOp(InstructOperator::Clone))
839     }
841     pub fn new_record<'a>(
842         alloc: &'a bumpalo::Bump,
843         id: ClassId<'a>,
844         keys: &'a [&'a str],
845     ) -> InstrSeq<'a> {
846         let keys_ =
847             Slice::new(alloc.alloc_slice_fill_iter(keys.into_iter().map(|s| Str::from(*s))));
848         instr(
849             alloc,
850             Instruct::ILitConst(InstructLitConst::NewRecord(id, keys_)),
851         )
852     }
854     pub fn newstructdict<'a>(alloc: &'a bumpalo::Bump, keys: &'a [&'a str]) -> InstrSeq<'a> {
855         let keys_ =
856             Slice::new(alloc.alloc_slice_fill_iter(keys.into_iter().map(|s| Str::from(*s))));
857         instr(
858             alloc,
859             Instruct::ILitConst(InstructLitConst::NewStructDict(keys_)),
860         )
861     }
863     pub fn newcol<'a>(alloc: &'a bumpalo::Bump, collection_type: CollectionType) -> InstrSeq<'a> {
864         instr(
865             alloc,
866             Instruct::ILitConst(InstructLitConst::NewCol(collection_type)),
867         )
868     }
870     pub fn colfromarray<'a>(
871         alloc: &'a bumpalo::Bump,
872         collection_type: CollectionType,
873     ) -> InstrSeq<'a> {
874         instr(
875             alloc,
876             Instruct::ILitConst(InstructLitConst::ColFromArray(collection_type)),
877         )
878     }
880     pub fn entrynop<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
881         instr(alloc, Instruct::IBasic(InstructBasic::EntryNop))
882     }
884     pub fn typedvalue<'a>(alloc: &'a bumpalo::Bump, xs: TypedValue<'a>) -> InstrSeq<'a> {
885         instr(alloc, Instruct::ILitConst(InstructLitConst::TypedValue(xs)))
886     }
888     pub fn basel<'a>(
889         alloc: &'a bumpalo::Bump,
890         local: Local<'a>,
891         mode: MemberOpMode,
892         readonly_op: ReadonlyOp,
893     ) -> InstrSeq<'a> {
894         instr(
895             alloc,
896             Instruct::IBase(InstructBase::BaseL(local, mode, readonly_op)),
897         )
898     }
900     pub fn basec<'a>(
901         alloc: &'a bumpalo::Bump,
902         stack_index: StackIndex,
903         mode: MemberOpMode,
904     ) -> InstrSeq<'a> {
905         instr(
906             alloc,
907             Instruct::IBase(InstructBase::BaseC(stack_index, mode)),
908         )
909     }
911     pub fn basegc<'a>(
912         alloc: &'a bumpalo::Bump,
913         stack_index: StackIndex,
914         mode: MemberOpMode,
915     ) -> InstrSeq<'a> {
916         instr(
917             alloc,
918             Instruct::IBase(InstructBase::BaseGC(stack_index, mode)),
919         )
920     }
922     pub fn basegl<'a>(
923         alloc: &'a bumpalo::Bump,
924         local: Local<'a>,
925         mode: MemberOpMode,
926     ) -> InstrSeq<'a> {
927         instr(alloc, Instruct::IBase(InstructBase::BaseGL(local, mode)))
928     }
930     pub fn basesc<'a>(
931         alloc: &'a bumpalo::Bump,
932         y: StackIndex,
933         z: StackIndex,
934         mode: MemberOpMode,
935         readonly_op: ReadonlyOp,
936     ) -> InstrSeq<'a> {
937         instr(
938             alloc,
939             Instruct::IBase(InstructBase::BaseSC(y, z, mode, readonly_op)),
940         )
941     }
943     pub fn baseh<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
944         instr(alloc, Instruct::IBase(InstructBase::BaseH))
945     }
947     pub fn cgetcunop<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
948         instr(alloc, Instruct::IMisc(InstructMisc::CGetCUNop))
949     }
951     pub fn ugetcunop<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
952         instr(alloc, Instruct::IMisc(InstructMisc::UGetCUNop))
953     }
955     pub fn memoget<'a>(
956         alloc: &'a bumpalo::Bump,
957         label: Label,
958         range: Option<(Local<'a>, isize)>,
959     ) -> InstrSeq<'a> {
960         instr(
961             alloc,
962             Instruct::IMisc(InstructMisc::MemoGet(
963                 label,
964                 match range {
965                     Some((fst, snd)) => Just(Pair(fst, snd)),
966                     None => Nothing,
967                 },
968             )),
969         )
970     }
972     // Factored out to reduce verbosity.
973     fn range_opt_to_maybe<'a>(range: Option<(Local<'a>, isize)>) -> Maybe<Pair<Local<'a>, isize>> {
974         match range {
975             Some((fst, snd)) => Just(Pair(fst, snd)),
976             None => Nothing,
977         }
978     }
980     pub fn memoget_eager<'a>(
981         alloc: &'a bumpalo::Bump,
982         label1: Label,
983         label2: Label,
984         range: Option<(Local<'a>, isize)>,
985     ) -> InstrSeq<'a> {
986         instr(
987             alloc,
988             Instruct::IMisc(InstructMisc::MemoGetEager(
989                 label1,
990                 label2,
991                 range_opt_to_maybe(range),
992             )),
993         )
994     }
996     pub fn memoset<'a>(
997         alloc: &'a bumpalo::Bump,
998         range: Option<(Local<'a>, isize)>,
999     ) -> InstrSeq<'a> {
1000         instr(
1001             alloc,
1002             Instruct::IMisc(InstructMisc::MemoSet(range_opt_to_maybe(range))),
1003         )
1004     }
1006     pub fn memoset_eager<'a>(
1007         alloc: &'a bumpalo::Bump,
1008         range: Option<(Local<'a>, isize)>,
1009     ) -> InstrSeq<'a> {
1010         instr(
1011             alloc,
1012             Instruct::IMisc(InstructMisc::MemoSetEager(range_opt_to_maybe(range))),
1013         )
1014     }
1016     pub fn getmemokeyl<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
1017         instr(alloc, Instruct::IMisc(InstructMisc::GetMemoKeyL(local)))
1018     }
1020     pub fn barethis<'a>(alloc: &'a bumpalo::Bump, notice: BareThisOp) -> InstrSeq<'a> {
1021         instr(alloc, Instruct::IMisc(InstructMisc::BareThis(notice)))
1022     }
1024     pub fn checkthis<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1025         instr(alloc, Instruct::IMisc(InstructMisc::CheckThis))
1026     }
1028     pub fn verify_ret_type_c<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1029         instr(alloc, Instruct::IMisc(InstructMisc::VerifyRetTypeC))
1030     }
1032     pub fn verify_ret_type_ts<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1033         instr(alloc, Instruct::IMisc(InstructMisc::VerifyRetTypeTS))
1034     }
1036     pub fn verify_out_type<'a>(alloc: &'a bumpalo::Bump, i: ParamId<'a>) -> InstrSeq<'a> {
1037         instr(alloc, Instruct::IMisc(InstructMisc::VerifyOutType(i)))
1038     }
1040     pub fn verify_param_type<'a>(alloc: &'a bumpalo::Bump, i: ParamId<'a>) -> InstrSeq<'a> {
1041         instr(alloc, Instruct::IMisc(InstructMisc::VerifyParamType(i)))
1042     }
1044     pub fn verify_param_type_ts<'a>(alloc: &'a bumpalo::Bump, i: ParamId<'a>) -> InstrSeq<'a> {
1045         instr(alloc, Instruct::IMisc(InstructMisc::VerifyParamTypeTS(i)))
1046     }
1048     pub fn dim<'a>(alloc: &'a bumpalo::Bump, op: MemberOpMode, key: MemberKey<'a>) -> InstrSeq<'a> {
1049         instr(alloc, Instruct::IBase(InstructBase::Dim(op, key)))
1050     }
1052     pub fn dim_warn_pt<'a>(
1053         alloc: &'a bumpalo::Bump,
1054         key: PropId<'a>,
1055         readonly_op: ReadonlyOp,
1056     ) -> InstrSeq<'a> {
1057         dim(alloc, MemberOpMode::Warn, MemberKey::PT(key, readonly_op))
1058     }
1060     pub fn dim_define_pt<'a>(
1061         alloc: &'a bumpalo::Bump,
1062         key: PropId<'a>,
1063         readonly_op: ReadonlyOp,
1064     ) -> InstrSeq<'a> {
1065         dim(alloc, MemberOpMode::Define, MemberKey::PT(key, readonly_op))
1066     }
1068     pub fn fcallclsmethod<'a>(
1069         alloc: &'a bumpalo::Bump,
1070         is_log_as_dynamic_call: IsLogAsDynamicCallOp,
1071         fcall_args: FcallArgs<'a>,
1072     ) -> InstrSeq<'a> {
1073         instr(
1074             alloc,
1075             Instruct::ICall(InstructCall::FCallClsMethod(
1076                 fcall_args,
1077                 is_log_as_dynamic_call,
1078             )),
1079         )
1080     }
1082     pub fn fcallclsmethodd<'a>(
1083         alloc: &'a bumpalo::Bump,
1084         fcall_args: FcallArgs<'a>,
1085         method_name: MethodId<'a>,
1086         class_name: ClassId<'a>,
1087     ) -> InstrSeq<'a> {
1088         instr(
1089             alloc,
1090             Instruct::ICall(InstructCall::FCallClsMethodD(
1091                 fcall_args,
1092                 class_name,
1093                 method_name,
1094             )),
1095         )
1096     }
1098     pub fn fcallclsmethods<'a>(
1099         alloc: &'a bumpalo::Bump,
1100         fcall_args: FcallArgs<'a>,
1101         scref: SpecialClsRef,
1102     ) -> InstrSeq<'a> {
1103         instr(
1104             alloc,
1105             Instruct::ICall(InstructCall::FCallClsMethodS(fcall_args, scref)),
1106         )
1107     }
1109     pub fn fcallclsmethodsd<'a>(
1110         alloc: &'a bumpalo::Bump,
1111         fcall_args: FcallArgs<'a>,
1112         scref: SpecialClsRef,
1113         method_name: MethodId<'a>,
1114     ) -> InstrSeq<'a> {
1115         instr(
1116             alloc,
1117             Instruct::ICall(InstructCall::FCallClsMethodSD(
1118                 fcall_args,
1119                 scref,
1120                 method_name,
1121             )),
1122         )
1123     }
1125     pub fn fcallctor<'a>(alloc: &'a bumpalo::Bump, fcall_args: FcallArgs<'a>) -> InstrSeq<'a> {
1126         instr(alloc, Instruct::ICall(InstructCall::FCallCtor(fcall_args)))
1127     }
1129     pub fn fcallfunc<'a>(alloc: &'a bumpalo::Bump, fcall_args: FcallArgs<'a>) -> InstrSeq<'a> {
1130         instr(alloc, Instruct::ICall(InstructCall::FCallFunc(fcall_args)))
1131     }
1133     pub fn fcallfuncd<'a>(
1134         alloc: &'a bumpalo::Bump,
1135         fcall_args: FcallArgs<'a>,
1136         id: FunctionId<'a>,
1137     ) -> InstrSeq<'a> {
1138         instr(
1139             alloc,
1140             Instruct::ICall(InstructCall::FCallFuncD(fcall_args, id)),
1141         )
1142     }
1144     pub fn fcallobjmethod<'a>(
1145         alloc: &'a bumpalo::Bump,
1146         fcall_args: FcallArgs<'a>,
1147         flavor: ObjNullFlavor,
1148     ) -> InstrSeq<'a> {
1149         instr(
1150             alloc,
1151             Instruct::ICall(InstructCall::FCallObjMethod(fcall_args, flavor)),
1152         )
1153     }
1155     pub fn fcallobjmethodd<'a>(
1156         alloc: &'a bumpalo::Bump,
1157         fcall_args: FcallArgs<'a>,
1158         method: MethodId<'a>,
1159         flavor: ObjNullFlavor,
1160     ) -> InstrSeq<'a> {
1161         instr(
1162             alloc,
1163             Instruct::ICall(InstructCall::FCallObjMethodD(fcall_args, flavor, method)),
1164         )
1165     }
1167     pub fn fcallobjmethodd_nullthrows<'a>(
1168         alloc: &'a bumpalo::Bump,
1169         fcall_args: FcallArgs<'a>,
1170         method: MethodId<'a>,
1171     ) -> InstrSeq<'a> {
1172         fcallobjmethodd(alloc, fcall_args, method, ObjNullFlavor::NullThrows)
1173     }
1175     pub fn querym<'a>(
1176         alloc: &'a bumpalo::Bump,
1177         num_params: NumParams,
1178         op: QueryOp,
1179         key: MemberKey<'a>,
1180     ) -> InstrSeq<'a> {
1181         instr(
1182             alloc,
1183             Instruct::IFinal(InstructFinal::QueryM(num_params, op, key)),
1184         )
1185     }
1187     pub fn querym_cget_pt<'a>(
1188         alloc: &'a bumpalo::Bump,
1189         num_params: NumParams,
1190         key: PropId<'a>,
1191         readonly_op: ReadonlyOp,
1192     ) -> InstrSeq<'a> {
1193         querym(
1194             alloc,
1195             num_params,
1196             QueryOp::CGet,
1197             MemberKey::PT(key, readonly_op),
1198         )
1199     }
1201     pub fn setm<'a>(
1202         alloc: &'a bumpalo::Bump,
1203         num_params: NumParams,
1204         key: MemberKey<'a>,
1205     ) -> InstrSeq<'a> {
1206         instr(
1207             alloc,
1208             Instruct::IFinal(InstructFinal::SetM(num_params, key)),
1209         )
1210     }
1212     pub fn unsetm<'a>(
1213         alloc: &'a bumpalo::Bump,
1214         num_params: NumParams,
1215         key: MemberKey<'a>,
1216     ) -> InstrSeq<'a> {
1217         instr(
1218             alloc,
1219             Instruct::IFinal(InstructFinal::UnsetM(num_params, key)),
1220         )
1221     }
1223     pub fn setopm<'a>(
1224         alloc: &'a bumpalo::Bump,
1225         num_params: NumParams,
1226         op: EqOp,
1227         key: MemberKey<'a>,
1228     ) -> InstrSeq<'a> {
1229         instr(
1230             alloc,
1231             Instruct::IFinal(InstructFinal::SetOpM(num_params, op, key)),
1232         )
1233     }
1235     pub fn incdecm<'a>(
1236         alloc: &'a bumpalo::Bump,
1237         num_params: NumParams,
1238         op: IncdecOp,
1239         key: MemberKey<'a>,
1240     ) -> InstrSeq<'a> {
1241         instr(
1242             alloc,
1243             Instruct::IFinal(InstructFinal::IncDecM(num_params, op, key)),
1244         )
1245     }
1247     pub fn setm_pt<'a>(
1248         alloc: &'a bumpalo::Bump,
1249         num_params: NumParams,
1250         key: PropId<'a>,
1251         readonly_op: ReadonlyOp,
1252     ) -> InstrSeq<'a> {
1253         setm(alloc, num_params, MemberKey::PT(key, readonly_op))
1254     }
1256     pub fn resolve_func<'a>(alloc: &'a bumpalo::Bump, func_id: FunctionId<'a>) -> InstrSeq<'a> {
1257         instr(alloc, Instruct::IOp(InstructOperator::ResolveFunc(func_id)))
1258     }
1260     pub fn resolve_rfunc<'a>(alloc: &'a bumpalo::Bump, func_id: FunctionId<'a>) -> InstrSeq<'a> {
1261         instr(
1262             alloc,
1263             Instruct::IOp(InstructOperator::ResolveRFunc(func_id)),
1264         )
1265     }
1267     pub fn resolveclsmethod<'a>(alloc: &'a bumpalo::Bump, method_id: MethodId<'a>) -> InstrSeq<'a> {
1268         instr(
1269             alloc,
1270             Instruct::IOp(InstructOperator::ResolveClsMethod(method_id)),
1271         )
1272     }
1274     pub fn resolveclsmethodd<'a>(
1275         alloc: &'a bumpalo::Bump,
1276         class_id: ClassId<'a>,
1277         method_id: MethodId<'a>,
1278     ) -> InstrSeq<'a> {
1279         instr(
1280             alloc,
1281             Instruct::IOp(InstructOperator::ResolveClsMethodD(class_id, method_id)),
1282         )
1283     }
1285     pub fn resolveclsmethods<'a>(
1286         alloc: &'a bumpalo::Bump,
1287         scref: SpecialClsRef,
1288         method_id: MethodId<'a>,
1289     ) -> InstrSeq<'a> {
1290         instr(
1291             alloc,
1292             Instruct::IOp(InstructOperator::ResolveClsMethodS(scref, method_id)),
1293         )
1294     }
1296     pub fn resolverclsmethod<'a>(
1297         alloc: &'a bumpalo::Bump,
1298         method_id: MethodId<'a>,
1299     ) -> InstrSeq<'a> {
1300         instr(
1301             alloc,
1302             Instruct::IOp(InstructOperator::ResolveRClsMethod(method_id)),
1303         )
1304     }
1306     pub fn resolverclsmethodd<'a>(
1307         alloc: &'a bumpalo::Bump,
1308         class_id: ClassId<'a>,
1309         method_id: MethodId<'a>,
1310     ) -> InstrSeq<'a> {
1311         instr(
1312             alloc,
1313             Instruct::IOp(InstructOperator::ResolveRClsMethodD(class_id, method_id)),
1314         )
1315     }
1317     pub fn resolverclsmethods<'a>(
1318         alloc: &'a bumpalo::Bump,
1319         scref: SpecialClsRef,
1320         method_id: MethodId<'a>,
1321     ) -> InstrSeq<'a> {
1322         instr(
1323             alloc,
1324             Instruct::IOp(InstructOperator::ResolveRClsMethodS(scref, method_id)),
1325         )
1326     }
1328     pub fn resolve_meth_caller<'a>(
1329         alloc: &'a bumpalo::Bump,
1330         fun_id: FunctionId<'a>,
1331     ) -> InstrSeq<'a> {
1332         instr(
1333             alloc,
1334             Instruct::IOp(InstructOperator::ResolveMethCaller(fun_id)),
1335         )
1336     }
1338     pub fn resolveclass<'a>(alloc: &'a bumpalo::Bump, class_id: ClassId<'a>) -> InstrSeq<'a> {
1339         instr(
1340             alloc,
1341             Instruct::IOp(InstructOperator::ResolveClass(class_id)),
1342         )
1343     }
1345     pub fn lazyclass<'a>(alloc: &'a bumpalo::Bump, class_id: ClassId<'a>) -> InstrSeq<'a> {
1346         instr(
1347             alloc,
1348             Instruct::ILitConst(InstructLitConst::LazyClass(class_id)),
1349         )
1350     }
1352     pub fn oodeclexists<'a>(alloc: &'a bumpalo::Bump, class_kind: ClassishKind) -> InstrSeq<'a> {
1353         instr(
1354             alloc,
1355             Instruct::IMisc(InstructMisc::OODeclExists(class_kind)),
1356         )
1357     }
1359     pub fn fatal<'a>(alloc: &'a bumpalo::Bump, op: FatalOp) -> InstrSeq<'a> {
1360         instr(alloc, Instruct::IOp(InstructOperator::Fatal(op)))
1361     }
1363     pub fn await_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1364         instr(alloc, Instruct::IAsync(AsyncFunctions::Await))
1365     }
1367     pub fn yield_<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1368         instr(alloc, Instruct::IGenerator(GenCreationExecution::Yield))
1369     }
1371     pub fn yieldk<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1372         instr(alloc, Instruct::IGenerator(GenCreationExecution::YieldK))
1373     }
1375     pub fn createcont<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1376         instr(
1377             alloc,
1378             Instruct::IGenerator(GenCreationExecution::CreateCont),
1379         )
1380     }
1382     pub fn awaitall<'a>(
1383         alloc: &'a bumpalo::Bump,
1384         range: Option<(Local<'a>, isize)>,
1385     ) -> InstrSeq<'a> {
1386         instr(
1387             alloc,
1388             Instruct::IAsync(AsyncFunctions::AwaitAll(range_opt_to_maybe(range))),
1389         )
1390     }
1392     pub fn label<'a>(alloc: &'a bumpalo::Bump, label: Label) -> InstrSeq<'a> {
1393         instr(alloc, Instruct::ILabel(label))
1394     }
1396     pub fn awaitall_list<'a>(
1397         alloc: &'a bumpalo::Bump,
1398         unnamed_locals: std::vec::Vec<Local<'a>>,
1399     ) -> InstrSeq<'a> {
1400         use Local::Unnamed;
1401         match unnamed_locals.split_first() {
1402             None => panic!("Expected at least one await"),
1403             Some((hd, tl)) => {
1404                 if let Unnamed(hd_id) = hd {
1405                     let mut prev_id = hd_id;
1406                     for unnamed_local in tl.iter() {
1407                         match unnamed_local {
1408                             Unnamed(id) => {
1409                                 assert_eq!(*prev_id + 1, *id);
1410                                 prev_id = id;
1411                             }
1412                             _ => panic!("Expected unnamed local"),
1413                         }
1414                     }
1415                     awaitall(
1416                         alloc,
1417                         Some((Unnamed(*hd_id), unnamed_locals.len().try_into().unwrap())),
1418                     )
1419                 } else {
1420                     panic!("Expected unnamed local")
1421                 }
1422             }
1423         }
1424     }
1426     pub fn exit<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1427         instr(alloc, Instruct::IOp(InstructOperator::Exit))
1428     }
1430     pub fn idx<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1431         instr(alloc, Instruct::IMisc(InstructMisc::Idx))
1432     }
1434     pub fn array_idx<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1435         instr(alloc, Instruct::IMisc(InstructMisc::ArrayIdx))
1436     }
1438     pub fn createcl<'a>(
1439         alloc: &'a bumpalo::Bump,
1440         param_num: NumParams,
1441         cls_num: ClassNum,
1442     ) -> InstrSeq<'a> {
1443         instr(
1444             alloc,
1445             Instruct::IMisc(InstructMisc::CreateCl(param_num, cls_num)),
1446         )
1447     }
1449     pub fn eval<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1450         instr(
1451             alloc,
1452             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::Eval),
1453         )
1454     }
1456     pub fn incl<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1457         instr(
1458             alloc,
1459             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::Incl),
1460         )
1461     }
1463     pub fn inclonce<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1464         instr(
1465             alloc,
1466             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::InclOnce),
1467         )
1468     }
1470     pub fn req<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1471         instr(
1472             alloc,
1473             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::Req),
1474         )
1475     }
1477     pub fn reqdoc<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1478         instr(
1479             alloc,
1480             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::ReqDoc),
1481         )
1482     }
1484     pub fn reqonce<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1485         instr(
1486             alloc,
1487             Instruct::IIncludeEvalDefine(InstructIncludeEvalDefine::ReqOnce),
1488         )
1489     }
1491     pub fn silence_start<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
1492         instr(
1493             alloc,
1494             Instruct::IMisc(InstructMisc::Silence(local, OpSilence::Start)),
1495         )
1496     }
1498     pub fn silence_end<'a>(alloc: &'a bumpalo::Bump, local: Local<'a>) -> InstrSeq<'a> {
1499         instr(
1500             alloc,
1501             Instruct::IMisc(InstructMisc::Silence(local, OpSilence::End)),
1502         )
1503     }
1505     pub fn contcheck_check<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1506         instr(
1507             alloc,
1508             Instruct::IGenerator(GenCreationExecution::ContCheck(CheckStarted::CheckStarted)),
1509         )
1510     }
1512     pub fn contcheck_ignore<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1513         instr(
1514             alloc,
1515             Instruct::IGenerator(GenCreationExecution::ContCheck(CheckStarted::IgnoreStarted)),
1516         )
1517     }
1519     pub fn contenter<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1520         instr(alloc, Instruct::IGenerator(GenCreationExecution::ContEnter))
1521     }
1523     pub fn contraise<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1524         instr(alloc, Instruct::IGenerator(GenCreationExecution::ContRaise))
1525     }
1527     pub fn contvalid<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1528         instr(alloc, Instruct::IGenerator(GenCreationExecution::ContValid))
1529     }
1531     pub fn contcurrent<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1532         instr(
1533             alloc,
1534             Instruct::IGenerator(GenCreationExecution::ContCurrent),
1535         )
1536     }
1538     pub fn contkey<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1539         instr(alloc, Instruct::IGenerator(GenCreationExecution::ContKey))
1540     }
1542     pub fn contgetreturn<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1543         instr(
1544             alloc,
1545             Instruct::IGenerator(GenCreationExecution::ContGetReturn),
1546         )
1547     }
1549     pub fn nativeimpl<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1550         instr(alloc, Instruct::IMisc(InstructMisc::NativeImpl))
1551     }
1553     pub fn srcloc<'a>(
1554         alloc: &'a bumpalo::Bump,
1555         line_begin: isize,
1556         line_end: isize,
1557         col_begin: isize,
1558         col_end: isize,
1559     ) -> InstrSeq<'a> {
1560         instr(
1561             alloc,
1562             Instruct::ISrcLoc(Srcloc {
1563                 line_begin,
1564                 line_end,
1565                 col_begin,
1566                 col_end,
1567             }),
1568         )
1569     }
1571     pub fn is_type_structc_resolve<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1572         instr(
1573             alloc,
1574             Instruct::IOp(InstructOperator::IsTypeStructC(
1575                 TypestructResolveOp::Resolve,
1576             )),
1577         )
1578     }
1580     pub fn is_type_structc_dontresolve<'a>(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1581         instr(
1582             alloc,
1583             Instruct::IOp(InstructOperator::IsTypeStructC(
1584                 TypestructResolveOp::DontResolve,
1585             )),
1586         )
1587     }
1590 impl<'a> InstrSeq<'a> {
1591     /// We can't implement `std::Clone`` because of the need for an
1592     /// allocator. Instead, use this associated function.
1593     pub fn clone(alloc: &'a bumpalo::Bump, s: &InstrSeq<'a>) -> InstrSeq<'a> {
1594         InstrSeq::from_iter_in(alloc, InstrIter::new(s).cloned())
1595     }
1597     /// We can't implement `std::Default` because of the need
1598     /// for an allocator. Instead, use this associated function
1599     /// to produce an empty instruction sequence.
1600     pub fn new_empty(alloc: &'a bumpalo::Bump) -> InstrSeq<'a> {
1601         InstrSeq::List(BumpSliceMut::new(
1602             alloc,
1603             bumpalo::vec![in &alloc; ].into_bump_slice_mut(),
1604         ))
1605     }
1607     /// An instruction sequence of a single instruction.
1608     pub fn new_singleton(alloc: &'a bumpalo::Bump, i: Instruct<'a>) -> InstrSeq<'a> {
1609         InstrSeq::List(BumpSliceMut::new(
1610             alloc,
1611             bumpalo::vec![in &alloc; i].into_bump_slice_mut(),
1612         ))
1613     }
1615     /// An instruction sequence of a sequence of instructions.
1616     pub fn new_list(alloc: &'a bumpalo::Bump, is: &'a mut [Instruct<'a>]) -> InstrSeq<'a> {
1617         InstrSeq::List(BumpSliceMut::new(alloc, is))
1618     }
1620     /// An instruction sequence of a concatenation of instruction sequences.
1621     pub fn new_concat(alloc: &'a bumpalo::Bump, iss: &'a mut [InstrSeq<'a>]) -> InstrSeq<'a> {
1622         InstrSeq::Concat(BumpSliceMut::new(alloc, iss))
1623     }
1625     /// Move instructions out of a container.
1626     pub fn from_iter_in<T: IntoIterator<Item = Instruct<'a>>>(
1627         alloc: &'a bumpalo::Bump,
1628         it: T,
1629     ) -> InstrSeq<'a> {
1630         InstrSeq::new_list(
1631             alloc,
1632             bumpalo::collections::Vec::from_iter_in(it, alloc).into_bump_slice_mut(),
1633         )
1634     }
1636     /// Transitional version. We mean to write a `gather!` in the future.
1637     pub fn gather(alloc: &'a bumpalo::Bump, iss: std::vec::Vec<InstrSeq<'a>>) -> InstrSeq<'a> {
1638         fn prd<'a>(is: &InstrSeq<'a>) -> bool {
1639             match is {
1640                 InstrSeq::List(s) if s.is_empty() => false,
1641                 _ => true,
1642             }
1643         }
1645         let non_empty = bumpalo::collections::Vec::from_iter_in(iss.into_iter().filter(prd), alloc);
1646         if non_empty.is_empty() {
1647             InstrSeq::new_empty(alloc)
1648         } else {
1649             InstrSeq::new_concat(alloc, non_empty.into_bump_slice_mut())
1650         }
1651     }
1653     pub fn iter<'i>(&'i self) -> InstrIter<'i, 'a> {
1654         InstrIter::new(self)
1655     }
1657     pub fn compact_iter<'i>(&'i self) -> impl Iterator<Item = &Instruct<'a>> {
1658         CompactIter::new(self.iter())
1659     }
1661     pub fn create_try_catch(
1662         alloc: &'a bumpalo::Bump,
1663         label_gen: &mut label::Gen,
1664         opt_done_label: Option<Label>,
1665         skip_throw: bool,
1666         try_instrs: Self,
1667         catch_instrs: Self,
1668     ) -> Self {
1669         let done_label = match opt_done_label {
1670             Some(l) => l,
1671             None => label_gen.next_regular(),
1672         };
1673         InstrSeq::gather(
1674             alloc,
1675             vec![
1676                 instr::instr(alloc, Instruct::ITry(InstructTry::TryCatchBegin)),
1677                 try_instrs,
1678                 instr::jmp(alloc, done_label),
1679                 instr::instr(alloc, Instruct::ITry(InstructTry::TryCatchMiddle)),
1680                 catch_instrs,
1681                 if skip_throw {
1682                     instr::empty(alloc)
1683                 } else {
1684                     instr::instr(alloc, Instruct::IContFlow(InstructControlFlow::Throw))
1685                 },
1686                 instr::instr(alloc, Instruct::ITry(InstructTry::TryCatchEnd)),
1687                 instr::label(alloc, done_label),
1688             ],
1689         )
1690     }
1692     /// Test whether `i` is of case `Instruct::ISrcLoc`.
1693     fn is_srcloc(instruction: &Instruct<'a>) -> bool {
1694         match instruction {
1695             Instruct::ISrcLoc(_) => true,
1696             _ => false,
1697         }
1698     }
1700     pub fn first(&self) -> Option<&Instruct<'a>> {
1701         // self: &InstrSeq<'a>
1702         match self {
1703             InstrSeq::List(s) if s.is_empty() => None,
1704             InstrSeq::List(s) if s.len() == 1 => {
1705                 let i = &s[0];
1706                 if InstrSeq::is_srcloc(i) {
1707                     None
1708                 } else {
1709                     Some(i)
1710                 }
1711             }
1712             InstrSeq::List(s) => match s.iter().find(|&i| !InstrSeq::is_srcloc(i)) {
1713                 Some(i) => Some(i),
1714                 None => None,
1715             },
1716             InstrSeq::Concat(s) => s.iter().find_map(InstrSeq::first),
1717         }
1718     }
1720     /// Test for the empty instruction sequence.
1721     pub fn is_empty(&self) -> bool {
1722         // self:&InstrSeq<'a>
1723         match self {
1724             InstrSeq::List(s) if s.is_empty() => true,
1725             InstrSeq::List(s) if s.len() == 1 => InstrSeq::is_srcloc(&s[0]),
1726             InstrSeq::List(s) => s.is_empty() || s.iter().all(InstrSeq::is_srcloc),
1727             InstrSeq::Concat(s) => s.iter().all(InstrSeq::is_empty),
1728         }
1729     }
1731     pub fn flat_map_seq<F>(&self, alloc: &'a bumpalo::Bump, f: &mut F) -> Self
1732     where
1733         F: FnMut(&Instruct<'a>) -> Self,
1734     {
1735         // self: &InstrSeq<'a>
1736         match self {
1737             InstrSeq::List(s) if s.is_empty() => InstrSeq::new_empty(alloc),
1738             InstrSeq::List(s) if s.len() == 1 => f(&s[0]),
1739             InstrSeq::List(s) => InstrSeq::Concat(BumpSliceMut::new(
1740                 alloc,
1741                 bumpalo::collections::vec::Vec::from_iter_in(s.iter().map(|x| f(x)), alloc)
1742                     .into_bump_slice_mut(),
1743             )),
1744             InstrSeq::Concat(s) => InstrSeq::Concat(BumpSliceMut::new(
1745                 alloc,
1746                 bumpalo::collections::vec::Vec::from_iter_in(
1747                     s.iter().map(|x| x.flat_map_seq(alloc, f)),
1748                     alloc,
1749                 )
1750                 .into_bump_slice_mut(),
1751             )),
1752         }
1753     }
1755     pub fn fold_left<'i, F, A>(&'i self, f: &mut F, init: A) -> A
1756     where
1757         F: FnMut(A, &'i Instruct<'a>) -> A,
1758     {
1759         // self:& InstrSeq<'a>
1760         match self {
1761             InstrSeq::List(s) if s.is_empty() => init,
1762             InstrSeq::List(s) if s.len() == 1 => f(init, &s[0]),
1763             InstrSeq::List(s) => s.iter().fold(init, f),
1764             InstrSeq::Concat(s) => s.iter().fold(init, |acc, x| x.fold_left(f, acc)),
1765         }
1766     }
1768     pub fn filter_map<F>(&self, alloc: &'a bumpalo::Bump, f: &mut F) -> Self
1769     where
1770         F: FnMut(&Instruct<'a>) -> Option<Instruct<'a>>,
1771     {
1772         //self: &InstrSeq<'a>
1773         match self {
1774             InstrSeq::List(s) if s.is_empty() => InstrSeq::new_empty(alloc),
1775             InstrSeq::List(s) if s.len() == 1 => {
1776                 let x: &Instruct<'a> = &s[0];
1777                 match f(x) {
1778                     Some(x) => instr::instr(alloc, x),
1779                     None => InstrSeq::new_empty(alloc),
1780                 }
1781             }
1782             InstrSeq::List(s) => InstrSeq::List(BumpSliceMut::new(
1783                 alloc,
1784                 bumpalo::collections::vec::Vec::from_iter_in(s.iter().filter_map(f), alloc)
1785                     .into_bump_slice_mut(),
1786             )),
1787             InstrSeq::Concat(s) => InstrSeq::Concat(BumpSliceMut::new(
1788                 alloc,
1789                 bumpalo::collections::vec::Vec::from_iter_in(
1790                     s.iter().map(|x| x.filter_map(alloc, f)),
1791                     alloc,
1792                 )
1793                 .into_bump_slice_mut(),
1794             )),
1795         }
1796     }
1798     pub fn filter_map_mut<F>(&mut self, alloc: &'a bumpalo::Bump, f: &mut F)
1799     where
1800         F: FnMut(&mut Instruct<'a>) -> bool,
1801     {
1802         //self: &mut InstrSeq<'a>
1803         match self {
1804             InstrSeq::List(s) if s.is_empty() => {}
1805             InstrSeq::List(s) if s.len() == 1 => {
1806                 let x: &mut Instruct<'a> = &mut s[0];
1807                 if !f(x) {
1808                     *self = instr::empty(alloc)
1809                 }
1810             }
1811             InstrSeq::List(s) => {
1812                 let mut new_lst = bumpalo::vec![in alloc;];
1813                 for mut i in s.iter_mut() {
1814                     if f(&mut i) {
1815                         new_lst.push(i.clone())
1816                     }
1817                 }
1818                 *self = instr::instrs(alloc, new_lst.into_bump_slice_mut())
1819             }
1820             InstrSeq::Concat(s) => s.iter_mut().for_each(|x| x.filter_map_mut(alloc, f)),
1821         }
1822     }
1824     pub fn map_mut<F>(&mut self, f: &mut F)
1825     where
1826         F: FnMut(&mut Instruct<'a>),
1827     {
1828         //self: &mut InstrSeq<'a>
1829         match self {
1830             InstrSeq::List(s) if s.is_empty() => {}
1831             InstrSeq::List(s) if s.len() == 1 => f(&mut s[0]),
1832             InstrSeq::List(s) => s.iter_mut().for_each(f),
1833             InstrSeq::Concat(s) => s.iter_mut().for_each(|x| x.map_mut(f)),
1834         }
1835     }
1837     #[allow(clippy::result_unit_err)]
1838     pub fn map_result_mut<F>(&mut self, f: &mut F) -> Result<()>
1839     where
1840         F: FnMut(&mut Instruct<'a>) -> Result<()>,
1841     {
1842         //self: &mut InstrSeq<'a>
1843         match self {
1844             InstrSeq::List(s) if s.is_empty() => Ok(()),
1845             InstrSeq::List(s) if s.len() == 1 => f(&mut s[0]),
1846             InstrSeq::List(s) => s.iter_mut().try_for_each(|x| f(x)),
1847             InstrSeq::Concat(s) => s.iter_mut().try_for_each(|x| x.map_result_mut(f)),
1848         }
1849     }
1852 #[cfg(test)]
1853 mod tests {
1854     use super::*;
1855     use crate::instr::{instr, instrs};
1856     use pretty_assertions::assert_eq;
1858     #[test]
1859     fn iter() {
1860         let a = bumpalo::Bump::new();
1861         let alloc: &bumpalo::Bump = &a;
1862         let mk_i = || Instruct::IComment(Str::from(""));
1863         let empty = || InstrSeq::new_empty(alloc);
1865         let one = || instr(alloc, mk_i());
1866         let list0 = || instrs(alloc, bumpalo::vec![in alloc;].into_bump_slice_mut());
1867         let list1 = || instrs(alloc, bumpalo::vec![in alloc; mk_i()].into_bump_slice_mut());
1868         let list2 = || {
1869             instrs(
1870                 alloc,
1871                 bumpalo::vec![in alloc; mk_i(), mk_i()].into_bump_slice_mut(),
1872             )
1873         };
1874         let concat0 = || {
1875             InstrSeq::Concat(BumpSliceMut::new(
1876                 alloc,
1877                 bumpalo::vec![in alloc;].into_bump_slice_mut(),
1878             ))
1879         };
1880         let concat1 = || {
1881             InstrSeq::Concat(BumpSliceMut::new(
1882                 alloc,
1883                 bumpalo::vec![in alloc; one()].into_bump_slice_mut(),
1884             ))
1885         };
1887         assert_eq!(empty().iter().count(), 0);
1888         assert_eq!(one().iter().count(), 1);
1889         assert_eq!(list0().iter().count(), 0);
1890         assert_eq!(list1().iter().count(), 1);
1891         assert_eq!(list2().iter().count(), 2);
1892         assert_eq!(concat0().iter().count(), 0);
1893         assert_eq!(concat1().iter().count(), 1);
1895         let concat = InstrSeq::Concat(BumpSliceMut::new(
1896             alloc,
1897             bumpalo::vec![in alloc; empty()].into_bump_slice_mut(),
1898         ));
1899         assert_eq!(concat.iter().count(), 0);
1901         let concat = InstrSeq::Concat(BumpSliceMut::new(
1902             alloc,
1903             bumpalo::vec![in alloc; empty(), one()].into_bump_slice_mut(),
1904         ));
1905         assert_eq!(concat.iter().count(), 1);
1907         let concat = InstrSeq::Concat(BumpSliceMut::new(
1908             alloc,
1909             bumpalo::vec![in alloc; one(), empty()].into_bump_slice_mut(),
1910         ));
1911         assert_eq!(concat.iter().count(), 1);
1913         let concat = InstrSeq::Concat(BumpSliceMut::new(
1914             alloc,
1915             bumpalo::vec![in alloc; one(), list1()].into_bump_slice_mut(),
1916         ));
1917         assert_eq!(concat.iter().count(), 2);
1919         let concat = InstrSeq::Concat(BumpSliceMut::new(
1920             alloc,
1921             bumpalo::vec![in alloc; list2(), list1()].into_bump_slice_mut(),
1922         ));
1923         assert_eq!(concat.iter().count(), 3);
1925         let concat = InstrSeq::Concat(BumpSliceMut::new(
1926             alloc,
1927             bumpalo::vec![in alloc; concat0(), list2(), list1()].into_bump_slice_mut(),
1928         ));
1929         assert_eq!(concat.iter().count(), 3);
1931         let concat = InstrSeq::Concat(BumpSliceMut::new(
1932             alloc,
1933             bumpalo::vec![in alloc; concat1(), concat1()].into_bump_slice_mut(),
1934         ));
1935         assert_eq!(concat.iter().count(), 2);
1937         let concat = InstrSeq::Concat(BumpSliceMut::new(
1938             alloc,
1939             bumpalo::vec![in alloc; concat0(), concat1()].into_bump_slice_mut(),
1940         ));
1941         assert_eq!(concat.iter().count(), 1);
1943         let concat = InstrSeq::Concat(BumpSliceMut::new(
1944             alloc,
1945             bumpalo::vec![in alloc; list2(), concat1()].into_bump_slice_mut(),
1946         ));
1947         assert_eq!(concat.iter().count(), 3);
1949         let concat = InstrSeq::Concat(BumpSliceMut::new(
1950             alloc,
1951             bumpalo::vec![in alloc; list2(), concat0()].into_bump_slice_mut(),
1952         ));
1953         assert_eq!(concat.iter().count(), 2);
1955         let concat = InstrSeq::Concat(BumpSliceMut::new(
1956             alloc,
1957             bumpalo::vec![in alloc; one(), concat0()].into_bump_slice_mut(),
1958         ));
1959         assert_eq!(concat.iter().count(), 1);
1961         let concat = InstrSeq::Concat(BumpSliceMut::new(
1962             alloc,
1963             bumpalo::vec![in alloc; empty(), concat0()].into_bump_slice_mut(),
1964         ));
1965         assert_eq!(concat.iter().count(), 0);
1966     }
1969 #[no_mangle]
1970 pub unsafe extern "C" fn no_call_compile_only_USED_TYPES_instruction_sequence<'a, 'arena>(
1971     _: InstrSeq<'arena>,
1972 ) {
1973     unimplemented!()