| @@ -44,7 +44,7 @@ enum Fwd { |
| 44 | Text(String), | 44 | Text(String), |
| 45 | /// Also carries the impl's generic parameters and `Self` type: rendering | 45 | /// Also carries the impl's generic parameters and `Self` type: rendering |
| 46 | /// happens after collection, when that context is no longer current. | 46 | /// happens after collection, when that context is no longer current. |
| 47 | - Head(String, Box<syn::Signature>, Option<Nim>, Vec<String>, Option<Nim>), | 47 | + Head(String, Box<syn::Signature>, Option<Nim>, Vec<String>, Option<Nim>, Box<syn::Block>), |
| 48 | } | 48 | } |
| 49 | | 49 | |
| 50 | #[derive(Clone, Debug)] | 50 | #[derive(Clone, Debug)] |
| @@ -200,6 +200,10 @@ struct Variant { |
| 200 | /// `Error = 1` — Nim enums take explicit ordinals too, so the value is | 200 | /// `Error = 1` — Nim enums take explicit ordinals too, so the value is |
| 201 | /// preserved rather than the variant being renumbered. | 201 | /// preserved rather than the variant being renumbered. |
| 202 | discriminant: Option<String>, | 202 | discriminant: Option<String>, |
| | 203 | + /// The discriminant as written. Lowered in its own pass, because it may |
| | 204 | + /// call a function defined in a file that has not been collected yet -- |
| | 205 | + /// which made the result depend on the order the inputs were given in. |
| | 206 | + disc_expr: Option<syn::Expr>, |
| 203 | /// `(nim field name, type)`. Empty for a unit variant. Tuple variants get | 207 | /// `(nim field name, type)`. Empty for a unit variant. Tuple variants get |
| 204 | /// `f0`, `f1`, ...; every field is prefixed with the variant name because | 208 | /// `f0`, `f1`, ...; every field is prefixed with the variant name because |
| 205 | /// Nim requires the branches of a variant object to have distinct fields. | 209 | /// Nim requires the branches of a variant object to have distinct fields. |
| @@ -348,6 +352,11 @@ pub struct Lowerer { |
| 348 | /// `signature` is called again on the emission pass and has only the | 352 | /// `signature` is called again on the emission pass and has only the |
| 349 | /// signature to go on, so that is what the key is made of. | 353 | /// signature to go on, so that is what the key is made of. |
| 350 | opaque_ret: HashMap<String, Nim>, | 354 | opaque_ret: HashMap<String, Nim>, |
| | 355 | + /// Set around a call to `signature` when the caller knows which body the |
| | 356 | + /// signature belongs to. `signature` has only the signature to go on, and |
| | 357 | + /// two functions can share one -- `fn render(self) -> impl Display` twice |
| | 358 | + /// with different concrete types is real, and happens. |
| | 359 | + opaque_hint: Option<Nim>, |
| 351 | /// Module names supplied as separate input files. A `mod x;` naming one | 360 | /// Module names supplied as separate input files. A `mod x;` naming one |
| 352 | /// of these is satisfied by that file having been passed in. | 361 | /// of these is satisfied by that file having been passed in. |
| 353 | pub modules: Vec<String>, | 362 | pub modules: Vec<String>, |
| @@ -424,6 +433,7 @@ impl Lowerer { |
| 424 | const_gens: HashMap::new(), | 433 | const_gens: HashMap::new(), |
| 425 | opaque_fns: Vec::new(), | 434 | opaque_fns: Vec::new(), |
| 426 | opaque_ret: HashMap::new(), | 435 | opaque_ret: HashMap::new(), |
| | 436 | + opaque_hint: None, |
| 427 | modules: Vec::new(), | 437 | modules: Vec::new(), |
| 428 | emitted: 0, | 438 | emitted: 0, |
| 429 | features: Vec::new(), | 439 | features: Vec::new(), |
| @@ -530,6 +540,11 @@ impl Lowerer { |
| 530 | // ambiguous, so reading it off the body is exact rather than a guess. | 540 | // ambiguous, so reading it off the body is exact rather than a guess. |
| 531 | // Repeated to a fixpoint because one such function may return the | 541 | // Repeated to a fixpoint because one such function may return the |
| 532 | // result of another. | 542 | // result of another. |
| | 543 | + // Discriminants, now that every file's signatures are known. They can |
| | 544 | + // call ordinary functions -- `enumflags2` expands to exactly that -- |
| | 545 | + // and lowering them during collection made the answer depend on which |
| | 546 | + // order the input files happened to be given in. |
| | 547 | + self.resolve_discriminants()?; |
| 533 | self.resolve_opaque()?; | 548 | self.resolve_opaque()?; |
| 534 | | 549 | |
| 535 | // Pass 2: type definitions, which every signature may mention. | 550 | // Pass 2: type definitions, which every signature may mention. |
| @@ -547,10 +562,12 @@ impl Lowerer { |
| 547 | for f in self.forwards.clone() { | 562 | for f in self.forwards.clone() { |
| 548 | let f = match f { | 563 | let f = match f { |
| 549 | Fwd::Text(t) => t, | 564 | Fwd::Text(t) => t, |
| 550 | - Fwd::Head(nim, sig, recv, gens, self_ty) => { | 565 | + Fwd::Head(nim, sig, recv, gens, self_ty, block) => { |
| 551 | let og = std::mem::replace(&mut self.impl_generics, gens); | 566 | let og = std::mem::replace(&mut self.impl_generics, gens); |
| 552 | let os = std::mem::replace(&mut self.self_ty, self_ty); | 567 | let os = std::mem::replace(&mut self.self_ty, self_ty); |
| | 568 | + self.opaque_hint = self.opaque_ret.get(&opaque_key(&sig, &block)).cloned(); |
| 553 | let r = self.head_of(&nim, &sig, recv.as_ref()); | 569 | let r = self.head_of(&nim, &sig, recv.as_ref()); |
| | 570 | + self.opaque_hint = None; |
| 554 | self.impl_generics = og; | 571 | self.impl_generics = og; |
| 555 | self.self_ty = os; | 572 | self.self_ty = os; |
| 556 | r? | 573 | r? |
| @@ -717,7 +734,7 @@ impl Lowerer { |
| 717 | gen_names.extend(self.impl_trait_params(&f.sig)); | 734 | gen_names.extend(self.impl_trait_params(&f.sig)); |
| 718 | let name = f.sig.ident.to_string(); | 735 | let name = f.sig.ident.to_string(); |
| 719 | let nim = self.fn_name(&self.cur_mod, &name); | 736 | let nim = self.fn_name(&self.cur_mod, &name); |
| 720 | - self.forwards.push(Fwd::Head(nim.clone(), Box::new(f.sig.clone()), None, self.impl_generics.clone(), self.self_ty.clone())); | 737 | + self.forwards.push(Fwd::Head(nim.clone(), Box::new(f.sig.clone()), None, self.impl_generics.clone(), self.self_ty.clone(), Box::new((*f.block).clone()))); |
| 721 | self.fns | 738 | self.fns |
| 722 | .insert( | 739 | .insert( |
| 723 | (self.cur_mod.clone(), name.clone()), | 740 | (self.cur_mod.clone(), name.clone()), |
| @@ -835,6 +852,7 @@ impl Lowerer { |
| 835 | .map(|v| Variant { | 852 | .map(|v| Variant { |
| 836 | name: v.ident.to_string(), | 853 | name: v.ident.to_string(), |
| 837 | discriminant: None, | 854 | discriminant: None, |
| | 855 | + disc_expr: None, |
| 838 | fields: Vec::new(), | 856 | fields: Vec::new(), |
| 839 | }) | 857 | }) |
| 840 | .collect(), | 858 | .collect(), |
| @@ -844,10 +862,7 @@ impl Lowerer { |
| 844 | let mut variants = Vec::new(); | 862 | let mut variants = Vec::new(); |
| 845 | for v in &e.variants { | 863 | for v in &e.variants { |
| 846 | let vname = v.ident.to_string(); | 864 | let vname = v.ident.to_string(); |
| 847 | - let discriminant = match &v.discriminant { | 865 | + let disc_expr = v.discriminant.as_ref().map(|(_, e)| e.clone()); |
| 848 | - Some((_, e)) => Some(self.expr(e)?.code), | | |
| 849 | - None => None, | | |
| 850 | - }; | | |
| 851 | let mut fields = Vec::new(); | 866 | let mut fields = Vec::new(); |
| 852 | for (i, f) in v.fields.iter().enumerate() { | 867 | for (i, f) in v.fields.iter().enumerate() { |
| 853 | // Nim requires the branches of a variant object to have | 868 | // Nim requires the branches of a variant object to have |
| @@ -860,7 +875,7 @@ impl Lowerer { |
| 860 | let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() }; | 875 | let t = if returns_borrow(&f.ty) { t.unvar() } else { t.owned() }; |
| 861 | fields.push((fname, t)); | 876 | fields.push((fname, t)); |
| 862 | } | 877 | } |
| 863 | - variants.push(Variant { name: vname, discriminant, fields }); | 878 | + variants.push(Variant { name: vname, discriminant: None, disc_expr, fields }); |
| 864 | } | 879 | } |
| 865 | self.enums.insert( | 880 | self.enums.insert( |
| 866 | name.clone(), | 881 | name.clone(), |
| @@ -940,7 +955,7 @@ impl Lowerer { |
| 940 | // The source type may be a tuple, whose rendering has | 955 | // The source type may be a tuple, whose rendering has |
| 941 | // parens and commas in it; a Nim identifier may not. | 956 | // parens and commas in it; a Nim identifier may not. |
| 942 | let name = format!("rsFrom{}{}", mangle(&tyname), mangle(&type_name(&src))); | 957 | let name = format!("rsFrom{}{}", mangle(&tyname), mangle(&type_name(&src))); |
| 943 | - self.forwards.push(Fwd::Head(name.clone(), Box::new(m.sig.clone()), None, self.impl_generics.clone(), self.self_ty.clone())); | 958 | + self.forwards.push(Fwd::Head(name.clone(), Box::new(m.sig.clone()), None, self.impl_generics.clone(), self.self_ty.clone(), Box::new(m.block.clone()))); |
| 944 | self.from_types | 959 | self.from_types |
| 945 | .insert((type_name(&src), tyname.clone()), src.clone()); | 960 | .insert((type_name(&src), tyname.clone()), src.clone()); |
| 946 | self.from_impls | 961 | self.from_impls |
| @@ -981,7 +996,7 @@ impl Lowerer { |
| 981 | None | 996 | None |
| 982 | }; | 997 | }; |
| 983 | let nim = trait_method_name(&tyname, &tr, &mname, recv.is_some()); | 998 | let nim = trait_method_name(&tyname, &tr, &mname, recv.is_some()); |
| 984 | - self.forwards.push(Fwd::Head(nim.clone(), Box::new(m.sig.clone()), recv.clone(), self.impl_generics.clone(), self.self_ty.clone())); | 999 | + self.forwards.push(Fwd::Head(nim.clone(), Box::new(m.sig.clone()), recv.clone(), self.impl_generics.clone(), self.self_ty.clone(), Box::new(m.block.clone()))); |
| 985 | self.methods | 1000 | self.methods |
| 986 | .insert((tyname.clone(), mname.clone()), Sig { params, ret: ret.clone(), generics: gen_names.clone() }); | 1001 | .insert((tyname.clone(), mname.clone()), Sig { params, ret: ret.clone(), generics: gen_names.clone() }); |
| 987 | self.statics.insert((tyname.clone(), mname.clone()), nim); | 1002 | self.statics.insert((tyname.clone(), mname.clone()), nim); |
| @@ -1014,6 +1029,7 @@ impl Lowerer { |
| 1014 | recv.clone(), | 1029 | recv.clone(), |
| 1015 | self.impl_generics.clone(), | 1030 | self.impl_generics.clone(), |
| 1016 | self.self_ty.clone(), | 1031 | self.self_ty.clone(), |
| | 1032 | + Box::new(m.block.clone()), |
| 1017 | )); | 1033 | )); |
| 1018 | self.methods | 1034 | self.methods |
| 1019 | .insert((tyname.clone(), m.sig.ident.to_string()), Sig { params, ret: ret.clone(), generics: gen_names.clone() }); | 1035 | .insert((tyname.clone(), m.sig.ident.to_string()), Sig { params, ret: ret.clone(), generics: gen_names.clone() }); |
| @@ -1686,6 +1702,21 @@ impl Lowerer { |
| 1686 | } | 1702 | } |
| 1687 | | 1703 | |
| 1688 | | 1704 | |
| | 1705 | + /// Lower every enum discriminant, after all signatures are collected. |
| | 1706 | + fn resolve_discriminants(&mut self) -> Result<(), String> { |
| | 1707 | + let names: Vec<String> = self.enums.keys().cloned().collect(); |
| | 1708 | + for n in names { |
| | 1709 | + let Some(def) = self.enums.get(&n).cloned() else { continue }; |
| | 1710 | + let mut out = def.clone(); |
| | 1711 | + for (i, v) in def.variants.iter().enumerate() { |
| | 1712 | + let Some(e) = &v.disc_expr else { continue }; |
| | 1713 | + out.variants[i].discriminant = Some(self.expr(e)?.code); |
| | 1714 | + } |
| | 1715 | + self.enums.insert(n, out); |
| | 1716 | + } |
| | 1717 | + Ok(()) |
| | 1718 | + } |
| | 1719 | + |
| 1689 | /// Give every return-position `impl Trait` its concrete type, taken from | 1720 | /// Give every return-position `impl Trait` its concrete type, taken from |
| 1690 | /// the body that produces it. | 1721 | /// the body that produces it. |
| 1691 | /// | 1722 | /// |
| @@ -1705,22 +1736,7 @@ impl Lowerer { |
| 1705 | for (key, sig, block) in left { | 1736 | for (key, sig, block) in left { |
| 1706 | match self.opaque_of(&sig, &block) { | 1737 | match self.opaque_of(&sig, &block) { |
| 1707 | Some(t) if t != opaque => { | 1738 | Some(t) if t != opaque => { |
| 1708 | - let sk = quote::quote!(#sig).to_string(); | 1739 | + self.opaque_ret.insert(opaque_key(&sig, &block), t.clone()); |
| 1709 | - if let Some(prev) = self.opaque_ret.get(&sk) { | | |
| 1710 | - if prev != &t { | | |
| 1711 | - return Err(format!( | | |
| 1712 | - "two functions share the signature `{}` but \ | | |
| 1713 | - their opaque return types are different \ | | |
| 1714 | - (`{}` and `{}`); rustnim keys the \ | | |
| 1715 | - resolution on the signature text, so it \ | | |
| 1716 | - cannot tell them apart", | | |
| 1717 | - sk, | | |
| 1718 | - prev.render(), | | |
| 1719 | - t.render() | | |
| 1720 | - )); | | |
| 1721 | - } | | |
| 1722 | - } | | |
| 1723 | - self.opaque_ret.insert(sk, t.clone()); | | |
| 1724 | match &key { | 1740 | match &key { |
| 1725 | OpaqueKey::Free(m, n) => { | 1741 | OpaqueKey::Free(m, n) => { |
| 1726 | if let Some(s) = self.fns.get_mut(&(m.clone(), n.clone())) { | 1742 | if let Some(s) = self.fns.get_mut(&(m.clone(), n.clone())) { |
| @@ -1825,7 +1841,7 @@ impl Lowerer { |
| 1825 | ReturnType::Type(_, t) | 1841 | ReturnType::Type(_, t) |
| 1826 | if matches!(&**t, syn::Type::ImplTrait(_)) && self.map_ty(t).is_err() => | 1842 | if matches!(&**t, syn::Type::ImplTrait(_)) && self.map_ty(t).is_err() => |
| 1827 | { | 1843 | { |
| 1828 | - match self.opaque_ret.get("e::quote!(#sig).to_string()) { | 1844 | + match &self.opaque_hint { |
| 1829 | Some(t) => t.clone(), | 1845 | Some(t) => t.clone(), |
| 1830 | None => Nim::Named(OPAQUE.into(), Vec::new()), | 1846 | None => Nim::Named(OPAQUE.into(), Vec::new()), |
| 1831 | } | 1847 | } |
| @@ -2725,7 +2741,9 @@ impl Lowerer { |
| 2725 | body: &syn::Block, | 2741 | body: &syn::Block, |
| 2726 | recv: Option<Nim>, | 2742 | recv: Option<Nim>, |
| 2727 | ) -> Result<(), String> { | 2743 | ) -> Result<(), String> { |
| | 2744 | + self.opaque_hint = self.opaque_ret.get(&opaque_key(sig, body)).cloned(); |
| 2728 | let (ptys, ret) = self.signature(sig)?; | 2745 | let (ptys, ret) = self.signature(sig)?; |
| | 2746 | + self.opaque_hint = None; |
| 2729 | | 2747 | |
| 2730 | self.push_scope(); | 2748 | self.push_scope(); |
| 2731 | let mut rendered: Vec<String> = Vec::new(); | 2749 | let mut rendered: Vec<String> = Vec::new(); |
| @@ -7577,3 +7595,14 @@ fn rename_ident(ts: proc_macro2::TokenStream, from: &str, to: &str) -> proc_macr |
| 7577 | }) | 7595 | }) |
| 7578 | .collect() | 7596 | .collect() |
| 7579 | } | 7597 | } |
| | 7598 | + |
| | 7599 | +/// Identify a function by its signature *and* its body. A signature alone is |
| | 7600 | +/// not enough: `fn render(&self) -> impl Display` appears twice in one |
| | 7601 | +/// dependency graph with two different concrete types behind it. |
| | 7602 | +fn opaque_key(sig: &syn::Signature, block: &syn::Block) -> String { |
| | 7603 | + format!( |
| | 7604 | + "{}\u{1}{}", |
| | 7605 | + quote::quote!(#sig), |
| | 7606 | + quote::quote!(#block) |
| | 7607 | + ) |
| | 7608 | +} |