nested_impl_trait -> error

This commit is contained in:
Mazdak Farrokhzad 2019-08-03 21:59:22 +02:00
parent 8e27c4f312
commit 0cbd06ae1c
9 changed files with 56 additions and 299 deletions

View File

@ -446,16 +446,6 @@ declare_lint! {
};
}
declare_lint! {
pub NESTED_IMPL_TRAIT,
Warn,
"nested occurrence of `impl Trait` type",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>",
edition: None,
};
}
declare_lint! {
pub MUTABLE_BORROW_RESERVATION_CONFLICT,
Warn,
@ -534,7 +524,6 @@ declare_lint_pass! {
parser::META_VARIABLE_MISUSE,
DEPRECATED_IN_FUTURE,
AMBIGUOUS_ASSOCIATED_ITEMS,
NESTED_IMPL_TRAIT,
MUTABLE_BORROW_RESERVATION_CONFLICT,
INDIRECT_STRUCTURAL_MATCH,
SOFT_UNSTABLE,
@ -553,7 +542,6 @@ pub enum BuiltinLintDiagnostics {
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
UnknownCrateTypes(Span, String, String),
UnusedImports(String, Vec<(Span, String)>),
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
RedundantImport(Vec<(Span, bool)>, ast::Ident),
DeprecatedMacro(Option<Symbol>, Span),
}
@ -662,12 +650,6 @@ impl BuiltinLintDiagnostics {
);
}
}
BuiltinLintDiagnostics::NestedImplTrait {
outer_impl_trait_span, inner_impl_trait_span
} => {
db.span_label(outer_impl_trait_span, "outer `impl Trait`");
db.span_label(inner_impl_trait_span, "nested `impl Trait` here");
}
BuiltinLintDiagnostics::RedundantImport(spans, ident) => {
for (span, is_imported) in spans {
let introduced = if is_imported { "imported" } else { "defined" };

View File

@ -344,6 +344,8 @@ fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
"converted into hard error, see https://github.com/rust-lang/rust/issues/42238");
store.register_removed("duplicate_macro_exports",
"converted into hard error, see https://github.com/rust-lang/rust/issues/35896");
store.register_removed("nested_impl_trait",
"converted into hard error, see https://github.com/rust-lang/rust/issues/59014");
}
fn register_internals(store: &mut lint::LintStore) {

View File

@ -9,7 +9,6 @@
use std::mem;
use syntax::print::pprust;
use rustc::lint;
use rustc::lint::builtin::{BuiltinLintDiagnostics, NESTED_IMPL_TRAIT};
use rustc::session::Session;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::*;
@ -23,31 +22,6 @@ use syntax::{span_err, struct_span_err, walk_list};
use syntax_pos::{Span, MultiSpan};
use errors::{Applicability, FatalError};
#[derive(Copy, Clone, Debug)]
struct OuterImplTrait {
span: Span,
/// rust-lang/rust#57979: a bug in original implementation caused
/// us to fail sometimes to record an outer `impl Trait`.
/// Therefore, in order to reliably issue a warning (rather than
/// an error) in the *precise* places where we are newly injecting
/// the diagnostic, we have to distinguish between the places
/// where the outer `impl Trait` has always been recorded, versus
/// the places where it has only recently started being recorded.
only_recorded_since_pull_request_57730: bool,
}
impl OuterImplTrait {
/// This controls whether we should downgrade the nested impl
/// trait diagnostic to a warning rather than an error, based on
/// whether the outer impl trait had been improperly skipped in
/// earlier implementations of the analysis on the stable
/// compiler.
fn should_warn_instead_of_error(&self) -> bool {
self.only_recorded_since_pull_request_57730
}
}
struct AstValidator<'a> {
session: &'a Session,
has_proc_macro_decls: bool,
@ -55,7 +29,7 @@ struct AstValidator<'a> {
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
/// Nested `impl Trait` _is_ allowed in associated type position,
/// e.g., `impl Iterator<Item = impl Debug>`.
outer_impl_trait: Option<OuterImplTrait>,
outer_impl_trait: Option<Span>,
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
/// or `Foo::Bar<impl Trait>`
@ -65,26 +39,10 @@ struct AstValidator<'a> {
/// certain positions.
is_assoc_ty_bound_banned: bool,
/// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
/// until PRs #57730 and #57981 landed: it would jump directly to
/// walk_ty rather than visit_ty (or skip recurring entirely for
/// impl trait in projections), and thus miss some cases. We track
/// whether we should downgrade to a warning for short-term via
/// these booleans.
warning_period_57979_didnt_record_next_impl_trait: bool,
warning_period_57979_impl_trait_in_proj: bool,
lint_buffer: &'a mut lint::LintBuffer,
}
impl<'a> AstValidator<'a> {
fn with_impl_trait_in_proj_warning<T>(&mut self, v: bool, f: impl FnOnce(&mut Self) -> T) -> T {
let old = mem::replace(&mut self.warning_period_57979_impl_trait_in_proj, v);
let ret = f(self);
self.warning_period_57979_impl_trait_in_proj = old;
ret
}
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.is_impl_trait_banned, true);
f(self);
@ -97,7 +55,7 @@ impl<'a> AstValidator<'a> {
self.is_assoc_ty_bound_banned = old;
}
fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
f(self);
self.outer_impl_trait = old;
@ -105,14 +63,7 @@ impl<'a> AstValidator<'a> {
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
// rust-lang/rust#57979: bug in old `visit_generic_args` called
// `walk_ty` rather than `visit_ty`, skipping outer `impl Trait`
// if it happened to occur at `ty`.
if let TyKind::ImplTrait(..) = ty.kind {
self.warning_period_57979_didnt_record_next_impl_trait = true;
}
}
AssocTyConstraintKind::Equality { .. } => {}
AssocTyConstraintKind::Bound { .. } => {
if self.is_assoc_ty_bound_banned {
self.err_handler().span_err(constraint.span,
@ -124,37 +75,11 @@ impl<'a> AstValidator<'a> {
self.visit_assoc_ty_constraint(constraint);
}
fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) {
// rust-lang/rust#57979: bug in old `visit_generic_args` called
// `walk_ty` rather than `visit_ty`, skippping outer `impl Trait`
// if it happened to occur at `ty`.
if let TyKind::ImplTrait(..) = ty.kind {
self.warning_period_57979_didnt_record_next_impl_trait = true;
}
self.visit_ty(ty);
}
fn outer_impl_trait(&mut self, span: Span) -> OuterImplTrait {
let only_recorded_since_pull_request_57730 =
self.warning_period_57979_didnt_record_next_impl_trait;
// (This flag is designed to be set to `true`, and then only
// reach the construction point for the outer impl trait once,
// so its safe and easiest to unconditionally reset it to
// false.)
self.warning_period_57979_didnt_record_next_impl_trait = false;
OuterImplTrait {
span, only_recorded_since_pull_request_57730,
}
}
// Mirrors `visit::walk_ty`, but tracks relevant state.
fn walk_ty(&mut self, t: &'a Ty) {
match t.kind {
TyKind::ImplTrait(..) => {
let outer_impl_trait = self.outer_impl_trait(t.span);
self.with_impl_trait(Some(outer_impl_trait), |this| visit::walk_ty(this, t))
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
}
TyKind::Path(ref qself, ref path) => {
// We allow these:
@ -484,32 +409,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
TyKind::ImplTrait(_, ref bounds) => {
if self.is_impl_trait_banned {
if self.warning_period_57979_impl_trait_in_proj {
self.lint_buffer.buffer_lint(
NESTED_IMPL_TRAIT, ty.id, ty.span,
"`impl Trait` is not allowed in path parameters");
} else {
struct_span_err!(self.session, ty.span, E0667,
"`impl Trait` is not allowed in path parameters").emit();
}
struct_span_err!(
self.session, ty.span, E0667,
"`impl Trait` is not allowed in path parameters"
)
.emit();
}
if let Some(outer_impl_trait) = self.outer_impl_trait {
if outer_impl_trait.should_warn_instead_of_error() {
self.lint_buffer.buffer_lint_with_diagnostic(
NESTED_IMPL_TRAIT, ty.id, ty.span,
"nested `impl Trait` is not allowed",
BuiltinLintDiagnostics::NestedImplTrait {
outer_impl_trait_span: outer_impl_trait.span,
inner_impl_trait_span: ty.span,
});
} else {
struct_span_err!(self.session, ty.span, E0666,
"nested `impl Trait` is not allowed")
.span_label(outer_impl_trait.span, "outer `impl Trait`")
.span_label(ty.span, "nested `impl Trait` here")
.emit();
}
if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
struct_span_err!(
self.session, ty.span, E0666,
"nested `impl Trait` is not allowed"
)
.span_label(outer_impl_trait_sp, "outer `impl Trait`")
.span_label(ty.span, "nested `impl Trait` here")
.emit();
}
if !bounds.iter()
@ -517,7 +431,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.err_handler().span_err(ty.span, "at least one trait must be specified");
}
self.with_impl_trait_in_proj_warning(true, |this| this.walk_ty(ty));
self.walk_ty(ty);
return;
}
_ => {}
@ -726,7 +640,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
if let Some(ref type_) = data.output {
// `-> Foo` syntax is essentially an associated type binding,
// so it is also allowed to contain nested `impl Trait`.
self.with_impl_trait(None, |this| this.visit_ty_from_generic_args(type_));
self.with_impl_trait(None, |this| this.visit_ty(type_));
}
}
}
@ -844,8 +758,6 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffe
outer_impl_trait: None,
is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false,
warning_period_57979_didnt_record_next_impl_trait: false,
warning_period_57979_impl_trait_in_proj: false,
lint_buffer: lints,
};
visit::walk_crate(&mut validator, krate);

View File

@ -1,42 +1,17 @@
// rust-lang/rust#57979 : the initial support for `impl Trait` didn't
// properly check syntax hidden behind an associated type projection,
// but it did catch *some cases*. This is checking that we continue to
// properly emit errors for those, even with the new
// future-incompatibility warnings.
// properly emit errors for those.
//
// issue-57979-nested-impl-trait-in-assoc-proj.rs shows the main case
// that we were previously failing to catch.
struct Deeper<T>(T);
mod allowed {
#![allow(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
//~^ ERROR nested `impl Trait` is not allowed
}
mod warned {
#![warn(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
//~^ ERROR nested `impl Trait` is not allowed
}
mod denied {
#![deny(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
//~^ ERROR nested `impl Trait` is not allowed
}
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { }
//~^ ERROR nested `impl Trait` is not allowed
fn main() { }

View File

@ -1,30 +1,12 @@
error[E0666]: nested `impl Trait` is not allowed
--> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:18:59
--> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:14:48
|
LL | pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
LL | pub fn demo(_: impl Quux<Assoc=Deeper<impl Foo<impl Bar>>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
--> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:28:59
|
LL | pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
--> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:38:59
|
LL | pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
error: aborting due to 3 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0666`.

View File

@ -3,35 +3,10 @@
// Here we test behavior of occurrences of `impl Trait` within a path
// component in that context.
mod allowed {
#![allow(nested_impl_trait)]
pub trait Bar { }
pub trait Quux<T> { type Assoc; }
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
impl<T> Quux<T> for () { type Assoc = u32; }
}
mod warned {
#![warn(nested_impl_trait)]
pub trait Bar { }
pub trait Quux<T> { type Assoc; }
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
//~^ WARN `impl Trait` is not allowed in path parameters
//~| WARN will become a hard error in a future release!
impl<T> Quux<T> for () { type Assoc = u32; }
}
mod denied {
#![deny(nested_impl_trait)]
pub trait Bar { }
pub trait Quux<T> { type Assoc; }
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
//~^ ERROR `impl Trait` is not allowed in path parameters
//~| WARN will become a hard error in a future release!
impl<T> Quux<T> for () { type Assoc = u32; }
}
pub trait Bar { }
pub trait Quux<T> { type Assoc; }
pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
//~^ ERROR `impl Trait` is not allowed in path parameters
impl<T> Quux<T> for () { type Assoc = u32; }
fn main() { }

View File

@ -1,30 +1,8 @@
warning: `impl Trait` is not allowed in path parameters
--> $DIR/issue-57979-impl-trait-in-path.rs:20:52
error[E0667]: `impl Trait` is not allowed in path parameters
--> $DIR/issue-57979-impl-trait-in-path.rs:8:48
|
LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
| ^^^^^^^^
|
note: lint level defined here
--> $DIR/issue-57979-impl-trait-in-path.rs:16:13
|
LL | #![warn(nested_impl_trait)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
error: `impl Trait` is not allowed in path parameters
--> $DIR/issue-57979-impl-trait-in-path.rs:31:52
|
LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
| ^^^^^^^^
|
note: lint level defined here
--> $DIR/issue-57979-impl-trait-in-path.rs:27:13
|
LL | #![deny(nested_impl_trait)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
| ^^^^^^^^
error: aborting due to previous error

View File

@ -3,35 +3,10 @@
// Here we test behavior of occurrences of `impl Trait` within an
// `impl Trait` in that context.
mod allowed {
#![allow(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
}
mod warned {
#![warn(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
//~^ WARN nested `impl Trait` is not allowed
//~| WARN will become a hard error in a future release!
}
mod denied {
#![deny(nested_impl_trait)]
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
//~^ ERROR nested `impl Trait` is not allowed
//~| WARN will become a hard error in a future release!
}
pub trait Foo<T> { }
pub trait Bar { }
pub trait Quux { type Assoc; }
pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
//~^ ERROR nested `impl Trait` is not allowed
fn main() { }

View File

@ -1,36 +1,12 @@
warning: nested `impl Trait` is not allowed
--> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:21:45
error[E0666]: nested `impl Trait` is not allowed
--> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:9:41
|
LL | pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
|
note: lint level defined here
--> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:16:13
|
LL | #![warn(nested_impl_trait)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
error: nested `impl Trait` is not allowed
--> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:32:45
|
LL | pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
|
note: lint level defined here
--> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:27:13
|
LL | #![deny(nested_impl_trait)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
LL | pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
| ---------^^^^^^^^-
| | |
| | nested `impl Trait` here
| outer `impl Trait`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0666`.