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
6 changed files with 91 additions and 12 deletions
|
@ -156,7 +156,7 @@ impl<'a> Parser<'a> {
|
||||||
self.expect_gt()?;
|
self.expect_gt()?;
|
||||||
(params, span_lo.to(self.prev_span))
|
(params, span_lo.to(self.prev_span))
|
||||||
} else {
|
} else {
|
||||||
(vec![], self.prev_span.between(self.token.span))
|
(vec![], self.prev_span.shrink_to_hi())
|
||||||
};
|
};
|
||||||
Ok(ast::Generics {
|
Ok(ast::Generics {
|
||||||
params,
|
params,
|
||||||
|
|
|
@ -555,7 +555,11 @@ impl<'a> Parser<'a> {
|
||||||
let mut generics = if self.choose_generics_over_qpath() {
|
let mut generics = if self.choose_generics_over_qpath() {
|
||||||
self.parse_generics()?
|
self.parse_generics()?
|
||||||
} else {
|
} 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.
|
// 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.
|
// allowed. `allow_ty_infer` gates this behavior.
|
||||||
crate::collect::placeholder_type_error(
|
crate::collect::placeholder_type_error(
|
||||||
tcx,
|
tcx,
|
||||||
ident_span.unwrap_or(DUMMY_SP),
|
ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
|
||||||
generic_params,
|
generic_params,
|
||||||
visitor.0,
|
visitor.0,
|
||||||
ident_span.is_some(),
|
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.
|
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
|
||||||
crate fn placeholder_type_error(
|
crate fn placeholder_type_error(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
ident_span: Span,
|
span: Span,
|
||||||
generics: &[hir::GenericParam<'_>],
|
generics: &[hir::GenericParam<'_>],
|
||||||
placeholder_types: Vec<Span>,
|
placeholder_types: Vec<Span>,
|
||||||
suggest: bool,
|
suggest: bool,
|
||||||
|
@ -150,7 +150,14 @@ crate fn placeholder_type_error(
|
||||||
let mut sugg: Vec<_> =
|
let mut sugg: Vec<_> =
|
||||||
placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
|
placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
|
||||||
if generics.is_empty() {
|
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 {
|
} else {
|
||||||
sugg.push((
|
sugg.push((
|
||||||
generics.iter().last().unwrap().span.shrink_to_hi(),
|
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 {
|
let (generics, suggest) = match &item.kind {
|
||||||
hir::ItemKind::Union(_, generics)
|
hir::ItemKind::Union(_, generics)
|
||||||
| hir::ItemKind::Enum(_, generics)
|
| hir::ItemKind::Enum(_, generics)
|
||||||
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
|
| hir::ItemKind::TraitAlias(generics, _)
|
||||||
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
|
| 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.
|
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
@ -181,7 +192,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
|
||||||
let mut visitor = PlaceholderHirTyCollector::default();
|
let mut visitor = PlaceholderHirTyCollector::default();
|
||||||
visitor.visit_item(item);
|
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> {
|
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
|
/// 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.
|
/// use inference to provide suggestions for the appropriate type if possible.
|
||||||
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
|
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
|
||||||
|
use hir::TyKind::*;
|
||||||
match &ty.kind {
|
match &ty.kind {
|
||||||
hir::TyKind::Infer => true,
|
Infer => true,
|
||||||
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty),
|
Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
|
||||||
hir::TyKind::Tup(tys) => tys.iter().any(|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,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,3 +131,16 @@ trait T {
|
||||||
fn assoc_fn_test3() -> _;
|
fn assoc_fn_test3() -> _;
|
||||||
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
|
//~^ 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
|
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:4:14
|
--> $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
|
| | not allowed in type signatures
|
||||||
| help: replace with the correct return type: `(i32, i32)`
|
| 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
|
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||||
--> $DIR/typeck_type_placeholder_item.rs:121:31
|
--> $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; }
|
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.
|
Some errors have detailed explanations: E0121, E0282.
|
||||||
For more information about an error, try `rustc --explain E0121`.
|
For more information about an error, try `rustc --explain E0121`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue