nandi/rustnimpublic Fork
⑂ 62d5926
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

Resolve `impl Trait` nested in a return type

`-> Option<impl Display>` is opaque in the same way a bare `-> impl Display`
is, and the body determines the whole return type, so the resolution added two
commits ago already answers for it -- the guard was just too narrow, matching
only a bare `impl Trait`.

Found by the dependency run, in `drm-fourcc`'s `fourcc_display_form`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T10:28:50-07:00 Browse files
62d5926 parent: 3ba74c0
modified src/lower.rs +24 -3
@@ -1851,9 +1851,10 @@ impl Lowerer {
18511851 // the body produces. Rust hides which; it does not permit two. So
18521852 // the type is recoverable from the body, and `resolve_opaque`
18531853 // recovers it. Marked here, resolved between passes.
1854- ReturnType::Type(_, t)
1855- if matches!(&**t, syn::Type::ImplTrait(_)) && self.map_ty(t).is_err() =>
1856- {
1854+ // Not only a *bare* `impl Trait`: `-> Option<impl Display>` is
1855+ // opaque in the same way, and the body determines the whole
1856+ // return type, so the same resolution answers for both.
1857+ ReturnType::Type(_, t) if contains_impl_trait(t) && self.map_ty(t).is_err() => {
18571858 match &self.opaque_hint {
18581859 Some(t) => t.clone(),
18591860 None => Nim::Named(OPAQUE.into(), Vec::new()),
@@ -7655,3 +7656,23 @@ fn result_exprs(e: &Expr) -> Vec<Expr> {
76557656 other => vec![other.clone()],
76567657 }
76577658 }
7659+
7660+/// Whether a type contains an `impl Trait` anywhere inside it.
7661+fn contains_impl_trait(t: &syn::Type) -> bool {
7662+ use syn::Type;
7663+ match t {
7664+ Type::ImplTrait(_) => true,
7665+ Type::Reference(r) => contains_impl_trait(&r.elem),
7666+ Type::Slice(s) => contains_impl_trait(&s.elem),
7667+ Type::Array(a) => contains_impl_trait(&a.elem),
7668+ Type::Paren(p) => contains_impl_trait(&p.elem),
7669+ Type::Group(g) => contains_impl_trait(&g.elem),
7670+ Type::Tuple(tu) => tu.elems.iter().any(contains_impl_trait),
7671+ Type::Path(p) => p.path.segments.iter().any(|seg| {
7672+ matches!(&seg.arguments, syn::PathArguments::AngleBracketed(a)
7673+ if a.args.iter().any(|g| matches!(g, syn::GenericArgument::Type(t)
7674+ if contains_impl_trait(t))))
7675+ }),
7676+ _ => false,
7677+ }
7678+}
@@ -1851,9 +1851,10 @@ impl Lowerer {
1851 // the body produces. Rust hides which; it does not permit two. So1851 // the body produces. Rust hides which; it does not permit two. So
1852 // the type is recoverable from the body, and `resolve_opaque`1852 // the type is recoverable from the body, and `resolve_opaque`
1853 // recovers it. Marked here, resolved between passes.1853 // recovers it. Marked here, resolved between passes.
1854- ReturnType::Type(_, t)1854+ // Not only a *bare* `impl Trait`: `-> Option<impl Display>` is
1855- if matches!(&**t, syn::Type::ImplTrait(_)) && self.map_ty(t).is_err() =>1855+ // opaque in the same way, and the body determines the whole
1856- {1856+ // return type, so the same resolution answers for both.
1857+ ReturnType::Type(_, t) if contains_impl_trait(t) && self.map_ty(t).is_err() => {
1857 match &self.opaque_hint {1858 match &self.opaque_hint {
1858 Some(t) => t.clone(),1859 Some(t) => t.clone(),
1859 None => Nim::Named(OPAQUE.into(), Vec::new()),1860 None => Nim::Named(OPAQUE.into(), Vec::new()),
@@ -7655,3 +7656,23 @@ fn result_exprs(e: &Expr) -> Vec<Expr> {
7655 other => vec![other.clone()],7656 other => vec![other.clone()],
7656 }7657 }
7657 }7658 }
7659+
7660+/// Whether a type contains an `impl Trait` anywhere inside it.
7661+fn contains_impl_trait(t: &syn::Type) -> bool {
7662+ use syn::Type;
7663+ match t {
7664+ Type::ImplTrait(_) => true,
7665+ Type::Reference(r) => contains_impl_trait(&r.elem),
7666+ Type::Slice(s) => contains_impl_trait(&s.elem),
7667+ Type::Array(a) => contains_impl_trait(&a.elem),
7668+ Type::Paren(p) => contains_impl_trait(&p.elem),
7669+ Type::Group(g) => contains_impl_trait(&g.elem),
7670+ Type::Tuple(tu) => tu.elems.iter().any(contains_impl_trait),
7671+ Type::Path(p) => p.path.segments.iter().any(|seg| {
7672+ matches!(&seg.arguments, syn::PathArguments::AngleBracketed(a)
7673+ if a.args.iter().any(|g| matches!(g, syn::GenericArgument::Type(t)
7674+ if contains_impl_trait(t))))
7675+ }),
7676+ _ => false,
7677+ }
7678+}
modified tests/cases/056-return-impl-trait.rs +14 -0
@@ -38,9 +38,23 @@ fn pick(n: u32) -> impl Display {
3838 }
3939 }
4040
41+// `impl Trait` nested in the return type. Opaque in the same way, and the
42+// body determines the whole type, so the same resolution answers for it.
43+fn maybe(n: u32) -> Option<impl Display> {
44+ if n > 0 { Some(Tag { n }) } else { None }
45+}
46+
4147 fn main() {
4248 println!("{}", make(3));
4349 println!("{}", relay(3));
4450 println!("{}", Wrap.build(9));
4551 println!("{} {}", pick(0), pick(7));
52+ match maybe(5) {
53+ Some(v) => println!("{}", v),
54+ None => println!("none"),
55+ }
56+ match maybe(0) {
57+ Some(v) => println!("{}", v),
58+ None => println!("none"),
59+ }
4660 }
@@ -38,9 +38,23 @@ fn pick(n: u32) -> impl Display {
38 }38 }
39 }39 }
40 40
41+// `impl Trait` nested in the return type. Opaque in the same way, and the
42+// body determines the whole type, so the same resolution answers for it.
43+fn maybe(n: u32) -> Option<impl Display> {
44+ if n > 0 { Some(Tag { n }) } else { None }
45+}
46+
41 fn main() {47 fn main() {
42 println!("{}", make(3));48 println!("{}", make(3));
43 println!("{}", relay(3));49 println!("{}", relay(3));
44 println!("{}", Wrap.build(9));50 println!("{}", Wrap.build(9));
45 println!("{} {}", pick(0), pick(7));51 println!("{} {}", pick(0), pick(7));
52+ match maybe(5) {
53+ Some(v) => println!("{}", v),
54+ None => println!("none"),
55+ }
56+ match maybe(0) {
57+ Some(v) => println!("{}", v),
58+ None => println!("none"),
59+ }
46 }60 }