cove_ir/lower/mod.rs
1//! Turning a checked package into the executable IR.
2//!
3//! This reads the answers `cove-sema` already settled and writes them down
4//! as slots and instructions. It re-derives nothing: an expression's type
5//! comes from [`Facts::ty`](cove_sema::Facts::ty), a declaration's boundary
6//! from [`Facts::signature`](cove_sema::Facts::signature), and where the two
7//! could disagree the checker is right by construction because this asked it
8//! rather than working it out again.
9//!
10//! # There is no refusal
11//!
12//! A valid checked program lowers. That is the whole contract, and it is
13//! what [ADR 0034](../../../../docs/adr/0034-one-physical-word-stack.md)
14//! replaces the predecessor's admission predicate with. The two ways this
15//! can answer `Err` are the two `gap` module builds — an unsettled type and
16//! a construct this crate has not been taught yet — and neither is a
17//! judgement about the program.
18//!
19//! # A value is a run of words, and the lowering is what knows how many
20//!
21//! `docs/LINEAR_VM.md` puts the fields of a struct where the value is, so
22//! `l.from.x` is a slot number this module computes and not an instruction
23//! the machine runs. A field access on an inline value is *arithmetic on a
24//! slot*, and only a field of a heap object is a load. That is why
25//! `Val` is a base slot and a layout rather than a slot and a `Repr`: the
26//! layout is what a copy's width, a location's reference words and a field's
27//! offset are all read off.
28//!
29//! # A generic is one function per instantiation
30//!
31//! `docs/LINEAR_VM.md` says why there was no choice: a slot's `Repr` is fixed
32//! for the whole function, that is what makes one static reference map
33//! correct at every program counter, and a generic value's width is a fact
34//! about the type argument — `Cell<Int>` is one word and `Cell<Point>` is
35//! two. Carrying layouts at run time would make widths dynamic and take the
36//! map with them; boxing every generic value would allocate on `f(1)` and
37//! make a type parameter mean what `dyn Trait` already means. So `f<Int>` and
38//! `f<Point>` are two functions and two frames, and a generic `struct` at two
39//! instantiations is two layouts.
40//!
41//! It costs one substitution and no second walk. The checker walked the
42//! generic body once with its type parameters rigid, so every fact in it is
43//! recorded in terms of them, and `Body::ty` completes one as it is read.
44//! Which arguments a call site asks for is read off the facts the checker
45//! settled there — `Body::instantiation` is that reading, and it is also why
46//! an explicit type argument needs no path of its own: the checker applied
47//! it before this crate saw anything.
48//!
49//! # The shape of a lowered body
50//!
51//! Control flow is flat. There are no basic blocks and no block arguments:
52//! an `if` is a [`Inst::BranchFalse`] over a run of instructions, a `while`
53//! is a backward [`Inst::Jump`], and both are emitted with an unpatchable
54//! target that is filled in once the destination is known. A loop keeps the
55//! jumps its `break`s left behind and patches them when it learns where its
56//! end is.
57//!
58//! Every function ends in [`Inst::Return`], and it is emitted
59//! unconditionally — even after a body that already returned on every path.
60//! That is one dead word, and what it buys is that every patched target
61//! lands on an instruction: a branch whose destination is "after everything"
62//! has something to be after. Tracking reachability well enough to drop it
63//! would mean tracking which pending patches point past the end, which is
64//! more machinery than the word is worth.
65
66mod assertions;
67mod cells;
68mod closures;
69mod collections;
70mod dispatch;
71mod dropping;
72mod expr;
73mod frame;
74mod frees;
75mod gap;
76mod inline;
77mod limits;
78mod methods;
79mod pattern;
80mod shapes;
81mod stmt;
82mod tails;
83mod tasks;
84mod walks;
85
86#[cfg(test)]
87mod tests;
88
89use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
90use std::sync::Arc;
91
92use cove_diag::{Diagnostic, SourceMap, Span};
93use cove_schema::HostSchemas;
94use cove_sema::facts::MethodTarget;
95use cove_sema::resolve::{FnKey, Node, Program as Checked};
96use cove_sema::typeck::Ty;
97use cove_syntax::ast::{Expr, FnDecl};
98
99use crate::inst::{Inst, Pc, Slot};
100use crate::layout::LayoutId;
101use crate::program::{
102 Arg, ArgsId, Builtin, BuiltinId, Function, FunctionId, HostOp, HostOpId, Program, StrId, Table,
103 TableId,
104};
105use crate::repr::{RefMap, Repr};
106
107use frame::{Frame, Val};
108use shapes::Shapes;
109
110/// The target of a jump that has been emitted but whose destination is not
111/// known yet.
112///
113/// `u32::MAX` rather than `0`, so that a patch this lowering forgot is a
114/// verifier fault naming the instruction rather than a silent jump to the
115/// top of the function.
116const PENDING: Pc = Pc::MAX;
117
118/// Where a form assembles its answer: a base slot and the layout that says
119/// how wide it is.
120///
121/// A destination is a *location*, not a slot, because a value may be several
122/// words and both a branch join and a block tail have to write all of them.
123#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124pub(crate) struct Dest {
125 pub slot: Slot,
126 pub layout: LayoutId,
127}
128
129impl Dest {
130 fn of(val: &Val) -> Dest {
131 Dest {
132 slot: val.slot,
133 layout: val.layout,
134 }
135 }
136}
137
138/// Lowers a checked package: every declaration it has, whether or not
139/// anything reaches it.
140///
141/// The result either runs or names what stopped it. Nothing in between: a
142/// lowered [`Program`] has been through [`crate::verify()`], so a caller that
143/// holds one holds a program whose locations, jumps and calls are all in
144/// range and whose reference map is the one its reprs imply.
145///
146/// `sources` is the package's own text, and it is here for one reason:
147/// `assert` and `assertEqual` quote the code that failed, so the lowering
148/// has to read the bytes an argument's span covers. See this module's
149/// `assertions` submodule for why they are lowered rather than performed.
150///
151/// `schemas` is the set of host modules this compilation was given, and it
152/// must be the set the *checker* was given. A type a host module declares has
153/// a layout — a `files.Reader` is one [`Repr::Host`] word and an
154/// `http.Response` is its fields inline — and the schema is the only thing
155/// that says which of the two a name is. Reading `cove_schema::hosts` here
156/// instead would describe the shipped modules and no others, so a program
157/// that names a type an embedding registered would lower for fewer types than
158/// it checked against: a backend refusing a program the language admits,
159/// rather than a gap somebody can build. `HostApi` is a trait, and an
160/// embedder's module is not a lesser kind of host.
161///
162/// [`lower_roots`] is the same lowering over what a named set of roots
163/// reaches, and it is what a command that runs a program should use — a
164/// command names the roots it is about to run and this crate works out the
165/// slice. This one is what a whole-package listing means — everything the
166/// package declares is part of it — and it is what the lowering's own tests
167/// and the corpus survey ask for.
168pub fn lower(
169 checked: &Checked,
170 sources: &SourceMap,
171 schemas: &HostSchemas,
172) -> Result<Program, Vec<Diagnostic>> {
173 let mut plan = Plan::index(checked);
174 let everything: HashSet<FunctionId> = (0..plan.decls.len())
175 .map(|at| FunctionId(at as u32))
176 .collect();
177 let Lowering {
178 program, errors, ..
179 } = emit(checked, sources, schemas, &mut plan, &everything);
180 finish(program, errors)
181}
182
183/// Lowers only the declarations `roots` can reach.
184///
185/// A package holds programs that have nothing to do with each other —
186/// `benches/` is nine of them and `tests/e2e/` is a hundred — and a gap in
187/// one of them is not a reason to refuse the others. So a command lowers
188/// what it is about to run and leaves the rest as a stub nothing names.
189///
190/// A root is a `(module, name)` pair naming a declaration the way the
191/// checker's own tables do, and the slice is what *any* of them reaches.
192/// That is the whole of the API a command needs: it selects roots — the
193/// entry it was asked for, the test it is about to run, the entries a
194/// package configures — and reachability stays here. A caller that walked
195/// the call graph itself would be a second answer to a question this
196/// module already has to answer, and the two would drift.
197///
198/// A root that names nothing this package declares contributes nothing. It
199/// is not an error here, because what a name denotes is the checker's
200/// question and every caller has already asked it: `run_entry` answers
201/// "this package does not declare `m.f`" better than a lowering could, and
202/// it answers it about the program that was actually going to run.
203///
204/// # One answer for the whole set
205///
206/// The gaps this returns are the gaps of everything `roots` reaches,
207/// together, and there is no telling which root a gap came from. So a
208/// caller that needs one root's failure to be one root's failure passes
209/// one root — which is what [`lower_entry`] is, and why `cove test` lowers
210/// each test rather than the suite.
211///
212/// # What "reachable" is, and how this is sure of it
213///
214/// The seed is [`Program::call_graph`](cove_sema::resolve::Program::call_graph),
215/// which the checker already derived: for each declaration, every declaration
216/// it may call. Both precisions are followed, because
217/// [`CallPrecision::Approximate`](cove_sema::resolve::CallPrecision) is a
218/// superset of what may run and a slice has to hold everything that might.
219///
220/// The seed is not the answer, though, and the graph itself says why: a
221/// callee that is a *value* — `xs.map(double)`, a conformance a `dyn`
222/// dispatch picks, a `Snapshot` implementation nothing writes a call to —
223/// contributes no edge, because there is no call site naming it. A
224/// declaration missing from the slice is not a gap the person holding the
225/// source can act on; it is a stub that answers `()` where a call was meant
226/// to go.
227///
228/// So the slice is closed against the lowering rather than against the
229/// graph. Every place that turns a name into a [`FunctionId`] asks whether
230/// this pass lowered it first, and a body that names a declaration this
231/// slice left out records it rather than emitting a call to a stub. What was
232/// recorded is added to the slice and the package is lowered again,
233/// until a round wants nothing — which is a fixed point over *what this
234/// lowering emits references to*, not over what a second reachability
235/// analysis believes.
236///
237/// The call graph is what makes that one round rather than one per level of
238/// the call tree: seeded with nothing, each round could only discover the
239/// callees of what the round before it lowered.
240pub fn lower_roots(
241 checked: &Checked,
242 sources: &SourceMap,
243 schemas: &HostSchemas,
244 roots: &[(&str, &str)],
245) -> Result<Program, Vec<Diagnostic>> {
246 let mut plan = Plan::index(checked);
247 let mut reach = plan.reachable_from(checked, roots);
248 loop {
249 let Lowering {
250 program,
251 errors,
252 wanted,
253 } = emit(checked, sources, schemas, &mut plan, &reach);
254 if wanted.is_empty() {
255 return finish(program, errors);
256 }
257 reach.extend(wanted);
258 }
259}
260
261/// Lowers only the declarations `module.name` can reach.
262///
263/// The one-root case of [`lower_roots`], which is where everything this
264/// does is written down. It has a name of its own because one root is what
265/// almost every caller has — `cove run` has the entry it was asked for,
266/// `cove replay` has the entry the tape was recorded from, `cove test` has
267/// the test it is about to run — and because a set of one is the only set
268/// whose gaps belong to a single root.
269pub fn lower_entry(
270 checked: &Checked,
271 sources: &SourceMap,
272 schemas: &HostSchemas,
273 module: &str,
274 name: &str,
275) -> Result<Program, Vec<Diagnostic>> {
276 lower_roots(checked, sources, schemas, &[(module, name)])
277}
278
279/// One pass of the lowering over one set of declarations.
280struct Lowering {
281 program: Program,
282 errors: Vec<Diagnostic>,
283 /// The declarations a body named that this pass had left out.
284 ///
285 /// Empty for a whole-package lowering, because nothing is left out.
286 /// For a sliced one it is the correction: see [`lower_entry`].
287 wanted: HashSet<FunctionId>,
288}
289
290/// Lowers `reach` and stubs the rest.
291fn emit<'a>(
292 checked: &'a Checked,
293 sources: &SourceMap,
294 schemas: &HostSchemas,
295 plan: &mut Plan<'a>,
296 reach: &HashSet<FunctionId>,
297) -> Lowering {
298 let mut errors = Vec::new();
299 let mut wanted = HashSet::new();
300 let mut pool = Pool::new(schemas.clone());
301 plan.boundaries(checked, reach, &mut pool, &mut errors);
302 let mut functions = Vec::new();
303 for id in 0..plan.decls.len() {
304 functions.push(if reach.contains(&FunctionId(id as u32)) {
305 lower_function(
306 checked,
307 sources,
308 plan,
309 id,
310 &mut pool,
311 &mut errors,
312 &mut wanted,
313 )
314 } else {
315 stub(&plan.decls[id])
316 });
317 }
318 // A lambda and an instantiation are `Function`s of their own, numbered
319 // after every declaration and discovered while a body is being walked
320 // rather than by the plan. Either may be appended while the body that
321 // asked for it is still being lowered, so this list is complete only once
322 // the loop above has finished — which is why it is drained here and not
323 // built beside `plan.decls`.
324 functions.extend(
325 pool.appended
326 .drain(..)
327 .map(|held| held.expect("every reserved function was lowered into its own slot")),
328 );
329
330 let program = Program {
331 functions,
332 layouts: pool.shapes.into_table(),
333 str_layout: shapes::STR,
334 bytes_layout: shapes::BYTES,
335 buffer_layout: shapes::BYTE_BUFFER,
336 boxed_layout: shapes::BOXED,
337 strings: pool.strings,
338 args: pool.args.lists,
339 tables: pool.tables,
340 host_ops: pool.host_ops,
341 builtins: pool.builtins,
342 // Only what this pass lowered is nameable. A stub answers `()`, so
343 // an entry point that resolved to one would run and say nothing
344 // rather than saying it was not there — and `run_entry` already has
345 // a good answer for a name a program does not carry.
346 //
347 // A generic declaration is a stub for the same reason and is left out
348 // for the same reason. What a program carries is its
349 // instantiations — `f<Int>` — and there is no entry point among them:
350 // a command names a declaration, and which instantiation of a generic
351 // one it meant is not a question a command line can answer.
352 by_name: plan
353 .by_name
354 .iter()
355 .filter(|(_, id)| reach.contains(id))
356 .filter(|(_, id)| plan.decls[id.index()].decl.generics.is_empty())
357 .map(|(key, id)| (key.clone(), *id))
358 .collect(),
359 };
360 Lowering {
361 program,
362 errors,
363 wanted,
364 }
365}
366
367/// The lowered program, or what stopped it — and the verifier's word that
368/// the first of the two is well formed.
369fn finish(mut program: Program, errors: Vec<Diagnostic>) -> Result<Program, Vec<Diagnostic>> {
370 if !errors.is_empty() {
371 return Err(only_once(errors));
372 }
373
374 // A call to a small leaf is expanded where it is made, before the two
375 // passes below run: what an expansion leaves behind is exactly the shape
376 // they are for — a clear that frees nothing, and a clear a `return` was
377 // about to make pointless — and running them first would mean running
378 // them twice. See `inline`.
379 inline::expand_small_leaf_calls(&mut program);
380
381 // A clear the `return` after it was going to make pointless is dropped
382 // here rather than never emitted, because the emission sites are many and
383 // the condition is about the *code* — what follows an instruction — which
384 // only the finished code can be asked. See `tails`.
385 tails::drop_clears_before_return(&mut program);
386
387 // And a clear that frees nothing at all — because the word it zeroes is
388 // already null, or is the address of a literal placed once for the
389 // whole run and never collected, whatever this frame does. Here for the
390 // reason above and for one more: the condition is about a *path*
391 // through the finished code, which is a graph the lowering does not
392 // have while it is building one. See `frees`.
393 frees::drop_clears_that_free_nothing(&mut program);
394
395 // A frame wider than a sixteen-bit slot operand can name is the one thing
396 // this lowering refuses about a program it otherwise understood. It is
397 // checked here rather than as each body finishes because here is where
398 // every function exists — a lambda and an instantiation are appended
399 // while another body is still being lowered — and because a diagnostic
400 // about the *program* should list every function at fault rather than the
401 // first. See `limits`.
402 let oversized = limits::oversized_frames(&program);
403 if !oversized.is_empty() {
404 return Err(oversized);
405 }
406
407 // A fault here is a bug in this module, not a fault in the user's
408 // program: everything the verifier checks is something this lowering
409 // decided. Reporting it as a diagnostic would put it in front of the
410 // person least able to act on it, so it fails loudly and with the whole
411 // list, because one lowering bug usually shows up in several places and
412 // seeing all of them is what says which one is the cause.
413 if let Err(faults) = crate::verify(&program) {
414 let listing: Vec<String> = faults.iter().map(ToString::to_string).collect();
415 panic!(
416 "the lowering produced a program the verifier rejects:\n {}",
417 listing.join("\n ")
418 );
419 }
420
421 Ok(program)
422}
423
424/// Keeps the first diagnostic about each place.
425///
426/// One unsettled type is read once per operand it feeds, so the same
427/// expression can be reported several times over. What a reader needs is
428/// the place, once.
429fn only_once(errors: Vec<Diagnostic>) -> Vec<Diagnostic> {
430 let mut seen = HashSet::new();
431 errors
432 .into_iter()
433 .filter(|item| {
434 let at = item.primary.map(|span| (span.file.0, span.start, span.end));
435 seen.insert((item.code.clone(), at))
436 })
437 .collect()
438}
439
440// ---------------------------------------------------------------- the plan
441
442/// What one declaration becomes: its identity, and the frame boundary a call
443/// to it has to match.
444struct Decl<'a> {
445 module: Arc<str>,
446 name: Arc<str>,
447 decl: &'a FnDecl,
448 /// `None` for a declaration outside this lowering's scope, and for one
449 /// this pass never asked about. A gap has already been reported for the
450 /// first, so the stub that takes its place is never seen: `lower`
451 /// answers `Err` before the program leaves. The second is a declaration
452 /// the slice left out, and [`Plan::reached`] is what tells the two
453 /// apart.
454 boundary: Option<Boundary>,
455 /// The trait whose default body this method is, when it is one.
456 ///
457 /// What it decides is which substitution the body is lowered under. The
458 /// checker walks a default body **once**, with `self` typed as a rigid
459 /// `Ty::Param("Self")` bounded by the trait, so every fact recorded
460 /// inside it is written in terms of `Self` — which is the same situation
461 /// a generic declaration is in, one parameter at a time. See
462 /// [`Decl::substitution`].
463 from_trait_default: Option<String>,
464 /// The type this is a method of, as the receiver's own type.
465 ///
466 /// `None` for a free function, and for a method of a *generic* type,
467 /// whose receiver's width depends on a type argument this does not have —
468 /// see [`Decl::on_generic_type`].
469 ///
470 /// It is written in the package's own vocabulary — `m.Booking` rather
471 /// than `Booking` — because a conformance may be declared in the module
472 /// that declares the *trait* (ADR 0006's orphan rule), and then the
473 /// type's bare name means nothing where the body is lowered.
474 receiver_ty: Option<Ty>,
475 /// The generic type this is a method of, when it is one.
476 ///
477 /// A method of `Cell<T>` has no boundary of its own for the same reason a
478 /// generic function has none — its receiver's width depends on `T` — and
479 /// it needs one thing more than a generic function does: the parameters
480 /// are the *type*'s rather than the declaration's, so which arguments a
481 /// call settles is read off the receiver rather than off the signature.
482 /// That is not built, and this is what names it as the work rather than
483 /// letting it fail as "a value of type `Cell<T>`", which says where the
484 /// trouble is and not what is owed.
485 on_generic_type: Option<String>,
486}
487
488/// The one type parameter a trait's default body is written in terms of.
489const SELF: &str = "Self";
490
491impl Decl<'_> {
492 /// The type parameters this declaration's facts are recorded in terms
493 /// of, and what this lowering puts in their place.
494 ///
495 /// Empty for almost everything, and then the substitution is the
496 /// identity. A **trait method's default body** is the one declaration
497 /// that is neither generic nor ordinary: `resolve::conform` synthesises
498 /// one `FnDecl` per conforming type, all of them carrying the *trait
499 /// method's* span, and `Checker::check_trait_defaults` records one
500 /// `Signature` at that span with the receiver typed `Ty::Param("Self")`.
501 ///
502 /// So a default body is a generic declaration with one parameter, and
503 /// this is what says which. Nothing else is needed: the boundary is
504 /// [`boundary_of`] under this substitution, the body is [`lower_body`]
505 /// under it, and a call the body makes on `self` finds the conforming
506 /// type's own implementation through [`Body::conformance`] — which is
507 /// the path a bounded generic already takes, for the same reason. One
508 /// recorded walk serves every conformance.
509 ///
510 /// A default body on a *generic* type would need `Self` to stand for an
511 /// instantiation rather than for a declaration, so it is left to
512 /// [`Plan::boundaries`]'s earlier arm.
513 fn substitution(&self) -> (Vec<Arc<str>>, Vec<Ty>) {
514 match (&self.from_trait_default, &self.receiver_ty) {
515 (Some(_), Some(ty)) => (vec![Arc::from(SELF)], vec![ty.clone()]),
516 _ => (Vec::new(), Vec::new()),
517 }
518 }
519}
520
521/// A declaration's parameters and answer, as layouts.
522///
523/// A generic declaration has one of these per instantiation rather than one
524/// of its own, so it is cloned into [`Instance`] and read from there at a
525/// call site — see [`Body::shape`].
526#[derive(Clone)]
527struct Boundary {
528 /// The layout of each parameter, **receiver first** where the
529 /// declaration has one. There are no type groups and nothing is
530 /// permuted; a method's receiver is first because it is the first thing
531 /// a call supplies. A `var` parameter's layout is
532 /// [`shapes::ADDR`]: it names the caller's storage rather than holding a
533 /// value.
534 params: Vec<LayoutId>,
535 /// The types those locations hold, in the same order.
536 ///
537 /// The layout alone is not enough at a call site. A parameter written
538 /// `dyn Trait` and one written `String` are both one [`Repr::Ref`] word,
539 /// and only the first is a place where a concrete value is erased — so
540 /// the call site has to read the type the checker settled, not the
541 /// layout this lowering derived from it.
542 types: Vec<Ty>,
543 returns: LayoutId,
544 /// What the declaration answers, as the checker settled it.
545 ///
546 /// The layout is not enough for `?`, which has to build the enclosing
547 /// function's own `Err` or `None` and therefore needs to know which of
548 /// the two the answer is.
549 ret: Ty,
550 /// Whether the first parameter is the receiver: `self`, or the address
551 /// `var self` names.
552 receiver: bool,
553 /// Whether the last parameter collects the arguments the ones before it
554 /// did not take.
555 ///
556 /// One flag rather than a position, because the checker has already
557 /// refused a variadic parameter anywhere but last — `cove::type::
558 /// variadic_position` — and refused one written with a default.
559 variadic: bool,
560 /// Whether the declaration was written `async fn`.
561 ///
562 /// It changes nothing about the function and everything about the call.
563 /// `returns` above is the layout of `T` and not of `Task<T>`, because
564 /// the checker's `Signature::ret` is `T` and because the oracle's
565 /// `Interpreter::invoke_body` produces a `T` — the task is made *around*
566 /// the answer, by the caller, after the body has already run. So the
567 /// declaration is lowered as an ordinary function and every Cove call
568 /// site follows its [`Inst::Call`] with an [`Inst::Settled`].
569 ///
570 /// The three places that reach a body from outside Cove — an entry, a
571 /// host `invoke`, and a host calling a Cove callback — all *await* what
572 /// they get in the oracle, and awaiting a settled task is the value.
573 /// Here they get the value, because no task was made. That is the same
574 /// answer arrived at by not building the thing that would be undone.
575 is_async: bool,
576}
577
578/// Every declaration the package will have a [`Function`] for, numbered.
579///
580/// The order is module then name, both from a `BTreeMap`, so a package
581/// lowers to the same function ids every time it is lowered. A test that
582/// pins a listing is pinning something stable rather than a hash order.
583/// Within a module the free functions come first and the methods follow, so
584/// adding a method to a type does not renumber a package's functions.
585struct Plan<'a> {
586 decls: Vec<Decl<'a>>,
587 by_name: BTreeMap<(Arc<str>, Arc<str>), FunctionId>,
588 lookup: HashMap<(String, String), FunctionId>,
589 /// A method, keyed the way [`MethodTarget`] names one: the module that
590 /// declares the *type*, the type, and the method.
591 ///
592 /// That is not always the module the `impl` block is written in — ADR
593 /// 0006's orphan rule lets a conformance be written where the trait is —
594 /// so this is keyed by what a call site holds rather than by where the
595 /// code ended up.
596 methods: HashMap<(String, String, String), FunctionId>,
597 /// The declarations this pass is lowering rather than stubbing.
598 ///
599 /// It is the whole numbering for [`lower`] and one entry's reachable set
600 /// for [`lower_entry`]. [`Plan::reached`] is what reads it, and every
601 /// place that names a declaration asks before it emits a call.
602 lowered: HashSet<FunctionId>,
603}
604
605impl<'a> Plan<'a> {
606 /// Numbers every declaration the package has.
607 ///
608 /// The numbering is over the whole package whether or not a slice will
609 /// use all of it, and that is what makes a [`FunctionId`] mean the same
610 /// thing in every pass [`lower_entry`] runs: a set of ids gathered by one
611 /// round names the same declarations in the next.
612 ///
613 /// Nothing here reads a signature or builds a layout. What a call to a
614 /// declaration passes is [`Plan::boundaries`], which is asked only about
615 /// the declarations a pass is actually lowering — so a slice pays for the
616 /// types it reaches and not for the package's.
617 fn index(checked: &'a Checked) -> Plan<'a> {
618 let mut plan = Plan {
619 decls: Vec::new(),
620 by_name: BTreeMap::new(),
621 lookup: HashMap::new(),
622 methods: HashMap::new(),
623 lowered: HashSet::new(),
624 };
625 for (name, resolved) in &checked.modules {
626 for (fn_name, entry) in &resolved.functions {
627 let module: Arc<str> = Arc::from(name.as_str());
628 let id = plan.declare(module, Arc::from(fn_name.as_str()), entry.decl.as_ref());
629 plan.lookup.insert((name.clone(), fn_name.clone()), id);
630 }
631 for ((type_name, method), entry) in &resolved.methods {
632 let module: Arc<str> = Arc::from(name.as_str());
633 // A method is named `Type.method` in the module whose `impl`
634 // block writes it. A type and a free function of one name
635 // cannot both be declared in a module, and a `.` is not a
636 // name character, so the two namings cannot collide and
637 // `m.Point.scaled` reads in a diagnostic as it is written.
638 let lowered: Arc<str> = Arc::from(format!("{type_name}.{method}"));
639 let id = plan.declare(module, lowered, entry.decl.as_ref());
640 plan.decls[id.index()].from_trait_default = entry.from_trait_default.clone();
641 let owner = resolved.owner_of(type_name).unwrap_or(name.as_str());
642 if is_generic_type(checked, owner, type_name) {
643 plan.decls[id.index()].on_generic_type = Some(type_name.clone());
644 } else {
645 plan.decls[id.index()].receiver_ty = receiver_ty(checked, owner, type_name);
646 }
647 plan.methods
648 .insert((owner.to_string(), type_name.clone(), method.clone()), id);
649 }
650 }
651 plan
652 }
653
654 /// Reads the boundary of every declaration in `reach`, and reports what
655 /// stopped one.
656 ///
657 /// This is where a pass's errors about *declarations* come from, and
658 /// restricting it to the slice is most of what slicing is worth: a
659 /// generic function or an `async fn` in a module the entry never enters
660 /// is not work this entry is waiting on.
661 fn boundaries(
662 &mut self,
663 checked: &'a Checked,
664 reach: &HashSet<FunctionId>,
665 pool: &mut Pool,
666 errors: &mut Vec<Diagnostic>,
667 ) {
668 self.lowered = reach.clone();
669 for at in 0..self.decls.len() {
670 let id = FunctionId(at as u32);
671 if !reach.contains(&id) {
672 continue;
673 }
674 let decl = &self.decls[at];
675 let module = decl.module.to_string();
676 let (generics, args) = decl.substitution();
677 let boundary = if let Some(type_name) = &decl.on_generic_type {
678 let named = format!("`{type_name}.{}`", short_name(&decl.name));
679 errors.push(gap::gap(
680 &format!("{named}, a method of a generic type"),
681 decl.decl.span,
682 ));
683 None
684 } else if decl.from_trait_default.is_some() && generics.is_empty() {
685 // A default body whose conforming type this lowering could
686 // not name. Nothing in the corpus reaches it — a conformance
687 // is declared for a type of the package — and it is named
688 // rather than left out because the alternative is a stub that
689 // answers `()`.
690 let named = format!("`{}`", decl.name);
691 errors.push(gap::gap(
692 &format!("{named}, a trait method's default body on a type with no layout"),
693 decl.decl.span,
694 ));
695 None
696 } else if !decl.decl.generics.is_empty() {
697 // A generic declaration has no one boundary. Its parameters'
698 // widths depend on what its type parameters stand for —
699 // `Cell<Int>` is one word and `Cell<Point>` is two — so the
700 // boundary belongs to an instantiation and
701 // [`Body::instantiate`] reads one per set of arguments. What
702 // stands here is a stub nothing names.
703 None
704 } else {
705 boundary_of(checked, &module, decl.decl, &generics, &args, pool, errors)
706 };
707 self.decls[at].boundary = boundary;
708 }
709 }
710
711 /// Numbers one declaration and records the name it answers to.
712 fn declare(&mut self, module: Arc<str>, name: Arc<str>, decl: &'a FnDecl) -> FunctionId {
713 let id = FunctionId(self.decls.len() as u32);
714 self.by_name.insert((module.clone(), name.clone()), id);
715 self.decls.push(Decl {
716 module,
717 name,
718 decl,
719 boundary: None,
720 from_trait_default: None,
721 receiver_ty: None,
722 on_generic_type: None,
723 });
724 id
725 }
726
727 /// The declarations any of `roots` can reach, as the checker's call
728 /// graph answers it.
729 ///
730 /// A seed rather than a verdict: see [`lower_roots`] for what the graph
731 /// cannot see and what closes the gap.
732 ///
733 /// One walk over every root rather than one walk each, because the
734 /// answer is a union and `seen` is what makes a shared callee cost the
735 /// walk once no matter how many roots reach it.
736 ///
737 /// This does *not* seed the walk with
738 /// [`cove_schema::builtins::standard_library`]'s functions, and that
739 /// was tried and measured wrong rather than assumed: seeding
740 /// `std.array.isEmpty` put it in `reach` whether or not any root called
741 /// it, and a generic declaration's *un-instantiated* id in `reach` is
742 /// not nothing — [`Plan::boundaries`] gives it no [`Boundary`] and
743 /// [`lower_function`] stubs it, so every lowered program carried a
744 /// dead, nameless stub function for a method it never called. A call
745 /// that *does* reach `std.array.isEmpty` is still found, one round
746 /// later, by the same `wanted` correction documented on
747 /// [`lower_roots`] that finds any other declaration `reach` left out —
748 /// [`Body::call_target`]'s `reached` check defers the call site to the
749 /// next round exactly as it would for a package's own generic function,
750 /// and a probe confirmed the two are lowered identically. So a builtin
751 /// method whose body has moved into the standard library costs a
752 /// program nothing extra unless a program actually calls it, which is
753 /// the same promise every other builtin already keeps.
754 fn reachable_from(&self, checked: &'a Checked, roots: &[(&str, &str)]) -> HashSet<FunctionId> {
755 let mut seen: BTreeSet<Node> = BTreeSet::new();
756 let mut stack: Vec<Node> = roots
757 .iter()
758 .map(|(module, name)| (module.to_string(), FnKey::Fn(name.to_string())))
759 .collect();
760 while let Some(node) = stack.pop() {
761 if !seen.insert(node.clone()) {
762 continue;
763 }
764 let Some(edges) = checked.call_graph.get(&node) else {
765 continue;
766 };
767 stack.extend(edges.keys().cloned());
768 }
769 seen.iter().filter_map(|node| self.id_of(node)).collect()
770 }
771
772 /// The declaration a call-graph node names.
773 fn id_of(&self, node: &Node) -> Option<FunctionId> {
774 let (module, key) = node;
775 match key {
776 FnKey::Fn(name) => self.lookup.get(&(module.clone(), name.clone())).copied(),
777 FnKey::Method(type_name, method) => self
778 .by_name
779 .get(&(
780 Arc::from(module.as_str()),
781 Arc::from(format!("{type_name}.{method}")),
782 ))
783 .copied(),
784 }
785 }
786
787 /// Whether this pass lowered `id` rather than stubbing it.
788 ///
789 /// Every place that turns a name into a [`FunctionId`] asks this before
790 /// it emits anything naming one, because a stub answers `()` and a call
791 /// to it would be a wrong answer rather than a refusal. What a caller
792 /// does with a `false` is [`Body::reached`]: record the declaration and
793 /// let the next pass lower it.
794 fn reached(&self, id: FunctionId) -> bool {
795 self.lowered.contains(&id)
796 }
797
798 /// The declaration `name` denotes where the module `from` can see it.
799 ///
800 /// A module's own declaration wins over an imported one, which is the
801 /// order resolution already established: a `use` that would shadow a
802 /// local declaration was refused there.
803 fn resolve(&self, checked: &Checked, from: &str, name: &str) -> Option<FunctionId> {
804 if let Some(id) = self.lookup.get(&(from.to_string(), name.to_string())) {
805 return Some(*id);
806 }
807 let owner = checked.modules.get(from)?.imports.get(name)?;
808 self.lookup.get(&(owner.clone(), name.to_string())).copied()
809 }
810
811 /// The function a [`MethodTarget`] names.
812 fn method(&self, target: &MethodTarget) -> Option<FunctionId> {
813 self.methods
814 .get(&(
815 target.module.clone(),
816 target.type_name.clone(),
817 target.method.clone(),
818 ))
819 .copied()
820 }
821
822 /// The function `type_module.type_name` answers `method` with.
823 fn method_of(&self, type_module: &str, type_name: &str, method: &str) -> Option<FunctionId> {
824 self.methods
825 .get(&(
826 type_module.to_string(),
827 type_name.to_string(),
828 method.to_string(),
829 ))
830 .copied()
831 }
832
833 /// What a call to `id` passes and answers, as owned values: a call site
834 /// reads this while it is still holding the body it is lowering.
835 ///
836 /// `None` for an id past the declarations — a lambda or an instantiation
837 /// — which [`Body::shape`] answers instead.
838 fn shape(&self, id: FunctionId) -> Option<CallShape> {
839 Some(self.decls.get(id.index())?.boundary.as_ref()?.shape())
840 }
841}
842
843impl Boundary {
844 /// What one call site has to match, as owned values.
845 fn shape(&self) -> CallShape {
846 CallShape {
847 params: self.params.clone(),
848 types: self.types.clone(),
849 returns: self.returns,
850 receiver: self.receiver,
851 variadic: self.variadic,
852 is_async: self.is_async,
853 }
854 }
855}
856
857/// What one call site has to match, held apart from the [`Plan`] so that a
858/// body can read it while it is writing into its own frame.
859struct CallShape {
860 params: Vec<LayoutId>,
861 types: Vec<Ty>,
862 returns: LayoutId,
863 receiver: bool,
864 variadic: bool,
865 is_async: bool,
866}
867
868impl CallShape {
869 /// How many parameters the call site writes, which is every one but the
870 /// receiver.
871 ///
872 /// It is no longer the number of *arguments* a call passes: a variadic
873 /// parameter takes any number and a defaulted one takes none, so what
874 /// lines a call up with a frame is [`Body::assign`] rather than a count.
875 fn written(&self) -> usize {
876 self.params.len() - usize::from(self.receiver)
877 }
878
879 /// The layout of written parameter `at`, past the receiver.
880 fn param(&self, at: usize) -> LayoutId {
881 self.params[usize::from(self.receiver) + at]
882 }
883
884 /// The type of written parameter `at`, past the receiver.
885 ///
886 /// For a variadic one this is the *element* type, because that is what
887 /// each collected argument is.
888 fn ty(&self, at: usize) -> &Ty {
889 &self.types[usize::from(self.receiver) + at]
890 }
891}
892
893/// The type a method of `owner`'s declaration of `name` receives, written
894/// the way the package names it.
895///
896/// `m.Booking` rather than `Booking`, because a conformance may be written
897/// in the module that declares the *trait* — ADR 0006's orphan rule — and
898/// the type's bare name means nothing there. It is the same reason
899/// [`shapes::qualified`] exists, and `shapes::declaring` reads a qualified
900/// name back apart.
901///
902/// A method's receiver is otherwise read off the checker's `Signature`, and
903/// this is not a second answer to that: it is asked only where a signature
904/// records `Ty::Param("Self")` and something has to say what `Self` is.
905///
906/// A declaration this cannot place — a conformance on a type the package
907/// does not declare — answers `None`, and a default body on one is a gap.
908fn receiver_ty(checked: &Checked, owner: &str, name: &str) -> Option<Ty> {
909 let resolved = checked.modules.get(owner)?;
910 let qualified: Arc<str> = Arc::from(format!("{owner}.{name}"));
911 if resolved.structs.contains_key(name) {
912 return Some(Ty::Struct(qualified, Vec::new()));
913 }
914 if resolved.enums.contains_key(name) {
915 return Some(Ty::Enum(qualified, Vec::new()));
916 }
917 None
918}
919
920/// Whether `owner`'s declaration of `name` binds type parameters.
921fn is_generic_type(checked: &Checked, owner: &str, name: &str) -> bool {
922 let Some(resolved) = checked.modules.get(owner) else {
923 return false;
924 };
925 let generic = |generics: &[cove_syntax::ast::GenericParam]| !generics.is_empty();
926 resolved
927 .structs
928 .get(name)
929 .is_some_and(|entry| generic(&entry.decl.generics))
930 || resolved
931 .enums
932 .get(name)
933 .is_some_and(|entry| generic(&entry.decl.generics))
934}
935
936/// The method half of a `Type.method` declaration name.
937fn short_name(name: &str) -> &str {
938 name.rsplit_once('.').map_or(name, |(_, method)| method)
939}
940
941/// What a call to this declaration passes and answers, read off the
942/// checker's signature rather than off the source annotations.
943///
944/// The annotations are names; the signature is what those names resolved to
945/// in the module they were written in, which is the only reading of a
946/// `-> other.Thing` that means the same in both modules.
947///
948/// `generics` and `args` are the declaration's type parameters and what this
949/// instantiation puts in their place, and they are empty for a declaration
950/// that binds none. A generic declaration has a boundary *per instantiation*
951/// and no boundary of its own: `fn f<T>(x: T)` says how many parameters there
952/// are and nothing about how wide one is, and a width is what a frame is made
953/// of.
954#[allow(clippy::too_many_arguments)]
955fn boundary_of(
956 checked: &Checked,
957 module: &str,
958 decl: &FnDecl,
959 generics: &[Arc<str>],
960 args: &[Ty],
961 pool: &mut Pool,
962 errors: &mut Vec<Diagnostic>,
963) -> Option<Boundary> {
964 let mut ok = true;
965 let Some(signature) = checked.facts.signature(decl.span.file, decl.span) else {
966 errors.push(gap::gap(
967 "a declaration the checker recorded no signature for",
968 decl.span,
969 ));
970 return None;
971 };
972
973 let mut params = Vec::new();
974 let mut types = Vec::new();
975 // The receiver comes first because that is the order a call supplies it
976 // in, and `Signature` records it apart from the parameters so that this
977 // does not have to be inferred from a count.
978 if let Some(receiver) = &signature.receiver {
979 let span = decl.receiver.map_or(decl.span, |it| it.span);
980 let receiver = &receiver.instantiate(generics, args);
981 match pool.shapes.of(checked, module, receiver) {
982 // `var self` is a `var` parameter written in the receiver
983 // position: the method names the caller's storage, so the first
984 // parameter holds its address and a write to a field of `self`
985 // reaches the caller's own words with no copy back.
986 Some(_) if decl.receiver.is_some_and(|it| it.is_var) => params.push(shapes::ADDR),
987 Some(layout) => params.push(layout),
988 None => {
989 errors.push(describe(&pool.shapes, receiver, span));
990 ok = false;
991 }
992 }
993 types.push(receiver.clone());
994 }
995 for (param, ty) in decl.params.iter().zip(&signature.params) {
996 let ty = &ty.instantiate(generics, args);
997 // A variadic parameter is an immutable `Array<T>` inside the body
998 // whatever stands in front of it, and the signature records the
999 // element type `T` rather than the array — so the location the callee
1000 // reads is one layout wider out than the one a written argument fits
1001 // into. `Boundary::types` keeps the element type, because that is
1002 // what each collected argument is erased to.
1003 let held = if param.variadic {
1004 Ty::Array(Box::new(ty.clone()))
1005 } else {
1006 ty.clone()
1007 };
1008 match pool.shapes.of(checked, module, &held) {
1009 // A `var` parameter is an ordinary slot whose `Repr` is `Addr`:
1010 // it names the caller's storage, so the word is the address of
1011 // it rather than a copy of what is in it. The type is still
1012 // read, because a type with no layout is a gap whichever side of
1013 // the alias it is on. A variadic one is not an alias whatever the
1014 // source wrote, which is the `is_var && !variadic` the checker's
1015 // own `ParamSig` records.
1016 Some(_) if param.is_var && !param.variadic => params.push(shapes::ADDR),
1017 Some(layout) => params.push(layout),
1018 None => {
1019 errors.push(describe(&pool.shapes, &held, param.span));
1020 ok = false;
1021 }
1022 }
1023 types.push(ty.clone());
1024 }
1025 let ret = signature.ret.instantiate(generics, args);
1026 let returns = match pool.shapes.of(checked, module, &ret) {
1027 Some(layout) => layout,
1028 None => {
1029 let span = decl.return_type.as_ref().map_or(decl.span, |ty| ty.span);
1030 errors.push(describe(&pool.shapes, &ret, span));
1031 ok = false;
1032 shapes::UNIT
1033 }
1034 };
1035
1036 ok.then_some(Boundary {
1037 receiver: signature.receiver.is_some(),
1038 variadic: decl.params.last().is_some_and(|param| param.variadic),
1039 // The signature's `ret` is `T` for an `async fn`, so `returns` above
1040 // is the layout of the value the body produces and the handle is the
1041 // call site's to make. See `Boundary::is_async`.
1042 is_async: decl.is_async,
1043 params,
1044 types,
1045 returns,
1046 ret,
1047 })
1048}
1049
1050/// Why a type has no layout here: the checker settled nothing, it settled a
1051/// declaration whose layout contains itself, or it settled something this
1052/// task has not reached.
1053///
1054/// The middle one is separated because it is not the same kind of thing.
1055/// [ADR 0035](../../../../docs/adr/0035-a-value-type-may-not-contain-itself.md)
1056/// makes an implicitly recursive value layout a *checker* error, so this is a
1057/// program that will stop being a program — and saying only "a value of type
1058/// `Node`" would read as a piece of work someone here still owes.
1059fn describe(shapes: &Shapes, ty: &Ty, span: Span) -> Diagnostic {
1060 match ty {
1061 Ty::Unknown(_) => gap::unknown(ty, span),
1062 Ty::Struct(name, _) | Ty::Enum(name, _) if shapes.contains_itself(name) => {
1063 gap::gap(&format!("`{name}`, whose layout contains itself"), span)
1064 }
1065 _ => gap::gap(&format!("a value of type `{ty}`"), span),
1066 }
1067}
1068
1069// ------------------------------------------------------------ interning
1070
1071/// The program-wide pool of argument lists.
1072///
1073/// A call's arguments are a static list of source slots, and a repeated call
1074/// shape is one list rather than one per site — which is the whole reason
1075/// [`Inst::Call`] names an [`ArgsId`] instead of carrying the list inline.
1076#[derive(Default)]
1077struct Args {
1078 lists: Vec<Vec<Arg>>,
1079 index: HashMap<Vec<Arg>, ArgsId>,
1080}
1081
1082impl Args {
1083 fn intern(&mut self, args: Vec<Arg>) -> ArgsId {
1084 if let Some(id) = self.index.get(&args) {
1085 return *id;
1086 }
1087 let id = ArgsId(self.lists.len() as u32);
1088 self.index.insert(args.clone(), id);
1089 self.lists.push(args);
1090 id
1091 }
1092}
1093
1094/// Everything a [`Program`] holds once for the whole package, being built.
1095///
1096/// It is one struct rather than a parameter each because every one of them
1097/// is written from inside a body and read only when the program is
1098/// assembled: a body that meets a string literal, a `match`, a host call or
1099/// a struct is adding to a table that outlives the function it is in.
1100///
1101/// Each table interns. Two call sites of the same shape share one argument
1102/// list, two `"{n}"`s share one string, and two `Option<Int>`s share one
1103/// layout — which is what keeps these tables as long as the shapes a program
1104/// has rather than as long as the expressions that mention them.
1105struct Pool {
1106 args: Args,
1107 strings: Vec<Arc<str>>,
1108 tables: Vec<Table>,
1109 host_ops: Vec<HostOp>,
1110 builtins: Vec<Builtin>,
1111 shapes: Shapes,
1112 /// The functions numbered after every declaration: the body a lambda
1113 /// lowered to, and the body one instantiation of a generic declaration
1114 /// lowered to.
1115 ///
1116 /// A slot is reserved — `None` — before the body is lowered, because
1117 /// that body may close over a lambda or ask for an instantiation of its
1118 /// own and the inner one has to be numbered after the outer. So the
1119 /// entry is filled in on the way back out, and a `None` left at the end
1120 /// would be a lowering that reserved a number and never used it.
1121 ///
1122 /// The two kinds share one list because they share the one thing that
1123 /// matters about it — a number past the declarations, taken before the
1124 /// body is known — and two lists would have to agree on which of them a
1125 /// given number was from.
1126 appended: Vec<Option<Function>>,
1127 /// What each instantiation is, keyed by the id it was given.
1128 ///
1129 /// A call site reads a boundary and a declaration off this the way it
1130 /// reads them off [`Plan`] for an ordinary declaration.
1131 instances: HashMap<FunctionId, Instance>,
1132 /// The id one declaration at one set of type arguments was given.
1133 ///
1134 /// This is what makes a generic instantiated twice at one type cost one
1135 /// function, and it is also what makes a *recursive* generic terminate:
1136 /// the id is recorded before the body is lowered, so a call the body
1137 /// makes to itself finds the number rather than starting again.
1138 instance_ids: HashMap<(FunctionId, String), FunctionId>,
1139 /// The instantiations being lowered right now, outermost first.
1140 ///
1141 /// A chain rather than a count, because what a program that exceeds the
1142 /// bound needs told is which instantiation asked for which — see
1143 /// [`Body::instantiate`].
1144 open: Vec<String>,
1145}
1146
1147/// One monomorphisation: which declaration it lowers, and for what.
1148///
1149/// A generic declaration is not a function here. `fn f<T>(x: T)` says how
1150/// many parameters there are and nothing about how wide one is, and a width
1151/// is what a frame is made of — so what is lowered is one `Function` per set
1152/// of type arguments, and this is what says which one.
1153struct Instance {
1154 /// The generic declaration in [`Plan::decls`], which is where the labels,
1155 /// the defaults and the syntax of the body are read from.
1156 decl: FunctionId,
1157 /// The type parameters the declaration binds, in declaration order.
1158 generics: Vec<Arc<str>>,
1159 /// What this instantiation puts in their place, in the same order.
1160 args: Vec<Ty>,
1161 /// The boundary those arguments settle.
1162 boundary: Boundary,
1163}
1164
1165impl Pool {
1166 fn new(schemas: HostSchemas) -> Pool {
1167 Pool {
1168 args: Args::default(),
1169 strings: Vec::new(),
1170 tables: Vec::new(),
1171 host_ops: Vec::new(),
1172 builtins: Vec::new(),
1173 shapes: Shapes::new(schemas),
1174 appended: Vec::new(),
1175 instances: HashMap::new(),
1176 instance_ids: HashMap::new(),
1177 open: Vec::new(),
1178 }
1179 }
1180
1181 fn string(&mut self, text: &str) -> StrId {
1182 match self.strings.iter().position(|held| &**held == text) {
1183 Some(at) => StrId(at as u32),
1184 None => {
1185 self.strings.push(Arc::from(text));
1186 StrId((self.strings.len() - 1) as u32)
1187 }
1188 }
1189 }
1190
1191 /// A jump table. Not interned: a `match`'s targets are program counters
1192 /// of the function it is in, so two tables that happen to agree agree by
1193 /// accident.
1194 fn table(&mut self, table: Table) -> TableId {
1195 self.tables.push(table);
1196 TableId((self.tables.len() - 1) as u32)
1197 }
1198
1199 fn host_op(&mut self, op: HostOp) -> HostOpId {
1200 match self.host_ops.iter().position(|held| *held == op) {
1201 Some(at) => HostOpId(at as u32),
1202 None => {
1203 self.host_ops.push(op);
1204 HostOpId((self.host_ops.len() - 1) as u32)
1205 }
1206 }
1207 }
1208
1209 fn builtin(&mut self, builtin: Builtin) -> BuiltinId {
1210 match self.builtins.iter().position(|held| *held == builtin) {
1211 Some(at) => BuiltinId(at as u32),
1212 None => {
1213 self.builtins.push(builtin);
1214 BuiltinId((self.builtins.len() - 1) as u32)
1215 }
1216 }
1217 }
1218}
1219
1220// --------------------------------------------------------------- one body
1221
1222/// A loop being lowered, and what it owes its `break`s.
1223struct Loop {
1224 /// Where `continue` goes: the condition, so the next turn is decided
1225 /// again rather than assumed.
1226 head: Pc,
1227 /// How many scopes were open outside the body, so an early exit knows
1228 /// which ones it is leaving.
1229 depth: usize,
1230 /// How many temporaries were live outside the loop, so an early exit
1231 /// knows which ones it made and which ones it merely found.
1232 ///
1233 /// A `break` clears the temporaries above this mark and none below it.
1234 /// The ones below are the loop's own machinery and the enclosing
1235 /// expression's — the array a `for` is walking is read again after the
1236 /// `break` lands, and an enclosing loop's is read for the rest of *its*
1237 /// run.
1238 held: usize,
1239 /// Jumps emitted by `break` with nowhere to go yet.
1240 breaks: Vec<Pc>,
1241 /// The location a `for` binds each turn, when it holds a reference.
1242 ///
1243 /// The loop owns it rather than the per-turn scope, because the scope
1244 /// gives its slots back when it ends and the next turn writes this one
1245 /// again. That leaves nobody to clear it on the one path that does not
1246 /// reach the end of a turn, which is what this is: a `break` clears the
1247 /// element it was holding on its way out.
1248 element: Option<Dest>,
1249}
1250
1251/// A task scope being lowered, and what leaving it early owes it.
1252struct OpenScope {
1253 /// The `Repr::Scope` slot the [`Inst::ScopeEnter`] wrote.
1254 slot: Slot,
1255 /// How many loops were open outside this scope.
1256 ///
1257 /// What it decides is which of the two directions a jump is going. A
1258 /// `break` leaves every scope opened *inside* its own loop and none
1259 /// opened outside it, and that is the same question `Loop::depth` asks
1260 /// about lexical scopes, asked the other way round.
1261 loops: usize,
1262 /// Whether any child spawned into this scope answers a `Result`.
1263 ///
1264 /// What it decides is whether leaving the scope can produce a failure at
1265 /// all. `wait_for_children` returns a child's `Err` from the function the
1266 /// scope was written in, so that function must be able to carry one — but
1267 /// only if a child can *make* one, and a scope over `Task<Verdict>`
1268 /// children cannot. Asking every scope for a failure layout refused two
1269 /// corpus programs the checker had already cleared, for the same reason
1270 /// and by the same predicate `Checker::spawned` uses.
1271 can_fail: bool,
1272}
1273
1274/// The state of lowering one function body.
1275struct Body<'a> {
1276 checked: &'a Checked,
1277 /// The package's own text, which `assert` and `assertEqual` quote.
1278 ///
1279 /// Nothing else in this crate reads it: a lowering answers what the
1280 /// checker settled, and source text is not one of those answers. The two
1281 /// assertions are the exception the language itself makes — their failure
1282 /// message names the condition in the words the test was written in, and
1283 /// only the compiler has them.
1284 sources: &'a SourceMap,
1285 plan: &'a Plan<'a>,
1286 pool: &'a mut Pool,
1287 errors: &'a mut Vec<Diagnostic>,
1288 /// The declarations this body named that the pass had left out of its
1289 /// slice. See [`lower_entry`].
1290 wanted: &'a mut HashSet<FunctionId>,
1291 /// The module the body is written in, which is what an unqualified name
1292 /// in it is resolved against.
1293 module: &'a str,
1294 /// What this body is called, which is what a lambda written inside it is
1295 /// named after: `f#0`, and `f#0#0` for one nested in that.
1296 name: Arc<str>,
1297 /// How many lambdas this body has already made, which is the number the
1298 /// next one is given.
1299 lambdas: u32,
1300 frame: Frame,
1301 code: Vec<Inst>,
1302 spans: Vec<Span>,
1303 loops: Vec<Loop>,
1304 /// The task scopes this body has open, outermost first.
1305 ///
1306 /// A scope is left by waiting for or cancelling its children, and there
1307 /// are two ways out of one: the body reaches its end, which is
1308 /// [`Inst::ScopeLeave`], or control leaves through a `return`, a `?`, a
1309 /// `break` or a `continue`, which is [`Inst::ScopeCancel`]. Only the
1310 /// first is written where the `scope` is. The second is an obligation on
1311 /// every exit path, exactly as [`Inst::Clear`] is, and this is the list
1312 /// that says which scopes a given jump is leaving.
1313 scopes: Vec<OpenScope>,
1314 /// The temporaries this body is holding that a collection would trace,
1315 /// innermost last.
1316 ///
1317 /// A scope answers which *bindings* it owns, and that is what
1318 /// [`Frame::pop_scope`] and [`Frame::refs_within`] are for. A temporary
1319 /// belongs to no scope: it is the expression's own, and the expression
1320 /// that made it ends its live range with [`Body::release`]. That works
1321 /// for every path that reaches the release — and an early exit does not.
1322 ///
1323 /// `f(a, if c { b } else { break })` evaluates `a` into a temporary, and
1324 /// the `break` leaves before the call that would have consumed it. The
1325 /// scopes hold nothing about `a`, so `leave_turn` cleared the bindings
1326 /// and the loop's element and left the temporary holding a reference for
1327 /// the rest of the frame. This is the list that answers it.
1328 held: Vec<(Slot, LayoutId)>,
1329 /// The location the body's answer is assembled in, and the one the
1330 /// trailing [`Inst::Return`] names.
1331 answer: Dest,
1332 /// What this function answers, as a type rather than as a layout.
1333 ///
1334 /// `?` needs it: the value it leaves through is the enclosing
1335 /// function's own `Err` or `None`, built here, and building one needs
1336 /// to know which of the two *this* function answers rather than what the
1337 /// `?` was applied to.
1338 returns: Ty,
1339 /// The type parameters the declaration this body lowers binds, in
1340 /// declaration order. Empty for a declaration that binds none.
1341 generics: Vec<Arc<str>>,
1342 /// What this instantiation puts in their place, in the same order.
1343 ///
1344 /// The checker walked a generic body **once**, with its parameters rigid,
1345 /// so every fact recorded inside it is written in terms of `generics`.
1346 /// This is what completes one: [`Body::ty`] answers `m.Article` where the
1347 /// fact says `T`, and everything downstream — a layout, a width, which
1348 /// conformance a bounded call reaches — falls out of that one
1349 /// substitution rather than out of a rule per construct.
1350 args: Vec<Ty>,
1351 /// The layout of the value behind each [`shapes::ADDR`] slot: what a
1352 /// `var` parameter, or a `var self`, names in the caller's frame.
1353 ///
1354 /// A slot's [`Repr`] is all a frame records, and `Addr` says only that
1355 /// the word is an address. Almost nothing needs more, because every
1356 /// *read* of a `var` parameter is at the layout the checker settled for
1357 /// the expression doing the reading — [`Body::name`] and
1358 /// [`Body::place_of`] both take it from there.
1359 ///
1360 /// A capture is the one place with no such expression: `Body::captured_by`
1361 /// holds a name and a slot and nothing the checker recorded a type for.
1362 /// So the parameter's own layout is written down where the boundary was
1363 /// read, which is the only place it is known without asking a second
1364 /// time.
1365 aliases: HashMap<Slot, LayoutId>,
1366}
1367
1368#[allow(clippy::too_many_arguments)]
1369fn lower_function(
1370 checked: &Checked,
1371 sources: &SourceMap,
1372 plan: &Plan,
1373 id: usize,
1374 pool: &mut Pool,
1375 errors: &mut Vec<Diagnostic>,
1376 wanted: &mut HashSet<FunctionId>,
1377) -> Function {
1378 let decl = &plan.decls[id];
1379 let Some(boundary) = &decl.boundary else {
1380 return stub(decl);
1381 };
1382 let name = decl.name.clone();
1383 // The same substitution the boundary was read under, so that a fact
1384 // recorded in terms of `Self` completes to the same type in the frame
1385 // and in the body.
1386 let (generics, args) = decl.substitution();
1387 lower_body(
1388 checked, sources, plan, decl, boundary, name, &generics, &args, pool, errors, wanted,
1389 )
1390}
1391
1392/// Lowers one declaration's body, at one instantiation of its type
1393/// parameters.
1394///
1395/// `generics` and `args` are empty for an ordinary declaration, and then the
1396/// substitution is the identity and this is exactly what it always was. For a
1397/// generic declaration they are what the call site asked for, and they are
1398/// carried on the [`Body`] rather than applied to the syntax: the checker
1399/// walked the body once, so the facts are recorded once in terms of the
1400/// parameters, and completing a fact as it is read is what makes one recorded
1401/// walk serve every instantiation.
1402#[allow(clippy::too_many_arguments)]
1403fn lower_body(
1404 checked: &Checked,
1405 sources: &SourceMap,
1406 plan: &Plan,
1407 decl: &Decl,
1408 boundary: &Boundary,
1409 name: Arc<str>,
1410 generics: &[Arc<str>],
1411 args: &[Ty],
1412 pool: &mut Pool,
1413 errors: &mut Vec<Diagnostic>,
1414 wanted: &mut HashSet<FunctionId>,
1415) -> Function {
1416 let mut frame = Frame::new();
1417 let mut param_slots = Vec::with_capacity(boundary.params.len());
1418 for layout in &boundary.params {
1419 param_slots.push(frame.param(pool.shapes.words(*layout)));
1420 }
1421 // What each `var` parameter names, at the width the parameter was
1422 // declared. `boundary_of` resolved that type to a layout before it chose
1423 // `ADDR` for the slot, so this asks the interned table for an answer it
1424 // already holds.
1425 let mut aliases = HashMap::new();
1426 for (at, layout) in boundary.params.iter().enumerate() {
1427 if *layout != shapes::ADDR {
1428 continue;
1429 }
1430 if let Some(held) = pool.shapes.of(checked, &decl.module, &boundary.types[at]) {
1431 aliases.insert(param_slots[at], held);
1432 }
1433 }
1434 // The answer is taken before any temporary, so it is live for the whole
1435 // body and never handed to something else.
1436 let answer = Dest {
1437 slot: frame.alloc(pool.shapes.words(boundary.returns)),
1438 layout: boundary.returns,
1439 };
1440
1441 let mut body = Body {
1442 checked,
1443 sources,
1444 plan,
1445 pool,
1446 errors,
1447 wanted,
1448 module: &decl.module,
1449 name: name.clone(),
1450 lambdas: 0,
1451 frame,
1452 code: Vec::new(),
1453 spans: Vec::new(),
1454 loops: Vec::new(),
1455 scopes: Vec::new(),
1456 held: Vec::new(),
1457 answer,
1458 returns: boundary.ret.clone(),
1459 generics: generics.to_vec(),
1460 args: args.to_vec(),
1461 aliases,
1462 };
1463
1464 body.frame.push_scope();
1465 // The receiver is the first parameter where there is one, so a written
1466 // parameter's location is its position shifted past it. Nothing else
1467 // about a method differs: the body reads `self` the way it reads any
1468 // binding, and where the receiver is an `Addr` — `var self` — reading it
1469 // is a `Load` through the word, which is the same rule a `var` parameter
1470 // already follows.
1471 let mut at = 0;
1472 let start = body.here();
1473 if boundary.receiver {
1474 body.frame
1475 .bind("self", param_slots[0], boundary.params[0], start);
1476 at = 1;
1477 }
1478 for (index, param) in decl.decl.params.iter().enumerate() {
1479 body.frame.bind(
1480 ¶m.name.node,
1481 param_slots[at + index],
1482 boundary.params[at + index],
1483 start,
1484 );
1485 }
1486 body.block(&decl.decl.body, Some(answer));
1487 // The epilogue is written at the *tail*, not at the block: a `return`
1488 // answers the expression the body ends with, and that is the line a
1489 // reader stopped there wants named. The block's own span begins at its
1490 // opening brace, which is the declaration's line and says nothing about
1491 // where the answer came from.
1492 //
1493 // It was not visible until issue #302. The tail used to leave its answer
1494 // in a temporary and a `copy` carried it into the answer's location, so
1495 // the instruction a caller resumed at was that copy and it was written
1496 // at the tail. Forwarding the destination removed the copy and left the
1497 // `Return` standing where it had stood, which is how a debugger session
1498 // came to name the declaration's brace instead of the call that had just
1499 // answered.
1500 let ends = decl
1501 .decl
1502 .body
1503 .tail
1504 .as_ref()
1505 .map_or(decl.decl.body.span, |tail| tail.span);
1506 let end = body.here();
1507 let clears = body.frame.pop_scope(end);
1508 body.clear(&clears, ends);
1509 body.emit(Inst::Return { src: answer.slot }, ends);
1510
1511 let reprs = body.frame.reprs().to_vec();
1512 let mut locals = body.frame.locals();
1513 // Every parameter, including a receiver bound at `param_slots[0]`, is
1514 // live for the whole call — see `Frame::close_whole_function` for the
1515 // proof — and this is the one place that both holds the parameters'
1516 // slots and knows how long the finished body is.
1517 let end = body.code.len() as Pc;
1518 Frame::close_whole_function(&mut locals, ¶m_slots, end);
1519 Function {
1520 module: decl.module.clone(),
1521 name,
1522 params: boundary.params.clone(),
1523 refs: RefMap::of(&reprs),
1524 reprs,
1525 returns: boundary.returns,
1526 captures: Vec::new(),
1527 code: body.code,
1528 spans: body.spans,
1529 locals,
1530 inlined: Vec::new(),
1531 span: decl.decl.span,
1532 is_async: decl.decl.is_async,
1533 stub: false,
1534 }
1535}
1536
1537/// What stands in for a declaration this pass did not lower.
1538///
1539/// Three kinds reach it, and they end differently.
1540///
1541/// One is a declaration this lowering reported a gap about, and nothing ever
1542/// runs that: a gap is an error and the program is not handed back.
1543///
1544/// The second is a declaration [`lower_entry`]'s slice left out, and that one
1545/// is in a program that *does* run. Nothing can name it: no call was emitted
1546/// to it — the fixed point is what makes that true — and it is left out of
1547/// [`Program::by_name`], so it is not an entry point either. It exists so
1548/// that function ids stay dense, which is what lets a set of ids gathered by
1549/// one pass mean the same thing in the next.
1550///
1551/// The third is a **generic declaration**, and it is in a program that runs
1552/// and is not an error. It is not a stand-in for anything: a generic
1553/// declaration is not one function, so there is nothing here for it to be.
1554/// What the program carries instead is its instantiations, each a function
1555/// of its own numbered past the declarations. This holds its number for the
1556/// same reason the second kind does, and is left out of
1557/// [`Program::by_name`] for the same reason too.
1558fn stub(decl: &Decl) -> Function {
1559 let reprs = vec![Repr::Unit];
1560 Function {
1561 module: decl.module.clone(),
1562 name: decl.name.clone(),
1563 params: Vec::new(),
1564 refs: RefMap::of(&reprs),
1565 reprs,
1566 returns: shapes::UNIT,
1567 captures: Vec::new(),
1568 code: vec![Inst::Return { src: 0 }],
1569 spans: vec![decl.decl.span],
1570 locals: Vec::new(),
1571 inlined: Vec::new(),
1572 span: decl.decl.span,
1573 is_async: false,
1574 stub: true,
1575 }
1576}
1577
1578impl Body<'_> {
1579 // ---- emitting -------------------------------------------------------
1580
1581 /// Appends one instruction and the span it came from, answering where it
1582 /// landed so a jump can be patched later.
1583 fn emit(&mut self, inst: Inst, span: Span) -> Pc {
1584 let at = self.here();
1585 self.code.push(inst);
1586 self.spans.push(span);
1587 at
1588 }
1589
1590 /// Where the next instruction will land, which is what a forward jump is
1591 /// patched to.
1592 fn here(&self) -> Pc {
1593 self.code.len() as Pc
1594 }
1595
1596 fn patch(&mut self, at: Pc, to: Pc) {
1597 match &mut self.code[at as usize] {
1598 Inst::Jump { to: target } | Inst::BranchFalse { to: target, .. } => *target = to,
1599 other => unreachable!("patched a {other:?}, which is not a jump"),
1600 }
1601 }
1602
1603 // ---- locations -------------------------------------------------------
1604
1605 /// The words a value of `layout` occupies.
1606 fn words(&self, layout: LayoutId) -> Vec<Repr> {
1607 self.pool.shapes.words(layout).to_vec()
1608 }
1609
1610 fn width(&self, layout: LayoutId) -> u32 {
1611 self.pool.shapes.width(layout)
1612 }
1613
1614 /// Whether a location of this layout holds anything a collection traces,
1615 /// or an address whose live range this lowering ends.
1616 fn holds_ref(&self, layout: LayoutId) -> bool {
1617 self.pool.shapes.holds_ref(layout)
1618 }
1619
1620 /// A run of the frame wide enough for a value of `layout`.
1621 fn alloc(&mut self, layout: LayoutId) -> Slot {
1622 let words = self.words(layout);
1623 self.frame.alloc(&words)
1624 }
1625
1626 /// A temporary location of `layout`.
1627 ///
1628 /// A temporary that holds a reference is recorded in [`Body::held`] for
1629 /// the length of its live range, so that an early exit from a loop can
1630 /// clear the ones a scope knows nothing about.
1631 fn temp(&mut self, layout: LayoutId) -> Val {
1632 let slot = self.alloc(layout);
1633 if self.holds_ref(layout) {
1634 self.hold(slot, layout);
1635 }
1636 Val::temp(slot, layout)
1637 }
1638
1639 /// Records that a temporary at `slot` is live.
1640 ///
1641 /// Any earlier entry for the same slot is dropped first. A run holds one
1642 /// value at a time — the frame only hands one out again after it has been
1643 /// freed — so a second entry for a slot supersedes the first rather than
1644 /// standing beside it, and a stale one would be a `Clear` of a location
1645 /// something else is now using.
1646 fn hold(&mut self, slot: Slot, layout: LayoutId) {
1647 self.forget(slot);
1648 self.held.push((slot, layout));
1649 }
1650
1651 /// Ends the record of the temporary at `slot`, whether or not there was
1652 /// one.
1653 fn forget(&mut self, slot: Slot) {
1654 self.held.retain(|(held, _)| *held != slot);
1655 }
1656
1657 /// Gives a location's run back without ending anything's live range.
1658 ///
1659 /// Every consumer of a *value* calls [`Body::release`] instead; this is
1660 /// for a run the lowering allocated and knows holds nothing.
1661 fn give_back(&mut self, slot: Slot, layout: LayoutId) {
1662 let width = self.width(layout);
1663 self.forget(slot);
1664 self.frame.free(slot, width);
1665 }
1666
1667 /// One [`Inst::Copy`]: ADR 0001's field-wise shallow copy, as many words
1668 /// as the layout says.
1669 fn copy(&mut self, dst: Slot, src: Slot, layout: LayoutId, span: Span) {
1670 if dst == src {
1671 return;
1672 }
1673 self.emit(Inst::Copy { dst, src, layout }, span);
1674 }
1675
1676 /// Zeroes a location's words.
1677 fn zero(&mut self, slot: Slot, layout: LayoutId, span: Span) {
1678 self.emit(Inst::Clear { slot, layout }, span);
1679 }
1680
1681 /// Puts a value in a form a location of `want` can hold.
1682 ///
1683 /// There is one conversion in the language and it is erasure, so the
1684 /// only difference this bridges is a box — and a box has two directions.
1685 /// A concrete value on its way into a `dyn` or an `Any` location is
1686 /// boxed; an erased value on its way into a location whose type is
1687 /// written is opened, which is [`Body::unbox`].
1688 ///
1689 /// Anything else is a copy of the wrong width. It is reported as a gap
1690 /// rather than emitted, because `lower` answers `Err` before the
1691 /// verifier ever sees it — which is the difference between a construct
1692 /// this lowering has not been taught and a program in the heap with the
1693 /// wrong number of words in it.
1694 fn fit(&mut self, value: Val, want: LayoutId, span: Span) -> Val {
1695 if value.layout == want {
1696 return value;
1697 }
1698 if self.is_boxed(want) {
1699 let dst = self.temp(want);
1700 self.emit(
1701 Inst::Box {
1702 dst: dst.slot,
1703 src: value.slot,
1704 layout: value.layout,
1705 },
1706 span,
1707 );
1708 self.release(value, span);
1709 return dst;
1710 }
1711 if self.is_boxed(value.layout) {
1712 return self.unbox(value, want, span);
1713 }
1714 let held = self.pool.shapes.layout(value.layout).name.clone();
1715 let wanted = self.pool.shapes.layout(want).name.clone();
1716 self.errors.push(gap::gap(
1717 &format!("a `{held}` where a `{wanted}` goes, which this lowering cannot convert"),
1718 span,
1719 ));
1720 self.release(value, span);
1721 self.temp(want)
1722 }
1723
1724 /// Opens an erased value at the layout the place using it names.
1725 ///
1726 /// Where `want` comes from is the whole of what this depends on, and it
1727 /// is never invented here: it is a type the source *wrote* at the place
1728 /// the value is being used — a declared parameter, a declared return
1729 /// type, a field's declared type — or, for an operator, the layout of
1730 /// the operand beside it. A use where nothing says is a gap raised by
1731 /// the caller rather than a layout guessed here.
1732 ///
1733 /// The trap is [`Inst::Unbox`]'s: a box carries the [`LayoutId`] of what
1734 /// was put in it, and reading it as something else fails the run rather
1735 /// than reinterpreting the words. That is what makes erasure safe
1736 /// without the checker having proved anything about it.
1737 fn unbox(&mut self, value: Val, want: LayoutId, span: Span) -> Val {
1738 let dst = self.temp(want);
1739 self.emit(
1740 Inst::Unbox {
1741 dst: dst.slot,
1742 src: value.slot,
1743 layout: want,
1744 },
1745 span,
1746 );
1747 self.release(value, span);
1748 dst
1749 }
1750
1751 // ---- reading a layout ------------------------------------------------
1752
1753 /// The field `name` of a struct-shaped layout: its word offset within
1754 /// the value and its own layout.
1755 ///
1756 /// This is where a field access stops being an instruction. `l.from.x`
1757 /// is `base + Field::at` twice over, computed here and added to a slot
1758 /// number, because the fields of an inline value are *where the value
1759 /// is*.
1760 fn field_of(&self, layout: LayoutId, name: &str) -> Option<crate::layout::Field> {
1761 self.pool.shapes.layout(layout).field(name).cloned()
1762 }
1763
1764 /// The fields of a struct-shaped layout, in declaration order.
1765 fn fields_of(&self, layout: LayoutId) -> Option<Vec<crate::layout::Field>> {
1766 match &self.pool.shapes.layout(layout).shape {
1767 crate::layout::Shape::Struct { fields, .. } => Some(fields.clone()),
1768 _ => None,
1769 }
1770 }
1771
1772 /// The parts of case `index` of an enum-shaped layout, and the payload
1773 /// region's own words.
1774 ///
1775 /// A part's `at` is an offset within the payload region, which begins
1776 /// *after* the discriminant, so a part of the value is at
1777 /// `base + 1 + at`.
1778 /// How many cases an enum-shaped layout has, for sizing a switch table.
1779 fn case_count(&self, layout: LayoutId) -> Option<usize> {
1780 match &self.pool.shapes.layout(layout).shape {
1781 crate::layout::Shape::Enum { cases, .. } => Some(cases.len()),
1782 _ => None,
1783 }
1784 }
1785
1786 fn case_of(
1787 &self,
1788 layout: LayoutId,
1789 index: u32,
1790 ) -> Option<(Vec<crate::layout::Part>, Vec<Repr>)> {
1791 match &self.pool.shapes.layout(layout).shape {
1792 crate::layout::Shape::Enum { cases, payload } => cases
1793 .get(index as usize)
1794 .map(|case| (case.parts.clone(), payload.clone())),
1795 _ => None,
1796 }
1797 }
1798
1799 /// Whether a value of this layout is one heap address naming a box.
1800 ///
1801 /// A `dyn Trait` is the one this lowering builds: erasure is where a
1802 /// value stops having a static width, and a heap object is where a value
1803 /// without a static width lives.
1804 fn is_boxed(&self, layout: LayoutId) -> bool {
1805 matches!(
1806 self.pool.shapes.layout(layout).shape,
1807 crate::layout::Shape::Boxed
1808 )
1809 }
1810
1811 /// The layout of one element of a run-of-elements family.
1812 ///
1813 /// `None` for everything else, because everything else is not a run: the
1814 /// question is asked where a lowering holds a sequence's own layout and
1815 /// needs the stride, which is the element layout's width.
1816 fn element_layout(&self, layout: LayoutId) -> Option<LayoutId> {
1817 match self.pool.shapes.layout(layout).shape {
1818 crate::layout::Shape::Elements { elem, .. } => Some(elem),
1819 _ => None,
1820 }
1821 }
1822
1823 /// Whether a value of this layout is one word of scalar bits, which is
1824 /// what an instruction rather than a walk can compare.
1825 fn is_scalar(&self, layout: LayoutId) -> bool {
1826 matches!(
1827 self.pool.shapes.layout(layout).shape,
1828 crate::layout::Shape::Word(_)
1829 )
1830 }
1831
1832 /// Whether a value of this layout is a case index and nothing else.
1833 ///
1834 /// An enum with no payload is one word wide and that word is the
1835 /// discriminant, so `Kind.Space == Kind.Word` is `1 == 2`.
1836 ///
1837 /// Asked separately from [`Self::is_scalar`] because the layout is not a
1838 /// [`Shape::Word`](crate::layout::Shape::Word): the shape says what a
1839 /// value is *made of*, and an enum is made of a discriminant and a
1840 /// payload region however empty that region turns out to be. What this
1841 /// asks is narrower — whether the instruction set can compare it in one
1842 /// step.
1843 fn is_case_index(&self, layout: LayoutId) -> bool {
1844 matches!(
1845 &self.pool.shapes.layout(layout).shape,
1846 crate::layout::Shape::Enum { payload, .. } if payload.is_empty()
1847 )
1848 }
1849
1850 /// Whether `layout` is the string family.
1851 ///
1852 /// A `String` is the one heap value the language orders: `a < b` on two
1853 /// of them compares their bytes. Every other heap value the checker
1854 /// admits an operator on admits only `==` and `!=`.
1855 fn is_text(&self, layout: LayoutId) -> bool {
1856 matches!(
1857 self.pool.shapes.layout(layout).shape,
1858 crate::layout::Shape::Str
1859 )
1860 }
1861
1862 /// Ends the live range of the reference locations a scope owned.
1863 ///
1864 /// A scalar body emits nothing here, because [`Frame::pop_scope`]
1865 /// answers an empty list. A body that holds an object emits one clear
1866 /// per binding, and that clear is what keeps a static reference map from
1867 /// being a leak: the map says which slots a collection *reads*, and only
1868 /// the data can say when the value in one stopped being needed.
1869 fn clear(&mut self, locations: &[(Slot, LayoutId)], span: Span) {
1870 for (slot, layout) in locations {
1871 self.zero(*slot, *layout, span);
1872 }
1873 }
1874
1875 /// Ends a temporary's live range, clearing the location when it held
1876 /// something the collector would otherwise trace.
1877 ///
1878 /// Every consumer of a value calls this rather than freeing the run
1879 /// behind it, so a reference a body stopped needing is null from that
1880 /// instruction onwards rather than until the frame returns. It is
1881 /// unconditional for a location holding a `Ref` or an `Addr`: the run
1882 /// goes back on a free list here, and whether some later value of the
1883 /// same shape happens to overwrite it is a fact about the rest of the
1884 /// body, which this cannot see and must not assume.
1885 ///
1886 /// A borrowed location is not cleared, because it is not this
1887 /// expression's to end: a parameter, a local, or the answer outlives the
1888 /// expression that read it, and the scope that owns it clears it.
1889 fn release(&mut self, value: Val, span: Span) {
1890 if !value.temp {
1891 return;
1892 }
1893 if self.holds_ref(value.layout) {
1894 self.zero(value.slot, value.layout, span);
1895 }
1896 self.give_back(value.slot, value.layout);
1897 }
1898
1899 /// A string of the program's pool, added only if it is not already in
1900 /// it.
1901 fn string(&mut self, text: &str) -> StrId {
1902 self.pool.string(text)
1903 }
1904
1905 /// The layout of a value of `ty`, reporting the type this lowering
1906 /// cannot build one for.
1907 fn layout(&mut self, ty: &Ty, span: Span) -> Option<LayoutId> {
1908 match self.pool.shapes.of(self.checked, self.module, ty) {
1909 Some(id) => Some(id),
1910 None => {
1911 self.report(ty, span);
1912 None
1913 }
1914 }
1915 }
1916
1917 /// Says why a type has no layout here, in the words [`describe`] chooses.
1918 fn report(&mut self, ty: &Ty, span: Span) {
1919 let item = describe(&self.pool.shapes, ty, span);
1920 self.errors.push(item);
1921 }
1922
1923 // ---- reading the checker's answers -----------------------------------
1924
1925 /// The type the checker settled for `expr`, in the terms the declaration
1926 /// was written in.
1927 ///
1928 /// Inside a generic body that is a `Ty::Param`, because the checker
1929 /// walked the body once with its type parameters rigid. Almost nothing
1930 /// wants that: [`Body::ty`] is what a lowering asks, and this is for the
1931 /// two questions that are about the *declaration* rather than about the
1932 /// value — whether a receiver is a bounded type parameter, and whether an
1933 /// expression diverges.
1934 fn raw_ty(&self, expr: &Expr) -> Option<&Ty> {
1935 self.checked.facts.ty(expr.span.file, expr.id)
1936 }
1937
1938 /// The type the checker settled for `expr`, as this instantiation
1939 /// settles it.
1940 ///
1941 /// Owned rather than borrowed because a body of a generic declaration is
1942 /// lowered once per set of type arguments and the answer is built from
1943 /// the fact rather than being the fact. For a declaration that binds no
1944 /// type parameters the substitution is the identity and this is a clone.
1945 fn ty(&self, expr: &Expr) -> Option<Ty> {
1946 self.raw_ty(expr).map(|ty| self.complete(ty))
1947 }
1948
1949 /// A type written in the declaration's own terms, as this instantiation
1950 /// settles it.
1951 fn complete(&self, ty: &Ty) -> Ty {
1952 ty.instantiate(&self.generics, &self.args)
1953 }
1954
1955 /// The same as [`Body::ty`], reporting an expression the checker recorded
1956 /// nothing for.
1957 fn settled_ty(&mut self, expr: &Expr) -> Option<Ty> {
1958 match self.ty(expr) {
1959 Some(ty) => Some(ty),
1960 None => {
1961 self.errors.push(gap::gap(
1962 "an expression the checker recorded no type for",
1963 expr.span,
1964 ));
1965 None
1966 }
1967 }
1968 }
1969
1970 /// The layout of `expr`'s value, reporting the reason there is none.
1971 ///
1972 /// A reported failure answers the one-word `Unit` layout so that
1973 /// lowering can carry on and find the rest of what is wrong in the same
1974 /// run. The answer is never acted on: `lower` has an error and will not
1975 /// hand the program back.
1976 fn layout_of(&mut self, expr: &Expr) -> LayoutId {
1977 let Some(ty) = self.ty(expr) else {
1978 self.errors.push(gap::gap(
1979 "an expression the checker recorded no type for",
1980 expr.span,
1981 ));
1982 return shapes::UNIT;
1983 };
1984 self.layout(&ty, expr.span).unwrap_or(shapes::UNIT)
1985 }
1986
1987 /// Whether this expression leaves rather than answering: a `return`, a
1988 /// `break`, a `continue`, or a form built out of them.
1989 ///
1990 /// What it decides is whether the surrounding form copies the answer.
1991 /// Nothing is ever written to a diverging expression's location, so
1992 /// copying from it would move words that were never produced — and where
1993 /// the surrounding form wants a different layout, it would not even be
1994 /// well formed.
1995 ///
1996 /// The fact is read as it was recorded. `Ty::Never` holds no type
1997 /// parameter, so no instantiation can turn one into it or it into
1998 /// anything else, and this is asked once per stored value.
1999 fn diverges(&self, expr: &Expr) -> bool {
2000 matches!(self.raw_ty(expr), Some(Ty::Never))
2001 }
2002
2003 /// Copies an expression's answer into the location the surrounding form
2004 /// is assembling its own in.
2005 ///
2006 /// The one thing this is not is a copy in every case. A body whose
2007 /// declared return type is `dyn Trait` erases its tail on the way into
2008 /// the answer, because a declared return type is a written type and that
2009 /// is where the language's one implicit conversion happens. The answer
2010 /// is taken before any temporary and is never handed to anything else,
2011 /// so `dst == self.answer` names exactly the function's own tail and no
2012 /// nested form's destination.
2013 fn store(&mut self, dst: Dest, value: &Val, from: &Expr) {
2014 if self.diverges(from) || value.slot == dst.slot {
2015 return;
2016 }
2017 // Where the two disagree the value is erased on the way in, and
2018 // that is the language's one implicit conversion. `Body::erase`
2019 // covers the positions where a `dyn` type is *written*; this covers
2020 // the ones where the checker settled `dyn` for an expression whose
2021 // value was never put through one — the tail of a body declared
2022 // `-> dyn Trait`, an arm of an `if` in a `dyn` position.
2023 //
2024 // The source is borrowed here whatever it was: whoever called this
2025 // still owns it and will end its live range itself.
2026 if value.layout != dst.layout {
2027 let held = self.fit(
2028 Val::borrowed(value.slot, value.layout),
2029 dst.layout,
2030 from.span,
2031 );
2032 self.copy(dst.slot, held.slot, dst.layout, from.span);
2033 self.release(held, from.span);
2034 return;
2035 }
2036 self.copy(dst.slot, value.slot, dst.layout, from.span);
2037 }
2038
2039 /// A location for a value nothing will produce, so that a diverging
2040 /// expression still answers something the caller can hold.
2041 fn dead(&mut self, expr: &Expr) -> Val {
2042 let layout = self.layout_of(expr);
2043 self.temp(layout)
2044 }
2045
2046 /// Whether `id` is a declaration this pass lowered, recording it for the
2047 /// next one when it is not.
2048 ///
2049 /// A `false` is not a gap and is deliberately silent: it says the slice
2050 /// [`lower_entry`] took was too small, which is this crate's mistake to
2051 /// correct rather than the program's to answer for. The caller emits
2052 /// nothing naming `id`, the errors of this pass are thrown away, and the
2053 /// pass after it has the declaration.
2054 ///
2055 /// A whole-package lowering never sees one, because nothing is left out.
2056 fn reached(&mut self, id: FunctionId) -> bool {
2057 if self.plan.reached(id) {
2058 return true;
2059 }
2060 self.wanted.insert(id);
2061 false
2062 }
2063
2064 /// The source text a span covers, which is what an assertion quotes.
2065 ///
2066 /// `?` for a span the map does not hold, exactly as the oracle's own
2067 /// reader answers, so a message worded here and one worded there cannot
2068 /// differ even in the case neither expects.
2069 fn source_text(&self, span: Span) -> &str {
2070 self.sources
2071 .files()
2072 .find(|file| file.id == span.file)
2073 .and_then(|file| file.text.get(span.start as usize..span.end as usize))
2074 .unwrap_or("?")
2075 }
2076
2077 /// Reports a construct this lowering has not been taught, answering a
2078 /// location of the right shape so the walk can continue and report the
2079 /// rest.
2080 fn gap(&mut self, what: &str, expr: &Expr) -> Val {
2081 self.errors.push(gap::gap(what, expr.span));
2082 self.dead(expr)
2083 }
2084}