Skip to content

Commit 95e5605

Browse files
committed
Suggest ?Sized when applicable for ADTs
Fix #71790.
1 parent ff4a253 commit 95e5605

File tree

4 files changed

+166
-34
lines changed

4 files changed

+166
-34
lines changed

src/librustc_hir/hir.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -2729,14 +2729,8 @@ impl Node<'_> {
27292729
pub fn generics(&self) -> Option<&Generics<'_>> {
27302730
match self {
27312731
Node::TraitItem(TraitItem { generics, .. })
2732-
| Node::ImplItem(ImplItem { generics, .. })
2733-
| Node::Item(Item {
2734-
kind:
2735-
ItemKind::Trait(_, _, generics, ..)
2736-
| ItemKind::Impl { generics, .. }
2737-
| ItemKind::Fn(_, generics, _),
2738-
..
2739-
}) => Some(generics),
2732+
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
2733+
Node::Item(item) => item.kind.generics(),
27402734
_ => None,
27412735
}
27422736
}

src/librustc_trait_selection/traits/error_reporting/mod.rs

+88-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;
@@ -1695,36 +1696,69 @@ 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)
1699+
let (pred, item_def_id, span) = match (obligation.predicate.kind(), &obligation.cause.code)
17021700
{
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,
1723-
);
1724-
return;
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 { param: param.name.ident().name, valid: true };
1744+
visitor.visit_item(item);
1745+
if !visitor.valid {
1746+
continue;
17251747
}
17261748
}
1749+
_ => {}
17271750
}
1751+
let (span, separator) = match param.bounds {
1752+
[] => (span.shrink_to_hi(), ":"),
1753+
[.., bound] => (bound.span().shrink_to_hi(), " +"),
1754+
};
1755+
err.span_suggestion_verbose(
1756+
span,
1757+
"consider relaxing the implicit `Sized` restriction",
1758+
format!("{} ?Sized", separator),
1759+
Applicability::MachineApplicable,
1760+
);
1761+
return;
17281762
}
17291763
}
17301764

@@ -1744,6 +1778,34 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
17441778
}
17451779
}
17461780

1781+
/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
1782+
/// `param: ?Sized` would be a valid constraint.
1783+
struct FindTypeParam {
1784+
param: rustc_span::Symbol,
1785+
valid: bool,
1786+
}
1787+
1788+
impl<'v> Visitor<'v> for FindTypeParam {
1789+
type Map = rustc_hir::intravisit::ErasedMap<'v>;
1790+
1791+
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
1792+
hir::intravisit::NestedVisitorMap::None
1793+
}
1794+
1795+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
1796+
match ty.kind {
1797+
hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => return,
1798+
hir::TyKind::Path(hir::QPath::Resolved(None, path))
1799+
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
1800+
{
1801+
self.valid = false;
1802+
}
1803+
_ => {}
1804+
}
1805+
hir::intravisit::walk_ty(self, ty);
1806+
}
1807+
}
1808+
17471809
pub fn recursive_type_with_infinite_size_error(
17481810
tcx: TyCtxt<'tcx>,
17491811
type_def_id: DefId,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
}
6+
7+
struct Struct1<T>{
8+
_t: std::marker::PhantomData<*const T>,
9+
}
10+
struct Struct2<'a, T>{
11+
_t: &'a T,
12+
}
13+
struct Struct3<T>{
14+
_t: T,
15+
}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error[E0277]: the size for values of type `Self` cannot be known at compilation time
2+
--> $DIR/adt-param-with-implicit-sized-bound.rs:2:19
3+
|
4+
LL | fn func1() -> Struct1<Self>;
5+
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
...
7+
LL | struct Struct1<T>{
8+
| - required by this bound in `Struct1`
9+
|
10+
= help: the trait `std::marker::Sized` is not implemented for `Self`
11+
= 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 further restricting `Self`
13+
|
14+
LL | fn func1() -> Struct1<Self> where Self: std::marker::Sized;
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
help: consider relaxing the implicit `Sized` restriction
17+
|
18+
LL | struct Struct1<T: ?Sized>{
19+
| ^^^^^^^^
20+
21+
error[E0277]: the size for values of type `Self` cannot be known at compilation time
22+
--> $DIR/adt-param-with-implicit-sized-bound.rs:3:23
23+
|
24+
LL | fn func2<'a>() -> Struct2<'a, Self>;
25+
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
26+
...
27+
LL | struct Struct2<'a, T>{
28+
| - required by this bound in `Struct2`
29+
|
30+
= help: the trait `std::marker::Sized` is not implemented for `Self`
31+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
32+
help: consider further restricting `Self`
33+
|
34+
LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
36+
help: consider relaxing the implicit `Sized` restriction
37+
|
38+
LL | struct Struct2<'a, T: ?Sized>{
39+
| ^^^^^^^^
40+
41+
error[E0277]: the size for values of type `Self` cannot be known at compilation time
42+
--> $DIR/adt-param-with-implicit-sized-bound.rs:4:19
43+
|
44+
LL | fn func3() -> Struct3<Self>;
45+
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
46+
...
47+
LL | struct Struct3<T>{
48+
| - required by this bound in `Struct3`
49+
|
50+
= help: the trait `std::marker::Sized` is not implemented for `Self`
51+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
52+
help: consider further restricting `Self`
53+
|
54+
LL | fn func3() -> Struct3<Self> where Self: std::marker::Sized;
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
57+
error: aborting due to 3 previous errors
58+
59+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)