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,
|
||||
"nested `impl Trait` is not allowed")
|
||||
.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();
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
visit::walk_crate(
|
||||
|
@ -490,5 +550,11 @@ pub fn check_crate(session: &Session, krate: &Crate) {
|
|||
outer_impl_trait: None,
|
||||
}, krate);
|
||||
|
||||
visit::walk_crate(
|
||||
&mut ImplTraitProjectionVisitor {
|
||||
session,
|
||||
is_banned: false,
|
||||
}, krate);
|
||||
|
||||
visit::walk_crate(&mut AstValidator { session: session }, krate)
|
||||
}
|
||||
|
|
|
@ -321,4 +321,5 @@ register_diagnostics! {
|
|||
E0568, // auto traits can not have super traits
|
||||
E0642, // patterns aren't allowed in methods without bodies
|
||||
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