mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Extend support of _
in type parameters
- Account for `impl Trait<_>`. - Provide a reasonable `Span` for empty `Generics` in `impl`s. - Account for `fn foo<_>(_: _) {}` to suggest `fn foo<T>(_: T) {}`. - Fix #67995.
This commit is contained in:
parent
ed6468da16
commit
c751961d29
@ -156,7 +156,7 @@ impl<'a> Parser<'a> {
|
||||
self.expect_gt()?;
|
||||
(params, span_lo.to(self.prev_span))
|
||||
} else {
|
||||
(vec![], self.prev_span.between(self.token.span))
|
||||
(vec![], self.prev_span.shrink_to_hi())
|
||||
};
|
||||
Ok(ast::Generics {
|
||||
params,
|
||||
|
@ -555,7 +555,11 @@ impl<'a> Parser<'a> {
|
||||
let mut generics = if self.choose_generics_over_qpath() {
|
||||
self.parse_generics()?
|
||||
} else {
|
||||
Generics::default()
|
||||
let mut generics = Generics::default();
|
||||
// impl A for B {}
|
||||
// /\ this is where `generics.span` should point when there are no type params.
|
||||
generics.span = self.prev_span.shrink_to_hi();
|
||||
generics
|
||||
};
|
||||
|
||||
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
|
||||
|
@ -2803,7 +2803,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
// allowed. `allow_ty_infer` gates this behavior.
|
||||
crate::collect::placeholder_type_error(
|
||||
tcx,
|
||||
ident_span.unwrap_or(DUMMY_SP),
|
||||
ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
|
||||
generic_params,
|
||||
visitor.0,
|
||||
ident_span.is_some(),
|
||||
|
@ -124,7 +124,7 @@ struct CollectItemTypesVisitor<'tcx> {
|
||||
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
|
||||
crate fn placeholder_type_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ident_span: Span,
|
||||
span: Span,
|
||||
generics: &[hir::GenericParam<'_>],
|
||||
placeholder_types: Vec<Span>,
|
||||
suggest: bool,
|
||||
@ -150,7 +150,14 @@ crate fn placeholder_type_error(
|
||||
let mut sugg: Vec<_> =
|
||||
placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
|
||||
if generics.is_empty() {
|
||||
sugg.push((ident_span.shrink_to_hi(), format!("<{}>", type_name)));
|
||||
sugg.push((span, format!("<{}>", type_name)));
|
||||
} else if let Some(arg) = generics.iter().find(|arg| match arg.name {
|
||||
hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
|
||||
_ => false,
|
||||
}) {
|
||||
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
|
||||
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
|
||||
sugg.push((arg.span, format!("{}", type_name)));
|
||||
} else {
|
||||
sugg.push((
|
||||
generics.iter().last().unwrap().span.shrink_to_hi(),
|
||||
@ -172,8 +179,12 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
|
||||
let (generics, suggest) = match &item.kind {
|
||||
hir::ItemKind::Union(_, generics)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
|
||||
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::Trait(_, _, generics, ..)
|
||||
| hir::ItemKind::Impl(_, _, _, generics, ..)
|
||||
| hir::ItemKind::Struct(_, generics) => (generics, true),
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
|
||||
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
|
||||
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
|
||||
_ => return,
|
||||
};
|
||||
@ -181,7 +192,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
|
||||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
visitor.visit_item(item);
|
||||
|
||||
placeholder_type_error(tcx, item.ident.span, generics, visitor.0, suggest);
|
||||
placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
||||
@ -1789,10 +1800,19 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||
/// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to
|
||||
/// use inference to provide suggestions for the appropriate type if possible.
|
||||
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
|
||||
use hir::TyKind::*;
|
||||
match &ty.kind {
|
||||
hir::TyKind::Infer => true,
|
||||
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty),
|
||||
hir::TyKind::Tup(tys) => tys.iter().any(|ty| is_suggestable_infer_ty(ty)),
|
||||
Infer => true,
|
||||
Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
|
||||
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
|
||||
Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
|
||||
Def(_, generic_args) => generic_args
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
hir::GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
.any(is_suggestable_infer_ty),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -131,3 +131,16 @@ trait T {
|
||||
fn assoc_fn_test3() -> _;
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
}
|
||||
|
||||
struct BadStruct<_>(_);
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
trait BadTrait<_> {}
|
||||
//~^ ERROR expected identifier, found reserved identifier `_`
|
||||
impl BadTrait<_> for BadStruct<_> {}
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
|
||||
fn impl_trait() -> impl BadTrait<_> {
|
||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:135:18
|
||||
|
|
||||
LL | struct BadStruct<_>(_);
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/typeck_type_placeholder_item.rs:138:16
|
||||
|
|
||||
LL | trait BadTrait<_> {}
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:4:14
|
||||
|
|
||||
@ -255,6 +267,36 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) }
|
||||
| | not allowed in type signatures
|
||||
| help: replace with the correct return type: `(i32, i32)`
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:135:21
|
||||
|
|
||||
LL | struct BadStruct<_>(_);
|
||||
| ^ not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | struct BadStruct<T>(T);
|
||||
| ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:140:15
|
||||
|
|
||||
LL | impl BadTrait<_> for BadStruct<_> {}
|
||||
| ^ ^ not allowed in type signatures
|
||||
| |
|
||||
| not allowed in type signatures
|
||||
|
|
||||
help: use type parameters instead
|
||||
|
|
||||
LL | impl<T> BadTrait<T> for BadStruct<T> {}
|
||||
| ^^^ ^ ^
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:143:34
|
||||
|
|
||||
LL | fn impl_trait() -> impl BadTrait<_> {
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/typeck_type_placeholder_item.rs:121:31
|
||||
|
|
||||
@ -405,7 +447,7 @@ help: use type parameters instead
|
||||
LL | fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
|
||||
| ^^^ ^
|
||||
|
||||
error: aborting due to 40 previous errors
|
||||
error: aborting due to 45 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0121, E0282.
|
||||
For more information about an error, try `rustc --explain E0121`.
|
||||
|
Loading…
Reference in New Issue
Block a user