Skip to content

Commit

Permalink
Provide help when T: ?Sized can't be suggested
Browse files Browse the repository at this point in the history
  • Loading branch information
estebank committed Jun 17, 2020
1 parent d2b8e60 commit aa84b0f
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 10 deletions.
54 changes: 45 additions & 9 deletions src/librustc_trait_selection/traits/error_reporting/mod.rs
Expand Up @@ -26,7 +26,7 @@ use rustc_middle::ty::{
TypeFoldable, WithConstness,
};
use rustc_session::DiagnosticMessageId;
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
use std::fmt;

use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
Expand Down Expand Up @@ -1740,10 +1740,36 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
// is not.
let mut visitor = FindTypeParam { param: param.name.ident().name, valid: true };
let mut visitor = FindTypeParam {
param: param.name.ident().name,
invalid_spans: vec![],
nested: false,
};
visitor.visit_item(item);
if !visitor.valid {
continue;
if !visitor.invalid_spans.is_empty() {
let mut multispan: MultiSpan = param.span.into();
multispan.push_span_label(
param.span,
format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
);
for sp in visitor.invalid_spans {
multispan.push_span_label(
sp,
format!(
"...if indirection was used here: `Box<{}>`",
param.name.ident(),
),
);
}
err.span_help(
multispan,
&format!(
"you could relax the implicit `Sized` bound on `{T}` if it were \
used through indirection like `&{T}` or `Box<{T}>`",
T = param.name.ident(),
),
);
return;
}
}
_ => {}
Expand Down Expand Up @@ -1782,7 +1808,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
/// `param: ?Sized` would be a valid constraint.
struct FindTypeParam {
param: rustc_span::Symbol,
valid: bool,
invalid_spans: Vec<Span>,
nested: bool,
}

impl<'v> Visitor<'v> for FindTypeParam {
Expand All @@ -1794,15 +1821,24 @@ impl<'v> Visitor<'v> for FindTypeParam {

fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
match ty.kind {
hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => return,
hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
hir::TyKind::Path(hir::QPath::Resolved(None, path))
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
{
self.valid = false;
if !self.nested {
self.invalid_spans.push(ty.span);
}
}
hir::TyKind::Path(_) => {
let prev = self.nested;
self.nested = true;
hir::intravisit::walk_ty(self, ty);
self.nested = prev;
}
_ => {
hir::intravisit::walk_ty(self, ty);
}
_ => {}
}
hir::intravisit::walk_ty(self, ty);
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/issues/issue-18919.stderr
Expand Up @@ -9,6 +9,13 @@ LL | enum Option<T> {
|
= help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/issue-18919.rs:7:13
|
LL | enum Option<T> {
| ^ this could be changed to `T: ?Sized`...
LL | Some(T),
| - ...if indirection was used here: `Box<T>`

error: aborting due to previous error

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/issues/issue-23281.stderr
Expand Up @@ -9,6 +9,13 @@ LL | struct Vec<T> {
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/issue-23281.rs:8:12
|
LL | struct Vec<T> {
| ^ this could be changed to `T: ?Sized`...
LL | t: T,
| - ...if indirection was used here: `Box<T>`

error: aborting due to previous error

Expand Down
11 changes: 11 additions & 0 deletions src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs
Expand Up @@ -2,6 +2,7 @@ trait Trait {
fn func1() -> Struct1<Self>; //~ ERROR E0277
fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
fn func3() -> Struct3<Self>; //~ ERROR E0277
fn func4() -> Struct4<Self>; //~ ERROR E0277
}

struct Struct1<T>{
Expand All @@ -14,4 +15,14 @@ struct Struct3<T>{
_t: T,
}

struct X<T>(T);

struct Struct4<T>{
_t: X<T>,
}

struct Struct5<T: ?Sized>{
_t: X<T>, //~ ERROR E0277
}

fn main() {}
@@ -1,3 +1,24 @@
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/adt-param-with-implicit-sized-bound.rs:25:5
|
LL | struct X<T>(T);
| - required by this bound in `X`
...
LL | struct Struct5<T: ?Sized>{
| - this type parameter needs to be `std::marker::Sized`
LL | _t: X<T>,
| ^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/adt-param-with-implicit-sized-bound.rs:18:10
|
LL | struct X<T>(T);
| ^ - ...if indirection was used here: `Box<T>`
| |
| this could be changed to `T: ?Sized`...

error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
|
Expand Down Expand Up @@ -49,11 +70,38 @@ LL | struct Struct3<T>{
|
= help: the trait `std::marker::Sized` is not implemented for `Self`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/adt-param-with-implicit-sized-bound.rs:14:16
|
LL | struct Struct3<T>{
| ^ this could be changed to `T: ?Sized`...
LL | _t: T,
| - ...if indirection was used here: `Box<T>`
help: consider further restricting `Self`
|
LL | fn func3() -> Struct3<Self> where Self: std::marker::Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> $DIR/adt-param-with-implicit-sized-bound.rs:5:19
|
LL | fn func4() -> Struct4<Self>;
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
...
LL | struct Struct4<T>{
| - required by this bound in `Struct4`
|
= help: the trait `std::marker::Sized` is not implemented for `Self`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: consider further restricting `Self`
|
LL | fn func4() -> Struct4<Self> where Self: std::marker::Sized;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider relaxing the implicit `Sized` restriction
|
LL | struct Struct4<T: ?Sized>{
| ^^^^^^^^

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
7 changes: 7 additions & 0 deletions src/test/ui/unsized/unsized-enum.stderr
Expand Up @@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>`
--> $DIR/unsized-enum.rs:4:10
|
LL | enum Foo<U> { FooSome(U), FooNone }
| ^ - ...if indirection was used here: `Box<U>`
| |
| this could be changed to `U: ?Sized`...

error: aborting due to previous error

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/unsized/unsized-inherent-impl-self-type.stderr
Expand Up @@ -11,6 +11,13 @@ LL | impl<X: ?Sized> S5<X> {
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
--> $DIR/unsized-inherent-impl-self-type.rs:5:11
|
LL | struct S5<Y>(Y);
| ^ - ...if indirection was used here: `Box<Y>`
| |
| this could be changed to `Y: ?Sized`...

error: aborting due to previous error

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/unsized/unsized-struct.stderr
Expand Up @@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() }
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/unsized-struct.rs:4:12
|
LL | struct Foo<T> { data: T }
| ^ - ...if indirection was used here: `Box<T>`
| |
| this could be changed to `T: ?Sized`...

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> $DIR/unsized-struct.rs:13:24
Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/unsized/unsized-trait-impl-self-type.stderr
Expand Up @@ -11,6 +11,13 @@ LL | impl<X: ?Sized> T3<X> for S5<X> {
|
= help: the trait `std::marker::Sized` is not implemented for `X`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>`
--> $DIR/unsized-trait-impl-self-type.rs:8:11
|
LL | struct S5<Y>(Y);
| ^ - ...if indirection was used here: `Box<Y>`
| |
| this could be changed to `Y: ?Sized`...

error: aborting due to previous error

Expand Down
7 changes: 7 additions & 0 deletions src/test/ui/wf/wf-fn-where-clause.stderr
Expand Up @@ -23,6 +23,13 @@ LL | struct Vec<T> {
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
--> $DIR/wf-fn-where-clause.rs:16:12
|
LL | struct Vec<T> {
| ^ this could be changed to `T: ?Sized`...
LL | t: T,
| - ...if indirection was used here: `Box<T>`

error[E0038]: the trait `std::marker::Copy` cannot be made into an object
--> $DIR/wf-fn-where-clause.rs:12:16
Expand Down

0 comments on commit aa84b0f

Please sign in to comment.