parent
ff4a2533a0
commit
95e5605108
@ -2729,14 +2729,8 @@ impl Node<'_> {
|
||||
pub fn generics(&self) -> Option<&Generics<'_>> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { generics, .. })
|
||||
| Node::ImplItem(ImplItem { generics, .. })
|
||||
| Node::Item(Item {
|
||||
kind:
|
||||
ItemKind::Trait(_, _, generics, ..)
|
||||
| ItemKind::Impl { generics, .. }
|
||||
| ItemKind::Fn(_, generics, _),
|
||||
..
|
||||
}) => Some(generics),
|
||||
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
|
||||
Node::Item(item) => item.kind.generics(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
@ -1695,36 +1696,69 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) {
|
||||
if let (
|
||||
ty::PredicateKind::Trait(pred, _),
|
||||
ObligationCauseCode::BindingObligation(item_def_id, span),
|
||||
) = (obligation.predicate.kind(), &obligation.cause.code)
|
||||
let (pred, item_def_id, span) = match (obligation.predicate.kind(), &obligation.cause.code)
|
||||
{
|
||||
if let (Some(generics), true) = (
|
||||
self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()),
|
||||
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
|
||||
) {
|
||||
for param in generics.params {
|
||||
if param.span == *span
|
||||
&& !param.bounds.iter().any(|bound| {
|
||||
bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
})
|
||||
{
|
||||
let (span, separator) = match param.bounds {
|
||||
[] => (span.shrink_to_hi(), ":"),
|
||||
[.., bound] => (bound.span().shrink_to_hi(), " +"),
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"consider relaxing the implicit `Sized` restriction",
|
||||
format!("{} ?Sized", separator),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return;
|
||||
(
|
||||
ty::PredicateKind::Trait(pred, _),
|
||||
ObligationCauseCode::BindingObligation(item_def_id, span),
|
||||
) => (pred, item_def_id, span),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let node = match (
|
||||
self.tcx.hir().get_if_local(*item_def_id),
|
||||
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
|
||||
) {
|
||||
(Some(node), true) => node,
|
||||
_ => return,
|
||||
};
|
||||
let generics = match node.generics() {
|
||||
Some(generics) => generics,
|
||||
None => return,
|
||||
};
|
||||
for param in generics.params {
|
||||
if param.span != *span
|
||||
|| param.bounds.iter().any(|bound| {
|
||||
bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
|
||||
== self.tcx.lang_items().sized_trait()
|
||||
})
|
||||
{
|
||||
continue;
|
||||
}
|
||||
match node {
|
||||
hir::Node::Item(
|
||||
item
|
||||
@
|
||||
hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::Union(..),
|
||||
..
|
||||
},
|
||||
) => {
|
||||
// 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 };
|
||||
visitor.visit_item(item);
|
||||
if !visitor.valid {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let (span, separator) = match param.bounds {
|
||||
[] => (span.shrink_to_hi(), ":"),
|
||||
[.., bound] => (bound.span().shrink_to_hi(), " +"),
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"consider relaxing the implicit `Sized` restriction",
|
||||
format!("{} ?Sized", separator),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1744,6 +1778,34 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
|
||||
/// `param: ?Sized` would be a valid constraint.
|
||||
struct FindTypeParam {
|
||||
param: rustc_span::Symbol,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for FindTypeParam {
|
||||
type Map = rustc_hir::intravisit::ErasedMap<'v>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
|
||||
hir::intravisit::NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
|
||||
match ty.kind {
|
||||
hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => return,
|
||||
hir::TyKind::Path(hir::QPath::Resolved(None, path))
|
||||
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
|
||||
{
|
||||
self.valid = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
hir::intravisit::walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recursive_type_with_infinite_size_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
type_def_id: DefId,
|
||||
|
@ -0,0 +1,17 @@
|
||||
trait Trait {
|
||||
fn func1() -> Struct1<Self>; //~ ERROR E0277
|
||||
fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277
|
||||
fn func3() -> Struct3<Self>; //~ ERROR E0277
|
||||
}
|
||||
|
||||
struct Struct1<T>{
|
||||
_t: std::marker::PhantomData<*const T>,
|
||||
}
|
||||
struct Struct2<'a, T>{
|
||||
_t: &'a T,
|
||||
}
|
||||
struct Struct3<T>{
|
||||
_t: T,
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,59 @@
|
||||
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
|
||||
|
|
||||
LL | fn func1() -> Struct1<Self>;
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct1<T>{
|
||||
| - required by this bound in `Struct1`
|
||||
|
|
||||
= 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 func1() -> Struct1<Self> where Self: std::marker::Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | struct Struct1<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:3:23
|
||||
|
|
||||
LL | fn func2<'a>() -> Struct2<'a, Self>;
|
||||
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct2<'a, T>{
|
||||
| - required by this bound in `Struct2`
|
||||
|
|
||||
= 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 func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | struct Struct2<'a, 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:4:19
|
||||
|
|
||||
LL | fn func3() -> Struct3<Self>;
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
...
|
||||
LL | struct Struct3<T>{
|
||||
| - required by this bound in `Struct3`
|
||||
|
|
||||
= 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 func3() -> Struct3<Self> where Self: std::marker::Sized;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user