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

struct constructors are some kind of weird type/path hybrid #41740

Closed
durka opened this issue May 4, 2017 · 1 comment
Closed

struct constructors are some kind of weird type/path hybrid #41740

durka opened this issue May 4, 2017 · 1 comment
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST C-bug Category: This is a bug.

Comments

@durka
Copy link
Contributor

durka commented May 4, 2017

Is this a known issue?

Consider the following setup:

mod foo {
    pub struct Bar<T>(pub T);
}

You can construct a Bar:

let _ = foo::Bar::<i32>(42);

Now I want to try it with a macro.

macro_rules! construct {
    ($strukt:path, $val:expr) => {
        $strukt($val)
    }
}

The obvious thing doesn't parse at all:

let _ = construct!(foo::Bar::<i32>, 42); // ERROR
//                         ^ unexpected token `::`

We need to remove the second ::, which makes things inconsistent with the macro-less syntax:

let _ = construct!(foo::Bar<i32>, 42); // ok

Why this inconsistency? It seems like a struct constructor isn't really a path. But that's the only macro fragment that can be used in that position (besides ident and tt).

@petrochenkov
Copy link
Contributor

This issue is not related to struct constructors in general, it's related to what path matcher accepts in macros.
Minimal example:

macro_rules! m {
    ($p: path) => {}
}

fn main() {
    m!(a<b>); // OK
    m!(a::<b>); // FAIL
}

There are two flavors of paths (syntactically) - with disambiguating "turbofish" (a::<b>) and without it (a<b>). :: is required in expressions for disambiguation, but in other contexts it's not necessary and should probably just be optional, but is currently prohibited instead (I don't know why, maybe there's a history behind it, maybe not). The issue is that paths passed to macros through path matchers are considered "non-expression" paths.
As I said previously turbofish being rejected in non-expression paths is an artificial restriction and this issue gives a good motivation for removing it.

@petrochenkov petrochenkov added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST labels May 4, 2017
@petrochenkov petrochenkov self-assigned this May 4, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 27, 2017
bors added a commit that referenced this issue Aug 21, 2017
syntax: Relax path grammar

TLDR: Accept the disambiguator `::` in "type" paths (`Type::<Args>`), accept the disambiguator `::` before parenthesized generic arguments (`Fn::(Args)`).

The "turbofish" disambiguator `::<>` in expression paths is a necessary evil required for path parsing to be both simple and to give reasonable results.
Since paths in expressions usually refer to values (but not necessarily, e.g. `Struct::<u8> { field: 0 }` is disambiguated, but refers to a type), people often consider `::<>` to be inherent to *values*, and not *expressions* and want to write disambiguated paths for values even in contexts where disambiguation is not strictly necessary, for example when a path is passed to a macro `m!(Vec::<i32>::new)`.
The problem is that currently, if the disambiguator is not *required*, then it's *prohibited*. This results in confusion - see #41740, https://internals.rust-lang.org/t/macro-path-uses-novel-syntax/5561.

This PR makes the disambiguator *optional* instead of prohibited in contexts where it's not strictly required, so people can pass paths to macros in whatever form they consider natural (e.g. disambiguated form for value paths).
This PR also accepts the disambiguator in paths with parenthesized arguments (`Fn::(Args)`) for consistency and to simplify testing of stuff like #41856 (comment).

Closes #41740

cc @rust-lang/lang
r? @nikomatsakis
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, ..) A-parser Area: The parsing of Rust source code to an AST C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants