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

Tweak output for invalid negative impl AST errors #69722

Merged
merged 7 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/librustc_ast/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2117,14 +2117,14 @@ pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
/// `impl !Trait for Type`
Negative,
Negative(Span),
}

impl fmt::Debug for ImplPolarity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ImplPolarity::Positive => "positive".fmt(f),
ImplPolarity::Negative => "negative".fmt(f),
ImplPolarity::Negative(_) => "negative".fmt(f),
}
}
}
Expand Down
89 changes: 58 additions & 31 deletions src/librustc_ast_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
defaultness: _,
constness: _,
generics: _,
of_trait: Some(_),
of_trait: Some(ref t),
ref self_ty,
items: _,
} => {
Expand All @@ -794,13 +794,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
.help("use `auto trait Trait {}` instead")
.emit();
}
if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) {
struct_span_err!(
this.session,
item.span,
Centril marked this conversation as resolved.
Show resolved Hide resolved
sp.to(t.path.span),
E0198,
"negative impls cannot be unsafe"
)
.span_label(sp, "negative because of this")
.span_label(span, "unsafe because of this")
.emit();
}
Expand All @@ -816,38 +817,36 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
constness,
generics: _,
of_trait: None,
self_ty: _,
ref self_ty,
items: _,
} => {
let error = |annotation_span, annotation| {
let mut err = self.err_handler().struct_span_err(
self_ty.span,
&format!("inherent impls cannot be {}", annotation),
);
err.span_label(annotation_span, &format!("{} because of this", annotation));
err.span_label(self_ty.span, "inherent impl for this type");
err
};

self.invalid_visibility(
&item.vis,
Some("place qualifiers on individual impl items instead"),
);
if let Unsafe::Yes(span) = unsafety {
struct_span_err!(
self.session,
item.span,
E0197,
"inherent impls cannot be unsafe"
)
.span_label(span, "unsafe because of this")
.emit();
error(span, "unsafe").code(error_code!(E0197)).emit();
}
if polarity == ImplPolarity::Negative {
self.err_handler().span_err(item.span, "inherent impls cannot be negative");
if let ImplPolarity::Negative(span) = polarity {
error(span, "negative").emit();
}
if let Defaultness::Default(def_span) = defaultness {
let span = self.session.source_map().def_span(item.span);
self.err_handler()
.struct_span_err(span, "inherent impls cannot be `default`")
.span_label(def_span, "`default` because of this")
error(def_span, "`default`")
.note("only trait implementations may be annotated with `default`")
.emit();
}
if let Const::Yes(span) = constness {
self.err_handler()
.struct_span_err(item.span, "inherent impls cannot be `const`")
.span_label(span, "`const` because of this")
error(span, "`const`")
.note("only trait implementations may be annotated with `const`")
.emit();
}
Expand Down Expand Up @@ -883,30 +882,54 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
if !generics.params.is_empty() {
struct_span_err!(
let mut err = struct_span_err!(
self.session,
item.span,
generics.span,
E0567,
"auto traits cannot have generic parameters"
)
.emit();
);
err.span_label(
item.ident.span,
"auto trait cannot have generic parameters",
);
err.span_suggestion(
generics.span,
"remove the parameters",
String::new(),
Applicability::MachineApplicable,
);
err.emit();
estebank marked this conversation as resolved.
Show resolved Hide resolved
}
if !bounds.is_empty() {
struct_span_err!(
let span = match &bounds[..] {
[] => unreachable!(),
[single] => single.span(),
[first, .., last] => first.span().to(last.span()),
estebank marked this conversation as resolved.
Show resolved Hide resolved
};
let mut err = struct_span_err!(
self.session,
item.span,
span,
E0568,
"auto traits cannot have super traits"
)
.emit();
);
err.span_label(item.ident.span, "auto trait cannot have super traits");
err.span_suggestion(
span,
"remove the super traits",
String::new(),
Applicability::MachineApplicable,
);
err.emit();
estebank marked this conversation as resolved.
Show resolved Hide resolved
}
if !trait_items.is_empty() {
let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
estebank marked this conversation as resolved.
Show resolved Hide resolved
struct_span_err!(
self.session,
item.span,
spans,
E0380,
"auto traits cannot have methods or associated items"
)
.span_label(item.ident.span, "auto trait cannot have items")
.emit();
}
}
Expand Down Expand Up @@ -1153,9 +1176,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}) = fk.header()
{
self.err_handler()
.struct_span_err(span, "functions cannot be both `const` and `async`")
.struct_span_err(
vec![*cspan, *aspan],
"functions cannot be both `const` and `async`",
)
.span_label(*cspan, "`const` because of this")
.span_label(*aspan, "`async` because of this")
.span_label(span, "") // Point at the fn header.
.emit();
}

Expand Down
8 changes: 4 additions & 4 deletions src/librustc_ast_passes/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}

ast::ItemKind::Impl { polarity, defaultness, .. } => {
if polarity == ast::ImplPolarity::Negative {
ast::ItemKind::Impl { polarity, defaultness, ref of_trait, .. } => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
&self,
optin_builtin_traits,
i.span,
span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)),
"negative trait bounds are not yet fully implemented; \
use marker types for now"
use marker types for now"
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ast_pretty/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ impl<'a> State<'a> {
self.s.space();
}

if polarity == ast::ImplPolarity::Negative {
if let ast::ImplPolarity::Negative(_) = polarity {
self.s.word("!");
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl<'a> State<'a> {
self.word_nbsp("const");
}

if let hir::ImplPolarity::Negative = polarity {
if let hir::ImplPolarity::Negative(_) = polarity {
self.s.word("!");
}

Expand Down
18 changes: 11 additions & 7 deletions src/librustc_parse/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,16 @@ impl<'a> Parser<'a> {
self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])
}

fn parse_polarity(&mut self) -> ast::ImplPolarity {
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
self.bump(); // `!`
ast::ImplPolarity::Negative(self.prev_token.span)
} else {
ast::ImplPolarity::Positive
}
}

/// Parses an implementation item.
///
/// ```
Expand Down Expand Up @@ -411,13 +421,7 @@ impl<'a> Parser<'a> {
self.sess.gated_spans.gate(sym::const_trait_impl, span);
}

// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
self.bump(); // `!`
ast::ImplPolarity::Negative
} else {
ast::ImplPolarity::Positive
};
let polarity = self.parse_polarity();

// Parse both types and traits as a type, then reinterpret if necessary.
let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span));
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_save_analysis/sig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ impl Sig for ast::Item {
text.push(' ');

let trait_sig = if let Some(ref t) = *of_trait {
if polarity == ast::ImplPolarity::Negative {
if let ast::ImplPolarity::Negative(_) = polarity {
text.push('!');
}
let trait_sig = t.path.make(offset + text.len(), id, scx)?;
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/coherence/unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ impl UnsafetyChecker<'tcx> {
.emit();
}

(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => {
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
// Reported in AST validation
self.tcx.sess.delay_span_bug(item.span, "unsafe negative impl");
}
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative)
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
| (Unsafety::Normal, None, Unsafety::Normal, _) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1548,7 +1548,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
let item = tcx.hir().expect_item(hir_id);
match &item.kind {
hir::ItemKind::Impl { polarity: hir::ImplPolarity::Negative, .. } => {
hir::ItemKind::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => {
if is_rustc_reservation {
tcx.sess.span_err(item.span, "reservation impls can't be negative");
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/async-await/no-const-async.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: functions cannot be both `const` and `async`
--> $DIR/no-const-async.rs:4:1
--> $DIR/no-const-async.rs:4:5
|
LL | pub const async fn x() {}
| ^^^^-----^-----^^^^^^^^^^
| ----^^^^^-^^^^^----------
| | |
| | `async` because of this
| `const` because of this
Expand Down
18 changes: 12 additions & 6 deletions src/test/ui/auto-trait-validation.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
error[E0567]: auto traits cannot have generic parameters
--> $DIR/auto-trait-validation.rs:3:1
--> $DIR/auto-trait-validation.rs:3:19
|
LL | auto trait Generic<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
| -------^^^ help: remove the parameters
| |
| auto trait cannot have generic parameters

error[E0568]: auto traits cannot have super traits
--> $DIR/auto-trait-validation.rs:5:1
--> $DIR/auto-trait-validation.rs:5:20
|
LL | auto trait Bound : Copy {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| ----- ^^^^ help: remove the super traits
| |
| auto trait cannot have super traits

error[E0380]: auto traits cannot have methods or associated items
--> $DIR/auto-trait-validation.rs:7:1
--> $DIR/auto-trait-validation.rs:7:25
|
LL | auto trait MyTrait { fn foo() {} }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ------- ^^^
| |
| auto trait cannot have items

error: aborting due to 3 previous errors

Expand Down
7 changes: 4 additions & 3 deletions src/test/ui/coherence/coherence-negative-impls-safe.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
error[E0198]: negative impls cannot be unsafe
--> $DIR/coherence-negative-impls-safe.rs:7:1
--> $DIR/coherence-negative-impls-safe.rs:7:13
|
LL | unsafe impl !Send for TestType {}
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| ------ -^^^^
| | |
| | negative because of this
| unsafe because of this

error: aborting due to previous error
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0197.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0197]: inherent impls cannot be unsafe
--> $DIR/E0197.rs:3:1
--> $DIR/E0197.rs:3:13
|
LL | unsafe impl Foo { }
| ------^^^^^^^^^^^^^
| ------ ^^^ inherent impl for this type
| |
| unsafe because of this

Expand Down
7 changes: 4 additions & 3 deletions src/test/ui/error-codes/E0198.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
error[E0198]: negative impls cannot be unsafe
--> $DIR/E0198.rs:5:1
--> $DIR/E0198.rs:5:13
|
LL | unsafe impl !Send for Foo { }
| ------^^^^^^^^^^^^^^^^^^^^^^^
| |
| ------ -^^^^
| | |
| | negative because of this
| unsafe because of this

error: aborting due to previous error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ LL | auto trait AutoDummyTrait {}
= help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable

error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now
--> $DIR/feature-gate-optin-builtin-traits.rs:9:1
--> $DIR/feature-gate-optin-builtin-traits.rs:9:6
|
LL | impl !AutoDummyTrait for DummyStruct {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^
|
= note: see issue #13231 <https://github.com/rust-lang/rust/issues/13231> for more information
= help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable
Expand Down
3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-23080-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#![feature(optin_builtin_traits)]

unsafe auto trait Trait {
//~^ ERROR E0380
type Output;
type Output; //~ ERROR E0380
}

fn call_method<T: Trait>(x: T) {}
Expand Down
Loading