Skip to content

Commit 4910206

Browse files
authored
Rollup merge of #73261 - estebank:generics-sized, r=nikomatsakis
Suggest `?Sized` when applicable for ADTs Address #71790, fix #27964.
2 parents 17064da + 40b27ff commit 4910206

17 files changed

+352
-34
lines changed

src/librustc_hir/hir.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -2741,14 +2741,8 @@ impl Node<'_> {
27412741
pub fn generics(&self) -> Option<&Generics<'_>> {
27422742
match self {
27432743
Node::TraitItem(TraitItem { generics, .. })
2744-
| Node::ImplItem(ImplItem { generics, .. })
2745-
| Node::Item(Item {
2746-
kind:
2747-
ItemKind::Trait(_, _, generics, ..)
2748-
| ItemKind::Impl { generics, .. }
2749-
| ItemKind::Fn(_, generics, _),
2750-
..
2751-
}) => Some(generics),
2744+
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
2745+
Node::Item(item) => item.kind.generics(),
27522746
_ => None,
27532747
}
27542748
}

src/librustc_trait_selection/traits/error_reporting/mod.rs

+130-26
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
1515
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
1616
use rustc_hir as hir;
1717
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
18+
use rustc_hir::intravisit::Visitor;
1819
use rustc_hir::Node;
1920
use rustc_middle::mir::interpret::ErrorHandled;
2021
use rustc_middle::ty::error::ExpectedFound;
@@ -25,7 +26,7 @@ use rustc_middle::ty::{
2526
TypeFoldable, WithConstness,
2627
};
2728
use rustc_session::DiagnosticMessageId;
28-
use rustc_span::{ExpnKind, Span, DUMMY_SP};
29+
use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP};
2930
use std::fmt;
3031

3132
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -1695,36 +1696,95 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16951696
err: &mut DiagnosticBuilder<'tcx>,
16961697
obligation: &PredicateObligation<'tcx>,
16971698
) {
1698-
if let (
1699-
ty::PredicateKind::Trait(pred, _),
1700-
ObligationCauseCode::BindingObligation(item_def_id, span),
1701-
) = (obligation.predicate.kind(), &obligation.cause.code)
1702-
{
1703-
if let (Some(generics), true) = (
1704-
self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
1705-
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
1706-
) {
1707-
for param in generics.params {
1708-
if param.span == *span
1709-
&& !param.bounds.iter().any(|bound| {
1710-
bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
1711-
== self.tcx.lang_items().sized_trait()
1712-
})
1713-
{
1714-
let (span, separator) = match param.bounds {
1715-
[] => (span.shrink_to_hi(), ":"),
1716-
[.., bound] => (bound.span().shrink_to_hi(), " +"),
1717-
};
1718-
err.span_suggestion_verbose(
1719-
span,
1720-
"consider relaxing the implicit `Sized` restriction",
1721-
format!("{} ?Sized", separator),
1722-
Applicability::MachineApplicable,
1699+
let (pred, item_def_id, span) =
1700+
match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) {
1701+
(
1702+
ty::PredicateKind::Trait(pred, _),
1703+
ObligationCauseCode::BindingObligation(item_def_id, span),
1704+
) => (pred, item_def_id, span),
1705+
_ => return,
1706+
};
1707+
1708+
let node = match (
1709+
self.tcx.hir().get_if_local(*item_def_id),
1710+
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
1711+
) {
1712+
(Some(node), true) => node,
1713+
_ => return,
1714+
};
1715+
let generics = match node.generics() {
1716+
Some(generics) => generics,
1717+
None => return,
1718+
};
1719+
for param in generics.params {
1720+
if param.span != *span
1721+
|| param.bounds.iter().any(|bound| {
1722+
bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
1723+
== self.tcx.lang_items().sized_trait()
1724+
})
1725+
{
1726+
continue;
1727+
}
1728+
match node {
1729+
hir::Node::Item(
1730+
item
1731+
@
1732+
hir::Item {
1733+
kind:
1734+
hir::ItemKind::Enum(..)
1735+
| hir::ItemKind::Struct(..)
1736+
| hir::ItemKind::Union(..),
1737+
..
1738+
},
1739+
) => {
1740+
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
1741+
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
1742+
// is not.
1743+
let mut visitor = FindTypeParam {
1744+
param: param.name.ident().name,
1745+
invalid_spans: vec![],
1746+
nested: false,
1747+
};
1748+
visitor.visit_item(item);
1749+
if !visitor.invalid_spans.is_empty() {
1750+
let mut multispan: MultiSpan = param.span.into();
1751+
multispan.push_span_label(
1752+
param.span,
1753+
format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
1754+
);
1755+
for sp in visitor.invalid_spans {
1756+
multispan.push_span_label(
1757+
sp,
1758+
format!(
1759+
"...if indirection was used here: `Box<{}>`",
1760+
param.name.ident(),
1761+
),
1762+
);
1763+
}
1764+
err.span_help(
1765+
multispan,
1766+
&format!(
1767+
"you could relax the implicit `Sized` bound on `{T}` if it were \
1768+
used through indirection like `&{T}` or `Box<{T}>`",
1769+
T = param.name.ident(),
1770+
),
17231771
);
17241772
return;
17251773
}
17261774
}
1775+
_ => {}
17271776
}
1777+
let (span, separator) = match param.bounds {
1778+
[] => (span.shrink_to_hi(), ":"),
1779+
[.., bound] => (bound.span().shrink_to_hi(), " +"),
1780+
};
1781+
err.span_suggestion_verbose(
1782+
span,
1783+
"consider relaxing the implicit `Sized` restriction",
1784+
format!("{} ?Sized", separator),
1785+
Applicability::MachineApplicable,
1786+
);
1787+
return;
17281788
}
17291789
}
17301790

@@ -1744,6 +1804,50 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
17441804
}
17451805
}
17461806

1807+
/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
1808+
/// `param: ?Sized` would be a valid constraint.
1809+
struct FindTypeParam {
1810+
param: rustc_span::Symbol,
1811+
invalid_spans: Vec<Span>,
1812+
nested: bool,
1813+
}
1814+
1815+
impl<'v> Visitor<'v> for FindTypeParam {
1816+
type Map = rustc_hir::intravisit::ErasedMap<'v>;
1817+
1818+
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
1819+
hir::intravisit::NestedVisitorMap::None
1820+
}
1821+
1822+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
1823+
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
1824+
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
1825+
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
1826+
// obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
1827+
// and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
1828+
// in that case should make what happened clear enough.
1829+
match ty.kind {
1830+
hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
1831+
hir::TyKind::Path(hir::QPath::Resolved(None, path))
1832+
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
1833+
{
1834+
if !self.nested {
1835+
self.invalid_spans.push(ty.span);
1836+
}
1837+
}
1838+
hir::TyKind::Path(_) => {
1839+
let prev = self.nested;
1840+
self.nested = true;
1841+
hir::intravisit::walk_ty(self, ty);
1842+
self.nested = prev;
1843+
}
1844+
_ => {
1845+
hir::intravisit::walk_ty(self, ty);
1846+
}
1847+
}
1848+
}
1849+
}
1850+
17471851
pub fn recursive_type_with_infinite_size_error(
17481852
tcx: TyCtxt<'tcx>,
17491853
type_def_id: DefId,

src/test/ui/dst/dst-sized-trait-param.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ LL | impl Foo<[isize]> for usize { }
99
|
1010
= help: the trait `std::marker::Sized` is not implemented for `[isize]`
1111
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
12+
help: consider relaxing the implicit `Sized` restriction
13+
|
14+
LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
15+
| ^^^^^^^^
1216

1317
error[E0277]: the size for values of type `[usize]` cannot be known at compilation time
1418
--> $DIR/dst-sized-trait-param.rs:10:6

src/test/ui/extern/extern-types-unsized.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ LL | assert_sized::<Foo>();
2626
= help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A`
2727
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
2828
= note: required because it appears within the type `Foo`
29+
help: consider relaxing the implicit `Sized` restriction
30+
|
31+
LL | fn assert_sized<T: ?Sized>() { }
32+
| ^^^^^^^^
2933

3034
error[E0277]: the size for values of type `A` cannot be known at compilation time
3135
--> $DIR/extern-types-unsized.rs:28:5
@@ -39,6 +43,10 @@ LL | assert_sized::<Bar<A>>();
3943
= help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A`
4044
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
4145
= note: required because it appears within the type `Bar<A>`
46+
help: consider relaxing the implicit `Sized` restriction
47+
|
48+
LL | fn assert_sized<T: ?Sized>() { }
49+
| ^^^^^^^^
4250

4351
error[E0277]: the size for values of type `A` cannot be known at compilation time
4452
--> $DIR/extern-types-unsized.rs:31:5
@@ -53,6 +61,10 @@ LL | assert_sized::<Bar<Bar<A>>>();
5361
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
5462
= note: required because it appears within the type `Bar<A>`
5563
= note: required because it appears within the type `Bar<Bar<A>>`
64+
help: consider relaxing the implicit `Sized` restriction
65+
|
66+
LL | fn assert_sized<T: ?Sized>() { }
67+
| ^^^^^^^^
5668

5769
error: aborting due to 4 previous errors
5870

src/test/ui/issues/issue-10412.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ LL | impl<'self> Serializable<str> for &'self str {
5757
|
5858
= help: the trait `std::marker::Sized` is not implemented for `str`
5959
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
60+
help: consider relaxing the implicit `Sized` restriction
61+
|
62+
LL | trait Serializable<'self, T: ?Sized> {
63+
| ^^^^^^^^
6064

6165
error: aborting due to 9 previous errors
6266

src/test/ui/issues/issue-18919.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ LL | enum Option<T> {
99
|
1010
= help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize`
1111
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
12+
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
13+
--> $DIR/issue-18919.rs:7:13
14+
|
15+
LL | enum Option<T> {
16+
| ^ this could be changed to `T: ?Sized`...
17+
LL | Some(T),
18+
| - ...if indirection was used here: `Box<T>`
1219

1320
error: aborting due to previous error
1421

src/test/ui/issues/issue-23281.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ LL | struct Vec<T> {
99
|
1010
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)`
1111
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
12+
help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
13+
--> $DIR/issue-23281.rs:8:12
14+
|
15+
LL | struct Vec<T> {
16+
| ^ this could be changed to `T: ?Sized`...
17+
LL | t: T,
18+
| - ...if indirection was used here: `Box<T>`
1219

1320
error: aborting due to previous error
1421

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
trait Trait {
2+
fn func1() -> Struct1<Self>; //~ ERROR E0277
3+
fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
4+
fn func3() -> Struct3<Self>; //~ ERROR E0277
5+
fn func4() -> Struct4<Self>; //~ ERROR E0277
6+
}
7+
8+
struct Struct1<T>{
9+
_t: std::marker::PhantomData<*const T>,
10+
}
11+
struct Struct2<'a, T>{
12+
_t: &'a T,
13+
}
14+
struct Struct3<T>{
15+
_t: T,
16+
}
17+
18+
struct X<T>(T);
19+
20+
struct Struct4<T>{
21+
_t: X<T>,
22+
}
23+
24+
struct Struct5<T: ?Sized>{
25+
_t: X<T>, //~ ERROR E0277
26+
}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)