nandi/rustnimpublic Fork
⑂ 2eee1c9
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

Lower nested argument-position `impl Trait`

`fn f(x: Option<impl Label>)` is the same desugaring as `fn f(x: impl Label)`
-- a generic parameter -- but rustnim only recognised the bare form, so the
nested one fell through to `ty::map` and was reported as a return-position
opaque type, which it is not. `iced` writes it.

`rewrite_apit` now walks a parameter type and replaces every `impl Trait`
without a direct mapping with a fresh parameter, in source order; both the
generics list and the signature go through it, so the name invented for a
given position always agrees. `impl Iterator`/`impl Fn`/`impl Future` are
untouched, since those have real Nim equivalents already.

Two call-site consequences, both fixed here:

  * A parameter type mentioning the *callee's* type variables is useless as an
    expectation -- `ImplT1` names nothing at the call site -- so it is no
    longer handed down. `mentions_any` decides that.
  * With the expectation gone, `Some(x)` falls back to the payload's own type,
    and `None::<T>` reads its turbofish. Both are more accurate than what they
    replace, not just sufficient here.

Also accepts `impl DoubleEndedIterator` / `impl ExactSizeIterator` in return
position: the forward half is exactly a Nim closure iterator, and the extra
capabilities are not approximated -- `next_back`, `rev` and `len` are simply
not implemented, so they are rejected at the call site like anything else.

tests/cases/050.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T09:27:16-07:00 Browse files
2eee1c9 parent: abb295c
modified src/lower.rs +130 -31
@@ -1197,6 +1197,31 @@ impl Lowerer {
11971197 }
11981198 }
11991199
1200+ /// Whether a type mentions one of the *callee's* type parameters.
1201+ ///
1202+ /// Such a type is useless as an expectation at a call site: `T` names
1203+ /// nothing there, and handing it down would annotate a construction with
1204+ /// an unbound identifier. The argument is lowered without an expectation
1205+ /// instead, and Nim infers the instantiation -- which is what it does for
1206+ /// a generic call anyway.
1207+ fn mentions_any(t: &Nim, names: &[String]) -> bool {
1208+ if names.is_empty() {
1209+ return false;
1210+ }
1211+ match t {
1212+ Nim::Named(n, a) => {
1213+ names.iter().any(|g| g == n) || a.iter().any(|x| Self::mentions_any(x, names))
1214+ }
1215+ Nim::Seq(e) | Nim::OpenArray(e) | Nim::Var(e) | Nim::Array(_, e) | Nim::Ptr(e)
1216+ | Nim::ConstPtr(e) | Nim::Iter(e) | Nim::Future(e) => Self::mentions_any(e, names),
1217+ Nim::Tuple(ts) => ts.iter().any(|x| Self::mentions_any(x, names)),
1218+ Nim::Proc(a, r) => {
1219+ a.iter().any(|x| Self::mentions_any(x, names)) || Self::mentions_any(r, names)
1220+ }
1221+ _ => false,
1222+ }
1223+ }
1224+
12001225 fn subst(t: &Nim, m: &HashMap<String, Nim>) -> Nim {
12011226 match t {
12021227 Nim::Named(n, a) if a.is_empty() => m.get(n).cloned().unwrap_or_else(|| t.clone()),
@@ -1357,15 +1382,62 @@ impl Lowerer {
13571382 /// bound is dropped like any other, so what is left is a fresh parameter.
13581383 /// In return position it is an opaque type instead, and has no equivalent.
13591384 fn impl_trait_params(&self, sig: &syn::Signature) -> Vec<String> {
1360- let mut out = Vec::new();
1385+ let mut n = 0usize;
13611386 for a in &sig.inputs {
13621387 if let FnArg::Typed(t) = a {
1363- if matches!(&*t.ty, syn::Type::ImplTrait(_)) && self.map_ty(&t.ty).is_err() {
1364- out.push(format!("ImplT{}", out.len() + 1));
1388+ self.rewrite_apit(&t.ty, &mut n);
1389+ }
1390+ }
1391+ (1..=n).map(|i| format!("ImplT{i}")).collect()
1392+ }
1393+
1394+ /// Replace every `impl Trait` in a parameter type that has no direct
1395+ /// mapping with a fresh generic parameter, naming them in source order.
1396+ ///
1397+ /// The desugaring is not only for a *bare* `impl Trait` parameter:
1398+ /// `Option<impl Into<X>>` is a generic parameter too, in exactly the same
1399+ /// way, and `iced` writes it. Traits that do have a direct mapping --
1400+ /// `impl Iterator`, `impl Fn`, `impl Future` -- are left alone, since
1401+ /// `map_ty` already produces the real Nim equivalent for those.
1402+ ///
1403+ /// Both this and `signature` walk with the same helper, so the parameter
1404+ /// they invent for a given position always carries the same name.
1405+ fn rewrite_apit(&self, ty: &syn::Type, next: &mut usize) -> syn::Type {
1406+ use syn::Type;
1407+ if let Type::ImplTrait(_) = ty {
1408+ if self.map_ty(ty).is_err() {
1409+ *next += 1;
1410+ let name = format!("ImplT{next}");
1411+ return syn::parse_str::<Type>(&name).expect("generated ident parses");
1412+ }
1413+ return ty.clone();
1414+ }
1415+ let mut ty = ty.clone();
1416+ match &mut ty {
1417+ Type::Reference(r) => *r.elem = self.rewrite_apit(&r.elem, next),
1418+ Type::Slice(sl) => *sl.elem = self.rewrite_apit(&sl.elem, next),
1419+ Type::Array(a) => *a.elem = self.rewrite_apit(&a.elem, next),
1420+ Type::Paren(p) => *p.elem = self.rewrite_apit(&p.elem, next),
1421+ Type::Group(g) => *g.elem = self.rewrite_apit(&g.elem, next),
1422+ Type::Tuple(t) => {
1423+ for e in t.elems.iter_mut() {
1424+ *e = self.rewrite_apit(e, next);
1425+ }
1426+ }
1427+ Type::Path(p) => {
1428+ for seg in p.path.segments.iter_mut() {
1429+ if let syn::PathArguments::AngleBracketed(a) = &mut seg.arguments {
1430+ for g in a.args.iter_mut() {
1431+ if let syn::GenericArgument::Type(t) = g {
1432+ *t = self.rewrite_apit(t, next);
1433+ }
1434+ }
1435+ }
13651436 }
13661437 }
1438+ _ => {}
13671439 }
1368- out
1440+ ty
13691441 }
13701442
13711443 fn signature(&self, sig: &syn::Signature) -> Result<(Vec<Nim>, Nim), String> {
@@ -1385,17 +1457,8 @@ impl Lowerer {
13851457 let mut fresh = 0usize;
13861458 for a in &sig.inputs {
13871459 if let FnArg::Typed(t) = a {
1388- match self.map_ty(&t.ty) {
1389- Ok(n) => params.push(n),
1390- Err(e) => {
1391- if matches!(&*t.ty, syn::Type::ImplTrait(_)) {
1392- fresh += 1;
1393- params.push(Nim::Named(format!("ImplT{fresh}"), vec![]));
1394- } else {
1395- return Err(e);
1396- }
1397- }
1398- }
1460+ let rewritten = self.rewrite_apit(&t.ty, &mut fresh);
1461+ params.push(self.map_ty(&rewritten)?);
13991462 }
14001463 }
14011464 let ret = match &sig.output {
@@ -3874,7 +3937,23 @@ impl Lowerer {
38743937 Expr::Path(p) => {
38753938 let name = path_name(&p.path);
38763939 if name == "None" {
3877- return Ok(Val::new(self.none_of(expect), expect.cloned()));
3940+ // `None::<T>` says the type itself, and is the only thing
3941+ // that does when the expectation is a callee's type
3942+ // variable rather than a type.
3943+ let tf = p.path.segments.last().and_then(|seg| match &seg.arguments {
3944+ syn::PathArguments::AngleBracketed(a) => {
3945+ a.args.iter().find_map(|g| match g {
3946+ syn::GenericArgument::Type(t) => self.map_ty(t).ok(),
3947+ _ => None,
3948+ })
3949+ }
3950+ _ => None,
3951+ });
3952+ let want = match tf {
3953+ Some(t) => Some(Nim::Named("Option".into(), vec![t.owned()])),
3954+ None => expect.cloned(),
3955+ };
3956+ return Ok(Val::new(self.none_of(want.as_ref()), want));
38783957 }
38793958 // `Ordering::SeqCst` and friends. Nim's names differ but the
38803959 // set is the same, and both mean the C11 ordering.
@@ -5022,14 +5101,12 @@ impl Lowerer {
50225101 }
50235102
50245103 let target = self.resolve_fn(&p.path);
5025- let ptys: Vec<Nim> = target
5026- .as_ref()
5027- .and_then(|k| self.fns.get(k))
5028- .map(|s| s.params.clone())
5029- .unwrap_or_default();
5104+ let callee = target.as_ref().and_then(|k| self.fns.get(k));
5105+ let cgen: Vec<String> = callee.map(|s| s.generics.clone()).unwrap_or_default();
5106+ let ptys: Vec<Nim> = callee.map(|s| s.params.clone()).unwrap_or_default();
50305107 let mut args = Vec::new();
50315108 for (i, a) in c.args.iter().enumerate() {
5032- let want = ptys.get(i).cloned();
5109+ let want = ptys.get(i).cloned().filter(|t| !Self::mentions_any(t, &cgen));
50335110 args.push(self.expr_at(a, want.as_ref())?);
50345111 }
50355112 let codes: Vec<String> = args.iter().map(|a| a.code.clone()).collect();
@@ -5039,17 +5116,31 @@ impl Lowerer {
50395116 // being constructed: Nim cannot infer `E` from an `Ok(v)` alone.
50405117 match name.as_str() {
50415118 "Some" => {
5042- let inner = match expect {
5043- Some(Nim::Named(n, a)) if n == "Option" && a.len() == 1 => a[0].render(),
5044- _ => {
5045- return Err("`Some(..)` needs a known `Option<T>` type here; \
5046- annotate the binding or the return type"
5047- .into())
5119+ // The expectation names `T` when there is one. Failing that,
5120+ // the payload's own type does: `Some(x)` is an `Option<T>` for
5121+ // whatever `x` is. That second route is what makes
5122+ // `f(Some(Tag(1)))` work when `f` takes `Option<impl Trait>` --
5123+ // there the parameter type is the callee's type variable,
5124+ // which names nothing at the call site.
5125+ let (inner, ty) = match expect {
5126+ Some(Nim::Named(n, a)) if n == "Option" && a.len() == 1 => {
5127+ (a[0].render(), expect.cloned())
50485128 }
5129+ _ => match args.first().and_then(|a| a.ty.clone()) {
5130+ Some(t) => {
5131+ let t = t.owned();
5132+ (t.render(), Some(Nim::Named("Option".into(), vec![t])))
5133+ }
5134+ None => {
5135+ return Err("`Some(..)` needs a known `Option<T>` type here; \
5136+ annotate the binding or the return type"
5137+ .into())
5138+ }
5139+ },
50495140 };
50505141 return Ok(Val::new(
50515142 format!("rsSome[{}]({})", inner, codes.join(", ")),
5052- expect.cloned(),
5143+ ty,
50535144 ));
50545145 }
50555146 "Ok" if self.fmt_param.is_some()
@@ -5371,8 +5462,9 @@ impl Lowerer {
53715462 let declared = sig.params.clone();
53725463 let mut args = args.clone();
53735464 let mut codes = codes.clone();
5465+ let cgen = sig.generics.clone();
53745466 for (i, a) in c.args.iter().enumerate() {
5375- if let Some(want) = declared.get(i) {
5467+ if let Some(want) = declared.get(i).filter(|t| !Self::mentions_any(t, &cgen)) {
53765468 let want = want.clone().unvar();
53775469 args[i] = self.expr_at(a, Some(&want))?;
53785470 codes[i] = args[i].code.clone();
@@ -6034,11 +6126,18 @@ impl Lowerer {
60346126 .as_ref()
60356127 .and_then(|k| self.methods.get(k))
60366128 .map(|s| s.params.clone());
6129+ let cgen: Vec<String> = key
6130+ .as_ref()
6131+ .and_then(|k| self.methods.get(k))
6132+ .map(|s| s.generics.clone())
6133+ .unwrap_or_default();
60376134 if let Some(d) = &declared {
60386135 // params[0] is the receiver for a method with `self`.
60396136 let skip = usize::from(d.len() == m.args.len() + 1);
60406137 for (i, a) in m.args.iter().enumerate() {
6041- if let Some(want) = d.get(i + skip) {
6138+ if let Some(want) =
6139+ d.get(i + skip).filter(|t| !Self::mentions_any(t, &cgen))
6140+ {
60426141 let want = want.clone().unvar();
60436142 args[i] = self.expr_at(a, Some(&want))?;
60446143 }
@@ -1197,6 +1197,31 @@ impl Lowerer {
1197 }1197 }
1198 }1198 }
1199 1199
1200+ /// Whether a type mentions one of the *callee's* type parameters.
1201+ ///
1202+ /// Such a type is useless as an expectation at a call site: `T` names
1203+ /// nothing there, and handing it down would annotate a construction with
1204+ /// an unbound identifier. The argument is lowered without an expectation
1205+ /// instead, and Nim infers the instantiation -- which is what it does for
1206+ /// a generic call anyway.
1207+ fn mentions_any(t: &Nim, names: &[String]) -> bool {
1208+ if names.is_empty() {
1209+ return false;
1210+ }
1211+ match t {
1212+ Nim::Named(n, a) => {
1213+ names.iter().any(|g| g == n) || a.iter().any(|x| Self::mentions_any(x, names))
1214+ }
1215+ Nim::Seq(e) | Nim::OpenArray(e) | Nim::Var(e) | Nim::Array(_, e) | Nim::Ptr(e)
1216+ | Nim::ConstPtr(e) | Nim::Iter(e) | Nim::Future(e) => Self::mentions_any(e, names),
1217+ Nim::Tuple(ts) => ts.iter().any(|x| Self::mentions_any(x, names)),
1218+ Nim::Proc(a, r) => {
1219+ a.iter().any(|x| Self::mentions_any(x, names)) || Self::mentions_any(r, names)
1220+ }
1221+ _ => false,
1222+ }
1223+ }
1224+
1200 fn subst(t: &Nim, m: &HashMap<String, Nim>) -> Nim {1225 fn subst(t: &Nim, m: &HashMap<String, Nim>) -> Nim {
1201 match t {1226 match t {
1202 Nim::Named(n, a) if a.is_empty() => m.get(n).cloned().unwrap_or_else(|| t.clone()),1227 Nim::Named(n, a) if a.is_empty() => m.get(n).cloned().unwrap_or_else(|| t.clone()),
@@ -1357,15 +1382,62 @@ impl Lowerer {
1357 /// bound is dropped like any other, so what is left is a fresh parameter.1382 /// bound is dropped like any other, so what is left is a fresh parameter.
1358 /// In return position it is an opaque type instead, and has no equivalent.1383 /// In return position it is an opaque type instead, and has no equivalent.
1359 fn impl_trait_params(&self, sig: &syn::Signature) -> Vec<String> {1384 fn impl_trait_params(&self, sig: &syn::Signature) -> Vec<String> {
1360- let mut out = Vec::new();1385+ let mut n = 0usize;
1361 for a in &sig.inputs {1386 for a in &sig.inputs {
1362 if let FnArg::Typed(t) = a {1387 if let FnArg::Typed(t) = a {
1363- if matches!(&*t.ty, syn::Type::ImplTrait(_)) && self.map_ty(&t.ty).is_err() {1388+ self.rewrite_apit(&t.ty, &mut n);
1364- out.push(format!("ImplT{}", out.len() + 1));1389+ }
1390+ }
1391+ (1..=n).map(|i| format!("ImplT{i}")).collect()
1392+ }
1393+
1394+ /// Replace every `impl Trait` in a parameter type that has no direct
1395+ /// mapping with a fresh generic parameter, naming them in source order.
1396+ ///
1397+ /// The desugaring is not only for a *bare* `impl Trait` parameter:
1398+ /// `Option<impl Into<X>>` is a generic parameter too, in exactly the same
1399+ /// way, and `iced` writes it. Traits that do have a direct mapping --
1400+ /// `impl Iterator`, `impl Fn`, `impl Future` -- are left alone, since
1401+ /// `map_ty` already produces the real Nim equivalent for those.
1402+ ///
1403+ /// Both this and `signature` walk with the same helper, so the parameter
1404+ /// they invent for a given position always carries the same name.
1405+ fn rewrite_apit(&self, ty: &syn::Type, next: &mut usize) -> syn::Type {
1406+ use syn::Type;
1407+ if let Type::ImplTrait(_) = ty {
1408+ if self.map_ty(ty).is_err() {
1409+ *next += 1;
1410+ let name = format!("ImplT{next}");
1411+ return syn::parse_str::<Type>(&name).expect("generated ident parses");
1412+ }
1413+ return ty.clone();
1414+ }
1415+ let mut ty = ty.clone();
1416+ match &mut ty {
1417+ Type::Reference(r) => *r.elem = self.rewrite_apit(&r.elem, next),
1418+ Type::Slice(sl) => *sl.elem = self.rewrite_apit(&sl.elem, next),
1419+ Type::Array(a) => *a.elem = self.rewrite_apit(&a.elem, next),
1420+ Type::Paren(p) => *p.elem = self.rewrite_apit(&p.elem, next),
1421+ Type::Group(g) => *g.elem = self.rewrite_apit(&g.elem, next),
1422+ Type::Tuple(t) => {
1423+ for e in t.elems.iter_mut() {
1424+ *e = self.rewrite_apit(e, next);
1425+ }
1426+ }
1427+ Type::Path(p) => {
1428+ for seg in p.path.segments.iter_mut() {
1429+ if let syn::PathArguments::AngleBracketed(a) = &mut seg.arguments {
1430+ for g in a.args.iter_mut() {
1431+ if let syn::GenericArgument::Type(t) = g {
1432+ *t = self.rewrite_apit(t, next);
1433+ }
1434+ }
1435+ }
1365 }1436 }
1366 }1437 }
1438+ _ => {}
1367 }1439 }
1368- out1440+ ty
1369 }1441 }
1370 1442
1371 fn signature(&self, sig: &syn::Signature) -> Result<(Vec<Nim>, Nim), String> {1443 fn signature(&self, sig: &syn::Signature) -> Result<(Vec<Nim>, Nim), String> {
@@ -1385,17 +1457,8 @@ impl Lowerer {
1385 let mut fresh = 0usize;1457 let mut fresh = 0usize;
1386 for a in &sig.inputs {1458 for a in &sig.inputs {
1387 if let FnArg::Typed(t) = a {1459 if let FnArg::Typed(t) = a {
1388- match self.map_ty(&t.ty) {1460+ let rewritten = self.rewrite_apit(&t.ty, &mut fresh);
1389- Ok(n) => params.push(n),1461+ params.push(self.map_ty(&rewritten)?);
1390- Err(e) => {
1391- if matches!(&*t.ty, syn::Type::ImplTrait(_)) {
1392- fresh += 1;
1393- params.push(Nim::Named(format!("ImplT{fresh}"), vec![]));
1394- } else {
1395- return Err(e);
1396- }
1397- }
1398- }
1399 }1462 }
1400 }1463 }
1401 let ret = match &sig.output {1464 let ret = match &sig.output {
@@ -3874,7 +3937,23 @@ impl Lowerer {
3874 Expr::Path(p) => {3937 Expr::Path(p) => {
3875 let name = path_name(&p.path);3938 let name = path_name(&p.path);
3876 if name == "None" {3939 if name == "None" {
3877- return Ok(Val::new(self.none_of(expect), expect.cloned()));3940+ // `None::<T>` says the type itself, and is the only thing
3941+ // that does when the expectation is a callee's type
3942+ // variable rather than a type.
3943+ let tf = p.path.segments.last().and_then(|seg| match &seg.arguments {
3944+ syn::PathArguments::AngleBracketed(a) => {
3945+ a.args.iter().find_map(|g| match g {
3946+ syn::GenericArgument::Type(t) => self.map_ty(t).ok(),
3947+ _ => None,
3948+ })
3949+ }
3950+ _ => None,
3951+ });
3952+ let want = match tf {
3953+ Some(t) => Some(Nim::Named("Option".into(), vec![t.owned()])),
3954+ None => expect.cloned(),
3955+ };
3956+ return Ok(Val::new(self.none_of(want.as_ref()), want));
3878 }3957 }
3879 // `Ordering::SeqCst` and friends. Nim's names differ but the3958 // `Ordering::SeqCst` and friends. Nim's names differ but the
3880 // set is the same, and both mean the C11 ordering.3959 // set is the same, and both mean the C11 ordering.
@@ -5022,14 +5101,12 @@ impl Lowerer {
5022 }5101 }
5023 5102
5024 let target = self.resolve_fn(&p.path);5103 let target = self.resolve_fn(&p.path);
5025- let ptys: Vec<Nim> = target5104+ let callee = target.as_ref().and_then(|k| self.fns.get(k));
5026- .as_ref()5105+ let cgen: Vec<String> = callee.map(|s| s.generics.clone()).unwrap_or_default();
5027- .and_then(|k| self.fns.get(k))5106+ let ptys: Vec<Nim> = callee.map(|s| s.params.clone()).unwrap_or_default();
5028- .map(|s| s.params.clone())
5029- .unwrap_or_default();
5030 let mut args = Vec::new();5107 let mut args = Vec::new();
5031 for (i, a) in c.args.iter().enumerate() {5108 for (i, a) in c.args.iter().enumerate() {
5032- let want = ptys.get(i).cloned();5109+ let want = ptys.get(i).cloned().filter(|t| !Self::mentions_any(t, &cgen));
5033 args.push(self.expr_at(a, want.as_ref())?);5110 args.push(self.expr_at(a, want.as_ref())?);
5034 }5111 }
5035 let codes: Vec<String> = args.iter().map(|a| a.code.clone()).collect();5112 let codes: Vec<String> = args.iter().map(|a| a.code.clone()).collect();
@@ -5039,17 +5116,31 @@ impl Lowerer {
5039 // being constructed: Nim cannot infer `E` from an `Ok(v)` alone.5116 // being constructed: Nim cannot infer `E` from an `Ok(v)` alone.
5040 match name.as_str() {5117 match name.as_str() {
5041 "Some" => {5118 "Some" => {
5042- let inner = match expect {5119+ // The expectation names `T` when there is one. Failing that,
5043- Some(Nim::Named(n, a)) if n == "Option" && a.len() == 1 => a[0].render(),5120+ // the payload's own type does: `Some(x)` is an `Option<T>` for
5044- _ => {5121+ // whatever `x` is. That second route is what makes
5045- return Err("`Some(..)` needs a known `Option<T>` type here; \5122+ // `f(Some(Tag(1)))` work when `f` takes `Option<impl Trait>` --
5046- annotate the binding or the return type"5123+ // there the parameter type is the callee's type variable,
5047- .into())5124+ // which names nothing at the call site.
5125+ let (inner, ty) = match expect {
5126+ Some(Nim::Named(n, a)) if n == "Option" && a.len() == 1 => {
5127+ (a[0].render(), expect.cloned())
5048 }5128 }
5129+ _ => match args.first().and_then(|a| a.ty.clone()) {
5130+ Some(t) => {
5131+ let t = t.owned();
5132+ (t.render(), Some(Nim::Named("Option".into(), vec![t])))
5133+ }
5134+ None => {
5135+ return Err("`Some(..)` needs a known `Option<T>` type here; \
5136+ annotate the binding or the return type"
5137+ .into())
5138+ }
5139+ },
5049 };5140 };
5050 return Ok(Val::new(5141 return Ok(Val::new(
5051 format!("rsSome[{}]({})", inner, codes.join(", ")),5142 format!("rsSome[{}]({})", inner, codes.join(", ")),
5052- expect.cloned(),5143+ ty,
5053 ));5144 ));
5054 }5145 }
5055 "Ok" if self.fmt_param.is_some()5146 "Ok" if self.fmt_param.is_some()
@@ -5371,8 +5462,9 @@ impl Lowerer {
5371 let declared = sig.params.clone();5462 let declared = sig.params.clone();
5372 let mut args = args.clone();5463 let mut args = args.clone();
5373 let mut codes = codes.clone();5464 let mut codes = codes.clone();
5465+ let cgen = sig.generics.clone();
5374 for (i, a) in c.args.iter().enumerate() {5466 for (i, a) in c.args.iter().enumerate() {
5375- if let Some(want) = declared.get(i) {5467+ if let Some(want) = declared.get(i).filter(|t| !Self::mentions_any(t, &cgen)) {
5376 let want = want.clone().unvar();5468 let want = want.clone().unvar();
5377 args[i] = self.expr_at(a, Some(&want))?;5469 args[i] = self.expr_at(a, Some(&want))?;
5378 codes[i] = args[i].code.clone();5470 codes[i] = args[i].code.clone();
@@ -6034,11 +6126,18 @@ impl Lowerer {
6034 .as_ref()6126 .as_ref()
6035 .and_then(|k| self.methods.get(k))6127 .and_then(|k| self.methods.get(k))
6036 .map(|s| s.params.clone());6128 .map(|s| s.params.clone());
6129+ let cgen: Vec<String> = key
6130+ .as_ref()
6131+ .and_then(|k| self.methods.get(k))
6132+ .map(|s| s.generics.clone())
6133+ .unwrap_or_default();
6037 if let Some(d) = &declared {6134 if let Some(d) = &declared {
6038 // params[0] is the receiver for a method with `self`.6135 // params[0] is the receiver for a method with `self`.
6039 let skip = usize::from(d.len() == m.args.len() + 1);6136 let skip = usize::from(d.len() == m.args.len() + 1);
6040 for (i, a) in m.args.iter().enumerate() {6137 for (i, a) in m.args.iter().enumerate() {
6041- if let Some(want) = d.get(i + skip) {6138+ if let Some(want) =
6139+ d.get(i + skip).filter(|t| !Self::mentions_any(t, &cgen))
6140+ {
6042 let want = want.clone().unvar();6141 let want = want.clone().unvar();
6043 args[i] = self.expr_at(a, Some(&want))?;6142 args[i] = self.expr_at(a, Some(&want))?;
6044 }6143 }
modified src/ty.rs +12 -1
@@ -438,7 +438,18 @@ pub fn map(t: &Type) -> Result<Nim, String> {
438438 // `impl Iterator<Item = T>`: Nim's closure iterator is
439439 // lazy and first-class as Rust's is, so this is a real
440440 // equivalent rather than a materialised `seq`.
441- if seg.ident == "Iterator" || seg.ident == "IntoIterator" {
441+ // `DoubleEndedIterator` and `ExactSizeIterator` are
442+ // subtraits of `Iterator`; the *forward* half is what
443+ // a Nim closure iterator is, exactly. The extra
444+ // capabilities are not approximated -- they are simply
445+ // not implemented, so `next_back`, `rev` and `len` on
446+ // the result are rejected at the call site like any
447+ // other unsupported method.
448+ if seg.ident == "Iterator"
449+ || seg.ident == "IntoIterator"
450+ || seg.ident == "DoubleEndedIterator"
451+ || seg.ident == "ExactSizeIterator"
452+ {
442453 if let PathArguments::AngleBracketed(a) = &seg.arguments {
443454 for g in &a.args {
444455 if let GenericArgument::AssocType(at) = g {
@@ -438,7 +438,18 @@ pub fn map(t: &Type) -> Result<Nim, String> {
438 // `impl Iterator<Item = T>`: Nim's closure iterator is438 // `impl Iterator<Item = T>`: Nim's closure iterator is
439 // lazy and first-class as Rust's is, so this is a real439 // lazy and first-class as Rust's is, so this is a real
440 // equivalent rather than a materialised `seq`.440 // equivalent rather than a materialised `seq`.
441- if seg.ident == "Iterator" || seg.ident == "IntoIterator" {441+ // `DoubleEndedIterator` and `ExactSizeIterator` are
442+ // subtraits of `Iterator`; the *forward* half is what
443+ // a Nim closure iterator is, exactly. The extra
444+ // capabilities are not approximated -- they are simply
445+ // not implemented, so `next_back`, `rev` and `len` on
446+ // the result are rejected at the call site like any
447+ // other unsupported method.
448+ if seg.ident == "Iterator"
449+ || seg.ident == "IntoIterator"
450+ || seg.ident == "DoubleEndedIterator"
451+ || seg.ident == "ExactSizeIterator"
452+ {
442 if let PathArguments::AngleBracketed(a) = &seg.arguments {453 if let PathArguments::AngleBracketed(a) = &seg.arguments {
443 for g in &a.args {454 for g in &a.args {
444 if let GenericArgument::AssocType(at) = g {455 if let GenericArgument::AssocType(at) = g {
added tests/cases/050-nested-impl-trait.rs +32 -0
new file mode 100644
@@ -0,0 +1,32 @@
1+// `impl Trait` in argument position is a generic parameter — including when it
2+// is nested inside another type. `Option<impl Trait>` is not a return-position
3+// opaque type; it is `fn f<T: Trait>(x: Option<T>)`.
4+trait Label {
5+ fn label(&self) -> String;
6+}
7+
8+struct Tag(u32);
9+
10+impl Label for Tag {
11+ fn label(&self) -> String {
12+ format!("tag-{}", self.0)
13+ }
14+}
15+
16+fn describe(x: Option<impl Label>) -> String {
17+ match x {
18+ Some(v) => v.label(),
19+ None => String::from("none"),
20+ }
21+}
22+
23+fn pair(a: impl Label, b: Option<impl Label>) -> String {
24+ format!("{} / {}", a.label(), describe(b))
25+}
26+
27+fn main() {
28+ println!("{}", describe(Some(Tag(1))));
29+ println!("{}", describe(None::<Tag>));
30+ println!("{}", pair(Tag(7), Some(Tag(9))));
31+ println!("{}", pair(Tag(7), None::<Tag>));
32+}
new file mode 100644
@@ -0,0 +1,32 @@
1+// `impl Trait` in argument position is a generic parameter — including when it
2+// is nested inside another type. `Option<impl Trait>` is not a return-position
3+// opaque type; it is `fn f<T: Trait>(x: Option<T>)`.
4+trait Label {
5+ fn label(&self) -> String;
6+}
7+
8+struct Tag(u32);
9+
10+impl Label for Tag {
11+ fn label(&self) -> String {
12+ format!("tag-{}", self.0)
13+ }
14+}
15+
16+fn describe(x: Option<impl Label>) -> String {
17+ match x {
18+ Some(v) => v.label(),
19+ None => String::from("none"),
20+ }
21+}
22+
23+fn pair(a: impl Label, b: Option<impl Label>) -> String {
24+ format!("{} / {}", a.label(), describe(b))
25+}
26+
27+fn main() {
28+ println!("{}", describe(Some(Tag(1))));
29+ println!("{}", describe(None::<Tag>));
30+ println!("{}", pair(Tag(7), Some(Tag(9))));
31+ println!("{}", pair(Tag(7), None::<Tag>));
32+}