Skip to content

Commit 2307f0c

Browse files
authored
Rollup merge of #68071 - estebank:ice-67995, r=Centril
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. Follow up to #67597.
2 parents 3bfa28c + 6e04cf0 commit 2307f0c

File tree

6 files changed

+280
-91
lines changed

6 files changed

+280
-91
lines changed

src/librustc_parse/parser/generics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<'a> Parser<'a> {
156156
self.expect_gt()?;
157157
(params, span_lo.to(self.prev_span))
158158
} else {
159-
(vec![], self.prev_span.between(self.token.span))
159+
(vec![], self.prev_span.shrink_to_hi())
160160
};
161161
Ok(ast::Generics {
162162
params,

src/librustc_parse/parser/item.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,11 @@ impl<'a> Parser<'a> {
556556
let mut generics = if self.choose_generics_over_qpath() {
557557
self.parse_generics()?
558558
} else {
559-
Generics::default()
559+
let mut generics = Generics::default();
560+
// impl A for B {}
561+
// /\ this is where `generics.span` should point when there are no type params.
562+
generics.span = self.prev_span.shrink_to_hi();
563+
generics
560564
};
561565

562566
let constness = if self.eat_keyword(kw::Const) {

src/librustc_typeck/astconv.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2803,7 +2803,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28032803
// allowed. `allow_ty_infer` gates this behavior.
28042804
crate::collect::placeholder_type_error(
28052805
tcx,
2806-
ident_span.unwrap_or(DUMMY_SP),
2806+
ident_span.map(|sp| sp.shrink_to_hi()).unwrap_or(DUMMY_SP),
28072807
generic_params,
28082808
visitor.0,
28092809
ident_span.is_some(),

src/librustc_typeck/collect.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ struct CollectItemTypesVisitor<'tcx> {
127127
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
128128
crate fn placeholder_type_error(
129129
tcx: TyCtxt<'tcx>,
130-
ident_span: Span,
130+
span: Span,
131131
generics: &[hir::GenericParam<'_>],
132132
placeholder_types: Vec<Span>,
133133
suggest: bool,
@@ -153,7 +153,14 @@ crate fn placeholder_type_error(
153153
let mut sugg: Vec<_> =
154154
placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect();
155155
if generics.is_empty() {
156-
sugg.push((ident_span.shrink_to_hi(), format!("<{}>", type_name)));
156+
sugg.push((span, format!("<{}>", type_name)));
157+
} else if let Some(arg) = generics.iter().find(|arg| match arg.name {
158+
hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
159+
_ => false,
160+
}) {
161+
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
162+
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
163+
sugg.push((arg.span, format!("{}", type_name)));
157164
} else {
158165
sugg.push((
159166
generics.iter().last().unwrap().span.shrink_to_hi(),
@@ -175,16 +182,20 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
175182
let (generics, suggest) = match &item.kind {
176183
hir::ItemKind::Union(_, generics)
177184
| hir::ItemKind::Enum(_, generics)
178-
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
179-
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
185+
| hir::ItemKind::TraitAlias(generics, _)
186+
| hir::ItemKind::Trait(_, _, generics, ..)
187+
| hir::ItemKind::Impl(_, _, _, generics, ..)
188+
| hir::ItemKind::Struct(_, generics) => (generics, true),
189+
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
190+
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
180191
// `static`, `fn` and `const` are handled elsewhere to suggest appropriate type.
181192
_ => return,
182193
};
183194

184195
let mut visitor = PlaceholderHirTyCollector::default();
185196
visitor.visit_item(item);
186197

187-
placeholder_type_error(tcx, item.ident.span, generics, visitor.0, suggest);
198+
placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest);
188199
}
189200

190201
impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -1798,10 +1809,19 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
17981809
/// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to
17991810
/// use inference to provide suggestions for the appropriate type if possible.
18001811
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
1812+
use hir::TyKind::*;
18011813
match &ty.kind {
1802-
hir::TyKind::Infer => true,
1803-
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_suggestable_infer_ty(ty),
1804-
hir::TyKind::Tup(tys) => tys.iter().any(|ty| is_suggestable_infer_ty(ty)),
1814+
Infer => true,
1815+
Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
1816+
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
1817+
Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
1818+
Def(_, generic_args) => generic_args
1819+
.iter()
1820+
.filter_map(|arg| match arg {
1821+
hir::GenericArg::Type(ty) => Some(ty),
1822+
_ => None,
1823+
})
1824+
.any(is_suggestable_infer_ty),
18051825
_ => false,
18061826
}
18071827
}

src/test/ui/typeck/typeck_type_placeholder_item.rs

+45
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(type_alias_impl_trait)] // Needed for single test `type Y = impl Trait<_>`
12
// This test checks that it is not possible to enable global type
23
// inference by using the `_` type placeholder.
34

@@ -42,6 +43,16 @@ impl Test9 {
4243
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
4344
}
4445

46+
fn test11(x: &usize) -> &_ {
47+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
48+
&x
49+
}
50+
51+
unsafe fn test12(x: *const usize) -> *const *const _ {
52+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
53+
&x
54+
}
55+
4556
impl Clone for Test9 {
4657
fn clone(&self) -> _ { Test9 }
4758
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
@@ -131,3 +142,37 @@ trait T {
131142
fn assoc_fn_test3() -> _;
132143
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
133144
}
145+
146+
struct BadStruct<_>(_);
147+
//~^ ERROR expected identifier, found reserved identifier `_`
148+
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
149+
trait BadTrait<_> {}
150+
//~^ ERROR expected identifier, found reserved identifier `_`
151+
impl BadTrait<_> for BadStruct<_> {}
152+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
153+
154+
fn impl_trait() -> impl BadTrait<_> {
155+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
156+
unimplemented!()
157+
}
158+
159+
struct BadStruct1<_, _>(_);
160+
//~^ ERROR expected identifier, found reserved identifier `_`
161+
//~| ERROR expected identifier, found reserved identifier `_`
162+
//~| ERROR the name `_` is already used
163+
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
164+
struct BadStruct2<_, T>(_, T);
165+
//~^ ERROR expected identifier, found reserved identifier `_`
166+
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
167+
168+
type X = Box<_>;
169+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
170+
171+
struct Struct;
172+
trait Trait<T> {}
173+
impl Trait<usize> for Struct {}
174+
type Y = impl Trait<_>;
175+
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
176+
fn foo() -> Y {
177+
Struct
178+
}

0 commit comments

Comments
 (0)