| @@ -356,6 +356,16 @@ pub struct Lowerer { |
| 356 | /// generic parameter: `alternatives.choice(i)` where the parameter is | 356 | /// generic parameter: `alternatives.choice(i)` where the parameter is |
| 357 | /// bound by `Alt<I, O, E>`. | 357 | /// bound by `Alt<I, O, E>`. |
| 358 | trait_methods: HashMap<(String, String), Sig>, | 358 | trait_methods: HashMap<(String, String), Sig>, |
| | 359 | + /// Traits with a blanket impl over a callable: `impl<I,O,E,F> Parser<I,O,E> |
| | 360 | + /// for F where F: FnMut(&mut I) -> Result<O,E>`. That impl is what makes a |
| | 361 | + /// closure usable where the trait is expected, and it says what signature |
| | 362 | + /// the closure must have -- which is the only thing that types a closure |
| | 363 | + /// passed to a generic parameter. |
| | 364 | + fn_blankets: HashMap<String, (Vec<String>, Vec<Nim>, Nim)>, |
| | 365 | + /// Bounds discovered while rewriting `impl Trait` parameters. `rewrite_apit` |
| | 366 | + /// runs from `&self`, so they are parked here and folded into `bounds` by |
| | 367 | + /// whoever called it. |
| | 368 | + pending_apit_bounds: std::cell::RefCell<Vec<(String, syn::punctuated::Punctuated<syn::TypeParamBound, syn::Token![+]>)>>, |
| 359 | /// The trait bounds on each generic parameter in scope, as `(trait, | 369 | /// The trait bounds on each generic parameter in scope, as `(trait, |
| 360 | /// arguments)`. | 370 | /// arguments)`. |
| 361 | bounds: HashMap<String, Vec<(String, Vec<Nim>)>>, | 371 | bounds: HashMap<String, Vec<(String, Vec<Nim>)>>, |
| @@ -451,6 +461,8 @@ impl Lowerer { |
| 451 | const_gens: HashMap::new(), | 461 | const_gens: HashMap::new(), |
| 452 | opaque_why: None, | 462 | opaque_why: None, |
| 453 | trait_methods: HashMap::new(), | 463 | trait_methods: HashMap::new(), |
| | 464 | + fn_blankets: HashMap::new(), |
| | 465 | + pending_apit_bounds: std::cell::RefCell::new(Vec::new()), |
| 454 | bounds: HashMap::new(), | 466 | bounds: HashMap::new(), |
| 455 | const_names_at: std::cell::Cell::new(None), | 467 | const_names_at: std::cell::Cell::new(None), |
| 456 | opaque_fns: Vec::new(), | 468 | opaque_fns: Vec::new(), |
| @@ -1073,6 +1085,7 @@ impl Lowerer { |
| 1073 | // the trait branches below return early. | 1085 | // the trait branches below return early. |
| 1074 | self.note_const_generics(&im.generics)?; | 1086 | self.note_const_generics(&im.generics)?; |
| 1075 | self.note_bounds(&im.generics); | 1087 | self.note_bounds(&im.generics); |
| | 1088 | + self.note_fn_blanket(im); |
| 1076 | // Associated consts are registered here for the same reason anything | 1089 | // Associated consts are registered here for the same reason anything |
| 1077 | // else is: an array length elsewhere may name one, and that name has | 1090 | // else is: an array length elsewhere may name one, and that name has |
| 1078 | // to resolve before any body is lowered. `assoc_const` records them | 1091 | // to resolve before any body is lowered. `assoc_const` records them |
| @@ -1564,6 +1577,99 @@ impl Lowerer { |
| 1564 | /// program mean something different — it only makes rustnim accept some | 1577 | /// program mean something different — it only makes rustnim accept some |
| 1565 | /// programs rustc would have rejected, which does not matter when the | 1578 | /// programs rustc would have rejected, which does not matter when the |
| 1566 | /// input is known-good Rust. | 1579 | /// input is known-good Rust. |
| | 1580 | + /// The proc type a value of this type variable must have, if one of its |
| | 1581 | + /// bounds is a trait implemented blanket-wise for a callable. |
| | 1582 | + fn callable_bound(&self, t: &Nim) -> Option<Nim> { |
| | 1583 | + let Nim::Named(name, _) = t else { return None }; |
| | 1584 | + let bs = self.bounds.get(name)?; |
| | 1585 | + for (tr, targs) in bs { |
| | 1586 | + let Some((tparams, args, ret)) = self.fn_blankets.get(tr) else { continue }; |
| | 1587 | + // The trait's parameters, bound to what this use site supplies. |
| | 1588 | + let mut m: HashMap<String, Nim> = HashMap::new(); |
| | 1589 | + for (p, a) in tparams.iter().zip(targs.iter()) { |
| | 1590 | + m.insert(p.clone(), a.clone()); |
| | 1591 | + } |
| | 1592 | + let args: Vec<Nim> = args.iter().map(|a| Self::subst(a, &m)).collect(); |
| | 1593 | + let ret = Self::subst(ret, &m); |
| | 1594 | + return Some(Nim::Proc(args, Box::new(ret))); |
| | 1595 | + } |
| | 1596 | + None |
| | 1597 | + } |
| | 1598 | + |
| | 1599 | + /// Record a trait's blanket impl over a callable, if it has one. |
| | 1600 | + /// |
| | 1601 | + /// `impl<I,O,E,F> Parser<I,O,E> for F where F: FnMut(&mut I) -> Result<O,E>` |
| | 1602 | + /// is what makes every winnow combinator's closure a `Parser`, and it is |
| | 1603 | + /// the only thing that says what signature such a closure has. Rust reads |
| | 1604 | + /// it the same way. |
| | 1605 | + fn note_fn_blanket(&mut self, im: &syn::ItemImpl) { |
| | 1606 | + let Some((path, _)) = &im.trait_ else { return }; |
| | 1607 | + let Some(seg) = path.segments.last() else { return }; |
| | 1608 | + let tname = seg.ident.to_string(); |
| | 1609 | + // The impl is *for* a bare generic parameter of the impl itself. |
| | 1610 | + let syn::Type::Path(sp) = &*im.self_ty else { return }; |
| | 1611 | + if sp.path.segments.len() != 1 { |
| | 1612 | + return; |
| | 1613 | + } |
| | 1614 | + let me = sp.path.segments[0].ident.to_string(); |
| | 1615 | + if !Self::generics_of(&im.generics).iter().any(|g| *g == me) { |
| | 1616 | + return; |
| | 1617 | + } |
| | 1618 | + // The trait's own arguments, in order, are what a use site supplies. |
| | 1619 | + let targs: Vec<String> = match &seg.arguments { |
| | 1620 | + syn::PathArguments::AngleBracketed(a) => a |
| | 1621 | + .args |
| | 1622 | + .iter() |
| | 1623 | + .filter_map(|g| match g { |
| | 1624 | + GenericArgument::Type(syn::Type::Path(p)) if p.path.segments.len() == 1 => { |
| | 1625 | + Some(p.path.segments[0].ident.to_string()) |
| | 1626 | + } |
| | 1627 | + _ => None, |
| | 1628 | + }) |
| | 1629 | + .collect(), |
| | 1630 | + _ => return, |
| | 1631 | + }; |
| | 1632 | + // And the `Fn` bound on that parameter gives the signature. |
| | 1633 | + let mut bounds: Vec<&syn::TypeParamBound> = Vec::new(); |
| | 1634 | + for p in &im.generics.params { |
| | 1635 | + if let syn::GenericParam::Type(t) = p { |
| | 1636 | + if t.ident == me { |
| | 1637 | + bounds.extend(t.bounds.iter()); |
| | 1638 | + } |
| | 1639 | + } |
| | 1640 | + } |
| | 1641 | + if let Some(w) = &im.generics.where_clause { |
| | 1642 | + for pred in &w.predicates { |
| | 1643 | + let syn::WherePredicate::Type(pt) = pred else { continue }; |
| | 1644 | + let syn::Type::Path(bp) = &pt.bounded_ty else { continue }; |
| | 1645 | + if bp.path.segments.len() == 1 && bp.path.segments[0].ident == me { |
| | 1646 | + bounds.extend(pt.bounds.iter()); |
| | 1647 | + } |
| | 1648 | + } |
| | 1649 | + } |
| | 1650 | + for b in bounds { |
| | 1651 | + let syn::TypeParamBound::Trait(tb) = b else { continue }; |
| | 1652 | + let Some(fs) = tb.path.segments.last() else { continue }; |
| | 1653 | + if !matches!(fs.ident.to_string().as_str(), "Fn" | "FnMut" | "FnOnce") { |
| | 1654 | + continue; |
| | 1655 | + } |
| | 1656 | + let syn::PathArguments::Parenthesized(pa) = &fs.arguments else { continue }; |
| | 1657 | + let Ok(args) = pa.inputs.iter().map(|a| self.map_ty(&a.ty)).collect::<Result<Vec<_>, _>>() |
| | 1658 | + else { |
| | 1659 | + continue; |
| | 1660 | + }; |
| | 1661 | + let ret = match &pa.output { |
| | 1662 | + ReturnType::Default => Nim::Unit, |
| | 1663 | + ReturnType::Type(_, t) => match self.map_ty(t) { |
| | 1664 | + Ok(t) => t, |
| | 1665 | + Err(_) => continue, |
| | 1666 | + }, |
| | 1667 | + }; |
| | 1668 | + self.fn_blankets.insert(tname, (targs, args, ret)); |
| | 1669 | + return; |
| | 1670 | + } |
| | 1671 | + } |
| | 1672 | + |
| 1567 | /// Record the trait bounds on a signature's generic parameters, from both | 1673 | /// Record the trait bounds on a signature's generic parameters, from both |
| 1568 | /// the parameter list and the `where` clause. | 1674 | /// the parameter list and the `where` clause. |
| 1569 | /// | 1675 | /// |
| @@ -1573,6 +1679,19 @@ impl Lowerer { |
| 1573 | /// instantiation without a bound to check. The bound is what lets rustnim | 1679 | /// instantiation without a bound to check. The bound is what lets rustnim |
| 1574 | /// *type* the call in between. | 1680 | /// *type* the call in between. |
| 1575 | fn note_bounds(&mut self, g: &syn::Generics) { | 1681 | fn note_bounds(&mut self, g: &syn::Generics) { |
| | 1682 | + let pending = std::mem::take(&mut *self.pending_apit_bounds.borrow_mut()); |
| | 1683 | + for (name, bounds) in pending { |
| | 1684 | + let mut tmp = syn::Generics::default(); |
| | 1685 | + tmp.params.push(syn::GenericParam::Type(syn::TypeParam { |
| | 1686 | + attrs: Vec::new(), |
| | 1687 | + ident: proc_macro2::Ident::new(&name, proc_macro2::Span::call_site()), |
| | 1688 | + colon_token: None, |
| | 1689 | + bounds, |
| | 1690 | + default: None, |
| | 1691 | + })); |
| | 1692 | + self.note_bounds(&tmp); |
| | 1693 | + } |
| | 1694 | + |
| 1576 | let mut add = |me: &mut Self, name: String, bounds: &syn::punctuated::Punctuated<syn::TypeParamBound, syn::Token![+]>| { | 1695 | let mut add = |me: &mut Self, name: String, bounds: &syn::punctuated::Punctuated<syn::TypeParamBound, syn::Token![+]>| { |
| 1577 | for b in bounds { | 1696 | for b in bounds { |
| 1578 | let syn::TypeParamBound::Trait(tb) = b else { continue }; | 1697 | let syn::TypeParamBound::Trait(tb) = b else { continue }; |
| @@ -1963,10 +2082,16 @@ impl Lowerer { |
| 1963 | /// they invent for a given position always carries the same name. | 2082 | /// they invent for a given position always carries the same name. |
| 1964 | fn rewrite_apit(&self, ty: &syn::Type, next: &mut usize) -> syn::Type { | 2083 | fn rewrite_apit(&self, ty: &syn::Type, next: &mut usize) -> syn::Type { |
| 1965 | use syn::Type; | 2084 | use syn::Type; |
| 1966 | - if let Type::ImplTrait(_) = ty { | 2085 | + if let Type::ImplTrait(it) = ty { |
| 1967 | if self.map_ty(ty).is_err() { | 2086 | if self.map_ty(ty).is_err() { |
| 1968 | *next += 1; | 2087 | *next += 1; |
| 1969 | let name = format!("ImplT{next}"); | 2088 | let name = format!("ImplT{next}"); |
| | 2089 | + // The bound travels with the parameter it becomes: it is what |
| | 2090 | + // says a closure passed here has to be callable, and with what |
| | 2091 | + // signature. See `fn_blankets`. |
| | 2092 | + self.pending_apit_bounds |
| | 2093 | + .borrow_mut() |
| | 2094 | + .push((name.clone(), it.bounds.clone())); |
| 1970 | return syn::parse_str::<Type>(&name).expect("generated ident parses"); | 2095 | return syn::parse_str::<Type>(&name).expect("generated ident parses"); |
| 1971 | } | 2096 | } |
| 1972 | return ty.clone(); | 2097 | return ty.clone(); |
| @@ -6268,7 +6393,15 @@ impl Lowerer { |
| 6268 | let ptys: Vec<Nim> = callee.map(|s| s.params.clone()).unwrap_or_default(); | 6393 | let ptys: Vec<Nim> = callee.map(|s| s.params.clone()).unwrap_or_default(); |
| 6269 | let mut args = Vec::new(); | 6394 | let mut args = Vec::new(); |
| 6270 | for (i, a) in c.args.iter().enumerate() { | 6395 | for (i, a) in c.args.iter().enumerate() { |
| 6271 | - let want = ptys.get(i).cloned().filter(|t| !Self::mentions_any(t, &cgen)); | 6396 | + let raw = ptys.get(i).cloned(); |
| | 6397 | + // A parameter that is a type variable says nothing by itself -- |
| | 6398 | + // except when its bound is a trait with a blanket impl over a |
| | 6399 | + // callable, which says exactly what a closure passed here must |
| | 6400 | + // look like. That is how Rust types these too. |
| | 6401 | + let want = match raw { |
| | 6402 | + Some(t) if Self::mentions_any(&t, &cgen) => self.callable_bound(&t), |
| | 6403 | + other => other, |
| | 6404 | + }; |
| 6272 | args.push(self.expr_at(a, want.as_ref())?); | 6405 | args.push(self.expr_at(a, want.as_ref())?); |
| 6273 | } | 6406 | } |
| 6274 | let codes: Vec<String> = args.iter().map(|a| a.code.clone()).collect(); | 6407 | let codes: Vec<String> = args.iter().map(|a| a.code.clone()).collect(); |