Skip to content

Invalid span of a struct's generics in presence of a where clause but no parameter #55991

Closed
@scampi

Description

@scampi

This is an issue that was reported initially to rustfmt in rust-lang/rustfmt#3194.
The problematic code was based on the Generics.span field, which gave a wrong BytePos in case of a struct with a where clause but no parameter.

Problem

Below is an explanation of the problem, and there is a runnable example below to test it out.

Observed

With the code mod m { struct S where A: B; }, the field generics.span of the struct item is equal to Span { lo: BytePos(0), hi: BytePos(0), .. }; this points to the start of the input.

Expected

The span value should point to the position just after the struct ident, i.e., Span { lo: BytePos(16), hi: BytePos(16), .. }.

Versions

$ rustc --version --verbose
rustc 1.32.0-nightly (6f93e93af 2018-11-14)
binary: rustc
commit-hash: 6f93e93af6f823948cc13d2938957757c6486d88
commit-date: 2018-11-14
host: x86_64-unknown-linux-gnu
release: 1.32.0-nightly
LLVM version: 8.0

Example code

  • tested with rustc-ap-syntax = "297.0.0"
extern crate syntax;

use syntax::ast::*;
use syntax::ext::quote::rt::FileName;
use syntax::parse;
use syntax::parse::ParseSess;
use syntax::source_map::FilePathMapping;

fn main() {
    // With source = "mod m { struct S<A> where A: B; }":
    // - the generics span is equal to `Span { lo: BytePos(16), hi: BytePos(19), .. }`
    //
    // With source = "mod m { struct S where A: B; }":
    // - the generics span is equal to `Span { lo: BytePos(0), hi: BytePos(0), .. }`
    // - it would be better if the span pointed to the portion just after the ident with the difference between `hi` and `lo` equal to 0, i.e., `Span { lo: BytePos(16), hi: BytePos(16), .. }`

    //let source = "mod m { struct S<A> where A: B; }";
    let source = "mod m { struct S where A: B; }";

    let session = ParseSess::new(FilePathMapping::empty());
    let file_name = FileName::Custom("source".to_string());

    syntax::with_globals(|| {
        let mut parser = parse::new_parser_from_source_str(&session, file_name, source.to_string());
        let result = parser.parse_crate_mod().unwrap();
        let item = &result.module.items[0];
        if let ItemKind::Mod(module) = &item.node {
            let item = &module.items[0];
            if let ItemKind::Struct(_data, generics) = &item.node {
                println!("generics.span = [{:?}]", generics.span);
                println!("generics.params = [{:?}]", generics.params.len());
            }
        }
    });
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lints

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions