Skip to content

Detect recursive instantiation of generic functions #50043

Open
@dtolnay

Description

@dtolnay

We currently have a quite helpful diagnostic for unconditionally recursive functions:

pub fn recur() {
    recur();
}
warning: function cannot return without recurring
 --> src/main.rs:1:1
  |
1 | pub fn recur() {
  | ^^^^^^^^^^^^^^ cannot return without recurring
2 |     recur();
  |     ------- recursive call site
  |
  = note: #[warn(unconditional_recursion)] on by default
  = help: a `loop` may express intention better if this is on purpose

And infinitely sized recursive types:

pub struct S {
    s: S,
}
error[E0072]: recursive type `S` has infinite size
 --> src/main.rs:1:1
  |
1 | pub struct S {
  | ^^^^^^^^^^^^ recursive type has infinite size
2 |     s: S,
  |     ---- recursive without indirection
  |
  = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `S` representable

But no good error for infinite instantiation of generic functions.

The following is minimized from @LPGhatguy's syntax tree library (original playground).

trait Serializer {
    type Associated;
    fn leaf() -> Self::Associated { unimplemented!() }
}

pub enum Expression {
    Leaf,
    Node(Box<Expression>),
}

fn print<S: Serializer>(e: Expression) {
    match e {
        Expression::Leaf => drop(S::leaf()),
        Expression::Node(e) => print::<Wrapper<S>>(*e),
    }
}

use std::marker::PhantomData as Wrapper;
impl<S: Serializer> Serializer for Wrapper<S> {
    type Associated = S::Associated;
}

enum Json {}
impl Serializer for Json {
    type Associated = ();
}

fn main() {
    print::<Json>(Expression::Leaf);
}

Here the instantiation of print::<Json> requires instantiating print::<Wrapper<Json>> which calls print::<Wrapper<Wrapper<Json>> which calls print::<Wrapper<Wrapper<Wrapper<Json>>>... (The use case in this example is noteworthy because it is conceptually sensible; the trouble happens only when combined with Rust's approach of monomorphizing generic functions. Analogous code in Swift where generics are not monomorphized does not hit the same overflow.)

As of rustc 1.27.0-nightly we get an unhelpful message with a recommendation that can't work. It would be better to detect this pattern of a generic function generating a tower of recursive instantiations.

error[E0275]: overflow evaluating the requirement `<Json as Serializer>::Associated`
  |
  = help: consider adding a `#![recursion_limit="128"]` attribute to your crate

error: aborting due to previous error

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-type-systemArea: Type systemC-enhancementCategory: An issue proposing an enhancement or a PR with one.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions