Disallow projections from impl Trait types
This commit is contained in:
parent
75f72c0de1
commit
70e1f4fc6d
4 changed files with 139 additions and 1 deletions
|
@ -447,7 +447,7 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
|
||||||
struct_span_err!(self.session, t.span, E0666,
|
struct_span_err!(self.session, t.span, E0666,
|
||||||
"nested `impl Trait` is not allowed")
|
"nested `impl Trait` is not allowed")
|
||||||
.span_label(outer_impl_trait, "outer `impl Trait`")
|
.span_label(outer_impl_trait, "outer `impl Trait`")
|
||||||
.span_label(t.span, "devilishly nested `impl Trait` here")
|
.span_label(t.span, "nested `impl Trait` here")
|
||||||
.emit();
|
.emit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -482,6 +482,66 @@ impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
|
||||||
|
struct ImplTraitProjectionVisitor<'a> {
|
||||||
|
session: &'a Session,
|
||||||
|
is_banned: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ImplTraitProjectionVisitor<'a> {
|
||||||
|
fn with_ban<F>(&mut self, f: F)
|
||||||
|
where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>)
|
||||||
|
{
|
||||||
|
let old_is_banned = self.is_banned;
|
||||||
|
self.is_banned = true;
|
||||||
|
f(self);
|
||||||
|
self.is_banned = old_is_banned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
|
||||||
|
fn visit_ty(&mut self, t: &'a Ty) {
|
||||||
|
match t.node {
|
||||||
|
TyKind::ImplTrait(_) => {
|
||||||
|
if self.is_banned {
|
||||||
|
struct_span_err!(self.session, t.span, E0667,
|
||||||
|
"`impl Trait` is not allowed in path parameters")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TyKind::Path(ref qself, ref path) => {
|
||||||
|
// We allow these:
|
||||||
|
// - `Option<impl Trait>`
|
||||||
|
// - `option::Option<impl Trait>`
|
||||||
|
// - `option::Option<T>::Foo<impl Trait>
|
||||||
|
//
|
||||||
|
// But not these:
|
||||||
|
// - `<impl Trait>::Foo`
|
||||||
|
// - `option::Option<impl Trait>::Foo`.
|
||||||
|
//
|
||||||
|
// To implement this, we disallow `impl Trait` from `qself`
|
||||||
|
// (for cases like `<impl Trait>::Foo>`)
|
||||||
|
// but we allow `impl Trait` in `PathParameters`
|
||||||
|
// iff there are no more PathSegments.
|
||||||
|
if let Some(ref qself) = *qself {
|
||||||
|
// `impl Trait` in `qself` is always illegal
|
||||||
|
self.with_ban(|this| this.visit_ty(&qself.ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, segment) in path.segments.iter().enumerate() {
|
||||||
|
// Allow `impl Trait` iff we're on the final path segment
|
||||||
|
if i == (path.segments.len() - 1) {
|
||||||
|
visit::walk_path_segment(self, path.span, segment);
|
||||||
|
} else {
|
||||||
|
self.with_ban(|this|
|
||||||
|
visit::walk_path_segment(this, path.span, segment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => visit::walk_ty(self, t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_crate(session: &Session, krate: &Crate) {
|
pub fn check_crate(session: &Session, krate: &Crate) {
|
||||||
visit::walk_crate(
|
visit::walk_crate(
|
||||||
|
@ -490,5 +550,11 @@ pub fn check_crate(session: &Session, krate: &Crate) {
|
||||||
outer_impl_trait: None,
|
outer_impl_trait: None,
|
||||||
}, krate);
|
}, krate);
|
||||||
|
|
||||||
|
visit::walk_crate(
|
||||||
|
&mut ImplTraitProjectionVisitor {
|
||||||
|
session,
|
||||||
|
is_banned: false,
|
||||||
|
}, krate);
|
||||||
|
|
||||||
visit::walk_crate(&mut AstValidator { session: session }, krate)
|
visit::walk_crate(&mut AstValidator { session: session }, krate)
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,4 +321,5 @@ register_diagnostics! {
|
||||||
E0568, // auto traits can not have super traits
|
E0568, // auto traits can not have super traits
|
||||||
E0642, // patterns aren't allowed in methods without bodies
|
E0642, // patterns aren't allowed in methods without bodies
|
||||||
E0666, // nested `impl Trait` is illegal
|
E0666, // nested `impl Trait` is illegal
|
||||||
|
E0667, // `impl Trait` in projections
|
||||||
}
|
}
|
||||||
|
|
43
src/test/ui/impl_trait_projections.rs
Normal file
43
src/test/ui/impl_trait_projections.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
#![feature(conservative_impl_trait, universal_impl_trait)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::option;
|
||||||
|
|
||||||
|
fn parametrized_type_is_allowed() -> Option<impl Debug> {
|
||||||
|
Some(5i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
|
||||||
|
Some(5i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
|
||||||
|
//~^ ERROR `impl Trait` is not allowed in path parameters
|
||||||
|
//~^^ ERROR ambiguous associated type
|
||||||
|
x.next().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projection_with_named_trait_is_disallowed(x: impl Iterator)
|
||||||
|
-> <impl Iterator as Iterator>::Item
|
||||||
|
//~^ ERROR `impl Trait` is not allowed in path parameters
|
||||||
|
{
|
||||||
|
x.next().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn projection_with_named_trait_inside_path_is_disallowed()
|
||||||
|
-> <::std::ops::Range<impl Debug> as Iterator>::Item
|
||||||
|
//~^ ERROR `impl Trait` is not allowed in path parameters
|
||||||
|
{
|
||||||
|
(1i32..100).next().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
28
src/test/ui/impl_trait_projections.stderr
Normal file
28
src/test/ui/impl_trait_projections.stderr
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
error[E0667]: `impl Trait` is not allowed in path parameters
|
||||||
|
--> $DIR/impl_trait_projections.rs:23:51
|
||||||
|
|
|
||||||
|
23 | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0667]: `impl Trait` is not allowed in path parameters
|
||||||
|
--> $DIR/impl_trait_projections.rs:30:9
|
||||||
|
|
|
||||||
|
30 | -> <impl Iterator as Iterator>::Item
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0667]: `impl Trait` is not allowed in path parameters
|
||||||
|
--> $DIR/impl_trait_projections.rs:37:27
|
||||||
|
|
|
||||||
|
37 | -> <::std::ops::Range<impl Debug> as Iterator>::Item
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0223]: ambiguous associated type
|
||||||
|
--> $DIR/impl_trait_projections.rs:23:50
|
||||||
|
|
|
||||||
|
23 | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type
|
||||||
|
|
|
||||||
|
= note: specify the type using the syntax `<impl std::iter::Iterator as Trait>::Item`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Reference in a new issue