rust-lang/rust · error

empty prefix in a simple import

Error message

empty prefix in a simple import

What it means

UseTree::ident() (ast.rs:3376) panics with expect("empty prefix in a simple import") when called on a Simple use tree with no rename whose prefix path has zero segments. The method contract is: it returns the trailing identifier of a simple import; for a glob or nested tree it panics with a different message. An empty prefix on a Simple tree means malformed AST.

Solutions

  1. Before calling .ident(), ensure the tree is Simple and prefix.segments is non-empty.
  2. If you construct UseTree nodes, always populate prefix with at least one segment for Simple imports.
  3. If this fires from rustc itself on real source, file an ICE with the minimized `use` statement.
  4. Switch to a method that does not assume a single identifier (handle Simple(rename), Glob, and Nested explicitly).

Example fix

// before
let name = use_tree.ident(); // panics if prefix is empty

// after
let name = match use_tree.kind {
    UseTreeKind::Simple(Some(rename)) => rename,
    UseTreeKind::Simple(None) => use_tree.prefix.segments
        .last()
        .expect("simple import needs a prefix segment").ident,
    _ => panic!("ident() only valid for simple imports"),
};
Defensive patterns

Strategy: validation

Validate before calling

fn simple_ident_or_none(tree: &UseTree) -> Option<Ident> {
    match tree.kind {
        UseTreeKind::Simple(Some(rename)) => Some(rename),
        UseTreeKind::Simple(None) => tree.prefix.segments.last().map(|s| s.ident),
        _ => None,
    }
}

Type guard

fn is_simple_with_prefix(tree: &UseTree) -> bool {
    matches!(tree.kind, UseTreeKind::Simple(_)) && !tree.prefix.segments.is_empty()
}

Try / catch

let name = use_tree.prefix.segments.last()
    .map(|s| s.ident)
    .unwrap_or_else(|| panic!("empty prefix in a simple import at {:?}", use_tree.prefix.span));

Prevention

When it happens

Trigger: Programmatically constructing or lowering an ast::UseTree with UseTreeKind::Simple(None) and an empty prefix.segments, then calling .ident(); or a parser/resolver bug producing such a tree.

Common situations: Tooling or proc-macro-adjacent code that builds UseTree nodes synthetically; a malformed `use` statement; a bug in a frontend that strips the prefix path. Well-formed source never triggers this.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/7e3d10ecb6426454. Report an issue: GitHub.

Appendix: source

Thrown at compiler/rustc_ast/src/ast.rs:3376

    Glob(Span),
}

/// A tree of paths sharing common prefixes.
/// Used in `use` items both at top-level and inside of braces in import groups.
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct UseTree {
    pub prefix: Path,
    pub kind: UseTreeKind,
}

impl UseTree {
    /// If the `UseTree` is just an identifier, return that.
    /// Panics if it's a glob (`*`) or a nested use tree.
    pub fn ident(&self) -> Ident {
        match self.kind {
            UseTreeKind::Simple(Some(rename)) => rename,
            UseTreeKind::Simple(None) => {
                self.prefix.segments.last().expect("empty prefix in a simple import").ident
            }
            _ => panic!("`UseTree::ident` can only be used on a simple import"),
        }
    }

    /// Returns the full span from the start of the path to the
    /// closing `}` or nested spans, `*` of glob spans or the end of the
    /// identifier of simple spans.
    pub fn span(&self) -> Span {
        self.prefix.span.to(self.hi_span())
    }

    /// Returns the trailing element's span. So for a nested
    /// span you get the entire `{}`-block, for a glob you
    /// get the span of the `*` itself, and for simple use trees
    /// you get the identifier to rename the import to or the full
    /// path if no rename is specified.
    pub fn hi_span(&self) -> Span {

View on GitHub (pinned to 7088e4b63a)