Lower `Borrow::borrow`, the free-function `PartialEq`, and `cmp::Ordering`
`equivalent` compiles -- the third of libcosmic's dependencies to go the whole way, and `cfg-if` makes a fourth: it had been failing on the output filename the inventory chose, not on anything rustnim did. `Borrow::borrow` yields a reference to the same value, and a reference is the value here. Not `RefCell::borrow`, which is a runtime borrow check returning a guard -- rustnim does not model `RefCell` at all, so there is nothing to confuse it with. `PartialEq::eq(a, b)` in the spelling the derived impls use, alongside the method form that was already there. `Ordering` needs its qualifier: `cmp::Ordering` and `atomic::Ordering` are different types that end in the same segment, and mapping on the last segment alone would have given an atomic's memory ordering a comparison type. A crate's own `Ordering` wins over both. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
211aebe parent: 8038a82 modified
src/lower.rs +33 -0 | @@ -1545,6 +1545,22 @@ impl Lowerer { | ||
| 1545 | 1545 | } |
| 1546 | 1546 | |
| 1547 | 1547 | fn map_ty_inner(&self, t: &syn::Type) -> Result<Nim, String> { |
| 1548 | + // `cmp::Ordering` and `atomic::Ordering` are different types that end | |
| 1549 | + // in the same segment, so this one needs the qualifier. A crate's own | |
| 1550 | + // `Ordering` wins over both. | |
| 1551 | + if let syn::Type::Path(p) = t { | |
| 1552 | + let segs: Vec<String> = | |
| 1553 | + p.path.segments.iter().map(|s| s.ident.to_string()).collect(); | |
| 1554 | + if segs.last().is_some_and(|n| n == "Ordering") | |
| 1555 | + && !self.enums.contains_key("Ordering") | |
| 1556 | + && !self.structs.contains_key("Ordering") | |
| 1557 | + { | |
| 1558 | + let atomic = segs.iter().any(|s| s == "atomic"); | |
| 1559 | + return Ok(Nim::Prim( | |
| 1560 | + if atomic { "MemoryOrder" } else { "RsOrdering" }.into(), | |
| 1561 | + )); | |
| 1562 | + } | |
| 1563 | + } | |
| 1548 | 1564 | // `Self::Item` names an associated type of the enclosing `impl`. |
| 1549 | 1565 | if let syn::Type::Path(p) = t { |
| 1550 | 1566 | let segs: Vec<String> = |
| @@ -7582,6 +7598,16 @@ impl Lowerer { | ||
| 7582 | 7598 | } |
| 7583 | 7599 | } |
| 7584 | 7600 | } |
| 7601 | + // `PartialEq::eq(a, b)` / `ne` in their free-function spelling, | |
| 7602 | + // which is what the derived impls use. | |
| 7603 | + "eq" | "ne" if codes.len() == 2 => { | |
| 7604 | + let op = if name == "eq" { "==" } else { "!=" }; | |
| 7605 | + let b = self.expr_at(&c.args[1], args[0].ty.as_ref())?; | |
| 7606 | + return Ok(Val::new( | |
| 7607 | + format!("({} {} {})", codes[0], op, b.code), | |
| 7608 | + Some(Nim::Prim("bool".into())), | |
| 7609 | + )); | |
| 7610 | + } | |
| 7585 | 7611 | // `cmp::max` / `cmp::min` are Nim's `max` / `min` on the same |
| 7586 | 7612 | // ordering. |
| 7587 | 7613 | "max" | "min" if codes.len() == 2 => { |
| @@ -8230,6 +8256,13 @@ impl Lowerer { | ||
| 8230 | 8256 | } |
| 8231 | 8257 | "clone" | "to_vec" | "to_owned" | "as_slice" | "as_ref" | "as_mut" | "iter" |
| 8232 | 8258 | | "into_iter" => (recv.code.clone(), rt.clone()), |
| 8259 | + // `Borrow::borrow` yields a reference to the same value, and a | |
| 8260 | + // reference *is* the value here. Not `RefCell::borrow`, which is | |
| 8261 | + // a runtime borrow check returning a guard -- rustnim does not | |
| 8262 | + // model `RefCell` at all, so there is nothing to confuse it with. | |
| 8263 | + "borrow" | "borrow_mut" if m.args.is_empty() => { | |
| 8264 | + (recv.code.clone(), rt.clone()) | |
| 8265 | + } | |
| 8233 | 8266 | "unwrap" | "expect" => { |
| 8234 | 8267 | // Expanded inline rather than called as a generic proc: when |
| 8235 | 8268 | // the payload is a view, Nim can only borrow from a path |
| @@ -1545,6 +1545,22 @@ impl Lowerer { | |||
| 1545 | } | 1545 | } |
| 1546 | 1546 | ||
| 1547 | fn map_ty_inner(&self, t: &syn::Type) -> Result<Nim, String> { | 1547 | fn map_ty_inner(&self, t: &syn::Type) -> Result<Nim, String> { |
| 1548 | + // `cmp::Ordering` and `atomic::Ordering` are different types that end | ||
| 1549 | + // in the same segment, so this one needs the qualifier. A crate's own | ||
| 1550 | + // `Ordering` wins over both. | ||
| 1551 | + if let syn::Type::Path(p) = t { | ||
| 1552 | + let segs: Vec<String> = | ||
| 1553 | + p.path.segments.iter().map(|s| s.ident.to_string()).collect(); | ||
| 1554 | + if segs.last().is_some_and(|n| n == "Ordering") | ||
| 1555 | + && !self.enums.contains_key("Ordering") | ||
| 1556 | + && !self.structs.contains_key("Ordering") | ||
| 1557 | + { | ||
| 1558 | + let atomic = segs.iter().any(|s| s == "atomic"); | ||
| 1559 | + return Ok(Nim::Prim( | ||
| 1560 | + if atomic { "MemoryOrder" } else { "RsOrdering" }.into(), | ||
| 1561 | + )); | ||
| 1562 | + } | ||
| 1563 | + } | ||
| 1548 | // `Self::Item` names an associated type of the enclosing `impl`. | 1564 | // `Self::Item` names an associated type of the enclosing `impl`. |
| 1549 | if let syn::Type::Path(p) = t { | 1565 | if let syn::Type::Path(p) = t { |
| 1550 | let segs: Vec<String> = | 1566 | let segs: Vec<String> = |
| @@ -7582,6 +7598,16 @@ impl Lowerer { | |||
| 7582 | } | 7598 | } |
| 7583 | } | 7599 | } |
| 7584 | } | 7600 | } |
| 7601 | + // `PartialEq::eq(a, b)` / `ne` in their free-function spelling, | ||
| 7602 | + // which is what the derived impls use. | ||
| 7603 | + "eq" | "ne" if codes.len() == 2 => { | ||
| 7604 | + let op = if name == "eq" { "==" } else { "!=" }; | ||
| 7605 | + let b = self.expr_at(&c.args[1], args[0].ty.as_ref())?; | ||
| 7606 | + return Ok(Val::new( | ||
| 7607 | + format!("({} {} {})", codes[0], op, b.code), | ||
| 7608 | + Some(Nim::Prim("bool".into())), | ||
| 7609 | + )); | ||
| 7610 | + } | ||
| 7585 | // `cmp::max` / `cmp::min` are Nim's `max` / `min` on the same | 7611 | // `cmp::max` / `cmp::min` are Nim's `max` / `min` on the same |
| 7586 | // ordering. | 7612 | // ordering. |
| 7587 | "max" | "min" if codes.len() == 2 => { | 7613 | "max" | "min" if codes.len() == 2 => { |
| @@ -8230,6 +8256,13 @@ impl Lowerer { | |||
| 8230 | } | 8256 | } |
| 8231 | "clone" | "to_vec" | "to_owned" | "as_slice" | "as_ref" | "as_mut" | "iter" | 8257 | "clone" | "to_vec" | "to_owned" | "as_slice" | "as_ref" | "as_mut" | "iter" |
| 8232 | | "into_iter" => (recv.code.clone(), rt.clone()), | 8258 | | "into_iter" => (recv.code.clone(), rt.clone()), |
| 8259 | + // `Borrow::borrow` yields a reference to the same value, and a | ||
| 8260 | + // reference *is* the value here. Not `RefCell::borrow`, which is | ||
| 8261 | + // a runtime borrow check returning a guard -- rustnim does not | ||
| 8262 | + // model `RefCell` at all, so there is nothing to confuse it with. | ||
| 8263 | + "borrow" | "borrow_mut" if m.args.is_empty() => { | ||
| 8264 | + (recv.code.clone(), rt.clone()) | ||
| 8265 | + } | ||
| 8233 | "unwrap" | "expect" => { | 8266 | "unwrap" | "expect" => { |
| 8234 | // Expanded inline rather than called as a generic proc: when | 8267 | // Expanded inline rather than called as a generic proc: when |
| 8235 | // the payload is a view, Nim can only borrow from a path | 8268 | // the payload is a view, Nim can only borrow from a path |