1use core::mem::{replace, take};
2use core::ops::Neg;
3
4use num::ToPrimitive;
5use tracing::instrument_ast;
6
7use crate::alloc::prelude::*;
8use crate::alloc::try_format;
9use crate::alloc::{self, Box, HashMap, HashSet};
10use crate::ast::{self, NumberSize, Spanned};
11use crate::compile::meta;
12use crate::compile::{self, ErrorKind, WithSpan};
13use crate::hash::ParametersBuilder;
14use crate::hir;
15use crate::parse::Resolve;
16use crate::query::AsyncBlock;
17use crate::query::Closure;
18use crate::query::SecondaryBuildEntry;
19use crate::query::{self, GenericsParameters, Named, SecondaryBuild};
20use crate::runtime::{ConstValue, ConstValueKind, Inline, Type, TypeCheck};
21use crate::{Hash, Item};
22
23use super::{Ctxt, Needs};
24
25#[instrument_ast(span = span)]
27pub(crate) fn empty_fn<'hir>(
28 cx: &mut Ctxt<'hir, '_, '_>,
29 ast: &ast::EmptyBlock,
30 span: &dyn Spanned,
31) -> compile::Result<hir::ItemFn<'hir>> {
32 Ok(hir::ItemFn {
33 span: span.span(),
34 args: &[],
35 body: statements(cx, None, &ast.statements, span)?,
36 })
37}
38
39#[instrument_ast(span = ast)]
41pub(crate) fn item_fn<'hir>(
42 cx: &mut Ctxt<'hir, '_, '_>,
43 ast: &ast::ItemFn,
44) -> compile::Result<hir::ItemFn<'hir>> {
45 alloc_with!(cx, ast);
46
47 Ok(hir::ItemFn {
48 span: ast.span(),
49 args: iter!(&ast.args, |(ast, _)| fn_arg(cx, ast)?),
50 body: block(cx, None, &ast.body)?,
51 })
52}
53
54#[instrument_ast(span = ast)]
56fn expr_call_closure<'hir>(
57 cx: &mut Ctxt<'hir, '_, '_>,
58 ast: &ast::ExprClosure,
59) -> compile::Result<hir::ExprKind<'hir>> {
60 alloc_with!(cx, ast);
61
62 let item =
63 cx.q.item_for("lowering closure call", ast.id)
64 .with_span(ast)?;
65
66 let Some(meta) = cx.q.query_meta(ast, item.item, Default::default())? else {
67 return Err(compile::Error::new(
68 ast,
69 ErrorKind::MissingItem {
70 item: cx.q.pool.item(item.item).try_to_owned()?,
71 },
72 ));
73 };
74
75 let meta::Kind::Closure { call, do_move, .. } = meta.kind else {
76 return Err(compile::Error::expected_meta(
77 ast,
78 meta.info(cx.q.pool)?,
79 "a closure",
80 ));
81 };
82
83 tracing::trace!("queuing closure build entry");
84
85 cx.scopes.push_captures()?;
86
87 let args = iter!(ast.args.as_slice(), |(arg, _)| fn_arg(cx, arg)?);
88 let body = alloc!(expr(cx, &ast.body)?);
89
90 let layer = cx.scopes.pop().with_span(&ast.body)?;
91
92 cx.q.set_used(&meta.item_meta)?;
93
94 let captures = &*iter!(layer.captures().map(|(_, id)| id));
95
96 let Some(queue) = cx.secondary_builds.as_mut() else {
97 return Err(compile::Error::new(ast, ErrorKind::ClosureInConst));
98 };
99
100 queue.try_push(SecondaryBuildEntry {
101 item_meta: meta.item_meta,
102 build: SecondaryBuild::Closure(Closure {
103 hir: alloc!(hir::ExprClosure {
104 args,
105 body,
106 captures,
107 }),
108 call,
109 }),
110 })?;
111
112 if captures.is_empty() {
113 return Ok(hir::ExprKind::Fn(meta.hash));
114 }
115
116 Ok(hir::ExprKind::CallClosure(alloc!(hir::ExprCallClosure {
117 hash: meta.hash,
118 do_move,
119 captures,
120 })))
121}
122
123#[inline]
124pub(crate) fn block<'hir>(
125 cx: &mut Ctxt<'hir, '_, '_>,
126 label: Option<&(ast::Label, T![:])>,
127 ast: &ast::Block,
128) -> compile::Result<hir::Block<'hir>> {
129 statements(cx, label, &ast.statements, ast)
130}
131
132#[instrument_ast(span = span)]
133fn statements<'hir>(
134 cx: &mut Ctxt<'hir, '_, '_>,
135 label: Option<&(ast::Label, T![:])>,
136 statements: &[ast::Stmt],
137 span: &dyn Spanned,
138) -> compile::Result<hir::Block<'hir>> {
139 alloc_with!(cx, span);
140
141 let label = match label {
142 Some((label, _)) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
143 None => None,
144 };
145
146 cx.scopes.push(label)?;
147
148 let at = cx.statements.len();
149
150 let mut value = None;
151
152 for ast in statements {
153 let last = match ast {
154 ast::Stmt::Local(ast) => {
155 let depacked = if ast.attributes.is_empty() && cx.q.options.lowering > 0 {
156 unpack_locals(cx, &ast.pat, &ast.expr)?
157 } else {
158 false
159 };
160
161 if !depacked {
162 let stmt = hir::Stmt::Local(alloc!(local(cx, ast)?));
163 cx.statement_buffer.try_push(stmt)?;
164 }
165
166 value.take()
167 }
168 ast::Stmt::Expr(ast) => {
169 if let Some(stmt) = value.replace(&*alloc!(expr(cx, ast)?)).map(hir::Stmt::Expr) {
170 cx.statement_buffer.try_push(stmt)?;
171 }
172
173 None
174 }
175 ast::Stmt::Semi(ast) => {
176 let stmt = hir::Stmt::Expr(alloc!(expr(cx, &ast.expr)?));
177 cx.statement_buffer.try_push(stmt)?;
178 value.take()
179 }
180 ast::Stmt::Item(..) => continue,
181 };
182
183 if let Some(last) = last {
184 cx.statements
185 .try_push(hir::Stmt::Expr(last))
186 .with_span(span)?;
187 }
188
189 for stmt in cx.statement_buffer.drain(..) {
190 cx.statements.try_push(stmt).with_span(span)?;
191 }
192 }
193
194 let statements = iter!(cx.statements.drain(at..));
195
196 let layer = cx.scopes.pop().with_span(span)?;
197
198 Ok(hir::Block {
199 span: span.span(),
200 label,
201 statements,
202 value,
203 drop: iter!(layer.into_drop_order()),
204 })
205}
206
207#[instrument_ast(span = ast)]
208fn expr_range<'hir>(
209 cx: &mut Ctxt<'hir, '_, '_>,
210 ast: &ast::ExprRange,
211) -> compile::Result<hir::ExprRange<'hir>> {
212 match (ast.start.as_deref(), ast.end.as_deref(), &ast.limits) {
213 (Some(start), None, ast::ExprRangeLimits::HalfOpen(..)) => Ok(hir::ExprRange::RangeFrom {
214 start: expr(cx, start)?,
215 }),
216 (None, None, ast::ExprRangeLimits::HalfOpen(..)) => Ok(hir::ExprRange::RangeFull),
217 (Some(start), Some(end), ast::ExprRangeLimits::Closed(..)) => {
218 Ok(hir::ExprRange::RangeInclusive {
219 start: expr(cx, start)?,
220 end: expr(cx, end)?,
221 })
222 }
223 (None, Some(end), ast::ExprRangeLimits::Closed(..)) => {
224 Ok(hir::ExprRange::RangeToInclusive {
225 end: expr(cx, end)?,
226 })
227 }
228 (None, Some(end), ast::ExprRangeLimits::HalfOpen(..)) => Ok(hir::ExprRange::RangeTo {
229 end: expr(cx, end)?,
230 }),
231 (Some(start), Some(end), ast::ExprRangeLimits::HalfOpen(..)) => Ok(hir::ExprRange::Range {
232 start: expr(cx, start)?,
233 end: expr(cx, end)?,
234 }),
235 (Some(..) | None, None, ast::ExprRangeLimits::Closed(..)) => Err(compile::Error::msg(
236 ast,
237 "Unsupported range, you probably want `..` instead of `..=`",
238 )),
239 }
240}
241
242#[instrument_ast(span = ast)]
243fn expr_object<'hir>(
244 cx: &mut Ctxt<'hir, '_, '_>,
245 ast: &ast::ExprObject,
246) -> compile::Result<hir::ExprKind<'hir>> {
247 alloc_with!(cx, ast);
248
249 let span = ast;
250 let mut keys_dup = HashMap::new();
251
252 let assignments = &mut *iter!(&ast.assignments, |(ast, _)| {
253 let key = object_key(cx, &ast.key)?;
254
255 if let Some(_existing) = keys_dup.try_insert(key.1, key.0)? {
256 return Err(compile::Error::new(
257 key.0,
258 ErrorKind::DuplicateObjectKey {
259 #[cfg(feature = "emit")]
260 existing: _existing.span(),
261 #[cfg(feature = "emit")]
262 object: key.0.span(),
263 },
264 ));
265 }
266
267 let assign = match &ast.assign {
268 Some((_, ast)) => expr(cx, ast)?,
269 None => {
270 let Some((name, _)) = cx.scopes.get(hir::Name::Str(key.1))? else {
271 return Err(compile::Error::new(
272 key.0,
273 ErrorKind::MissingLocal {
274 name: key.1.try_to_string()?.try_into()?,
275 },
276 ));
277 };
278
279 hir::Expr {
280 span: ast.span(),
281 kind: hir::ExprKind::Variable(name),
282 }
283 }
284 };
285
286 hir::FieldAssign {
287 key: (key.0.span(), key.1),
288 assign,
289 position: None,
290 }
291 });
292
293 let mut check_object_fields = |fields: &[meta::FieldMeta], item: &Item| {
294 let mut named = HashMap::new();
295
296 for f in fields.iter() {
297 named.try_insert(f.name.as_ref(), f)?;
298 }
299
300 for assign in assignments.iter_mut() {
301 match named.remove(assign.key.1) {
302 Some(field_meta) => {
303 assign.position = Some(field_meta.position);
304 }
305 None => {
306 return Err(compile::Error::new(
307 assign.key.0,
308 ErrorKind::LitObjectNotField {
309 field: assign.key.1.try_into()?,
310 item: item.try_to_owned()?,
311 },
312 ));
313 }
314 };
315 }
316
317 if let Some(field) = named.into_keys().next() {
318 return Err(compile::Error::new(
319 span,
320 ErrorKind::LitObjectMissingField {
321 field: field.try_into()?,
322 item: item.try_to_owned()?,
323 },
324 ));
325 }
326
327 Ok(())
328 };
329
330 let kind = match &ast.ident {
331 ast::ObjectIdent::Named(path) => {
332 let named = cx.q.convert_path(path)?;
333 let parameters = generics_parameters(cx, &named)?;
334 let meta = cx.lookup_meta(path, named.item, parameters)?;
335 let item = cx.q.pool.item(meta.item_meta.item);
336
337 match &meta.kind {
338 meta::Kind::Struct {
339 fields: meta::Fields::Empty,
340 constructor,
341 ..
342 } => {
343 check_object_fields(&[], item)?;
344
345 match constructor {
346 Some(_) => hir::ExprObjectKind::ExternalType {
347 hash: meta.hash,
348 args: 0,
349 },
350 None => hir::ExprObjectKind::Struct { hash: meta.hash },
351 }
352 }
353 meta::Kind::Struct {
354 fields: meta::Fields::Named(st),
355 constructor,
356 ..
357 } => {
358 check_object_fields(&st.fields, item)?;
359
360 match constructor {
361 Some(_) => hir::ExprObjectKind::ExternalType {
362 hash: meta.hash,
363 args: st.fields.len(),
364 },
365 None => hir::ExprObjectKind::Struct { hash: meta.hash },
366 }
367 }
368 _ => {
369 return Err(compile::Error::new(
370 span,
371 ErrorKind::UnsupportedLitObject {
372 meta: meta.info(cx.q.pool)?,
373 },
374 ));
375 }
376 }
377 }
378 ast::ObjectIdent::Anonymous(..) => hir::ExprObjectKind::Anonymous,
379 };
380
381 Ok(hir::ExprKind::Object(alloc!(hir::ExprObject {
382 kind,
383 assignments,
384 })))
385}
386
387#[instrument_ast(span = ast)]
389pub(crate) fn expr<'hir>(
390 cx: &mut Ctxt<'hir, '_, '_>,
391 ast: &ast::Expr,
392) -> compile::Result<hir::Expr<'hir>> {
393 alloc_with!(cx, ast);
394
395 let in_path = take(&mut cx.in_path);
396
397 let kind = match ast {
398 ast::Expr::Path(ast) => expr_path(cx, ast, in_path)?,
399 ast::Expr::Assign(ast) => hir::ExprKind::Assign(alloc!(hir::ExprAssign {
400 lhs: expr(cx, &ast.lhs)?,
401 rhs: expr(cx, &ast.rhs)?,
402 })),
403 ast::Expr::While(ast) => {
407 let label = match &ast.label {
408 Some((label, _)) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
409 None => None,
410 };
411
412 cx.scopes.push_loop(label)?;
413 let condition = condition(cx, &ast.condition)?;
414 let body = block(cx, None, &ast.body)?;
415 let layer = cx.scopes.pop().with_span(ast)?;
416
417 hir::ExprKind::Loop(alloc!(hir::ExprLoop {
418 label,
419 condition: Some(alloc!(condition)),
420 body,
421 drop: iter!(layer.into_drop_order()),
422 }))
423 }
424 ast::Expr::Loop(ast) => {
425 let label = match &ast.label {
426 Some((label, _)) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
427 None => None,
428 };
429
430 cx.scopes.push_loop(label)?;
431 let body = block(cx, None, &ast.body)?;
432 let layer = cx.scopes.pop().with_span(ast)?;
433
434 let kind = hir::ExprKind::Loop(alloc!(hir::ExprLoop {
435 label,
436 condition: None,
437 body,
438 drop: iter!(layer.into_drop_order()),
439 }));
440
441 kind
442 }
443 ast::Expr::For(ast) => {
444 let iter = expr(cx, &ast.iter)?;
445
446 let label = match &ast.label {
447 Some((label, _)) => Some(alloc_str!(label.resolve(resolve_context!(cx.q))?)),
448 None => None,
449 };
450
451 cx.scopes.push_loop(label)?;
452 let binding = pat_binding(cx, &ast.binding)?;
453 let body = block(cx, None, &ast.body)?;
454
455 let layer = cx.scopes.pop().with_span(ast)?;
456
457 hir::ExprKind::For(alloc!(hir::ExprFor {
458 label,
459 binding,
460 iter,
461 body,
462 drop: iter!(layer.into_drop_order()),
463 }))
464 }
465 ast::Expr::Let(ast) => hir::ExprKind::Let(alloc!(hir::ExprLet {
466 pat: pat_binding(cx, &ast.pat)?,
467 expr: expr(cx, &ast.expr)?,
468 })),
469 ast::Expr::If(ast) => hir::ExprKind::If(alloc!(expr_if(cx, ast)?)),
470 ast::Expr::Match(ast) => hir::ExprKind::Match(alloc!(hir::ExprMatch {
471 expr: alloc!(expr(cx, &ast.expr)?),
472 branches: iter!(&ast.branches, |(ast, _)| {
473 cx.scopes.push(None)?;
474
475 let pat = pat_binding(cx, &ast.pat)?;
476 let condition = option!(&ast.condition, |(_, ast)| expr(cx, ast)?);
477 let body = expr(cx, &ast.body)?;
478
479 let layer = cx.scopes.pop().with_span(ast)?;
480
481 hir::ExprMatchBranch {
482 span: ast.span(),
483 pat,
484 condition,
485 body,
486 drop: iter!(layer.into_drop_order()),
487 }
488 }),
489 })),
490 ast::Expr::Call(ast) => hir::ExprKind::Call(alloc!(expr_call(cx, ast)?)),
491 ast::Expr::FieldAccess(ast) => {
492 hir::ExprKind::FieldAccess(alloc!(expr_field_access(cx, ast)?))
493 }
494 ast::Expr::Empty(ast) => {
495 cx.in_path = in_path;
497 hir::ExprKind::Group(alloc!(expr(cx, &ast.expr)?))
498 }
499 ast::Expr::Binary(ast) => {
500 let rhs_needs = match &ast.op {
501 ast::BinOp::As(..) | ast::BinOp::Is(..) | ast::BinOp::IsNot(..) => Needs::Type,
502 _ => Needs::Value,
503 };
504
505 let lhs = expr(cx, &ast.lhs)?;
506
507 let needs = replace(&mut cx.needs, rhs_needs);
508 let rhs = expr(cx, &ast.rhs)?;
509 cx.needs = needs;
510
511 hir::ExprKind::Binary(alloc!(hir::ExprBinary {
512 lhs,
513 op: ast.op,
514 rhs,
515 }))
516 }
517 ast::Expr::Unary(ast) => expr_unary(cx, ast)?,
518 ast::Expr::Index(ast) => hir::ExprKind::Index(alloc!(hir::ExprIndex {
519 target: expr(cx, &ast.target)?,
520 index: expr(cx, &ast.index)?,
521 })),
522 ast::Expr::Block(ast) => expr_block(cx, ast)?,
523 ast::Expr::Break(ast) => hir::ExprKind::Break(alloc!(expr_break(cx, ast)?)),
524 ast::Expr::Continue(ast) => hir::ExprKind::Continue(alloc!(expr_continue(cx, ast)?)),
525 ast::Expr::Yield(ast) => hir::ExprKind::Yield(option!(&ast.expr, |ast| expr(cx, ast)?)),
526 ast::Expr::Return(ast) => hir::ExprKind::Return(option!(&ast.expr, |ast| expr(cx, ast)?)),
527 ast::Expr::Await(ast) => hir::ExprKind::Await(alloc!(expr(cx, &ast.expr)?)),
528 ast::Expr::Try(ast) => hir::ExprKind::Try(alloc!(expr(cx, &ast.expr)?)),
529 ast::Expr::Select(ast) => {
530 let mut default = None;
531 let mut branches = Vec::new();
532 let mut exprs = Vec::new();
533
534 for (ast, _) in &ast.branches {
535 match ast {
536 ast::ExprSelectBranch::Pat(ast) => {
537 cx.scopes.push(None)?;
538
539 let pat = pat_binding(cx, &ast.pat)?;
540 let body = expr(cx, &ast.body)?;
541
542 let layer = cx.scopes.pop().with_span(&ast)?;
543
544 exprs.try_push(expr(cx, &ast.expr)?).with_span(&ast.expr)?;
545
546 branches.try_push(hir::ExprSelectBranch {
547 pat,
548 body,
549 drop: iter!(layer.into_drop_order()),
550 })?;
551 }
552 ast::ExprSelectBranch::Default(ast) => {
553 if default.is_some() {
554 return Err(compile::Error::new(
555 ast,
556 ErrorKind::SelectMultipleDefaults,
557 ));
558 }
559
560 default = Some(alloc!(expr(cx, &ast.body)?));
561 }
562 }
563 }
564
565 hir::ExprKind::Select(alloc!(hir::ExprSelect {
566 branches: iter!(branches),
567 exprs: iter!(exprs),
568 default: option!(default),
569 }))
570 }
571 ast::Expr::Closure(ast) => expr_call_closure(cx, ast)?,
572 ast::Expr::Lit(ast) => hir::ExprKind::Lit(lit(cx, &ast.lit)?),
573 ast::Expr::Object(ast) => expr_object(cx, ast)?,
574 ast::Expr::Tuple(ast) => hir::ExprKind::Tuple(alloc!(hir::ExprSeq {
575 items: iter!(&ast.items, |(ast, _)| expr(cx, ast)?),
576 })),
577 ast::Expr::Vec(ast) => hir::ExprKind::Vec(alloc!(hir::ExprSeq {
578 items: iter!(&ast.items, |(ast, _)| expr(cx, ast)?),
579 })),
580 ast::Expr::Range(ast) => hir::ExprKind::Range(alloc!(expr_range(cx, ast)?)),
581 ast::Expr::Group(ast) => hir::ExprKind::Group(alloc!(expr(cx, &ast.expr)?)),
582 ast::Expr::MacroCall(ast) => {
583 let Some(id) = ast.id else {
584 return Err(compile::Error::msg(ast, "missing expanded macro id"));
585 };
586
587 match cx.q.builtin_macro_for(id).with_span(ast)?.as_ref() {
588 query::BuiltInMacro::Template(ast) => {
589 let old = replace(&mut cx.in_template, true);
590
591 let result = hir::ExprKind::Template(alloc!(hir::BuiltInTemplate {
592 span: ast.span,
593 from_literal: ast.from_literal,
594 exprs: iter!(&ast.exprs, |ast| expr(cx, ast)?),
595 }));
596
597 cx.in_template = old;
598 result
599 }
600 query::BuiltInMacro::Format(ast) => {
601 let spec = hir::BuiltInFormatSpec {
602 fill: ast.fill,
603 align: ast.align,
604 width: ast.width,
605 precision: ast.precision,
606 flags: ast.flags,
607 format_type: ast.format_type,
608 };
609
610 hir::ExprKind::Format(alloc!(hir::BuiltInFormat {
611 spec,
612 value: alloc!(expr(cx, &ast.value)?),
613 }))
614 }
615 query::BuiltInMacro::File(ast) => hir::ExprKind::Lit(lit(cx, &ast.value)?),
616 query::BuiltInMacro::Line(ast) => hir::ExprKind::Lit(lit(cx, &ast.value)?),
617 }
618 }
619 };
620
621 Ok(hir::Expr {
622 span: ast.span(),
623 kind,
624 })
625}
626
627#[instrument_ast(span = span)]
629fn pat_const_value<'hir>(
630 cx: &mut Ctxt<'hir, '_, '_>,
631 const_value: &ConstValue,
632 span: &dyn Spanned,
633) -> compile::Result<hir::Pat<'hir>> {
634 alloc_with!(cx, span);
635
636 let kind = 'kind: {
637 let lit = match *const_value.as_kind() {
638 ConstValueKind::Inline(value) => match value {
639 Inline::Unit => {
640 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
641 kind: hir::PatSequenceKind::Anonymous {
642 type_check: TypeCheck::Unit,
643 count: 0,
644 is_open: false,
645 },
646 items: &[],
647 }));
648 }
649 Inline::Bool(b) => hir::Lit::Bool(b),
650 Inline::Char(ch) => hir::Lit::Char(ch),
651 Inline::Unsigned(integer) => hir::Lit::Unsigned(integer),
652 Inline::Signed(integer) => hir::Lit::Signed(integer),
653 _ => {
654 return Err(compile::Error::msg(
655 span,
656 "Unsupported constant value in pattern",
657 ))
658 }
659 },
660 ConstValueKind::String(ref string) => hir::Lit::Str(alloc_str!(string.as_ref())),
661 ConstValueKind::Bytes(ref bytes) => hir::Lit::ByteStr(alloc_bytes!(bytes.as_ref())),
662 ConstValueKind::Vec(ref items) => {
663 let items = iter!(items.iter(), items.len(), |value| pat_const_value(
664 cx, value, span
665 )?);
666
667 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
668 kind: hir::PatSequenceKind::Anonymous {
669 type_check: TypeCheck::Vec,
670 count: items.len(),
671 is_open: false,
672 },
673 items,
674 }));
675 }
676 ConstValueKind::Tuple(ref items) => {
677 let items = iter!(items.iter(), items.len(), |value| pat_const_value(
678 cx, value, span
679 )?);
680
681 break 'kind hir::PatKind::Sequence(alloc!(hir::PatSequence {
682 kind: hir::PatSequenceKind::Anonymous {
683 type_check: TypeCheck::Vec,
684 count: items.len(),
685 is_open: false,
686 },
687 items,
688 }));
689 }
690 ConstValueKind::Object(ref fields) => {
691 let bindings = iter!(fields.iter(), fields.len(), |(key, value)| {
692 let pat = alloc!(pat_const_value(cx, value, span)?);
693
694 hir::Binding::Binding(span.span(), alloc_str!(key.as_ref()), pat)
695 });
696
697 break 'kind hir::PatKind::Object(alloc!(hir::PatObject {
698 kind: hir::PatSequenceKind::Anonymous {
699 type_check: TypeCheck::Object,
700 count: bindings.len(),
701 is_open: false,
702 },
703 bindings,
704 }));
705 }
706 _ => {
707 return Err(compile::Error::msg(
708 span,
709 "Unsupported constant value in pattern",
710 ));
711 }
712 };
713
714 hir::PatKind::Lit(alloc!(hir::Expr {
715 span: span.span(),
716 kind: hir::ExprKind::Lit(lit),
717 }))
718 };
719
720 Ok(hir::Pat {
721 span: span.span(),
722 kind,
723 })
724}
725
726#[instrument_ast(span = ast)]
727fn expr_if<'hir>(
728 cx: &mut Ctxt<'hir, '_, '_>,
729 ast: &ast::ExprIf,
730) -> compile::Result<hir::Conditional<'hir>> {
731 alloc_with!(cx, ast);
732
733 let length = 1 + ast.expr_else_ifs.len();
734
735 let then = [(
736 ast.if_.span().join(ast.block.span()),
737 &ast.condition,
738 &ast.block,
739 )]
740 .into_iter();
741
742 let else_ifs = ast
743 .expr_else_ifs
744 .iter()
745 .map(|ast| (ast.span(), &ast.condition, &ast.block));
746
747 let branches = iter!(then.chain(else_ifs), length, |(span, c, b)| {
748 cx.scopes.push(None)?;
749
750 let condition = condition(cx, c)?;
751 let block = block(cx, None, b)?;
752
753 let layer = cx.scopes.pop().with_span(ast)?;
754
755 let condition = &*alloc!(condition);
756 let drop = &*iter!(layer.into_drop_order());
757
758 hir::ConditionalBranch {
759 span,
760 condition,
761 block,
762 drop,
763 }
764 });
765
766 let fallback = match &ast.expr_else {
767 Some(ast) => Some(&*alloc!(block(cx, None, &ast.block)?)),
768 None => None,
769 };
770
771 Ok(hir::Conditional { branches, fallback })
772}
773
774#[instrument_ast(span = ast)]
775fn lit<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Lit) -> compile::Result<hir::Lit<'hir>> {
776 alloc_with!(cx, ast);
777
778 match ast {
779 ast::Lit::Bool(lit) => Ok(hir::Lit::Bool(lit.value)),
780 ast::Lit::Number(lit) => {
781 let n = lit.resolve(resolve_context!(cx.q))?;
782
783 match (n.value, n.suffix) {
784 (ast::NumberValue::Float(n), _) => Ok(hir::Lit::Float(n)),
785 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Unsigned(_, size))) => {
786 let Some(n) = int.to_u64() else {
787 return Err(compile::Error::new(
788 ast,
789 ErrorKind::BadUnsignedOutOfBounds { size },
790 ));
791 };
792
793 if !size.unsigned_in(n) {
794 return Err(compile::Error::new(
795 ast,
796 ErrorKind::BadUnsignedOutOfBounds { size },
797 ));
798 }
799
800 Ok(hir::Lit::Unsigned(n))
801 }
802 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Signed(_, size))) => {
803 let Some(n) = int.to_i64() else {
804 return Err(compile::Error::new(
805 ast,
806 ErrorKind::BadSignedOutOfBounds { size },
807 ));
808 };
809
810 if !size.signed_in(n) {
811 return Err(compile::Error::new(
812 ast,
813 ErrorKind::BadSignedOutOfBounds { size },
814 ));
815 }
816
817 Ok(hir::Lit::Signed(n))
818 }
819 (ast::NumberValue::Integer(int), _) => {
820 let Some(n) = int.to_i64() else {
821 return Err(compile::Error::new(
822 ast,
823 ErrorKind::BadSignedOutOfBounds {
824 size: NumberSize::S64,
825 },
826 ));
827 };
828
829 Ok(hir::Lit::Signed(n))
830 }
831 }
832 }
833 ast::Lit::Byte(lit) => {
834 let b = lit.resolve(resolve_context!(cx.q))?;
835 Ok(hir::Lit::Unsigned(b as u64))
836 }
837 ast::Lit::Char(lit) => {
838 let ch = lit.resolve(resolve_context!(cx.q))?;
839 Ok(hir::Lit::Char(ch))
840 }
841 ast::Lit::Str(lit) => {
842 let string = if cx.in_template {
843 lit.resolve_template_string(resolve_context!(cx.q))?
844 } else {
845 lit.resolve_string(resolve_context!(cx.q))?
846 };
847
848 Ok(hir::Lit::Str(alloc_str!(string.as_ref())))
849 }
850 ast::Lit::ByteStr(lit) => {
851 let bytes = lit.resolve(resolve_context!(cx.q))?;
852 Ok(hir::Lit::ByteStr(alloc_bytes!(bytes.as_ref())))
853 }
854 }
855}
856
857#[instrument_ast(span = ast)]
858fn expr_unary<'hir>(
859 cx: &mut Ctxt<'hir, '_, '_>,
860 ast: &ast::ExprUnary,
861) -> compile::Result<hir::ExprKind<'hir>> {
862 alloc_with!(cx, ast);
863
864 if let ast::UnOp::BorrowRef { .. } = ast.op {
866 return Err(compile::Error::new(ast, ErrorKind::UnsupportedRef));
867 }
868
869 let (
870 ast::UnOp::Neg(..),
871 ast::Expr::Lit(ast::ExprLit {
872 lit: ast::Lit::Number(n),
873 ..
874 }),
875 ) = (ast.op, &*ast.expr)
876 else {
877 return Ok(hir::ExprKind::Unary(alloc!(hir::ExprUnary {
878 op: ast.op,
879 expr: expr(cx, &ast.expr)?,
880 })));
881 };
882
883 let number = n.resolve(resolve_context!(cx.q))?;
884
885 match (number.value, number.suffix) {
886 (ast::NumberValue::Float(n), _) => Ok(hir::ExprKind::Lit(hir::Lit::Float(-n))),
887 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Unsigned(_, size))) => {
888 let Some(n) = int.neg().to_u64() else {
889 return Err(compile::Error::new(
890 ast,
891 ErrorKind::BadUnsignedOutOfBounds { size },
892 ));
893 };
894
895 if !size.unsigned_in(n) {
896 return Err(compile::Error::new(
897 ast,
898 ErrorKind::BadUnsignedOutOfBounds { size },
899 ));
900 }
901
902 Ok(hir::ExprKind::Lit(hir::Lit::Unsigned(n)))
903 }
904 (ast::NumberValue::Integer(int), Some(ast::NumberSuffix::Signed(_, size))) => {
905 let Some(n) = int.neg().to_i64() else {
906 return Err(compile::Error::new(
907 ast,
908 ErrorKind::BadSignedOutOfBounds { size },
909 ));
910 };
911
912 if !size.signed_in(n) {
913 return Err(compile::Error::new(
914 ast,
915 ErrorKind::BadSignedOutOfBounds { size },
916 ));
917 }
918
919 Ok(hir::ExprKind::Lit(hir::Lit::Signed(n)))
920 }
921 (ast::NumberValue::Integer(int), _) => {
922 let Some(n) = int.neg().to_i64() else {
923 return Err(compile::Error::new(
924 ast,
925 ErrorKind::BadSignedOutOfBounds {
926 size: NumberSize::S64,
927 },
928 ));
929 };
930
931 Ok(hir::ExprKind::Lit(hir::Lit::Signed(n)))
932 }
933 }
934}
935
936#[instrument_ast(span = ast)]
938fn expr_block<'hir>(
939 cx: &mut Ctxt<'hir, '_, '_>,
940 ast: &ast::ExprBlock,
941) -> compile::Result<hir::ExprKind<'hir>> {
942 #[derive(Debug, Clone, Copy, PartialEq)]
944 #[non_exhaustive]
945 pub(crate) enum ExprBlockKind {
946 Default,
947 Async,
948 Const,
949 }
950
951 alloc_with!(cx, ast);
952
953 let kind = match (&ast.async_token, &ast.const_token) {
954 (Some(..), None) => ExprBlockKind::Async,
955 (None, Some(..)) => ExprBlockKind::Const,
956 _ => ExprBlockKind::Default,
957 };
958
959 if let ExprBlockKind::Default = kind {
960 return Ok(hir::ExprKind::Block(alloc!(block(
961 cx,
962 ast.label.as_ref(),
963 &ast.block
964 )?)));
965 }
966
967 if cx.const_eval {
968 let ExprBlockKind::Const = kind else {
972 return Err(compile::Error::msg(
973 ast,
974 "Only constant blocks are supported in this context",
975 ));
976 };
977
978 if let Some(label) = &ast.label {
979 return Err(compile::Error::msg(
980 label,
981 "Constant blocks cannot be labelled",
982 ));
983 };
984
985 return Ok(hir::ExprKind::Block(alloc!(block(cx, None, &ast.block)?)));
986 };
987
988 let item =
989 cx.q.item_for("lowering block", ast.block.id)
990 .with_span(&ast.block)?;
991 let meta = cx.lookup_meta(ast, item.item, GenericsParameters::default())?;
992
993 match (kind, &meta.kind) {
994 (ExprBlockKind::Async, &meta::Kind::AsyncBlock { call, do_move, .. }) => {
995 tracing::trace!("queuing async block build entry");
996
997 if let Some(label) = &ast.label {
998 return Err(compile::Error::msg(
999 label,
1000 "Async blocks cannot be labelled",
1001 ));
1002 };
1003
1004 cx.scopes.push_captures()?;
1005 let block = alloc!(block(cx, None, &ast.block)?);
1006 let layer = cx.scopes.pop().with_span(&ast.block)?;
1007
1008 cx.q.set_used(&meta.item_meta)?;
1009
1010 let captures = &*iter!(layer.captures().map(|(_, id)| id));
1011
1012 let Some(queue) = cx.secondary_builds.as_mut() else {
1013 return Err(compile::Error::new(ast, ErrorKind::AsyncBlockInConst));
1014 };
1015
1016 queue.try_push(SecondaryBuildEntry {
1017 item_meta: meta.item_meta,
1018 build: SecondaryBuild::AsyncBlock(AsyncBlock {
1019 hir: alloc!(hir::AsyncBlock { block, captures }),
1020 call,
1021 }),
1022 })?;
1023
1024 Ok(hir::ExprKind::AsyncBlock(alloc!(hir::ExprAsyncBlock {
1025 hash: meta.hash,
1026 do_move,
1027 captures,
1028 })))
1029 }
1030 (ExprBlockKind::Const, meta::Kind::Const) => Ok(hir::ExprKind::Const(meta.hash)),
1031 _ => Err(compile::Error::expected_meta(
1032 ast,
1033 meta.info(cx.q.pool)?,
1034 "async or const block",
1035 )),
1036 }
1037}
1038
1039fn expr_break<'hir>(
1042 cx: &mut Ctxt<'hir, '_, '_>,
1043 ast: &ast::ExprBreak,
1044) -> compile::Result<hir::ExprBreak<'hir>> {
1045 alloc_with!(cx, ast);
1046
1047 let label = match &ast.label {
1048 Some(label) => Some(label.resolve(resolve_context!(cx.q))?),
1049 None => None,
1050 };
1051
1052 let Some(drop) = cx.scopes.loop_drop(label)? else {
1053 if let Some(label) = label {
1054 return Err(compile::Error::new(
1055 ast,
1056 ErrorKind::MissingLabel {
1057 label: label.try_into()?,
1058 },
1059 ));
1060 } else {
1061 return Err(compile::Error::new(ast, ErrorKind::BreakUnsupported));
1062 }
1063 };
1064
1065 Ok(hir::ExprBreak {
1066 label: match label {
1067 Some(label) => Some(alloc_str!(label)),
1068 None => None,
1069 },
1070 expr: match &ast.expr {
1071 Some(ast) => Some(alloc!(expr(cx, ast)?)),
1072 None => None,
1073 },
1074 drop: iter!(drop),
1075 })
1076}
1077
1078fn expr_continue<'hir>(
1081 cx: &Ctxt<'hir, '_, '_>,
1082 ast: &ast::ExprContinue,
1083) -> compile::Result<hir::ExprContinue<'hir>> {
1084 alloc_with!(cx, ast);
1085
1086 let label = match &ast.label {
1087 Some(label) => Some(label.resolve(resolve_context!(cx.q))?),
1088 None => None,
1089 };
1090
1091 let Some(drop) = cx.scopes.loop_drop(label)? else {
1092 if let Some(label) = label {
1093 return Err(compile::Error::new(
1094 ast,
1095 ErrorKind::MissingLabel {
1096 label: label.try_into()?,
1097 },
1098 ));
1099 } else {
1100 return Err(compile::Error::new(ast, ErrorKind::ContinueUnsupported));
1101 }
1102 };
1103
1104 Ok(hir::ExprContinue {
1105 label: match label {
1106 Some(label) => Some(alloc_str!(label)),
1107 None => None,
1108 },
1109 drop: iter!(drop),
1110 })
1111}
1112
1113fn fn_arg<'hir>(
1115 cx: &mut Ctxt<'hir, '_, '_>,
1116 ast: &ast::FnArg,
1117) -> compile::Result<hir::FnArg<'hir>> {
1118 alloc_with!(cx, ast);
1119
1120 Ok(match ast {
1121 ast::FnArg::SelfValue(ast) => {
1122 let id = cx.scopes.define(hir::Name::SelfValue, ast)?;
1123 hir::FnArg::SelfValue(ast.span(), id)
1124 }
1125 ast::FnArg::Pat(ast) => hir::FnArg::Pat(alloc!(pat_binding(cx, ast)?)),
1126 })
1127}
1128
1129fn local<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Local) -> compile::Result<hir::Local<'hir>> {
1131 let expr = expr(cx, &ast.expr)?;
1134 let pat = pat_binding(cx, &ast.pat)?;
1135
1136 Ok(hir::Local {
1137 span: ast.span(),
1138 pat,
1139 expr,
1140 })
1141}
1142
1143fn unpack_locals(cx: &mut Ctxt<'_, '_, '_>, p: &ast::Pat, e: &ast::Expr) -> compile::Result<bool> {
1146 alloc_with!(cx, p);
1147
1148 match (p, e) {
1149 (p @ ast::Pat::Path(inner), e) => {
1150 let Some(ast::PathKind::Ident(..)) = inner.path.as_kind() else {
1151 return Ok(false);
1152 };
1153
1154 let e = expr(cx, e)?;
1155 let p = pat_binding(cx, p)?;
1156
1157 cx.statement_buffer
1158 .try_push(hir::Stmt::Local(alloc!(hir::Local {
1159 span: p.span().join(e.span()),
1160 pat: p,
1161 expr: e,
1162 })))?;
1163
1164 return Ok(true);
1165 }
1166 (ast::Pat::Tuple(p), ast::Expr::Tuple(e)) => {
1167 if p.items.len() != e.items.len() {
1168 return Ok(false);
1169 }
1170
1171 for ((_, _), (p, _)) in e.items.iter().zip(&p.items) {
1172 if matches!(p, ast::Pat::Rest(..)) {
1173 return Ok(false);
1174 }
1175 }
1176
1177 let mut exprs = Vec::new();
1178
1179 for (e, _) in &e.items {
1180 exprs.try_push(expr(cx, e)?)?;
1181 }
1182
1183 for (e, (p, _)) in exprs.into_iter().zip(&p.items) {
1184 let p = pat_binding(cx, p)?;
1185
1186 cx.statement_buffer
1187 .try_push(hir::Stmt::Local(alloc!(hir::Local {
1188 span: p.span().join(e.span()),
1189 pat: p,
1190 expr: e,
1191 })))?;
1192 }
1193
1194 return Ok(true);
1195 }
1196 _ => {}
1197 };
1198
1199 Ok(false)
1200}
1201
1202fn pat_binding<'hir>(
1203 cx: &mut Ctxt<'hir, '_, '_>,
1204 ast: &ast::Pat,
1205) -> compile::Result<hir::PatBinding<'hir>> {
1206 alloc_with!(cx, ast);
1207
1208 let pat = pat(cx, ast)?;
1209 let names = iter!(cx.pattern_bindings.drain(..));
1210
1211 Ok(hir::PatBinding { pat, names })
1212}
1213
1214fn pat<'hir>(cx: &mut Ctxt<'hir, '_, '_>, ast: &ast::Pat) -> compile::Result<hir::Pat<'hir>> {
1215 fn filter((ast, _): &(ast::Pat, Option<ast::Comma>)) -> Option<&ast::Pat> {
1216 if matches!(ast, ast::Pat::Binding(..) | ast::Pat::Rest(..)) {
1217 return None;
1218 }
1219
1220 Some(ast)
1221 }
1222
1223 alloc_with!(cx, ast);
1224
1225 let kind = {
1226 match ast {
1227 ast::Pat::Ignore(..) => hir::PatKind::Ignore,
1228 ast::Pat::Path(ast) => {
1229 let named = cx.q.convert_path(&ast.path)?;
1230 let parameters = generics_parameters(cx, &named)?;
1231
1232 let path = 'path: {
1233 if let Some(meta) = cx.try_lookup_meta(&ast, named.item, ¶meters)? {
1234 match meta.kind {
1235 meta::Kind::Const => {
1236 let Some(const_value) = cx.q.get_const_value(meta.hash) else {
1237 return Err(compile::Error::msg(
1238 ast,
1239 try_format!("Missing constant for hash {}", meta.hash),
1240 ));
1241 };
1242
1243 let const_value = const_value.try_clone().with_span(ast)?;
1244 return pat_const_value(cx, &const_value, ast);
1245 }
1246 _ => {
1247 if let Some((0, kind)) = tuple_match_for(cx, &meta) {
1248 break 'path hir::PatPathKind::Kind(alloc!(kind));
1249 }
1250 }
1251 }
1252 };
1253
1254 if let Some(ident) = ast.path.try_as_ident() {
1255 let name = alloc_str!(ident.resolve(resolve_context!(cx.q))?);
1256 let name = cx.scopes.define(hir::Name::Str(name), ast)?;
1257 cx.pattern_bindings.try_push(name)?;
1258 break 'path hir::PatPathKind::Ident(name);
1259 }
1260
1261 return Err(compile::Error::new(ast, ErrorKind::UnsupportedBinding));
1262 };
1263
1264 hir::PatKind::Path(alloc!(path))
1265 }
1266 ast::Pat::Lit(ast) => hir::PatKind::Lit(alloc!(expr(cx, &ast.expr)?)),
1267 ast::Pat::Vec(ast) => {
1268 let (is_open, count) = pat_items_count(ast.items.as_slice())?;
1269 let items = iter!(
1270 ast.items.iter().filter_map(filter),
1271 ast.items.len(),
1272 |ast| pat(cx, ast)?
1273 );
1274
1275 hir::PatKind::Sequence(alloc!(hir::PatSequence {
1276 kind: hir::PatSequenceKind::Anonymous {
1277 type_check: TypeCheck::Vec,
1278 count,
1279 is_open
1280 },
1281 items,
1282 }))
1283 }
1284 ast::Pat::Tuple(ast) => {
1285 let (is_open, count) = pat_items_count(ast.items.as_slice())?;
1286 let items = iter!(
1287 ast.items.iter().filter_map(filter),
1288 ast.items.len(),
1289 |ast| pat(cx, ast)?
1290 );
1291
1292 let kind = if let Some(path) = &ast.path {
1293 let named = cx.q.convert_path(path)?;
1294 let parameters = generics_parameters(cx, &named)?;
1295 let meta = cx.lookup_meta(path, named.item, parameters)?;
1296
1297 let Some((args, kind)) = tuple_match_for(cx, &meta) else {
1300 return Err(compile::Error::expected_meta(
1301 path,
1302 meta.info(cx.q.pool)?,
1303 "type that can be used in a tuple pattern",
1304 ));
1305 };
1306
1307 if !(args == count || count < args && is_open) {
1308 return Err(compile::Error::new(
1309 path,
1310 ErrorKind::BadArgumentCount {
1311 expected: args,
1312 actual: count,
1313 },
1314 ));
1315 }
1316
1317 kind
1318 } else {
1319 hir::PatSequenceKind::Anonymous {
1320 type_check: TypeCheck::Tuple,
1321 count,
1322 is_open,
1323 }
1324 };
1325
1326 hir::PatKind::Sequence(alloc!(hir::PatSequence { kind, items }))
1327 }
1328 ast::Pat::Object(ast) => {
1329 let (is_open, count) = pat_items_count(ast.items.as_slice())?;
1330
1331 let mut keys_dup = HashMap::new();
1332
1333 let bindings = iter!(ast.items.iter().take(count), |(pat, _)| {
1334 let (key, binding) = match pat {
1335 ast::Pat::Binding(binding) => {
1336 let (span, key) = object_key(cx, &binding.key)?;
1337 (
1338 key,
1339 hir::Binding::Binding(
1340 span.span(),
1341 key,
1342 alloc!(self::pat(cx, &binding.pat)?),
1343 ),
1344 )
1345 }
1346 ast::Pat::Path(path) => {
1347 let Some(ident) = path.path.try_as_ident() else {
1348 return Err(compile::Error::new(
1349 path,
1350 ErrorKind::UnsupportedPatternExpr,
1351 ));
1352 };
1353
1354 let key = alloc_str!(ident.resolve(resolve_context!(cx.q))?);
1355 let id = cx.scopes.define(hir::Name::Str(key), ident)?;
1356 cx.pattern_bindings.try_push(id)?;
1357 (key, hir::Binding::Ident(path.span(), key, id))
1358 }
1359 _ => {
1360 return Err(compile::Error::new(
1361 pat,
1362 ErrorKind::UnsupportedPatternExpr,
1363 ));
1364 }
1365 };
1366
1367 if let Some(_existing) = keys_dup.try_insert(key, pat)? {
1368 return Err(compile::Error::new(
1369 pat,
1370 ErrorKind::DuplicateObjectKey {
1371 #[cfg(feature = "emit")]
1372 existing: _existing.span(),
1373 #[cfg(feature = "emit")]
1374 object: pat.span(),
1375 },
1376 ));
1377 }
1378
1379 binding
1380 });
1381
1382 let kind = match &ast.ident {
1383 ast::ObjectIdent::Named(path) => {
1384 let named = cx.q.convert_path(path)?;
1385 let parameters = generics_parameters(cx, &named)?;
1386 let meta = cx.lookup_meta(path, named.item, parameters)?;
1387
1388 let Some((mut fields, kind)) =
1389 struct_match_for(cx, &meta, is_open && count == 0)?
1390 else {
1391 return Err(compile::Error::expected_meta(
1392 path,
1393 meta.info(cx.q.pool)?,
1394 "type that can be used in a struct pattern",
1395 ));
1396 };
1397
1398 for binding in bindings.iter() {
1399 if !fields.remove(binding.key()) {
1400 return Err(compile::Error::new(
1401 ast,
1402 ErrorKind::LitObjectNotField {
1403 field: binding.key().try_into()?,
1404 item: cx.q.pool.item(meta.item_meta.item).try_to_owned()?,
1405 },
1406 ));
1407 }
1408 }
1409
1410 if !is_open && !fields.is_empty() {
1411 let mut fields = fields.into_iter().try_collect::<Box<[_]>>()?;
1412
1413 fields.sort();
1414
1415 return Err(compile::Error::new(
1416 ast,
1417 ErrorKind::PatternMissingFields {
1418 item: cx.q.pool.item(meta.item_meta.item).try_to_owned()?,
1419 #[cfg(feature = "emit")]
1420 fields,
1421 },
1422 ));
1423 }
1424
1425 kind
1426 }
1427 ast::ObjectIdent::Anonymous(..) => hir::PatSequenceKind::Anonymous {
1428 type_check: TypeCheck::Object,
1429 count,
1430 is_open,
1431 },
1432 };
1433
1434 hir::PatKind::Object(alloc!(hir::PatObject { kind, bindings }))
1435 }
1436 _ => {
1437 return Err(compile::Error::new(ast, ErrorKind::UnsupportedPatternExpr));
1438 }
1439 }
1440 };
1441
1442 Ok(hir::Pat {
1443 span: ast.span(),
1444 kind,
1445 })
1446}
1447
1448fn object_key<'hir, 'ast>(
1449 cx: &Ctxt<'hir, '_, '_>,
1450 ast: &'ast ast::ObjectKey,
1451) -> compile::Result<(&'ast dyn Spanned, &'hir str)> {
1452 alloc_with!(cx, ast);
1453
1454 Ok(match ast {
1455 ast::ObjectKey::LitStr(lit) => {
1456 let string = lit.resolve(resolve_context!(cx.q))?;
1457 (lit, alloc_str!(string.as_ref()))
1458 }
1459 ast::ObjectKey::Path(ast) => {
1460 let Some(ident) = ast.try_as_ident() else {
1461 return Err(compile::Error::expected(ast, "object key"));
1462 };
1463
1464 let string = ident.resolve(resolve_context!(cx.q))?;
1465 (ident, alloc_str!(string))
1466 }
1467 })
1468}
1469
1470#[instrument_ast(span = ast)]
1472fn expr_path<'hir>(
1473 cx: &mut Ctxt<'hir, '_, '_>,
1474 ast: &ast::Path,
1475 in_path: bool,
1476) -> compile::Result<hir::ExprKind<'hir>> {
1477 alloc_with!(cx, ast);
1478
1479 if let Some(ast::PathKind::SelfValue) = ast.as_kind() {
1480 let Some((id, _)) = cx.scopes.get(hir::Name::SelfValue)? else {
1481 return Err(compile::Error::new(ast, ErrorKind::MissingSelf));
1482 };
1483
1484 return Ok(hir::ExprKind::Variable(id));
1485 }
1486
1487 if let Needs::Value = cx.needs {
1488 if let Some(name) = ast.try_as_ident() {
1489 let name = alloc_str!(name.resolve(resolve_context!(cx.q))?);
1490
1491 if let Some((name, _)) = cx.scopes.get(hir::Name::Str(name))? {
1492 return Ok(hir::ExprKind::Variable(name));
1493 }
1494 }
1495 }
1496
1497 if in_path {
1500 return Ok(hir::ExprKind::Path);
1501 }
1502
1503 let named = cx.q.convert_path(ast)?;
1504 let parameters = generics_parameters(cx, &named)?;
1505
1506 if let Some(meta) = cx.try_lookup_meta(ast, named.item, ¶meters)? {
1507 return expr_path_meta(cx, &meta, ast);
1508 }
1509
1510 if let (Needs::Value, Some(local)) = (cx.needs, ast.try_as_ident()) {
1511 let local = local.resolve(resolve_context!(cx.q))?;
1512
1513 if !local.starts_with(char::is_uppercase) {
1516 return Err(compile::Error::new(
1517 ast,
1518 ErrorKind::MissingLocal {
1519 name: Box::<str>::try_from(local)?,
1520 },
1521 ));
1522 }
1523 }
1524
1525 let kind = if !parameters.parameters.is_empty() {
1526 ErrorKind::MissingItemParameters {
1527 item: cx.q.pool.item(named.item).try_to_owned()?,
1528 parameters: parameters.parameters,
1529 }
1530 } else {
1531 ErrorKind::MissingItem {
1532 item: cx.q.pool.item(named.item).try_to_owned()?,
1533 }
1534 };
1535
1536 Err(compile::Error::new(ast, kind))
1537}
1538
1539#[instrument_ast(span = span)]
1541fn expr_path_meta<'hir>(
1542 cx: &mut Ctxt<'hir, '_, '_>,
1543 meta: &meta::Meta,
1544 span: &dyn Spanned,
1545) -> compile::Result<hir::ExprKind<'hir>> {
1546 alloc_with!(cx, span);
1547
1548 if let Needs::Value = cx.needs {
1549 match &meta.kind {
1550 meta::Kind::Struct {
1551 fields: meta::Fields::Empty,
1552 ..
1553 } => Ok(hir::ExprKind::Call(alloc!(hir::ExprCall {
1554 call: hir::Call::Meta { hash: meta.hash },
1555 args: &[],
1556 }))),
1557 meta::Kind::Struct {
1558 fields: meta::Fields::Unnamed(0),
1559 ..
1560 } => Ok(hir::ExprKind::Call(alloc!(hir::ExprCall {
1561 call: hir::Call::Meta { hash: meta.hash },
1562 args: &[],
1563 }))),
1564 meta::Kind::Struct {
1565 fields: meta::Fields::Unnamed(..),
1566 ..
1567 } => Ok(hir::ExprKind::Fn(meta.hash)),
1568 meta::Kind::Function { .. } => Ok(hir::ExprKind::Fn(meta.hash)),
1569 meta::Kind::Const => Ok(hir::ExprKind::Const(meta.hash)),
1570 meta::Kind::Struct { .. } | meta::Kind::Type { .. } | meta::Kind::Enum { .. } => {
1571 Ok(hir::ExprKind::Type(Type::new(meta.hash)))
1572 }
1573 _ => Err(compile::Error::expected_meta(
1574 span,
1575 meta.info(cx.q.pool)?,
1576 "something that can be used as a value",
1577 )),
1578 }
1579 } else {
1580 let Some(type_hash) = meta.type_hash_of() else {
1581 return Err(compile::Error::expected_meta(
1582 span,
1583 meta.info(cx.q.pool)?,
1584 "something that has a type",
1585 ));
1586 };
1587
1588 Ok(hir::ExprKind::Type(Type::new(type_hash)))
1589 }
1590}
1591
1592fn condition<'hir>(
1593 cx: &mut Ctxt<'hir, '_, '_>,
1594 ast: &ast::Condition,
1595) -> compile::Result<hir::Condition<'hir>> {
1596 alloc_with!(cx, ast);
1597
1598 Ok(match ast {
1599 ast::Condition::Expr(ast) => hir::Condition::Expr(alloc!(expr(cx, ast)?)),
1600 ast::Condition::ExprLet(ast) => hir::Condition::ExprLet(alloc!(hir::ExprLet {
1601 pat: pat_binding(cx, &ast.pat)?,
1602 expr: expr(cx, &ast.expr)?,
1603 })),
1604 })
1605}
1606
1607fn pat_items_count(items: &[(ast::Pat, Option<ast::Comma>)]) -> compile::Result<(bool, usize)> {
1609 let mut it = items.iter();
1610
1611 let (is_open, mut count) = match it.next_back() {
1612 Some((pat, _)) => matches!(pat, ast::Pat::Rest { .. })
1613 .then(|| (true, 0))
1614 .unwrap_or((false, 1)),
1615 None => return Ok((false, 0)),
1616 };
1617
1618 for (pat, _) in it {
1619 if let ast::Pat::Rest { .. } = pat {
1620 return Err(compile::Error::new(pat, ErrorKind::UnsupportedPatternRest));
1621 }
1622
1623 count += 1;
1624 }
1625
1626 Ok((is_open, count))
1627}
1628
1629fn struct_match_for(
1635 cx: &Ctxt<'_, '_, '_>,
1636 meta: &meta::Meta,
1637 open: bool,
1638) -> alloc::Result<Option<(HashSet<Box<str>>, hir::PatSequenceKind)>> {
1639 let (fields, kind) = match meta.kind {
1640 meta::Kind::Struct {
1641 ref fields,
1642 enum_hash,
1643 ..
1644 } => {
1645 let kind = 'kind: {
1646 if let Some(type_check) = cx.q.context.type_check_for(meta.hash) {
1647 break 'kind hir::PatSequenceKind::BuiltInVariant { type_check };
1648 }
1649
1650 if enum_hash != Hash::EMPTY {
1651 break 'kind hir::PatSequenceKind::Variant {
1652 enum_hash,
1653 variant_hash: meta.hash,
1654 };
1655 }
1656
1657 hir::PatSequenceKind::Type { hash: meta.hash }
1658 };
1659
1660 (fields, kind)
1661 }
1662 _ => {
1663 return Ok(None);
1664 }
1665 };
1666
1667 let fields = match fields {
1668 meta::Fields::Unnamed(0) if open => HashSet::new(),
1669 meta::Fields::Empty if open => HashSet::new(),
1670 meta::Fields::Named(st) => st
1671 .fields
1672 .iter()
1673 .map(|f| f.name.try_clone())
1674 .try_collect::<alloc::Result<_>>()??,
1675 _ => return Ok(None),
1676 };
1677
1678 Ok(Some((fields, kind)))
1679}
1680
1681fn tuple_match_for(
1682 cx: &Ctxt<'_, '_, '_>,
1683 meta: &meta::Meta,
1684) -> Option<(usize, hir::PatSequenceKind)> {
1685 match meta.kind {
1686 meta::Kind::Struct {
1687 ref fields,
1688 enum_hash,
1689 ..
1690 } => {
1691 let args = match *fields {
1692 meta::Fields::Unnamed(args) => args,
1693 meta::Fields::Empty => 0,
1694 _ => return None,
1695 };
1696
1697 let kind = 'kind: {
1698 if let Some(type_check) = cx.q.context.type_check_for(meta.hash) {
1699 break 'kind hir::PatSequenceKind::BuiltInVariant { type_check };
1700 }
1701
1702 if enum_hash != Hash::EMPTY {
1703 break 'kind hir::PatSequenceKind::Variant {
1704 enum_hash,
1705 variant_hash: meta.hash,
1706 };
1707 }
1708
1709 hir::PatSequenceKind::Type { hash: meta.hash }
1710 };
1711
1712 Some((args, kind))
1713 }
1714 _ => None,
1715 }
1716}
1717
1718fn generics_parameters(
1719 cx: &mut Ctxt<'_, '_, '_>,
1720 named: &Named<'_>,
1721) -> compile::Result<GenericsParameters> {
1722 let mut parameters = GenericsParameters {
1723 trailing: named.trailing,
1724 parameters: [None, None],
1725 };
1726
1727 for (value, o) in named
1728 .parameters
1729 .iter()
1730 .zip(parameters.parameters.iter_mut())
1731 {
1732 if let &Some((span, generics)) = value {
1733 let mut builder = ParametersBuilder::new();
1734
1735 for (s, _) in generics {
1736 let hir::ExprKind::Type(ty) = expr(cx, &s.expr)?.kind else {
1737 return Err(compile::Error::new(s, ErrorKind::UnsupportedGenerics));
1738 };
1739
1740 builder = builder.add(ty.into_hash()).with_span(span)?;
1741 }
1742
1743 *o = Some(builder.finish());
1744 }
1745 }
1746
1747 Ok(parameters)
1748}
1749
1750#[instrument_ast(span = ast)]
1752fn expr_call<'hir>(
1753 cx: &mut Ctxt<'hir, '_, '_>,
1754 ast: &ast::ExprCall,
1755) -> compile::Result<hir::ExprCall<'hir>> {
1756 fn find_path(ast: &ast::Expr) -> Option<&ast::Path> {
1757 let mut current = ast;
1758
1759 loop {
1760 match current {
1761 ast::Expr::Path(path) => return Some(path),
1762 ast::Expr::Empty(ast) => {
1763 current = &*ast.expr;
1764 continue;
1765 }
1766 _ => return None,
1767 }
1768 }
1769 }
1770
1771 alloc_with!(cx, ast);
1772
1773 let in_path = replace(&mut cx.in_path, true);
1774 let expr = expr(cx, &ast.expr)?;
1775 cx.in_path = in_path;
1776
1777 let call = 'ok: {
1778 match expr.kind {
1779 hir::ExprKind::Variable(name) => {
1780 break 'ok hir::Call::Var { name };
1781 }
1782 hir::ExprKind::Path => {
1783 let Some(path) = find_path(&ast.expr) else {
1784 return Err(compile::Error::msg(&ast.expr, "Expected path"));
1785 };
1786
1787 let named = cx.q.convert_path(path)?;
1788 let parameters = generics_parameters(cx, &named)?;
1789
1790 let meta = cx.lookup_meta(path, named.item, parameters)?;
1791 debug_assert_eq!(meta.item_meta.item, named.item);
1792
1793 match &meta.kind {
1794 meta::Kind::Struct {
1795 fields: meta::Fields::Empty,
1796 ..
1797 } => {
1798 if !ast.args.is_empty() {
1799 return Err(compile::Error::new(
1800 &ast.args,
1801 ErrorKind::BadArgumentCount {
1802 expected: 0,
1803 actual: ast.args.len(),
1804 },
1805 ));
1806 }
1807 }
1808 meta::Kind::Struct {
1809 fields: meta::Fields::Unnamed(args),
1810 ..
1811 } => {
1812 if *args != ast.args.len() {
1813 return Err(compile::Error::new(
1814 &ast.args,
1815 ErrorKind::BadArgumentCount {
1816 expected: *args,
1817 actual: ast.args.len(),
1818 },
1819 ));
1820 }
1821
1822 if *args == 0 {
1823 cx.q.diagnostics.remove_tuple_call_parens(
1824 cx.source_id,
1825 &ast.args,
1826 path,
1827 None,
1828 )?;
1829 }
1830 }
1831 meta::Kind::Function { .. } => {
1832 if let Some(message) = cx.q.lookup_deprecation(meta.hash) {
1833 cx.q.diagnostics.used_deprecated(
1834 cx.source_id,
1835 &expr.span,
1836 None,
1837 message.try_into()?,
1838 )?;
1839 };
1840 }
1841 meta::Kind::ConstFn => {
1842 let from =
1843 cx.q.item_for("lowering constant function", ast.id)
1844 .with_span(ast)?;
1845
1846 break 'ok hir::Call::ConstFn {
1847 from_module: from.module,
1848 from_item: from.item,
1849 id: meta.item_meta.item,
1850 };
1851 }
1852 _ => {
1853 return Err(compile::Error::expected_meta(
1854 ast,
1855 meta.info(cx.q.pool)?,
1856 "something that can be called as a function",
1857 ));
1858 }
1859 };
1860
1861 break 'ok hir::Call::Meta { hash: meta.hash };
1862 }
1863 hir::ExprKind::FieldAccess(&hir::ExprFieldAccess {
1864 expr_field,
1865 expr: target,
1866 }) => {
1867 let hash = match expr_field {
1868 hir::ExprField::Index(index) => Hash::index(index),
1869 hir::ExprField::Ident(ident) => {
1870 cx.q.unit.insert_debug_ident(ident)?;
1871 Hash::ident(ident)
1872 }
1873 hir::ExprField::IdentGenerics(ident, hash) => {
1874 cx.q.unit.insert_debug_ident(ident)?;
1875 Hash::ident(ident).with_function_parameters(hash)
1876 }
1877 };
1878
1879 break 'ok hir::Call::Associated {
1880 target: alloc!(target),
1881 hash,
1882 };
1883 }
1884 _ => {}
1885 }
1886
1887 break 'ok hir::Call::Expr { expr: alloc!(expr) };
1888 };
1889
1890 Ok(hir::ExprCall {
1891 call,
1892 args: iter!(&ast.args, |(ast, _)| self::expr(cx, ast)?),
1893 })
1894}
1895
1896#[instrument_ast(span = ast)]
1897fn expr_field_access<'hir>(
1898 cx: &mut Ctxt<'hir, '_, '_>,
1899 ast: &ast::ExprFieldAccess,
1900) -> compile::Result<hir::ExprFieldAccess<'hir>> {
1901 alloc_with!(cx, ast);
1902
1903 let expr_field = match &ast.expr_field {
1904 ast::ExprField::LitNumber(ast) => {
1905 let number = ast.resolve(resolve_context!(cx.q))?;
1906
1907 let Some(index) = number.as_tuple_index() else {
1908 return Err(compile::Error::new(
1909 ast,
1910 ErrorKind::UnsupportedTupleIndex { number },
1911 ));
1912 };
1913
1914 hir::ExprField::Index(index)
1915 }
1916 ast::ExprField::Path(ast) => {
1917 let Some((ident, generics)) = ast.try_as_ident_generics() else {
1918 return Err(compile::Error::new(ast, ErrorKind::BadFieldAccess));
1919 };
1920
1921 let ident = alloc_str!(ident.resolve(resolve_context!(cx.q))?);
1922
1923 match generics {
1924 Some(generics) => {
1925 let mut builder = ParametersBuilder::new();
1926
1927 for (s, _) in generics {
1928 let hir::ExprKind::Type(ty) = expr(cx, &s.expr)?.kind else {
1929 return Err(compile::Error::new(s, ErrorKind::UnsupportedGenerics));
1930 };
1931
1932 builder = builder.add(ty.into_hash()).with_span(s)?;
1933 }
1934
1935 hir::ExprField::IdentGenerics(ident, builder.finish())
1936 }
1937 None => hir::ExprField::Ident(ident),
1938 }
1939 }
1940 };
1941
1942 Ok(hir::ExprFieldAccess {
1943 expr: expr(cx, &ast.expr)?,
1944 expr_field,
1945 })
1946}