Skip to content

Commit 6c8b2dc

Browse files
committed
Account for all item kinds when collecting and gateing _ in item defs
1 parent 8cb193a commit 6c8b2dc

File tree

5 files changed

+199
-150
lines changed

5 files changed

+199
-150
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::hir::def_id::DefId;
77
use crate::hir::print;
88
use crate::hir::ptr::P;
99
use crate::hir::{self, ExprKind, GenericArg, GenericArgs, HirVec};
10-
use crate::hir::intravisit::{NestedVisitorMap, Visitor};
10+
use crate::hir::intravisit::Visitor;
1111
use crate::lint;
1212
use crate::middle::lang_items::SizedTraitLangItem;
1313
use crate::middle::resolve_lifetime as rl;
@@ -16,6 +16,7 @@ use crate::require_c_abi_if_c_variadic;
1616
use crate::util::common::ErrorReported;
1717
use crate::util::nodemap::FxHashMap;
1818
use errors::{Applicability, DiagnosticId};
19+
use crate::collect::PlaceholderHirTyCollector;
1920
use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
2021
use rustc::traits;
2122
use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
@@ -2747,12 +2748,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27472748
}
27482749

27492750
pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
2750-
match ty.kind {
2751-
hir::TyKind::Infer if expected_ty.is_some() => {
2752-
self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
2753-
expected_ty.unwrap()
2754-
}
2755-
_ => self.ast_ty_to_ty(ty),
2751+
if crate::collect::is_infer_ty(ty) && expected_ty.is_some() {
2752+
self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
2753+
expected_ty.unwrap()
2754+
} else {
2755+
self.ast_ty_to_ty(ty)
27562756
}
27572757
}
27582758

@@ -2769,23 +2769,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27692769
let tcx = self.tcx();
27702770

27712771
// We proactively collect all the infered type params to emit a single error per fn def.
2772-
struct PlaceholderHirTyCollector(Vec<Span>);
2773-
impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
2774-
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
2775-
NestedVisitorMap::None
2776-
}
2777-
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
2778-
if let hir::TyKind::Infer = t.kind {
2779-
self.0.push(t.span);
2780-
}
2781-
hir::intravisit::walk_ty(self, t)
2782-
}
2783-
}
27842772
let mut placeholder_types = vec![];
27852773
let mut output_placeholder_types = vec![];
27862774

27872775
let input_tys = decl.inputs.iter().map(|a| {
2788-
let mut visitor = PlaceholderHirTyCollector(vec![]);
2776+
let mut visitor = PlaceholderHirTyCollector::new();
27892777
visitor.visit_ty(&a);
27902778
if visitor.0.is_empty() || self.allow_ty_infer() {
27912779
self.ty_of_arg(a, None)
@@ -2796,7 +2784,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27962784
});
27972785
let output_ty = match decl.output {
27982786
hir::Return(ref output) => {
2799-
let mut visitor = PlaceholderHirTyCollector(vec![]);
2787+
let mut visitor = PlaceholderHirTyCollector::new();
28002788
visitor.visit_ty(output);
28012789
let is_infer = if let hir::TyKind::Infer = output.kind {
28022790
true
@@ -2820,36 +2808,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
28202808

28212809
placeholder_types.extend(output_placeholder_types);
28222810

2823-
if !placeholder_types.is_empty() {
2824-
let mut sugg = placeholder_types.iter().cloned()
2825-
.map(|sp| (sp, "T".to_owned()))
2826-
.collect::<Vec<_>>();
2827-
if let Some(span) = ident_span {
2828-
if generic_params.is_empty() {
2829-
sugg.push((span.shrink_to_hi(), "<T>".to_string()));
2830-
} else {
2831-
sugg.push((
2832-
generic_params.iter().last().unwrap().span.shrink_to_hi(),
2833-
", T".to_string(),
2834-
));
2835-
}
2836-
}
2837-
let mut err = struct_span_err!(
2838-
tcx.sess,
2839-
placeholder_types,
2840-
E0121,
2841-
"the type placeholder `_` is not allowed within types on item signatures",
2842-
);
2843-
if ident_span.is_some() {
2844-
err.multipart_suggestion(
2845-
"use type parameters instead",
2846-
sugg,
2847-
Applicability::HasPlaceholders,
2848-
);
2849-
}
2850-
err.emit();
2851-
}
2852-
2811+
crate::collect::placeholder_type_error(
2812+
tcx,
2813+
ident_span.unwrap_or(DUMMY_SP),
2814+
generic_params,
2815+
placeholder_types,
2816+
ident_span.is_some(),
2817+
);
28532818

28542819
// Find any late-bound regions declared in return type that do
28552820
// not appear in the arguments. These are not well-formed.

src/librustc_typeck/collect.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,96 @@ pub struct ItemCtxt<'tcx> {
102102

103103
///////////////////////////////////////////////////////////////////////////
104104

105+
crate struct PlaceholderHirTyCollector(crate Vec<Span>);
106+
107+
impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
108+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
109+
NestedVisitorMap::None
110+
}
111+
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
112+
if let hir::TyKind::Infer = t.kind {
113+
self.0.push(t.span);
114+
}
115+
hir::intravisit::walk_ty(self, t)
116+
}
117+
}
118+
119+
impl PlaceholderHirTyCollector {
120+
pub fn new() -> PlaceholderHirTyCollector {
121+
PlaceholderHirTyCollector(vec![])
122+
}
123+
}
124+
105125
struct CollectItemTypesVisitor<'tcx> {
106126
tcx: TyCtxt<'tcx>,
107127
}
108128

129+
crate fn placeholder_type_error(
130+
tcx: TyCtxt<'tcx>,
131+
ident_span: Span,
132+
generics: &[hir::GenericParam<'_>],
133+
placeholder_types: Vec<Span>,
134+
suggest: bool,
135+
) {
136+
if !placeholder_types.is_empty() {
137+
let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, "T".to_string())).collect();
138+
if generics.is_empty() {
139+
sugg.push((ident_span.shrink_to_hi(), "<T>".to_string()));
140+
} else {
141+
sugg.push((generics.iter().last().unwrap().span.shrink_to_hi(), ", T".to_string()));
142+
}
143+
let mut err = struct_span_err!(
144+
tcx.sess,
145+
placeholder_types.clone(),
146+
E0121,
147+
"the type placeholder `_` is not allowed within types on item signatures",
148+
);
149+
for span in &placeholder_types {
150+
err.span_label(*span, "not allowed in type signatures");
151+
}
152+
if suggest {
153+
err.multipart_suggestion(
154+
"use type parameters instead",
155+
sugg,
156+
Applicability::HasPlaceholders,
157+
);
158+
}
159+
err.emit();
160+
}
161+
}
162+
163+
fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
164+
let (generics, suggest) = match &item.kind {
165+
hir::ItemKind::Union(_, generics)
166+
| hir::ItemKind::Enum(_, generics)
167+
| hir::ItemKind::Struct(_, generics) => (&generics.params[..], true),
168+
hir::ItemKind::Static(ty, ..) => {
169+
if let hir::TyKind::Infer = ty.kind {
170+
return; // We handle it elsewhere to attempt to suggest an appropriate type.
171+
} else {
172+
(&[][..], false)
173+
}
174+
}
175+
hir::ItemKind::TyAlias(_, generics) => (&generics.params[..], false),
176+
// hir::ItemKind::Fn(..) |
177+
// hir::ItemKind::Const(..) => {} // We handle these elsewhere to suggest appropriate type.
178+
_ => return,
179+
};
180+
181+
let mut visitor = PlaceholderHirTyCollector::new();
182+
visitor.visit_item(item);
183+
184+
placeholder_type_error(tcx, item.ident.span, generics, visitor.0, suggest);
185+
}
186+
109187
impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
110188
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
111189
NestedVisitorMap::OnlyBodies(&self.tcx.hir())
112190
}
113191

114192
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
115193
convert_item(self.tcx, item.hir_id);
194+
reject_placeholder_type_signatures_in_item(self.tcx, item);
116195
intravisit::walk_item(self, item);
117196
}
118197

@@ -200,8 +279,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
200279
}
201280

202281
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
203-
bad_placeholder_type(self.tcx(), span).emit();
204-
282+
self.tcx().sess.delay_span_bug(span, "bad placeholder type, but no error was emitted");
205283
self.tcx().types.err
206284
}
207285

@@ -1189,6 +1267,10 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
11891267
.and_then(|body_id| {
11901268
if let hir::TyKind::Infer = ty.kind {
11911269
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
1270+
} else if is_infer_ty(ty) {
1271+
// Infering this would cause a cycle error.
1272+
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
1273+
Some(tcx.types.err)
11921274
} else {
11931275
None
11941276
}
@@ -1208,6 +1290,10 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
12081290
ImplItemKind::Const(ref ty, body_id) => {
12091291
if let hir::TyKind::Infer = ty.kind {
12101292
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
1293+
} else if is_infer_ty(ty) {
1294+
// Infering this would cause a cycle error.
1295+
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
1296+
tcx.types.err
12111297
} else {
12121298
icx.to_ty(ty)
12131299
}
@@ -1233,6 +1319,10 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
12331319
ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
12341320
if let hir::TyKind::Infer = ty.kind {
12351321
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
1322+
} else if is_infer_ty(ty) {
1323+
// Infering this would cause a cycle error.
1324+
tcx.sess.delay_span_bug(ty.span, "`_` placeholder but no error emitted");
1325+
tcx.types.err
12361326
} else {
12371327
icx.to_ty(ty)
12381328
}
@@ -1703,7 +1793,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
17031793
}
17041794
}
17051795

1706-
fn is_infer_ty(ty: &hir::Ty<'_>) -> bool {
1796+
crate fn is_infer_ty(ty: &hir::Ty<'_>) -> bool {
17071797
match &ty.kind {
17081798
hir::TyKind::Infer => true,
17091799
hir::TyKind::Slice(ty) | hir::TyKind::Array(ty, _) => is_infer_ty(ty),

src/test/ui/self/self-infer.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
22
--> $DIR/self-infer.rs:4:16
33
|
44
LL | fn f(self: _) {}
5-
| ^
5+
| ^ not allowed in type signatures
66
|
77
help: use type parameters instead
88
|
@@ -13,7 +13,7 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
1313
--> $DIR/self-infer.rs:5:17
1414
|
1515
LL | fn g(self: &_) {}
16-
| ^
16+
| ^ not allowed in type signatures
1717
|
1818
help: use type parameters instead
1919
|

src/test/ui/typeck/typeck_type_placeholder_item.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ static TEST4: _ = 145;
1515

1616
static TEST5: (_, _) = (1, 2);
1717
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
18-
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
1918

2019
fn test6(_: _) { }
2120
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
@@ -48,8 +47,6 @@ struct Test10 {
4847
a: _,
4948
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
5049
b: (_, _),
51-
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
52-
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
5350
}
5451

5552
pub fn main() {
@@ -67,7 +64,6 @@ pub fn main() {
6764

6865
static FN_TEST5: (_, _) = (1, 2);
6966
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
70-
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
7167

7268
fn fn_test6(_: _) { }
7369
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
@@ -100,8 +96,6 @@ pub fn main() {
10096
a: _,
10197
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
10298
b: (_, _),
103-
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
104-
//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures
10599
}
106100

107101
fn fn_test11(_: _) -> (_, _) { panic!() }

0 commit comments

Comments
 (0)