Skip to content

Commit b2a093e

Browse files
authored
Rollup merge of rust-lang#57364 - hdhoang:33418_negative_bounds, r=estebank
Improve parsing diagnostic for negative supertrait bounds closes rust-lang#33418 r? @estebank
2 parents aadbc45 + 7cfddfb commit b2a093e

File tree

4 files changed

+131
-21
lines changed

4 files changed

+131
-21
lines changed

src/libsyntax/parse/parser.rs

+59-21
Original file line numberDiff line numberDiff line change
@@ -1733,7 +1733,7 @@ impl<'a> Parser<'a> {
17331733
}
17341734
} else if self.eat_keyword(keywords::Impl) {
17351735
// Always parse bounds greedily for better error recovery.
1736-
let bounds = self.parse_generic_bounds()?;
1736+
let bounds = self.parse_generic_bounds(None)?;
17371737
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
17381738
TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)
17391739
} else if self.check_keyword(keywords::Dyn) &&
@@ -1742,13 +1742,13 @@ impl<'a> Parser<'a> {
17421742
!can_continue_type_after_non_fn_ident(t))) {
17431743
self.bump(); // `dyn`
17441744
// Always parse bounds greedily for better error recovery.
1745-
let bounds = self.parse_generic_bounds()?;
1745+
let bounds = self.parse_generic_bounds(None)?;
17461746
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
17471747
TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)
17481748
} else if self.check(&token::Question) ||
17491749
self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) {
17501750
// Bound list (trait object type)
1751-
TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus)?,
1751+
TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?,
17521752
TraitObjectSyntax::None)
17531753
} else if self.eat_lt() {
17541754
// Qualified path
@@ -1794,7 +1794,7 @@ impl<'a> Parser<'a> {
17941794
let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
17951795
if parse_plus {
17961796
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
1797-
bounds.append(&mut self.parse_generic_bounds()?);
1797+
bounds.append(&mut self.parse_generic_bounds(None)?);
17981798
}
17991799
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
18001800
}
@@ -1819,7 +1819,7 @@ impl<'a> Parser<'a> {
18191819
}
18201820

18211821
self.bump(); // `+`
1822-
let bounds = self.parse_generic_bounds()?;
1822+
let bounds = self.parse_generic_bounds(None)?;
18231823
let sum_span = ty.span.to(self.prev_span);
18241824

18251825
let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178,
@@ -5496,18 +5496,24 @@ impl<'a> Parser<'a> {
54965496
/// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
54975497
/// TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`)
54985498
/// ```
5499-
fn parse_generic_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, GenericBounds> {
5499+
fn parse_generic_bounds_common(&mut self,
5500+
allow_plus: bool,
5501+
colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
55005502
let mut bounds = Vec::new();
5503+
let mut negative_bounds = Vec::new();
5504+
let mut last_plus_span = None;
55015505
loop {
55025506
// This needs to be synchronized with `Token::can_begin_bound`.
55035507
let is_bound_start = self.check_path() || self.check_lifetime() ||
5508+
self.check(&token::Not) || // used for error reporting only
55045509
self.check(&token::Question) ||
55055510
self.check_keyword(keywords::For) ||
55065511
self.check(&token::OpenDelim(token::Paren));
55075512
if is_bound_start {
55085513
let lo = self.span;
55095514
let has_parens = self.eat(&token::OpenDelim(token::Paren));
55105515
let inner_lo = self.span;
5516+
let is_negative = self.eat(&token::Not);
55115517
let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
55125518
if self.token.is_lifetime() {
55135519
if let Some(question_span) = question {
@@ -5538,28 +5544,60 @@ impl<'a> Parser<'a> {
55385544
if has_parens {
55395545
self.expect(&token::CloseDelim(token::Paren))?;
55405546
}
5541-
let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
5542-
let modifier = if question.is_some() {
5543-
TraitBoundModifier::Maybe
5547+
let poly_span = lo.to(self.prev_span);
5548+
if is_negative {
5549+
negative_bounds.push(
5550+
last_plus_span.or(colon_span).unwrap()
5551+
.to(poly_span));
55445552
} else {
5545-
TraitBoundModifier::None
5546-
};
5547-
bounds.push(GenericBound::Trait(poly_trait, modifier));
5553+
let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span);
5554+
let modifier = if question.is_some() {
5555+
TraitBoundModifier::Maybe
5556+
} else {
5557+
TraitBoundModifier::None
5558+
};
5559+
bounds.push(GenericBound::Trait(poly_trait, modifier));
5560+
}
55485561
}
55495562
} else {
55505563
break
55515564
}
55525565

55535566
if !allow_plus || !self.eat_plus() {
55545567
break
5555-
}
5568+
} else {
5569+
last_plus_span = Some(self.prev_span);
5570+
}
5571+
}
5572+
5573+
if !negative_bounds.is_empty() {
5574+
let plural = negative_bounds.len() > 1;
5575+
let mut err = self.struct_span_err(negative_bounds,
5576+
"negative trait bounds are not supported");
5577+
let bound_list = colon_span.unwrap().to(self.prev_span);
5578+
let mut new_bound_list = String::new();
5579+
if !bounds.is_empty() {
5580+
let mut snippets = bounds.iter().map(|bound| bound.span())
5581+
.map(|span| self.sess.source_map().span_to_snippet(span));
5582+
while let Some(Ok(snippet)) = snippets.next() {
5583+
new_bound_list.push_str(" + ");
5584+
new_bound_list.push_str(&snippet);
5585+
}
5586+
new_bound_list = new_bound_list.replacen(" +", ":", 1);
5587+
}
5588+
err.span_suggestion_short(bound_list,
5589+
&format!("remove the trait bound{}",
5590+
if plural { "s" } else { "" }),
5591+
new_bound_list,
5592+
Applicability::MachineApplicable);
5593+
err.emit();
55565594
}
55575595

55585596
return Ok(bounds);
55595597
}
55605598

5561-
fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
5562-
self.parse_generic_bounds_common(true)
5599+
fn parse_generic_bounds(&mut self, colon_span: Option<Span>) -> PResult<'a, GenericBounds> {
5600+
self.parse_generic_bounds_common(true, colon_span)
55635601
}
55645602

55655603
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -5587,7 +5625,7 @@ impl<'a> Parser<'a> {
55875625

55885626
// Parse optional colon and param bounds.
55895627
let bounds = if self.eat(&token::Colon) {
5590-
self.parse_generic_bounds()?
5628+
self.parse_generic_bounds(None)?
55915629
} else {
55925630
Vec::new()
55935631
};
@@ -5619,7 +5657,7 @@ impl<'a> Parser<'a> {
56195657

56205658
// Parse optional colon and param bounds.
56215659
let bounds = if self.eat(&token::Colon) {
5622-
self.parse_generic_bounds()?
5660+
self.parse_generic_bounds(None)?
56235661
} else {
56245662
Vec::new()
56255663
};
@@ -6032,7 +6070,7 @@ impl<'a> Parser<'a> {
60326070
// or with mandatory equality sign and the second type.
60336071
let ty = self.parse_ty()?;
60346072
if self.eat(&token::Colon) {
6035-
let bounds = self.parse_generic_bounds()?;
6073+
let bounds = self.parse_generic_bounds(None)?;
60366074
where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
60376075
ast::WhereBoundPredicate {
60386076
span: lo.to(self.prev_span),
@@ -6546,14 +6584,14 @@ impl<'a> Parser<'a> {
65466584

65476585
// Parse optional colon and supertrait bounds.
65486586
let bounds = if self.eat(&token::Colon) {
6549-
self.parse_generic_bounds()?
6587+
self.parse_generic_bounds(Some(self.prev_span))?
65506588
} else {
65516589
Vec::new()
65526590
};
65536591

65546592
if self.eat(&token::Eq) {
65556593
// it's a trait alias
6556-
let bounds = self.parse_generic_bounds()?;
6594+
let bounds = self.parse_generic_bounds(None)?;
65576595
tps.where_clause = self.parse_where_clause()?;
65586596
self.expect(&token::Semi)?;
65596597
if is_auto == IsAuto::Yes {
@@ -7588,7 +7626,7 @@ impl<'a> Parser<'a> {
75887626
tps.where_clause = self.parse_where_clause()?;
75897627
let alias = if existential {
75907628
self.expect(&token::Colon)?;
7591-
let bounds = self.parse_generic_bounds()?;
7629+
let bounds = self.parse_generic_bounds(None)?;
75927630
AliasKind::Existential(bounds)
75937631
} else {
75947632
self.expect(&token::Eq)?;

src/test/ui/parser/issue-33418.fixed

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
3+
trait Tr {} //~ ERROR negative trait bounds are not supported
4+
trait Tr2: SuperA {} //~ ERROR negative trait bounds are not supported
5+
trait Tr3: SuperB {} //~ ERROR negative trait bounds are not supported
6+
trait Tr4: SuperB + SuperD {}
7+
trait Tr5 {}
8+
9+
trait SuperA {}
10+
trait SuperB {}
11+
trait SuperC {}
12+
trait SuperD {}
13+
14+
fn main() {}

src/test/ui/parser/issue-33418.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
3+
trait Tr: !SuperA {} //~ ERROR negative trait bounds are not supported
4+
trait Tr2: SuperA + !SuperB {} //~ ERROR negative trait bounds are not supported
5+
trait Tr3: !SuperA + SuperB {} //~ ERROR negative trait bounds are not supported
6+
trait Tr4: !SuperA + SuperB //~ ERROR negative trait bounds are not supported
7+
+ !SuperC + SuperD {}
8+
trait Tr5: !SuperA //~ ERROR negative trait bounds are not supported
9+
+ !SuperB {}
10+
11+
trait SuperA {}
12+
trait SuperB {}
13+
trait SuperC {}
14+
trait SuperD {}
15+
16+
fn main() {}

src/test/ui/parser/issue-33418.stderr

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
error: negative trait bounds are not supported
2+
--> $DIR/issue-33418.rs:3:9
3+
|
4+
LL | trait Tr: !SuperA {} //~ ERROR negative trait bounds are not supported
5+
| ^^^^^^^^^ help: remove the trait bound
6+
7+
error: negative trait bounds are not supported
8+
--> $DIR/issue-33418.rs:4:19
9+
|
10+
LL | trait Tr2: SuperA + !SuperB {} //~ ERROR negative trait bounds are not supported
11+
| ---------^^^^^^^^^
12+
| |
13+
| help: remove the trait bound
14+
15+
error: negative trait bounds are not supported
16+
--> $DIR/issue-33418.rs:5:10
17+
|
18+
LL | trait Tr3: !SuperA + SuperB {} //~ ERROR negative trait bounds are not supported
19+
| ^^^^^^^^^---------
20+
| |
21+
| help: remove the trait bound
22+
23+
error: negative trait bounds are not supported
24+
--> $DIR/issue-33418.rs:6:10
25+
|
26+
LL | trait Tr4: !SuperA + SuperB //~ ERROR negative trait bounds are not supported
27+
| __________-^^^^^^^^
28+
LL | | + !SuperC + SuperD {}
29+
| |_____^^^^^^^^^________- help: remove the trait bounds
30+
31+
error: negative trait bounds are not supported
32+
--> $DIR/issue-33418.rs:8:10
33+
|
34+
LL | trait Tr5: !SuperA //~ ERROR negative trait bounds are not supported
35+
| __________-^^^^^^^^
36+
LL | | + !SuperB {}
37+
| | ^^^^^^^^-
38+
| |_____________|
39+
| help: remove the trait bounds
40+
41+
error: aborting due to 5 previous errors
42+

0 commit comments

Comments
 (0)