Report every unresolved opaque return type, not just the first
With a dependency graph in front of it, one report per run turns a list into a queue -- and reporting `left.first()` also made it look as though a function that resolves fine on its own had regressed, when it was only the first of several. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
113d857 parent: b714bd2 modified
src/lower.rs +31 -13 | @@ -2054,20 +2054,38 @@ impl Lowerer { | ||
| 2054 | 2054 | break; |
| 2055 | 2055 | } |
| 2056 | 2056 | } |
| 2057 | - if let Some((key, sig, _, _)) = left.first() { | |
| 2058 | - let what = match key { | |
| 2059 | - OpaqueKey::Free(_, n) => n.clone(), | |
| 2060 | - OpaqueKey::Method(t, n) => format!("{t}::{n}"), | |
| 2061 | - }; | |
| 2062 | - let ret = match &sig.output { | |
| 2063 | - ReturnType::Type(_, t) => quote::quote!(#t).to_string(), | |
| 2064 | - ReturnType::Default => String::new(), | |
| 2065 | - }; | |
| 2057 | + if !left.is_empty() { | |
| 2058 | + // Every one of them, not just the first: with a dependency graph | |
| 2059 | + // in front of it, one report per run turns a list into a queue. | |
| 2060 | + let mut names: Vec<String> = left | |
| 2061 | + .iter() | |
| 2062 | + .map(|(key, sig, _, _)| { | |
| 2063 | + let what = match key { | |
| 2064 | + OpaqueKey::Free(_, n) => n.clone(), | |
| 2065 | + OpaqueKey::Method(t, n) => format!("{t}::{n}"), | |
| 2066 | + }; | |
| 2067 | + let ret = match &sig.output { | |
| 2068 | + ReturnType::Type(_, t) => quote::quote!(#t).to_string(), | |
| 2069 | + ReturnType::Default => String::new(), | |
| 2070 | + }; | |
| 2071 | + format!(" {what}() -> {ret}") | |
| 2072 | + }) | |
| 2073 | + .collect(); | |
| 2074 | + names.sort(); | |
| 2075 | + names.dedup(); | |
| 2076 | + let shown: Vec<String> = names.iter().take(20).cloned().collect(); | |
| 2066 | 2077 | return Err(format!( |
| 2067 | - "`fn {what}() -> {ret}`: the concrete type behind the opaque \ | |
| 2068 | - return type could not be read off the body. Rust allows only \ | |
| 2069 | - one such type per function, so it is there -- rustnim could \ | |
| 2070 | - not work out what it is" | |
| 2078 | + "the concrete type behind {} opaque return type(s) could not \ | |
| 2079 | + be read off the body. Rust allows only one such type per \ | |
| 2080 | + function, so it is there -- rustnim could not work out what \ | |
| 2081 | + it is:\n{}{}", | |
| 2082 | + names.len(), | |
| 2083 | + shown.join("\n"), | |
| 2084 | + if names.len() > shown.len() { | |
| 2085 | + format!("\n ... and {} more", names.len() - shown.len()) | |
| 2086 | + } else { | |
| 2087 | + String::new() | |
| 2088 | + } | |
| 2071 | 2089 | )); |
| 2072 | 2090 | } |
| 2073 | 2091 | Ok(()) |
| @@ -2054,20 +2054,38 @@ impl Lowerer { | |||
| 2054 | break; | 2054 | break; |
| 2055 | } | 2055 | } |
| 2056 | } | 2056 | } |
| 2057 | - if let Some((key, sig, _, _)) = left.first() { | 2057 | + if !left.is_empty() { |
| 2058 | - let what = match key { | 2058 | + // Every one of them, not just the first: with a dependency graph |
| 2059 | - OpaqueKey::Free(_, n) => n.clone(), | 2059 | + // in front of it, one report per run turns a list into a queue. |
| 2060 | - OpaqueKey::Method(t, n) => format!("{t}::{n}"), | 2060 | + let mut names: Vec<String> = left |
| 2061 | - }; | 2061 | + .iter() |
| 2062 | - let ret = match &sig.output { | 2062 | + .map(|(key, sig, _, _)| { |
| 2063 | - ReturnType::Type(_, t) => quote::quote!(#t).to_string(), | 2063 | + let what = match key { |
| 2064 | - ReturnType::Default => String::new(), | 2064 | + OpaqueKey::Free(_, n) => n.clone(), |
| 2065 | - }; | 2065 | + OpaqueKey::Method(t, n) => format!("{t}::{n}"), |
| 2066 | + }; | ||
| 2067 | + let ret = match &sig.output { | ||
| 2068 | + ReturnType::Type(_, t) => quote::quote!(#t).to_string(), | ||
| 2069 | + ReturnType::Default => String::new(), | ||
| 2070 | + }; | ||
| 2071 | + format!(" {what}() -> {ret}") | ||
| 2072 | + }) | ||
| 2073 | + .collect(); | ||
| 2074 | + names.sort(); | ||
| 2075 | + names.dedup(); | ||
| 2076 | + let shown: Vec<String> = names.iter().take(20).cloned().collect(); | ||
| 2066 | return Err(format!( | 2077 | return Err(format!( |
| 2067 | - "`fn {what}() -> {ret}`: the concrete type behind the opaque \ | 2078 | + "the concrete type behind {} opaque return type(s) could not \ |
| 2068 | - return type could not be read off the body. Rust allows only \ | 2079 | + be read off the body. Rust allows only one such type per \ |
| 2069 | - one such type per function, so it is there -- rustnim could \ | 2080 | + function, so it is there -- rustnim could not work out what \ |
| 2070 | - not work out what it is" | 2081 | + it is:\n{}{}", |
| 2082 | + names.len(), | ||
| 2083 | + shown.join("\n"), | ||
| 2084 | + if names.len() > shown.len() { | ||
| 2085 | + format!("\n ... and {} more", names.len() - shown.len()) | ||
| 2086 | + } else { | ||
| 2087 | + String::new() | ||
| 2088 | + } | ||
| 2071 | )); | 2089 | )); |
| 2072 | } | 2090 | } |
| 2073 | Ok(()) | 2091 | Ok(()) |