Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust 'const iter' results in 'for'-errors #27639

Closed
oberien opened this issue Aug 10, 2015 · 6 comments
Closed

Rust 'const iter' results in 'for'-errors #27639

oberien opened this issue Aug 10, 2015 · 6 comments
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)

Comments

@oberien
Copy link
Contributor

oberien commented Aug 10, 2015

having the following code

fn main() {
    const iter: i32 = 5;

    for i in 0..10 {
        println!("{}", i);
    }
}

produces the following error:

src/main.rs:4:5: 6:6 error: type mismatch resolving ` as core::iter::IntoIterator>::IntoIter == i32`:
 expected struct `core::ops::Range`,
    found i32 [E0271]
src/main.rs:4     for i in 0..10 {
src/main.rs:5         println!("{}", i);
src/main.rs:6     }
note: in expansion of for loop expansion
src/main.rs:4:5: 6:6 note: expansion site
src/main.rs:4:5: 6:6 help: run `rustc --explain E0271` to see a detailed explanation
src/main.rs:4:5: 6:6 error: the trait `core::iter::Iterator` is not implemented for the type `i32` [E0277]
src/main.rs:4     for i in 0..10 {
src/main.rs:5         println!("{}", i);
src/main.rs:6     }
note: in expansion of for loop expansion
src/main.rs:4:5: 6:6 note: expansion site
src/main.rs:4:5: 6:6 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:4:5: 6:6 note: `i32` is not an iterator; maybe try calling `.iter()` or a similar method
src/main.rs:4     for i in 0..10 {
src/main.rs:5         println!("{}", i);
src/main.rs:6     }
note: in expansion of for loop expansion
src/main.rs:4:5: 6:6 note: expansion site
src/main.rs:4:5: 6:6 error: the trait `core::iter::Iterator` is not implemented for the type `i32` [E0277]
src/main.rs:4     for i in 0..10 {
src/main.rs:5         println!("{}", i);
src/main.rs:6     }
note: in expansion of for loop expansion
src/main.rs:4:5: 6:6 note: expansion site
src/main.rs:4:5: 6:6 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:4:5: 6:6 note: `i32` is not an iterator; maybe try calling `.iter()` or a similar method
src/main.rs:4     for i in 0..10 {
src/main.rs:5         println!("{}", i);
src/main.rs:6     }
note: in expansion of for loop expansion
src/main.rs:4:5: 6:6 note: expansion site
error: aborting due to 3 previous errors

Somehow defining the const 'iter' doesn't let rust build the iterator needed by the for-loop. I know, that renaming the const fixes this issue, but can someone explain this behavior to be, please?

Kind Regards,
BH16

@eefriedman
Copy link
Contributor

For loops are expanded roughly like this:

    {
        let result = match ::std::iter::IntoIterator::into_iter(<head>) {
            mut iter => {
                [opt_ident]: loop {
                    match ::std::iter::Iterator::next(&mut iter) {
                        ::std::option::Option::Some(<pat>) => <body>,
                        ::std::option::Option::None => break
                    }
                }
            }
        };
        result
    }

The use of the identifier "iter" in the expansion is somehow conflicting with the constant; a bug in the expansion code, I guess.

@tomjakubowski
Copy link
Contributor

I think macro expansion isn't hygienic with respect to identifiers in patterns when the identifier is also a const in the containing context (playpen):

macro_rules! foo {
    ($ex:expr) => {
        match $ex {
            Some(ouch) => println!("{}", ouch),
            None => println!("none")
        }
    }
}

pub fn main() {
    const ouch: i32 = 123;
    foo!(Some(567));
}
<anon>:3:9: 6:10 error: non-exhaustive patterns: `Some(_)` not covered [E0004]
<anon>:3         match $ex {
<anon>:4             Some(ouch) => println!("{}", ouch),
<anon>:5             None => println!("none")
<anon>:6         }

This is only an issue with consts; changing the ouch in main to a regular let binding works as expected.

@tomjakubowski
Copy link
Contributor

Ah, that's probably because you can't use values of let bindings in patterns to begin with.

@Aatch
Copy link
Contributor

Aatch commented Aug 11, 2015

It's likely because hygiene doesn't apply to item names and the names of constants are the only case where you can use a item as a pattern. The iter variable it uses is hygienic, its just the hygiene doesn't work here.

@steveklabnik
Copy link
Member

So is this not a bug?

@steveklabnik steveklabnik added the A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) label Aug 13, 2015
@Stebalien
Copy link
Contributor

This is very much a bug. iter isn't a reserved word and defining a constant iter should have no unexpected side effects.

bors added a commit that referenced this issue Dec 9, 2015
Instead of `ast::Ident`, bindings, paths and labels in HIR now keep a new structure called `hir::Ident` containing mtwt-renamed `name` and the original not-renamed `unhygienic_name`. `name` is supposed to be used by default, `unhygienic_name` is rarely used.

This is not ideal, but better than the status quo for two reasons:
- MTWT tables can be cleared immediately after lowering to HIR
- This is less bug-prone, because it is impossible now to forget applying `mtwt::resolve` to a name. It is still possible to use `name` instead of `unhygienic_name` by mistake, but `unhygienic_name`s are used only in few very special circumstances, so it shouldn't be a problem.

Besides name resolution `unhygienic_name` is used in some lints and debuginfo. `unhygienic_name` can be very well approximated by "reverse renaming" `token::intern(name.as_str())` or even plain string `name.as_str()`, except that it would break gensyms like `iter` in desugared `for` loops. This approximation is likely good enough for lints and debuginfo, but not for name resolution, unfortunately (see #27639), so `unhygienic_name` has to be kept.

cc #29782

r? @nrc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
Projects
None yet
Development

No branches or pull requests

6 participants