@@ -37,10 +37,17 @@ pub(crate) fn derive_parse_with_spec(
37
37
}
38
38
}
39
39
40
+ // Determine whether *any* variant is marked as `#[variable]`.
41
+ // If so, all *other* variants will automatically reject in-scope variable names.
42
+ let any_variable_variant = s
43
+ . variants ( )
44
+ . iter ( )
45
+ . any ( |v| has_variable_attr ( v. ast ( ) . attrs ) ) ;
46
+
40
47
let mut parse_variants = TokenStream :: new ( ) ;
41
48
for variant in s. variants ( ) {
42
49
let variant_name = Literal :: string ( & format ! ( "{}::{}" , s. ast( ) . ident, variant. ast( ) . ident) ) ;
43
- let v = parse_variant ( variant, external_spec) ?;
50
+ let v = parse_variant ( variant, external_spec, any_variable_variant ) ?;
44
51
let precedence = precedence ( & variant. ast ( ) . attrs ) ?. literal ( ) ;
45
52
parse_variants. extend ( quote_spanned ! (
46
53
variant. ast( ) . ident. span( ) =>
@@ -66,17 +73,27 @@ pub(crate) fn derive_parse_with_spec(
66
73
fn parse_variant (
67
74
variant : & synstructure:: VariantInfo ,
68
75
external_spec : Option < & FormalitySpec > ,
76
+ any_variable_variant : bool ,
69
77
) -> syn:: Result < TokenStream > {
70
78
let ast = variant. ast ( ) ;
79
+ let has_variable_attr = has_variable_attr ( ast. attrs ) ;
80
+ let mut stream = TokenStream :: default ( ) ;
81
+
82
+ // If there are variable variants -- but this is not one -- then we always begin by rejecting
83
+ // variable names. This avoids ambiguity in a case like `for<ty X> { X : Debug }`, where we
84
+ // want to parse `X` as a type variable.
85
+ if any_variable_variant && !has_variable_attr {
86
+ stream. extend ( quote_spanned ! ( ast. ident. span( ) => __p. reject_variable( ) ?; ) ) ;
87
+ }
71
88
72
89
// When invoked like `#[term(foo)]`, use the spec from `foo`
73
90
if let Some ( spec) = external_spec {
74
- return parse_variant_with_attr ( variant, spec) ;
91
+ return parse_variant_with_attr ( variant, spec, stream ) ;
75
92
}
76
93
77
94
// Else, look for a `#[grammar]` attribute on the variant
78
95
if let Some ( attr) = get_grammar_attr ( ast. attrs ) {
79
- return parse_variant_with_attr ( variant, & attr?) ;
96
+ return parse_variant_with_attr ( variant, & attr?, stream ) ;
80
97
}
81
98
82
99
// If no `#[grammar(...)]` attribute is provided, then we provide default behavior.
@@ -85,44 +102,46 @@ fn parse_variant(
85
102
// No bindings (e.g., `Foo`) -- just parse a keyword `foo`
86
103
let literal = Literal :: string ( & to_parse_ident ( ast. ident ) ) ;
87
104
let construct = variant. construct ( |_, _| quote ! { } ) ;
88
- Ok ( quote_spanned ! {
105
+ stream . extend ( quote_spanned ! {
89
106
ast. ident. span( ) =>
90
107
__p. expect_keyword( #literal) ?;
91
108
Ok ( #construct)
92
- } )
93
- } else if has_variable_attr ( variant . ast ( ) . attrs ) {
109
+ } ) ;
110
+ } else if has_variable_attr {
94
111
// Has the `#[variable]` attribute -- parse an identifier and then check to see if it is present
95
112
// in the scope. If so, downcast it and check that it has the correct kind.
96
- Ok ( quote_spanned ! {
113
+ stream . extend ( quote_spanned ! {
97
114
ast. ident. span( ) =>
98
115
let v = __p. variable( ) ?;
99
116
Ok ( v)
100
- } )
117
+ } ) ;
101
118
} else if has_cast_attr ( variant. ast ( ) . attrs ) {
102
119
// Has the `#[cast]` attribute -- just parse the bindings (comma separated, if needed)
103
120
let build: Vec < TokenStream > = parse_bindings ( variant. bindings ( ) ) ;
104
121
let construct = variant. construct ( field_ident) ;
105
- Ok ( quote_spanned ! {
122
+ stream . extend ( quote_spanned ! {
106
123
ast. ident. span( ) =>
107
124
__p. mark_as_cast_variant( ) ;
108
125
#( #build) *
109
126
Ok ( #construct)
110
- } )
127
+ } ) ;
111
128
} else {
112
129
// Otherwise -- parse `variant(binding0, ..., bindingN)`
113
130
let literal = Literal :: string ( & to_parse_ident ( ast. ident ) ) ;
114
131
let build: Vec < TokenStream > = parse_bindings ( variant. bindings ( ) ) ;
115
132
let construct = variant. construct ( field_ident) ;
116
- Ok ( quote_spanned ! {
133
+ stream . extend ( quote_spanned ! {
117
134
ast. ident. span( ) =>
118
135
__p. expect_keyword( #literal) ?;
119
136
__p. expect_char( '(' ) ?;
120
137
#( #build) *
121
138
__p. skip_trailing_comma( ) ;
122
139
__p. expect_char( ')' ) ?;
123
140
Ok ( #construct)
124
- } )
141
+ } ) ;
125
142
}
143
+
144
+ Ok ( stream)
126
145
}
127
146
128
147
/// When a type is given a formality attribute, we use that to guide parsing:
@@ -144,9 +163,8 @@ fn parse_variant(
144
163
fn parse_variant_with_attr (
145
164
variant : & synstructure:: VariantInfo ,
146
165
spec : & FormalitySpec ,
166
+ mut stream : TokenStream ,
147
167
) -> syn:: Result < TokenStream > {
148
- let mut stream = TokenStream :: new ( ) ;
149
-
150
168
for symbol in & spec. symbols {
151
169
stream. extend ( match symbol {
152
170
spec:: FormalitySpecSymbol :: Field { name, mode } => {
0 commit comments