| @@ -348,6 +348,9 @@ pub struct Lowerer { |
| 348 | /// Const generic parameters, by name, with their Nim type. Nim's `static` | 348 | /// Const generic parameters, by name, with their Nim type. Nim's `static` |
| 349 | /// parameter is the same thing: a generic parameter that is a value. | 349 | /// parameter is the same thing: a generic parameter that is a value. |
| 350 | const_gens: HashMap<String, String>, | 350 | const_gens: HashMap<String, String>, |
| | 351 | + /// Why the last opaque-return body failed to type, so the report can |
| | 352 | + /// say rather than only naming the function. |
| | 353 | + opaque_why: Option<String>, |
| 351 | /// Methods a `trait` declares, by `(trait, method)`, with the trait's own | 354 | /// Methods a `trait` declares, by `(trait, method)`, with the trait's own |
| 352 | /// generic parameters. Used to type a call on a value whose type is a | 355 | /// generic parameters. Used to type a call on a value whose type is a |
| 353 | /// generic parameter: `alternatives.choice(i)` where the parameter is | 356 | /// generic parameter: `alternatives.choice(i)` where the parameter is |
| @@ -446,6 +449,7 @@ impl Lowerer { |
| 446 | emitted_local: std::collections::HashSet::new(), | 449 | emitted_local: std::collections::HashSet::new(), |
| 447 | emitted_assoc: std::collections::HashSet::new(), | 450 | emitted_assoc: std::collections::HashSet::new(), |
| 448 | const_gens: HashMap::new(), | 451 | const_gens: HashMap::new(), |
| | 452 | + opaque_why: None, |
| 449 | trait_methods: HashMap::new(), | 453 | trait_methods: HashMap::new(), |
| 450 | bounds: HashMap::new(), | 454 | bounds: HashMap::new(), |
| 451 | const_names_at: std::cell::Cell::new(None), | 455 | const_names_at: std::cell::Cell::new(None), |
| @@ -2051,6 +2055,16 @@ impl Lowerer { |
| 2051 | /// means nothing until `c` is bound, which is what `pat_bind` does for | 2055 | /// means nothing until `c` is bound, which is what `pat_bind` does for |
| 2052 | /// the real lowering too. | 2056 | /// the real lowering too. |
| 2053 | 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); |
| | 2059 | + if r.is_none() && self.opaque_why.is_none() { |
| | 2060 | + if let Err(msg) = self.expr(e) { |
| | 2061 | + self.opaque_why = Some(msg); |
| | 2062 | + } |
| | 2063 | + } |
| | 2064 | + r |
| | 2065 | + } |
| | 2066 | + |
| | 2067 | + fn result_ty_inner(&mut self, e: &Expr) -> Option<Nim> { |
| 2054 | match e { | 2068 | match e { |
| 2055 | Expr::Match(m) => { | 2069 | Expr::Match(m) => { |
| 2056 | let scrut = self.expr(&m.expr).ok()?; | 2070 | let scrut = self.expr(&m.expr).ok()?; |
| @@ -2100,6 +2114,7 @@ impl Lowerer { |
| 2100 | fn resolve_opaque(&mut self) -> Result<(), String> { | 2114 | fn resolve_opaque(&mut self) -> Result<(), String> { |
| 2101 | let opaque = Nim::Named(OPAQUE.into(), Vec::new()); | 2115 | let opaque = Nim::Named(OPAQUE.into(), Vec::new()); |
| 2102 | let pending = std::mem::take(&mut self.opaque_fns); | 2116 | let pending = std::mem::take(&mut self.opaque_fns); |
| | 2117 | + let mut why: HashMap<String, String> = HashMap::new(); |
| 2103 | let mut left = pending.clone(); | 2118 | let mut left = pending.clone(); |
| 2104 | // One function's opaque type may be another's, so this iterates -- but | 2119 | // One function's opaque type may be another's, so this iterates -- but |
| 2105 | // it is bounded rather than run to exhaustion. Each round lowers every | 2120 | // it is bounded rather than run to exhaustion. Each round lowers every |
| @@ -2132,7 +2147,18 @@ impl Lowerer { |
| 2132 | } | 2147 | } |
| 2133 | progressed = true; | 2148 | progressed = true; |
| 2134 | } | 2149 | } |
| 2135 | - _ => still.push((key, sig, block, self_ty)), | 2150 | + _ => { |
| | 2151 | + if let Some(w) = self.opaque_why.take() { |
| | 2152 | + why.insert( |
| | 2153 | + match &key { |
| | 2154 | + OpaqueKey::Free(_, n) => n.clone(), |
| | 2155 | + OpaqueKey::Method(t, n) => format!("{t}::{n}"), |
| | 2156 | + }, |
| | 2157 | + w, |
| | 2158 | + ); |
| | 2159 | + } |
| | 2160 | + still.push((key, sig, block, self_ty)) |
| | 2161 | + } |
| 2136 | } | 2162 | } |
| 2137 | } | 2163 | } |
| 2138 | left = still; | 2164 | left = still; |
| @@ -2154,7 +2180,10 @@ impl Lowerer { |
| 2154 | ReturnType::Type(_, t) => quote::quote!(#t).to_string(), | 2180 | ReturnType::Type(_, t) => quote::quote!(#t).to_string(), |
| 2155 | ReturnType::Default => String::new(), | 2181 | ReturnType::Default => String::new(), |
| 2156 | }; | 2182 | }; |
| 2157 | - format!(" {what}() -> {ret}") | 2183 | + match why.get(&what) { |
| | 2184 | + Some(w) => format!(" {what}() -> {ret}\n {w}"), |
| | 2185 | + None => format!(" {what}() -> {ret}"), |
| | 2186 | + } |
| 2158 | }) | 2187 | }) |
| 2159 | .collect(); | 2188 | .collect(); |
| 2160 | names.sort(); | 2189 | names.sort(); |
| @@ -2230,6 +2259,7 @@ impl Lowerer { |
| 2230 | let saved_out = self.out.len(); | 2259 | let saved_out = self.out.len(); |
| 2231 | let saved_indent = self.indent; | 2260 | let saved_indent = self.indent; |
| 2232 | let saved_hoisted = self.hoisted.len(); | 2261 | let saved_hoisted = self.hoisted.len(); |
| | 2262 | + self.opaque_why = None; |
| 2233 | let found = self.result_ty(&tail); | 2263 | let found = self.result_ty(&tail); |
| 2234 | self.out.truncate(saved_out); | 2264 | self.out.truncate(saved_out); |
| 2235 | self.indent = saved_indent; | 2265 | self.indent = saved_indent; |