| @@ -2057,9 +2057,16 @@ impl Lowerer { |
| 2057 | fn result_ty(&mut self, e: &Expr) -> Option<Nim> { | 2057 | fn result_ty(&mut self, e: &Expr) -> Option<Nim> { |
| 2058 | let r = self.result_ty_inner(e); | 2058 | let r = self.result_ty_inner(e); |
| 2059 | if r.is_none() && self.opaque_why.is_none() { | 2059 | if r.is_none() && self.opaque_why.is_none() { |
| 2060 | - if let Err(msg) = self.expr(e) { | 2060 | + self.opaque_why = Some(match self.expr(e) { |
| 2061 | - self.opaque_why = Some(msg); | 2061 | + Err(msg) => msg, |
| 2062 | - } | 2062 | + // Lowered without complaint and still untyped. A different |
| | 2063 | + // thing from a refusal, and worth saying so: nothing is |
| | 2064 | + // missing from the lowering, it just has no type to report. |
| | 2065 | + Ok(_) => format!( |
| | 2066 | + "the body lowers but yields no type: `{}`", |
| | 2067 | + snippet("e::quote!(#e).to_string()) |
| | 2068 | + ), |
| | 2069 | + }); |
| 2063 | } | 2070 | } |
| 2064 | r | 2071 | r |
| 2065 | } | 2072 | } |
| @@ -2188,19 +2195,31 @@ impl Lowerer { |
| 2188 | .collect(); | 2195 | .collect(); |
| 2189 | names.sort(); | 2196 | names.sort(); |
| 2190 | names.dedup(); | 2197 | names.dedup(); |
| | 2198 | + // A histogram first: with seventy of these, which *causes* there |
| | 2199 | + // are matters more than which functions, and a truncated list of |
| | 2200 | + // names invites reading the first twenty as the whole picture. |
| | 2201 | + let mut counts: HashMap<String, usize> = HashMap::new(); |
| | 2202 | + for w in why.values() { |
| | 2203 | + let head = w.split(" -- `").next().unwrap_or(w).to_string(); |
| | 2204 | + *counts.entry(head).or_default() += 1; |
| | 2205 | + } |
| | 2206 | + let mut hist: Vec<(String, usize)> = counts.into_iter().collect(); |
| | 2207 | + hist.sort_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(&b.0))); |
| | 2208 | + let causes: Vec<String> = hist |
| | 2209 | + .iter() |
| | 2210 | + .map(|(w, n)| format!(" {n:>4} {w}")) |
| | 2211 | + .collect(); |
| 2191 | let shown: Vec<String> = names.iter().take(20).cloned().collect(); | 2212 | let shown: Vec<String> = names.iter().take(20).cloned().collect(); |
| 2192 | return Err(format!( | 2213 | return Err(format!( |
| 2193 | "the concrete type behind {} opaque return type(s) could not \ | 2214 | "the concrete type behind {} opaque return type(s) could not \ |
| 2194 | be read off the body. Rust allows only one such type per \ | 2215 | be read off the body. Rust allows only one such type per \ |
| 2195 | function, so it is there -- rustnim could not work out what \ | 2216 | function, so it is there -- rustnim could not work out what \ |
| 2196 | - it is:\n{}{}", | 2217 | + it is.\n\nby cause:\n{}\n\nfirst {} of {}:\n{}", |
| | 2218 | + names.len(), |
| | 2219 | + causes.join("\n"), |
| | 2220 | + shown.len(), |
| 2197 | names.len(), | 2221 | names.len(), |
| 2198 | shown.join("\n"), | 2222 | shown.join("\n"), |
| 2199 | - if names.len() > shown.len() { | | |
| 2200 | - format!("\n ... and {} more", names.len() - shown.len()) | | |
| 2201 | - } else { | | |
| 2202 | - String::new() | | |
| 2203 | - } | | |
| 2204 | )); | 2223 | )); |
| 2205 | } | 2224 | } |
| 2206 | Ok(()) | 2225 | Ok(()) |
| @@ -2213,16 +2232,27 @@ impl Lowerer { |
| 2213 | block: &syn::Block, | 2232 | block: &syn::Block, |
| 2214 | self_ty: Option<&Nim>, | 2233 | self_ty: Option<&Nim>, |
| 2215 | ) -> Option<Nim> { | 2234 | ) -> Option<Nim> { |
| 2216 | - let tail = block.stmts.iter().rev().find_map(|st| match st { | 2235 | + self.opaque_why = None; |
| | 2236 | + let Some(tail) = block.stmts.iter().rev().find_map(|st| match st { |
| 2217 | Stmt::Expr(e, None) => Some(e.clone()), | 2237 | Stmt::Expr(e, None) => Some(e.clone()), |
| 2218 | // `return e;` answers the same question. | 2238 | // `return e;` answers the same question. |
| 2219 | Stmt::Expr(Expr::Return(r), _) => r.expr.as_deref().cloned(), | 2239 | Stmt::Expr(Expr::Return(r), _) => r.expr.as_deref().cloned(), |
| 2220 | _ => None, | 2240 | _ => None, |
| 2221 | - })?; | 2241 | + }) else { |
| | 2242 | + self.opaque_why = |
| | 2243 | + Some("the body has no trailing expression to read a type from".into()); |
| | 2244 | + return None; |
| | 2245 | + }; |
| 2222 | | 2246 | |
| 2223 | // Parameters have to be in scope, or every mention of one is an | 2247 | // Parameters have to be in scope, or every mention of one is an |
| 2224 | // unknown name and the result types as nothing. | 2248 | // unknown name and the result types as nothing. |
| 2225 | - let (ptys, _) = self.signature(sig).ok()?; | 2249 | + let ptys = match self.signature(sig) { |
| | 2250 | + Ok((p, _)) => p, |
| | 2251 | + Err(e) => { |
| | 2252 | + self.opaque_why = Some(format!("the signature does not map: {e}")); |
| | 2253 | + return None; |
| | 2254 | + } |
| | 2255 | + }; |
| 2226 | self.push_scope(); | 2256 | self.push_scope(); |
| 2227 | // The receiver too: `match self { .. }` is the whole body of several | 2257 | // The receiver too: `match self { .. }` is the whole body of several |
| 2228 | // of these, and `self` is not a `FnArg::Typed`. | 2258 | // of these, and `self` is not a `FnArg::Typed`. |
| @@ -2259,7 +2289,6 @@ impl Lowerer { |
| 2259 | let saved_out = self.out.len(); | 2289 | let saved_out = self.out.len(); |
| 2260 | let saved_indent = self.indent; | 2290 | let saved_indent = self.indent; |
| 2261 | let saved_hoisted = self.hoisted.len(); | 2291 | let saved_hoisted = self.hoisted.len(); |
| 2262 | - self.opaque_why = None; | | |
| 2263 | let found = self.result_ty(&tail); | 2292 | let found = self.result_ty(&tail); |
| 2264 | self.out.truncate(saved_out); | 2293 | self.out.truncate(saved_out); |
| 2265 | self.indent = saved_indent; | 2294 | self.indent = saved_indent; |