nandi/rustnimpublic Fork
⑂ 670d6a7
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Say why an opaque return type could not be read

The report named the functions and stopped there, which left every one of
them a separate investigation. It now carries the error the body actually
failed with, so the list sorts into causes:

    7   only calls to named functions are supported
    7   a closure body with statements is not implemented yet
    2   cannot infer the type of closure parameter `e`
    1   `match` in value position
    ...

Those are ordinary gaps in the lowering, not anything exotic about opaque
types -- which is the useful thing to know, and was invisible while the reason
was being swallowed by `.ok()`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T19:27:13-07:00 Browse files
670d6a7 parent: f3e08c6
modified src/lower.rs +32 -2
@@ -348,6 +348,9 @@ pub struct Lowerer {
348348 /// Const generic parameters, by name, with their Nim type. Nim's `static`
349349 /// parameter is the same thing: a generic parameter that is a value.
350350 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>,
351354 /// Methods a `trait` declares, by `(trait, method)`, with the trait's own
352355 /// generic parameters. Used to type a call on a value whose type is a
353356 /// generic parameter: `alternatives.choice(i)` where the parameter is
@@ -446,6 +449,7 @@ impl Lowerer {
446449 emitted_local: std::collections::HashSet::new(),
447450 emitted_assoc: std::collections::HashSet::new(),
448451 const_gens: HashMap::new(),
452+ opaque_why: None,
449453 trait_methods: HashMap::new(),
450454 bounds: HashMap::new(),
451455 const_names_at: std::cell::Cell::new(None),
@@ -2051,6 +2055,16 @@ impl Lowerer {
20512055 /// means nothing until `c` is bound, which is what `pat_bind` does for
20522056 /// the real lowering too.
20532057 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> {
20542068 match e {
20552069 Expr::Match(m) => {
20562070 let scrut = self.expr(&m.expr).ok()?;
@@ -2100,6 +2114,7 @@ impl Lowerer {
21002114 fn resolve_opaque(&mut self) -> Result<(), String> {
21012115 let opaque = Nim::Named(OPAQUE.into(), Vec::new());
21022116 let pending = std::mem::take(&mut self.opaque_fns);
2117+ let mut why: HashMap<String, String> = HashMap::new();
21032118 let mut left = pending.clone();
21042119 // One function's opaque type may be another's, so this iterates -- but
21052120 // it is bounded rather than run to exhaustion. Each round lowers every
@@ -2132,7 +2147,18 @@ impl Lowerer {
21322147 }
21332148 progressed = true;
21342149 }
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+ }
21362162 }
21372163 }
21382164 left = still;
@@ -2154,7 +2180,10 @@ impl Lowerer {
21542180 ReturnType::Type(_, t) => quote::quote!(#t).to_string(),
21552181 ReturnType::Default => String::new(),
21562182 };
2157- format!(" {what}() -> {ret}")
2183+ match why.get(&what) {
2184+ Some(w) => format!(" {what}() -> {ret}\n {w}"),
2185+ None => format!(" {what}() -> {ret}"),
2186+ }
21582187 })
21592188 .collect();
21602189 names.sort();
@@ -2230,6 +2259,7 @@ impl Lowerer {
22302259 let saved_out = self.out.len();
22312260 let saved_indent = self.indent;
22322261 let saved_hoisted = self.hoisted.len();
2262+ self.opaque_why = None;
22332263 let found = self.result_ty(&tail);
22342264 self.out.truncate(saved_out);
22352265 self.indent = saved_indent;
@@ -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 own354 /// 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 a355 /// generic parameters. Used to type a call on a value whose type is a
353 /// generic parameter: `alternatives.choice(i)` where the parameter is356 /// 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 for2055 /// 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 -- but2119 // 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 every2120 // 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;