1use crate::compiler_error::{CompilerFailure, CompilerStage};
8use crate::tree_height;
9
10use crate::{
11 Ast, Binding, BindingKind, ClassMember, Expr, ExprId, ExprKind, Ident, ParamDecl,
12 PatternOrigin, Span, Stmt, StmtId, StmtKind,
13};
14
15pub fn lower(mut ast: Ast) -> Result<Ast, CompilerFailure> {
16 tree_height::check_syntax(&ast).map_err(|failure| failure.with_stage(CompilerStage::Infer))?;
19 let mut ctx = LowerCtx { next_tmp: 0 };
20 ctx.lower_arrows(&mut ast)?;
21 ctx.lower_function_params(&mut ast)?;
22 ctx.lower_class_member_params(&mut ast)?;
23 ctx.lower_for_of_patterns(&mut ast)?;
24 ctx.lower_for_pattern_inits(&mut ast)?;
25 ctx.lower_pattern_stmts(&mut ast)?;
26 Ok(ast)
27}
28
29const FRESH_MARKER: &str = "#pattern_";
31
32const PATTERN_PARAM: &str = "p";
34
35pub(crate) fn is_pattern_param(name: &str) -> bool {
39 name.is_empty()
40 || name
41 .strip_prefix(FRESH_MARKER)
42 .and_then(|rest| rest.strip_prefix(PATTERN_PARAM))
43 .is_some_and(|rest| rest.starts_with('_'))
44}
45
46struct LowerCtx {
47 next_tmp: u32,
48}
49
50#[derive(Clone, Copy)]
52struct PatternRoot {
53 is_const: bool,
54 annotated: bool,
57}
58
59impl LowerCtx {
60 fn fresh(&mut self, prefix: &str, span: Span) -> Result<Ident, CompilerFailure> {
61 let n = self.next_tmp;
62 self.next_tmp = self
63 .next_tmp
64 .checked_add(1)
65 .ok_or_else(|| CompilerFailure::Limit {
66 stage: CompilerStage::Infer,
67 span: None,
68 message: "pattern temporary capacity exceeded".into(),
69 help: vec![],
70 })?;
71 Ok(Ident {
72 name: format!("{FRESH_MARKER}{prefix}_{n}"),
74 span,
75 })
76 }
77
78 fn lower_arrows(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
79 for id in ast
80 .expr_ids()
81 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
82 {
83 let has_pattern = match &ast
84 .try_expr(id)
85 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
86 .kind
87 {
88 ExprKind::Arrow { params, .. } => params.iter().any(|p| p.pattern.is_some()),
89 _ => false,
90 };
91 if has_pattern {
92 self.lower_arrow(ast, id)?;
93 }
94 }
95
96 Ok(())
97 }
98
99 fn lower_arrow(&mut self, ast: &mut Ast, id: ExprId) -> Result<(), CompilerFailure> {
100 let kind = ast
103 .try_expr(id)
104 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
105 .kind
106 .clone();
107 let ExprKind::Arrow {
108 mut params,
109 return_type,
110 type_predicate,
111 body,
112 } = kind
113 else {
114 return Err(lowering_failure(
115 "unexpected node kind during pattern lowering",
116 ));
117 };
118
119 self.materialise_pattern_params(ast, &mut params)?;
120
121 ast.try_expr_mut(id)
122 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
123 .kind = ExprKind::Arrow {
124 params,
125 return_type,
126 type_predicate,
127 body,
128 };
129
130 Ok(())
131 }
132
133 fn lower_function_params(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
134 for id in ast
135 .stmt_ids()
136 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
137 {
138 let has_pattern = match &ast
139 .try_stmt(id)
140 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
141 .kind
142 {
143 StmtKind::Function { params, .. } => params.iter().any(|p| p.pattern.is_some()),
144 _ => false,
145 };
146 if has_pattern {
147 self.lower_function(ast, id)?;
148 }
149 }
150
151 Ok(())
152 }
153
154 fn lower_function(&mut self, ast: &mut Ast, id: StmtId) -> Result<(), CompilerFailure> {
155 let stmt_span = ast
156 .try_stmt(id)
157 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
158 .span;
159 let kind = std::mem::replace(
160 &mut ast
161 .try_stmt_mut(id)
162 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
163 .kind,
164 StmtKind::Block(Vec::new()), );
166 let StmtKind::Function {
167 name,
168 generics,
169 mut params,
170 return_type,
171 type_predicate,
172 body,
173 doc,
174 } = kind
175 else {
176 return Err(lowering_failure(
177 "unexpected node kind during pattern lowering",
178 ));
179 };
180
181 self.materialise_pattern_params(ast, &mut params)?;
182
183 ast.try_stmt_mut(id)
184 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
185 .kind = StmtKind::Function {
186 name,
187 generics,
188 params,
189 return_type,
190 type_predicate,
191 body,
192 doc,
193 };
194 let _ = stmt_span;
196
197 Ok(())
198 }
199
200 fn lower_class_member_params(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
201 for id in ast
202 .stmt_ids()
203 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
204 {
205 let StmtKind::ClassDecl { members, .. } = &mut ast
206 .try_stmt_mut(id)
207 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
208 .kind
209 else {
210 continue;
211 };
212 let mut taken = std::mem::take(members);
213 let lowered = self.lower_member_params(ast, &mut taken);
214 let StmtKind::ClassDecl { members, .. } = &mut ast
217 .try_stmt_mut(id)
218 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
219 .kind
220 else {
221 return Err(lowering_failure(
222 "unexpected node kind during pattern lowering",
223 ));
224 };
225 *members = taken;
226 lowered?;
227 }
228
229 Ok(())
230 }
231
232 fn lower_member_params(
233 &mut self,
234 ast: &mut Ast,
235 members: &mut [ClassMember],
236 ) -> Result<(), CompilerFailure> {
237 for member in members {
238 let params = match member {
239 ClassMember::Method { params, .. } | ClassMember::Constructor { params, .. } => {
240 params.as_mut_slice()
241 }
242 ClassMember::Accessor {
243 param: Some(param), ..
244 } => std::slice::from_mut(param.as_mut()),
245 ClassMember::Accessor { param: None, .. } | ClassMember::Field { .. } => continue,
246 };
247 self.materialise_pattern_params(ast, params)?;
248 }
249
250 Ok(())
251 }
252
253 fn lower_for_of_patterns(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
254 for id in ast
255 .stmt_ids()
256 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
257 {
258 if !matches!(
259 ast.try_stmt(id)
260 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
261 .kind,
262 StmtKind::ForOfPattern { .. }
263 ) {
264 continue;
265 }
266 self.expand_for_of_pattern(ast, id)?;
267 }
268
269 Ok(())
270 }
271
272 fn expand_for_of_pattern(&mut self, ast: &mut Ast, id: StmtId) -> Result<(), CompilerFailure> {
273 let stmt_span = ast
274 .try_stmt(id)
275 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
276 .span;
277 let kind = std::mem::replace(
278 &mut ast
279 .try_stmt_mut(id)
280 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
281 .kind,
282 StmtKind::Block(Vec::new()),
283 );
284 let StmtKind::ForOfPattern {
285 binding_kind,
286 binding,
287 ty,
288 iter,
289 body,
290 } = kind
291 else {
292 return Err(lowering_failure(
293 "unexpected node kind during pattern lowering",
294 ));
295 };
296
297 let pattern_span = binding.span();
298 let dst = self.fresh("dst", pattern_span)?;
299 let is_const = matches!(binding_kind, BindingKind::Const);
300 let root = PatternRoot {
301 is_const,
302 annotated: ty.is_some(),
303 };
304 let mut decompose = self.emit_decompose(
305 ast,
306 binding,
307 dst.clone(),
308 root,
309 None,
310 None,
311 )?;
312 let mut source_bindings = Vec::new();
313 for &id in &decompose {
314 match &ast
315 .try_stmt(id)
316 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
317 .kind
318 {
319 StmtKind::Let { name, .. }
320 | StmtKind::Const { name, .. }
321 | StmtKind::ObjectRest { name, .. } => source_bindings.push(name.clone()),
322 _ => {}
323 }
324 }
325 ast.for_of_pattern_bindings.insert(id, source_bindings);
326 decompose.push(body);
328 let body = ast
329 .try_push_stmt(Stmt {
330 kind: StmtKind::Block(decompose),
331 span: ast
332 .try_stmt(body)
333 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
334 .span,
335 })
336 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
337
338 ast.try_stmt_mut(id)
339 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
340 .kind = StmtKind::ForOf {
341 binding_kind,
342 name: dst,
343 ty,
344 iter,
345 body,
346 };
347 let _ = stmt_span;
348
349 Ok(())
350 }
351
352 fn lower_for_pattern_inits(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
353 for id in ast
354 .stmt_ids()
355 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
356 {
357 let StmtKind::For {
358 init: Some(init), ..
359 } = ast
360 .try_stmt(id)
361 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
362 .kind
363 else {
364 continue;
365 };
366 let is_let = match ast
367 .try_stmt(init)
368 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
369 .kind
370 {
371 StmtKind::LetPattern { .. } => true,
372 StmtKind::ConstPattern { .. } => false,
373 _ => continue,
374 };
375 self.hoist_for_pattern_init(ast, id, init, is_let)?;
376 }
377
378 Ok(())
379 }
380
381 fn hoist_for_pattern_init(
387 &mut self,
388 ast: &mut Ast,
389 id: StmtId,
390 init: StmtId,
391 is_let: bool,
392 ) -> Result<(), CompilerFailure> {
393 let mut hoisted = self.expand_pattern_stmt(ast, init)?;
394 let loop_stmt = ast
395 .try_stmt_mut(id)
396 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
397 let span = loop_stmt.span;
398 let kind = std::mem::replace(&mut loop_stmt.kind, StmtKind::Block(Vec::new()));
399 let StmtKind::For {
400 condition,
401 update,
402 body,
403 ..
404 } = kind
405 else {
406 return Err(lowering_failure(
407 "unexpected node kind during pattern lowering",
408 ));
409 };
410 let lowered_loop = ast
411 .try_push_stmt(Stmt {
412 kind: StmtKind::For {
413 init: None,
414 condition,
415 update,
416 body,
417 },
418 span,
419 })
420 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
421 if is_let {
422 let bindings = let_names(ast, &hoisted)?;
423 if !bindings.is_empty() {
424 ast.for_pattern_init_bindings.insert(lowered_loop, bindings);
425 }
426 }
427 hoisted.push(lowered_loop);
428 ast.try_stmt_mut(id)
429 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
430 .kind = StmtKind::Block(hoisted);
431
432 Ok(())
433 }
434
435 fn lower_pattern_stmts(&mut self, ast: &mut Ast) -> Result<(), CompilerFailure> {
436 let top = std::mem::take(&mut ast.top_level);
437 ast.top_level = self.expand_list(ast, top)?;
438
439 for id in ast
440 .stmt_ids()
441 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
442 {
443 let needs = matches!(
444 ast.try_stmt(id)
445 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
446 .kind,
447 StmtKind::Block(_)
448 );
449 if !needs {
450 continue;
451 }
452 let StmtKind::Block(taken) = std::mem::replace(
453 &mut ast
454 .try_stmt_mut(id)
455 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
456 .kind,
457 StmtKind::Block(Vec::new()),
458 ) else {
459 return Err(lowering_failure(
460 "unexpected node kind during pattern lowering",
461 ));
462 };
463 let expanded = self.expand_list(ast, taken)?;
464 ast.try_stmt_mut(id)
465 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
466 .kind = StmtKind::Block(expanded);
467 }
468
469 Ok(())
470 }
471
472 fn expand_list(
473 &mut self,
474 ast: &mut Ast,
475 ids: Vec<StmtId>,
476 ) -> Result<Vec<StmtId>, CompilerFailure> {
477 let mut out = Vec::with_capacity(ids.len());
478 for id in ids {
479 let is_pattern = matches!(
480 ast.try_stmt(id)
481 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
482 .kind,
483 StmtKind::LetPattern { .. } | StmtKind::ConstPattern { .. }
484 );
485 if !is_pattern {
486 out.push(id);
487 continue;
488 }
489 let expanded = self.expand_pattern_stmt(ast, id)?;
490 out.extend(expanded);
491 }
492 Ok(out)
493 }
494
495 fn expand_pattern_stmt(
496 &mut self,
497 ast: &mut Ast,
498 id: StmtId,
499 ) -> Result<Vec<StmtId>, CompilerFailure> {
500 let span = ast
501 .try_stmt(id)
502 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
503 .span;
504 let kind = std::mem::replace(
505 &mut ast
506 .try_stmt_mut(id)
507 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
508 .kind,
509 StmtKind::Block(Vec::new()), );
511 let (is_const, binding, ty, value, doc) = match kind {
512 StmtKind::LetPattern {
513 binding,
514 ty,
515 value,
516 doc,
517 } => (false, binding, ty, value, doc),
518 StmtKind::ConstPattern {
519 binding,
520 ty,
521 value,
522 doc,
523 } => (true, binding, ty, value, doc),
524 _ => {
525 return Err(lowering_failure(
526 "unexpected node kind during pattern lowering",
527 ));
528 }
529 };
530
531 let tuple_len = match ty {
532 None => tuple_source_len(ast, &binding, value)?,
533 Some(_) => None,
534 };
535 if let Some(len) = tuple_len {
536 pad_tuple_source(ast, value, len)?;
537 ast.tuple_pattern_sources.insert(value);
538 }
539 let pattern_span = binding.span();
540 let dst = self.fresh("dst", pattern_span)?;
541 let annotated = ty.is_some();
542
543 let dst_stmt = ast
545 .try_push_stmt(Stmt {
546 kind: StmtKind::Const {
547 name: dst.clone(),
548 ty,
549 value,
550 doc: None,
551 },
552 span,
553 })
554 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
555
556 let mut out = vec![dst_stmt];
557 let root = PatternRoot {
558 is_const,
559 annotated,
560 };
561 out.extend(self.emit_decompose(ast, binding, dst, root, doc, tuple_len)?);
562 Ok(out)
563 }
564
565 fn materialise_pattern_params(
566 &mut self,
567 ast: &mut Ast,
568 params: &mut [ParamDecl],
569 ) -> Result<(), CompilerFailure> {
570 for param in params.iter_mut() {
571 let Some(pattern) = param.pattern.take() else {
572 continue;
573 };
574 let fresh = self.fresh(PATTERN_PARAM, pattern.span())?;
575 param.name = fresh.clone();
576 let root = PatternRoot {
577 is_const: false,
578 annotated: param.ty.is_some(),
579 };
580 let statements = self.emit_decompose(
581 ast, pattern, fresh, root, None, None,
582 )?;
583 if ast
584 .parameter_bindings
585 .insert(param.name.span, statements)
586 .is_some()
587 {
588 return Err(lowering_failure(
589 "duplicate parameter binding span during pattern lowering",
590 ));
591 }
592 }
593
594 Ok(())
595 }
596
597 fn emit_decompose(
600 &mut self,
601 ast: &mut Ast,
602 binding: Binding,
603 source: Ident,
604 root: PatternRoot,
605 mut doc: Option<crate::DocComment>,
606 tuple_len: Option<usize>,
607 ) -> Result<Vec<StmtId>, CompilerFailure> {
608 let is_const = root.is_const;
609 let mut out = Vec::new();
610 match binding {
611 Binding::Object {
612 fields,
613 rest,
614 span: _,
615 } => {
616 let bound_names: Vec<Ident> = fields.iter().map(|f| f.source.clone()).collect();
617 for field in fields {
618 let recv = ast
619 .try_push_expr(Expr {
620 kind: ExprKind::Identifier(source.clone()),
621 span: field.span,
622 })
623 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
624 let access = ast
625 .try_push_expr(Expr {
626 kind: ExprKind::FieldAccess {
627 receiver: recv,
628 name: field.source.clone(),
629 },
630 span: field.span,
631 })
632 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
633 let value = self.apply_binding_default(
634 ast,
635 access,
636 field.default,
637 root.annotated,
638 field.span,
639 &mut out,
640 )?;
641 let decl = ast
642 .try_push_stmt(Stmt {
643 kind: make_decl(is_const, field.local, value, doc.take()),
644 span: field.span,
645 })
646 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
647 out.push(decl);
648 }
649 if let Some(rest_ident) = rest {
650 let src_expr = ast
651 .try_push_expr(Expr {
652 kind: ExprKind::Identifier(source.clone()),
653 span: rest_ident.span,
654 })
655 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
656 let decl = ast
657 .try_push_stmt(Stmt {
658 kind: StmtKind::ObjectRest {
659 is_const,
660 name: rest_ident.clone(),
661 source: src_expr,
662 exclude: bound_names,
663 ty: None,
664 doc: doc.take(),
665 },
666 span: rest_ident.span,
667 })
668 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
669 out.push(decl);
670 }
671 }
672 Binding::Array {
673 elems,
674 defaults,
675 rest,
676 span: pattern_span,
677 } => {
678 if elems.len() != defaults.len() {
679 return Err(lowering_failure(
680 "array pattern defaults do not match element positions",
681 ));
682 }
683 let elems_len = elems.len();
684 for (i, (slot, default)) in elems.into_iter().zip(defaults).enumerate() {
685 let Some(local) = slot else {
686 if default.is_some() {
687 return Err(lowering_failure("array pattern hole has a default value"));
688 }
689 continue;
690 };
691 let recv = ast
692 .try_push_expr(Expr {
693 kind: ExprKind::Identifier(source.clone()),
694 span: local.span,
695 })
696 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
697 let idx = ast
698 .try_push_expr(Expr {
699 kind: ExprKind::Number(i as f64),
700 span: local.span,
701 })
702 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
703 let access = ast
704 .try_push_expr(Expr {
705 kind: ExprKind::IndexAccess {
706 receiver: recv,
707 index: idx,
708 },
709 span: local.span,
710 })
711 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
712 ast.pattern_origins.insert(
714 access,
715 PatternOrigin {
716 pattern_span,
717 slot_arity: elems_len,
718 },
719 );
720 let access = if default.is_some() {
721 self.guard_defaulted_array_read(ast, recv, idx, access, local.span)?
722 } else {
723 access
724 };
725 let value = self.apply_binding_default(
726 ast,
727 access,
728 default,
729 root.annotated,
730 local.span,
731 &mut out,
732 )?;
733 let decl = ast
734 .try_push_stmt(Stmt {
735 kind: make_decl(is_const, local.clone(), value, doc.take()),
736 span: local.span,
737 })
738 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
739 out.push(decl);
740 }
741 if let Some(rest_ident) = rest {
742 let rest_value = match tuple_len {
743 Some(len) if len > elems_len => {
744 remaining_elements(ast, &source, elems_len..len, rest_ident.span)?
745 }
746 _ => array_rest(ast, &source, elems_len, rest_ident.span)?,
747 };
748 let decl = ast
749 .try_push_stmt(Stmt {
750 kind: make_decl(is_const, rest_ident.clone(), rest_value, doc.take()),
751 span: rest_ident.span,
752 })
753 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
754 out.push(decl);
755 }
756 }
757 }
758 Ok(out)
759 }
760
761 fn guard_defaulted_array_read(
764 &mut self,
765 ast: &mut Ast,
766 receiver: ExprId,
767 index: ExprId,
768 access: ExprId,
769 span: Span,
770 ) -> Result<ExprId, CompilerFailure> {
771 let length = push_expr(
772 ast,
773 ExprKind::FieldAccess {
774 receiver,
775 name: Ident {
776 name: "length".to_string(),
777 span,
778 },
779 },
780 span,
781 )?;
782 let in_bounds = push_expr(
783 ast,
784 ExprKind::Binary {
785 op: crate::BinOp::Lt,
786 lhs: index,
787 rhs: length,
788 },
789 span,
790 )?;
791 let zero = push_expr(ast, ExprKind::Number(0.0), span)?;
792 let undefined = push_expr(ast, ExprKind::Void { operand: zero }, span)?;
793 push_expr(
794 ast,
795 ExprKind::Ternary {
796 cond: in_bounds,
797 then_: access,
798 else_: undefined,
799 },
800 span,
801 )
802 }
803
804 fn apply_binding_default(
807 &mut self,
808 ast: &mut Ast,
809 access: ExprId,
810 default: Option<ExprId>,
811 annotated: bool,
812 span: Span,
813 out: &mut Vec<StmtId>,
814 ) -> Result<ExprId, CompilerFailure> {
815 let Some(default) = default else {
816 return Ok(access);
817 };
818 let saved = self.fresh("value", span)?;
819 let declaration = ast
820 .try_push_stmt(Stmt {
821 kind: make_decl(true, saved.clone(), access, None),
822 span,
823 })
824 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
825 out.push(declaration);
826 let saved_value = push_expr(ast, ExprKind::Identifier(saved.clone()), span)?;
827 let zero = push_expr(ast, ExprKind::Number(0.0), span)?;
828 let undefined = push_expr(ast, ExprKind::Void { operand: zero }, span)?;
829 let condition = push_expr(
830 ast,
831 ExprKind::Binary {
832 op: crate::BinOp::Eq,
833 lhs: saved_value,
834 rhs: undefined,
835 },
836 span,
837 )?;
838 let selected = push_expr(
839 ast,
840 ExprKind::Ternary {
841 cond: condition,
842 then_: default,
843 else_: saved_value,
844 },
845 span,
846 )?;
847 ast.binding_defaults.insert(
848 selected,
849 crate::ast::BindingDefault {
850 saved,
851 default,
852 annotated,
853 },
854 );
855 Ok(selected)
856 }
857}
858
859fn tuple_source_len(
866 ast: &Ast,
867 binding: &Binding,
868 value: ExprId,
869) -> Result<Option<usize>, CompilerFailure> {
870 let Binding::Array {
871 elems, defaults, ..
872 } = binding
873 else {
874 return Ok(None);
875 };
876 if elems.is_empty() {
877 return Ok(None);
878 }
879 let ExprKind::ArrayLiteral { elements } = &ast
880 .try_expr(value)
881 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
882 .kind
883 else {
884 return Ok(None);
885 };
886 let has_spread = elements
887 .iter()
888 .any(|element| matches!(element, crate::ArrayLiteralElement::Spread { .. }));
889 if has_spread {
890 return Ok(None);
891 }
892 let padded = elems.len() > elements.len()
893 && (elements.len()..elems.len()).all(|slot| {
894 elems.get(slot).is_some_and(Option::is_none)
895 || defaults.get(slot).is_some_and(Option::is_some)
896 });
897 Ok(Some(if padded { elems.len() } else { elements.len() }))
898}
899
900fn pad_tuple_source(ast: &mut Ast, value: ExprId, len: usize) -> Result<(), CompilerFailure> {
904 let expr = ast
905 .try_expr(value)
906 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?;
907 let span = expr.span;
908 let ExprKind::ArrayLiteral { elements } = &expr.kind else {
909 return Ok(());
910 };
911 let missing = len.saturating_sub(elements.len());
912 if missing == 0 {
913 return Ok(());
914 }
915 let mut padding = Vec::with_capacity(missing);
916 for _ in 0..missing {
917 let undefined = Ident {
918 name: "undefined".to_string(),
919 span,
920 };
921 let element = push_expr(ast, ExprKind::Identifier(undefined), span)?;
922 ast.synthetic_undefined.insert(element);
923 padding.push(crate::ArrayLiteralElement::Value(element));
924 }
925 if let ExprKind::ArrayLiteral { elements } = &mut ast
927 .try_expr_mut(value)
928 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
929 .kind
930 {
931 elements.extend(padding);
932 }
933 Ok(())
934}
935
936fn array_rest(
939 ast: &mut Ast,
940 source: &Ident,
941 from: usize,
942 span: Span,
943) -> Result<ExprId, CompilerFailure> {
944 let from_lit = push_expr(ast, ExprKind::Number(from as f64), span)?;
945 let slice_receiver = push_expr(ast, ExprKind::Identifier(source.clone()), span)?;
946 let slice_callee = push_expr(
947 ast,
948 ExprKind::FieldAccess {
949 receiver: slice_receiver,
950 name: Ident {
951 name: "slice".to_string(),
952 span,
953 },
954 },
955 span,
956 )?;
957 let length_receiver = push_expr(ast, ExprKind::Identifier(source.clone()), span)?;
958 let length_access = push_expr(
959 ast,
960 ExprKind::FieldAccess {
961 receiver: length_receiver,
962 name: Ident {
963 name: "length".to_string(),
964 span,
965 },
966 },
967 span,
968 )?;
969 let slice_call = push_expr(
970 ast,
971 ExprKind::Call {
972 callee: slice_callee,
973 type_args: None,
974 args: vec![from_lit, length_access],
975 },
976 span,
977 )?;
978 Ok(slice_call)
979}
980
981fn remaining_elements(
986 ast: &mut Ast,
987 source: &Ident,
988 indices: std::ops::Range<usize>,
989 span: Span,
990) -> Result<ExprId, CompilerFailure> {
991 let count = indices.len();
992 let mut elements = Vec::with_capacity(count);
993 for i in indices {
994 let receiver = push_expr(ast, ExprKind::Identifier(source.clone()), span)?;
995 let index = push_expr(ast, ExprKind::Number(i as f64), span)?;
996 let access = push_expr(ast, ExprKind::IndexAccess { receiver, index }, span)?;
997 elements.push(crate::ArrayLiteralElement::Value(access));
998 }
999 let remaining = push_expr(ast, ExprKind::ArrayLiteral { elements }, span)?;
1000 ast.tuple_pattern_sources.insert(remaining);
1001 let slice = push_expr(
1002 ast,
1003 ExprKind::FieldAccess {
1004 receiver: remaining,
1005 name: Ident {
1006 name: "slice".to_string(),
1007 span,
1008 },
1009 },
1010 span,
1011 )?;
1012 let from = push_expr(ast, ExprKind::Number(0.0), span)?;
1013 let to = push_expr(ast, ExprKind::Number(count as f64), span)?;
1014 push_expr(
1015 ast,
1016 ExprKind::Call {
1017 callee: slice,
1018 type_args: None,
1019 args: vec![from, to],
1020 },
1021 span,
1022 )
1023}
1024
1025fn push_expr(ast: &mut Ast, kind: ExprKind, span: Span) -> Result<ExprId, CompilerFailure> {
1026 ast.try_push_expr(Expr { kind, span })
1027 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))
1028}
1029
1030fn make_decl(
1031 is_const: bool,
1032 name: Ident,
1033 value: ExprId,
1034 doc: Option<crate::DocComment>,
1035) -> StmtKind {
1036 if is_const {
1037 StmtKind::Const {
1038 name,
1039 ty: None,
1040 value,
1041 doc,
1042 }
1043 } else {
1044 StmtKind::Let {
1045 name,
1046 ty: None,
1047 value,
1048 doc,
1049 }
1050 }
1051}
1052
1053fn let_names(ast: &Ast, stmts: &[StmtId]) -> Result<Vec<Ident>, CompilerFailure> {
1055 let mut names = Vec::new();
1056 for &stmt in stmts {
1057 if let StmtKind::Let { name, .. } = &ast
1058 .try_stmt(stmt)
1059 .map_err(|error| error.into_compiler_failure(CompilerStage::Infer))?
1060 .kind
1061 {
1062 names.push(name.clone());
1063 }
1064 }
1065 Ok(names)
1066}
1067
1068fn lowering_failure(message: &str) -> CompilerFailure {
1069 CompilerFailure::Internal {
1070 stage: CompilerStage::Infer,
1071 span: None,
1072 message: message.into(),
1073 }
1074}
1075
1076#[cfg(test)]
1077mod tests {
1078 use super::lower;
1079 use crate::{Asi, Binding, Stmt, StmtKind, Token, TokenKind, parse};
1080
1081 fn pipeline(source: &str) -> crate::Ast {
1082 let mut asi = Asi::new(source, crate::FileId(0));
1083 let mut tokens: Vec<Token> = Vec::new();
1084 loop {
1085 let t = asi.next_token();
1086 let is_eof = matches!(t.kind, TokenKind::Eof);
1087 tokens.push(t);
1088 if is_eof {
1089 break;
1090 }
1091 }
1092 let _ = asi.into_diagnostics();
1093 let (mut ast, diags) = parse(source, tokens, crate::FileId(0));
1094 assert!(diags.is_empty(), "unexpected parse diags: {diags:?}");
1095 ast = lower(ast).unwrap();
1096 ast
1097 }
1098
1099 fn no_patterns_left(ast: &crate::Ast) {
1100 for i in 0..ast.stmts_len() {
1101 let s = ast.try_stmt(crate::StmtId(i as u32)).unwrap();
1102 assert!(
1103 !matches!(
1104 s.kind,
1105 StmtKind::LetPattern { .. }
1106 | StmtKind::ConstPattern { .. }
1107 | StmtKind::ForOfPattern { .. }
1108 ),
1109 "found unlowered pattern at stmt #{i}: {:?}",
1110 s.kind,
1111 );
1112 if let StmtKind::Function { params, .. } = &s.kind {
1113 for (pi, p) in params.iter().enumerate() {
1114 assert!(
1115 p.pattern.is_none(),
1116 "function param #{pi} still has a pattern after lowering",
1117 );
1118 }
1119 }
1120 }
1121 for i in 0..ast.exprs_len() {
1122 let e = ast.try_expr(crate::ExprId(i as u32)).unwrap();
1123 if let crate::ExprKind::Arrow { params, .. } = &e.kind {
1124 for (pi, p) in params.iter().enumerate() {
1125 assert!(
1126 p.pattern.is_none(),
1127 "arrow param #{pi} still has a pattern after lowering",
1128 );
1129 }
1130 }
1131 }
1132 }
1133
1134 #[test]
1135 fn lowers_simple_object_destructure() {
1136 let ast = pipeline("const { a, b } = obj;");
1137 no_patterns_left(&ast);
1138 assert_eq!(ast.top_level.len(), 3);
1140 let names: Vec<String> = ast
1141 .top_level
1142 .iter()
1143 .map(|id| match &ast.try_stmt(*id).unwrap().kind {
1144 StmtKind::Const { name, .. } => name.name.clone(),
1145 other => panic!("expected Const, got {other:?}"),
1146 })
1147 .collect();
1148 assert!(names[0].starts_with("#pattern_dst_"));
1149 assert_eq!(names[1], "a");
1150 assert_eq!(names[2], "b");
1151 }
1152
1153 #[test]
1154 fn lowers_renamed_object_destructure() {
1155 let ast = pipeline("const { a: x, b: y } = obj;");
1156 no_patterns_left(&ast);
1157 let names: Vec<String> = ast
1158 .top_level
1159 .iter()
1160 .map(|id| match &ast.try_stmt(*id).unwrap().kind {
1161 StmtKind::Const { name, .. } => name.name.clone(),
1162 other => panic!("expected Const, got {other:?}"),
1163 })
1164 .collect();
1165 assert_eq!(names[1], "x");
1166 assert_eq!(names[2], "y");
1167 }
1168
1169 #[test]
1170 fn lowers_array_destructure() {
1171 let ast = pipeline("const [x, y] = arr;");
1172 no_patterns_left(&ast);
1173 assert_eq!(ast.top_level.len(), 3);
1174 if let StmtKind::Const { value, .. } = &ast.try_stmt(ast.top_level[1]).unwrap().kind {
1175 assert!(matches!(
1176 ast.try_expr(*value).unwrap().kind,
1177 crate::ExprKind::IndexAccess { .. }
1178 ));
1179 }
1180 }
1181
1182 #[test]
1183 fn lowers_array_with_hole_and_rest() {
1184 let ast = pipeline("const [, x, ...rest] = arr;");
1185 no_patterns_left(&ast);
1186 assert_eq!(ast.top_level.len(), 3);
1188 if let StmtKind::Const { name, value, .. } = &ast.try_stmt(ast.top_level[1]).unwrap().kind {
1189 assert_eq!(name.name, "x");
1190 if let crate::ExprKind::IndexAccess { index, .. } = &ast.try_expr(*value).unwrap().kind
1191 {
1192 assert_eq!(
1193 ast.try_expr(*index).unwrap().kind,
1194 crate::ExprKind::Number(1.0)
1195 );
1196 } else {
1197 panic!("expected IndexAccess");
1198 }
1199 }
1200 if let StmtKind::Const { name, value, .. } = &ast.try_stmt(ast.top_level[2]).unwrap().kind {
1201 assert_eq!(name.name, "rest");
1202 match &ast.try_expr(*value).unwrap().kind {
1203 crate::ExprKind::Call { callee, args, .. } => {
1204 assert_eq!(args.len(), 2, "slice takes (start, end)");
1205 assert_eq!(
1206 ast.try_expr(args[0]).unwrap().kind,
1207 crate::ExprKind::Number(2.0)
1208 );
1209 match &ast.try_expr(*callee).unwrap().kind {
1210 crate::ExprKind::FieldAccess { name, .. } => {
1211 assert_eq!(name.name, "slice");
1212 }
1213 other => panic!("expected slice FieldAccess, got {other:?}"),
1214 }
1215 }
1216 other => panic!("expected Call, got {other:?}"),
1217 }
1218 }
1219 }
1220
1221 #[test]
1222 fn lowers_object_rest_to_object_rest() {
1223 let ast = pipeline("const { a, ...rest } = obj;");
1224 no_patterns_left(&ast);
1225 assert_eq!(ast.top_level.len(), 3);
1226 match &ast.try_stmt(ast.top_level[2]).unwrap().kind {
1227 StmtKind::ObjectRest {
1228 is_const,
1229 name,
1230 exclude,
1231 ..
1232 } => {
1233 assert!(*is_const);
1234 assert_eq!(name.name, "rest");
1235 assert_eq!(exclude.len(), 1);
1236 assert_eq!(exclude[0].name, "a");
1237 }
1238 other => panic!("expected ObjectRest, got {other:?}"),
1239 }
1240 }
1241
1242 #[test]
1243 fn lowers_function_param_pattern() {
1244 let src = "function f({ a, b }: T): number { return a + b; }";
1245 let ast = pipeline(src);
1246 no_patterns_left(&ast);
1247 let Stmt {
1248 kind: StmtKind::Function { body, params, .. },
1249 ..
1250 } = ast.try_stmt(ast.top_level[0]).unwrap().clone()
1251 else {
1252 panic!("expected Function");
1253 };
1254 assert_eq!(params.len(), 1);
1255 assert!(params[0].pattern.is_none());
1256 assert!(params[0].name.name.starts_with("#pattern_p_"));
1257 let body_stmts = match &ast.try_stmt(body).unwrap().kind {
1258 StmtKind::Block(s) => s.clone(),
1259 _ => panic!("body is not a Block"),
1260 };
1261 assert_eq!(body_stmts.len(), 1);
1262 let bindings = ast.parameter_bindings.get(¶ms[0].name.span).unwrap();
1263 assert_eq!(bindings.len(), 2);
1264 if let StmtKind::Let { name, .. } = &ast.try_stmt(bindings[0]).unwrap().kind {
1265 assert_eq!(name.name, "a");
1266 } else {
1267 panic!("expected Let a");
1268 }
1269 if let StmtKind::Let { name, .. } = &ast.try_stmt(bindings[1]).unwrap().kind {
1270 assert_eq!(name.name, "b");
1271 } else {
1272 panic!("expected Let b");
1273 }
1274 assert!(matches!(
1275 ast.try_stmt(body_stmts[0]).unwrap().kind,
1276 StmtKind::Return(_)
1277 ));
1278 }
1279
1280 #[test]
1281 fn parameter_object_rest_has_a_mutable_authored_binding() {
1282 let ast = pipeline("function f({ head, ...tail }: T): number { return tail.value; }");
1283 let StmtKind::Function { params, .. } = &ast.try_stmt(ast.top_level[0]).unwrap().kind
1284 else {
1285 panic!("expected function");
1286 };
1287 let bindings = ast.parameter_bindings.get(¶ms[0].name.span).unwrap();
1288 assert_eq!(bindings.len(), 2);
1289 let StmtKind::ObjectRest { is_const, name, .. } = &ast.try_stmt(bindings[1]).unwrap().kind
1290 else {
1291 panic!("expected object rest binding");
1292 };
1293 assert!(!*is_const);
1294 assert_eq!(name.name, "tail");
1295 }
1296
1297 #[test]
1298 fn lowers_arrow_expr_body_with_pattern() {
1299 let src = "const f = ({a, b}: T): number => a + b;";
1300 let ast = pipeline(src);
1301 no_patterns_left(&ast);
1302 let mut found = false;
1303 for i in 0..ast.exprs_len() {
1304 let e = ast.try_expr(crate::ExprId(i as u32)).unwrap();
1305 if let crate::ExprKind::Arrow { params, body, .. } = &e.kind {
1306 assert!(matches!(body, crate::ArrowBody::Expr(_)));
1307 assert_eq!(
1308 ast.parameter_bindings
1309 .get(¶ms[0].name.span)
1310 .unwrap()
1311 .len(),
1312 2
1313 );
1314 found = true;
1315 }
1316 }
1317 assert!(found, "no Arrow found in expr arena");
1318 }
1319
1320 #[test]
1321 fn lowers_for_of_array_pattern() {
1322 let src = "function main(): void { for (const [a, b] of pairs) { use(a, b); } }";
1326 let ast = pipeline(src);
1327 no_patterns_left(&ast);
1328
1329 let Stmt {
1330 kind: StmtKind::Function { body, .. },
1331 ..
1332 } = ast.try_stmt(ast.top_level[0]).unwrap().clone()
1333 else {
1334 panic!("expected Function");
1335 };
1336 let body_stmts = match &ast.try_stmt(body).unwrap().kind {
1337 StmtKind::Block(s) => s.clone(),
1338 _ => panic!("function body is not a Block"),
1339 };
1340 assert_eq!(body_stmts.len(), 1, "main body has just the for-of");
1341
1342 let (loop_name, loop_body) = match &ast.try_stmt(body_stmts[0]).unwrap().kind {
1343 StmtKind::ForOf { name, body, .. } => (name.name.clone(), *body),
1344 other => panic!("expected ForOf, got {other:?}"),
1345 };
1346 assert!(
1347 loop_name.starts_with("#pattern_dst_"),
1348 "loop var was rewritten to a synth temp; got {loop_name}",
1349 );
1350
1351 let loop_body_stmts = match &ast.try_stmt(loop_body).unwrap().kind {
1352 StmtKind::Block(s) => s.clone(),
1353 _ => panic!("for-of body is not a Block"),
1354 };
1355 assert_eq!(loop_body_stmts.len(), 3);
1356 if let StmtKind::Const { name, value, .. } = &ast.try_stmt(loop_body_stmts[0]).unwrap().kind
1357 {
1358 assert_eq!(name.name, "a");
1359 assert!(matches!(
1360 ast.try_expr(*value).unwrap().kind,
1361 crate::ExprKind::IndexAccess { .. }
1362 ));
1363 assert!(ast.pattern_origins.contains_key(value));
1365 } else {
1366 panic!("expected Const a");
1367 }
1368 if let StmtKind::Const { name, .. } = &ast.try_stmt(loop_body_stmts[1]).unwrap().kind {
1369 assert_eq!(name.name, "b");
1370 } else {
1371 panic!("expected Const b");
1372 }
1373 }
1374
1375 #[test]
1376 fn lowers_let_pattern_preserves_mutability() {
1377 let ast = pipeline("let { a } = obj;");
1379 no_patterns_left(&ast);
1380 assert!(matches!(
1382 ast.try_stmt(ast.top_level[0]).unwrap().kind,
1383 StmtKind::Const { .. }
1384 ));
1385 assert!(matches!(
1386 ast.try_stmt(ast.top_level[1]).unwrap().kind,
1387 StmtKind::Let { .. }
1388 ));
1389 }
1390
1391 #[test]
1392 fn no_op_on_plain_program() {
1393 let src = "const x = 1; function main(): void { }";
1394 let before = {
1395 let mut asi = Asi::new(src, crate::FileId(0));
1396 let mut tokens: Vec<Token> = Vec::new();
1397 loop {
1398 let t = asi.next_token();
1399 let is_eof = matches!(t.kind, TokenKind::Eof);
1400 tokens.push(t);
1401 if is_eof {
1402 break;
1403 }
1404 }
1405 let _ = asi.into_diagnostics();
1406 let (ast, _) = parse(src, tokens, crate::FileId(0));
1407 ast
1408 };
1409 let after = pipeline(src);
1410 assert_eq!(format!("{before:?}"), format!("{after:?}"));
1411 }
1412
1413 #[test]
1414 fn lowers_pattern_in_nested_block() {
1415 let src = "function main(): void { const { a } = obj; }";
1416 let ast = pipeline(src);
1417 no_patterns_left(&ast);
1418 }
1419
1420 #[test]
1421 fn idempotent() {
1422 let src = "const { a, b } = obj;";
1423 let mut ast1 = pipeline(src);
1424 let snapshot = format!("{ast1:?}");
1425 ast1 = lower(ast1).unwrap();
1426 assert_eq!(snapshot, format!("{ast1:?}"));
1427 }
1428
1429 #[test]
1430 fn binding_span_preserved() {
1431 let (ast, _) = parse(
1432 "const { a } = obj;",
1433 tokens_of("const { a } = obj;"),
1434 crate::FileId(0),
1435 );
1436 match &ast.try_stmt(ast.top_level[0]).unwrap().kind {
1437 crate::StmtKind::ConstPattern {
1438 binding: Binding::Object { span, .. },
1439 ..
1440 } => {
1441 assert_eq!(*span, crate::Span::new(crate::FileId(0), 6, 11).unwrap());
1443 }
1444 other => panic!("expected ConstPattern Object, got {other:?}"),
1445 }
1446 }
1447
1448 #[test]
1449 fn defaults_save_each_access_once_and_test_undefined() {
1450 for source in [
1451 "const { a = fallback() } = source();",
1452 "const [a = fallback()] = source();",
1453 ] {
1454 let ast = pipeline(source);
1455 assert_eq!(ast.top_level.len(), 3);
1456 let StmtKind::Const {
1457 value: saved_access,
1458 ..
1459 } = ast.try_stmt(ast.top_level[1]).unwrap().kind
1460 else {
1461 panic!("expected saved read")
1462 };
1463 assert!(matches!(
1464 ast.try_expr(saved_access).unwrap().kind,
1465 crate::ExprKind::FieldAccess { .. } | crate::ExprKind::Ternary { .. }
1466 ));
1467 let StmtKind::Const { value, .. } = ast.try_stmt(ast.top_level[2]).unwrap().kind else {
1468 panic!("expected binding")
1469 };
1470 let crate::ExprKind::Ternary { cond, then_, else_ } = ast.try_expr(value).unwrap().kind
1471 else {
1472 panic!("expected lazy default")
1473 };
1474 let crate::ExprKind::Binary {
1475 op: crate::BinOp::Eq,
1476 lhs,
1477 rhs,
1478 } = ast.try_expr(cond).unwrap().kind
1479 else {
1480 panic!("expected undefined comparison")
1481 };
1482 assert_eq!(lhs, else_);
1483 assert!(matches!(
1484 ast.try_expr(rhs).unwrap().kind,
1485 crate::ExprKind::Void { .. }
1486 ));
1487 assert!(matches!(
1488 ast.try_expr(then_).unwrap().kind,
1489 crate::ExprKind::Call { .. }
1490 ));
1491 }
1492 }
1493
1494 #[test]
1495 fn array_defaults_keep_original_indices_and_origin_metadata() {
1496 let ast = pipeline("const [, a = 1] = values;");
1497 let StmtKind::Const { value, .. } = ast.try_stmt(ast.top_level[1]).unwrap().kind else {
1498 panic!("expected saved index read")
1499 };
1500 let crate::ExprKind::Ternary {
1501 cond,
1502 then_: access,
1503 else_,
1504 } = ast.try_expr(value).unwrap().kind
1505 else {
1506 panic!("expected bounds guard")
1507 };
1508 assert!(matches!(
1509 ast.try_expr(cond).unwrap().kind,
1510 crate::ExprKind::Binary {
1511 op: crate::BinOp::Lt,
1512 ..
1513 }
1514 ));
1515 assert!(matches!(
1516 ast.try_expr(else_).unwrap().kind,
1517 crate::ExprKind::Void { .. }
1518 ));
1519 let crate::ExprKind::IndexAccess { index, .. } = ast.try_expr(access).unwrap().kind else {
1520 panic!("expected guarded index")
1521 };
1522 assert!(matches!(
1523 ast.try_expr(index).unwrap().kind,
1524 crate::ExprKind::Number(1.0)
1525 ));
1526 assert_eq!(ast.pattern_origins.get(&access).unwrap().slot_arity, 2);
1527 }
1528
1529 #[test]
1530 fn lowers_class_method_parameter_defaults() {
1531 let ast = pipeline("class C { method({ x = 1 }: T): number { return x; } }");
1532 let StmtKind::ClassDecl { ref members, .. } = ast.try_stmt(ast.top_level[0]).unwrap().kind
1533 else {
1534 panic!("expected class")
1535 };
1536 let crate::ClassMember::Method { params, body, .. } = &members[0] else {
1537 panic!("expected method")
1538 };
1539 assert!(params[0].pattern.is_none());
1540 let StmtKind::Block(ref statements) = ast.try_stmt(*body).unwrap().kind else {
1541 panic!("expected block")
1542 };
1543 assert_eq!(statements.len(), 1);
1544 assert_eq!(
1545 ast.parameter_bindings
1546 .get(¶ms[0].name.span)
1547 .unwrap()
1548 .len(),
1549 2
1550 );
1551 }
1552
1553 fn tokens_of(source: &str) -> Vec<Token> {
1554 let mut asi = Asi::new(source, crate::FileId(0));
1555 let mut tokens = Vec::new();
1556 loop {
1557 let t = asi.next_token();
1558 let is_eof = matches!(t.kind, TokenKind::Eof);
1559 tokens.push(t);
1560 if is_eof {
1561 break;
1562 }
1563 }
1564 let _ = asi.into_diagnostics();
1565 tokens
1566 }
1567}