Skip to content

Commit ce25b7c

Browse files
committed
Silence some invalid type params in field errors
Reduce the verbosity of forgetting parentheses in methods with type parameters by keeping that AST information until HIR type-checking.
1 parent 97d47a5 commit ce25b7c

File tree

23 files changed

+57
-43
lines changed

23 files changed

+57
-43
lines changed

src/librustc_ast_lowering/expr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
129129
self.lower_expr(el),
130130
self.lower_expr(er),
131131
),
132-
ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident),
132+
ExprKind::Field(ref el, ident, args) => {
133+
hir::ExprKind::Field(self.lower_expr(el), ident, args)
134+
}
133135
ExprKind::Index(ref el, ref er) => {
134136
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
135137
}

src/librustc_ast_pretty/pprust.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2025,7 +2025,7 @@ impl<'a> State<'a> {
20252025
self.word_space("=");
20262026
self.print_expr_maybe_paren(rhs, prec);
20272027
}
2028-
ast::ExprKind::Field(ref expr, ident) => {
2028+
ast::ExprKind::Field(ref expr, ident, _) => {
20292029
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
20302030
self.s.word(".");
20312031
self.print_ident(ident);

src/librustc_hir/hir.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ impl Expr<'_> {
13961396

13971397
ExprKind::Unary(UnOp::UnDeref, _) => true,
13981398

1399-
ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _) => {
1399+
ExprKind::Field(ref base, ..) | ExprKind::Index(ref base, _) => {
14001400
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
14011401
}
14021402

@@ -1588,7 +1588,8 @@ pub enum ExprKind<'hir> {
15881588
/// E.g., `a += 1`.
15891589
AssignOp(BinOp, &'hir Expr<'hir>, &'hir Expr<'hir>),
15901590
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct or tuple field.
1591-
Field(&'hir Expr<'hir>, Ident),
1591+
/// The optional `Span` points at an *invalid* type parameter in the field expression.
1592+
Field(&'hir Expr<'hir>, Ident, Option<Span>),
15921593
/// An indexing operation (`foo[2]`).
15931594
Index(&'hir Expr<'hir>, &'hir Expr<'hir>),
15941595

src/librustc_hir/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
11101110
visitor.visit_expr(right_expression);
11111111
visitor.visit_expr(left_expression);
11121112
}
1113-
ExprKind::Field(ref subexpression, ident) => {
1113+
ExprKind::Field(ref subexpression, ident, _) => {
11141114
visitor.visit_expr(subexpression);
11151115
visitor.visit_ident(ident);
11161116
}

src/librustc_hir/print.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ impl<'a> State<'a> {
13441344
self.word_space("=");
13451345
self.print_expr_maybe_paren(&rhs, prec);
13461346
}
1347-
hir::ExprKind::Field(ref expr, ident) => {
1347+
hir::ExprKind::Field(ref expr, ident, _) => {
13481348
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
13491349
self.s.word(".");
13501350
self.print_ident(ident);
@@ -2315,7 +2315,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
23152315
hir::ExprKind::Unary(_, ref x)
23162316
| hir::ExprKind::Cast(ref x, _)
23172317
| hir::ExprKind::Type(ref x, _)
2318-
| hir::ExprKind::Field(ref x, _)
2318+
| hir::ExprKind::Field(ref x, ..)
23192319
| hir::ExprKind::Index(ref x, _) => {
23202320
// `&X { y: 1 }, X { y: 1 }.y`
23212321
contains_exterior_struct_lit(&x)

src/librustc_parse/parser/expr.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ impl<'a> Parser<'a> {
786786
) -> P<Expr> {
787787
let span = self.token.span;
788788
self.bump();
789-
let field = ExprKind::Field(base, Ident::new(field, span));
789+
let field = ExprKind::Field(base, Ident::new(field, span), None);
790790
self.expect_no_suffix(span, "a tuple index", suffix);
791791
self.mk_expr(lo.to(span), field, AttrVec::new())
792792
}
@@ -825,16 +825,12 @@ impl<'a> Parser<'a> {
825825
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new()))
826826
} else {
827827
// Field access `expr.f`
828-
if let Some(args) = segment.args {
829-
self.struct_span_err(
830-
args.span(),
831-
"field expressions may not have generic arguments",
832-
)
833-
.emit();
834-
}
835-
836828
let span = lo.to(self.prev_span);
837-
Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new()))
829+
Ok(self.mk_expr(
830+
span,
831+
ExprKind::Field(self_arg, segment.ident, segment.args.map(|args| args.span())),
832+
AttrVec::new(),
833+
))
838834
}
839835
}
840836

src/librustc_passes/liveness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
984984
self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
985985
}
986986

987-
hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
987+
hir::ExprKind::Field(ref e, ..) => self.propagate_through_expr(&e, succ),
988988

989989
hir::ExprKind::Closure(..) => {
990990
debug!(
@@ -1254,7 +1254,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
12541254

12551255
match expr.kind {
12561256
hir::ExprKind::Path(_) => succ,
1257-
hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
1257+
hir::ExprKind::Field(ref e, ..) => self.propagate_through_expr(&e, succ),
12581258
_ => self.propagate_through_expr(expr, succ),
12591259
}
12601260
}

src/librustc_passes/region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ fn resolve_local<'tcx>(
653653
match expr.kind {
654654
hir::ExprKind::AddrOf(_, _, ref subexpr)
655655
| hir::ExprKind::Unary(hir::UnOp::UnDeref, ref subexpr)
656-
| hir::ExprKind::Field(ref subexpr, _)
656+
| hir::ExprKind::Field(ref subexpr, ..)
657657
| hir::ExprKind::Index(ref subexpr, _) => {
658658
expr = &subexpr;
659659
}

src/librustc_resolve/late.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
20042004
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
20052005

20062006
// Equivalent to `visit::walk_expr` + passing some context to children.
2007-
ExprKind::Field(ref subexpression, _) => {
2007+
ExprKind::Field(ref subexpression, ..) => {
20082008
self.resolve_expr(subexpression, Some(expr));
20092009
}
20102010
ExprKind::MethodCall(ref segment, ref arguments) => {
@@ -2055,7 +2055,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
20552055

20562056
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
20572057
match expr.kind {
2058-
ExprKind::Field(_, ident) => {
2058+
ExprKind::Field(_, ident, _) => {
20592059
// FIXME(#6890): Even though you can't treat a method like a
20602060
// field, we need to add any trait methods we find that match
20612061
// the field name so that we can do some nice error reporting

src/librustc_resolve/late/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
415415
let is_expected = &|res| source.is_expected(res);
416416

417417
let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
418-
ExprKind::Field(_, ident) => {
418+
ExprKind::Field(_, ident, _) => {
419419
err.span_suggestion(
420420
expr.span,
421421
"use the path separator to refer to an item",

src/librustc_save_analysis/dump_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
14311431
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), base)
14321432
}
14331433
ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
1434-
ast::ExprKind::Field(ref sub_ex, _) => {
1434+
ast::ExprKind::Field(ref sub_ex, ..) => {
14351435
self.visit_expr(&sub_ex);
14361436

14371437
if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {

src/librustc_save_analysis/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
514514
return None;
515515
}
516516
match expr.kind {
517-
ast::ExprKind::Field(ref sub_ex, ident) => {
517+
ast::ExprKind::Field(ref sub_ex, ident, _) => {
518518
let sub_ex_hir_id = self.tcx.hir().node_to_hir_id(sub_ex.id);
519519
let hir_node = match self.tcx.hir().find(sub_ex_hir_id) {
520520
Some(Node::Expr(expr)) => expr,

src/librustc_typeck/check/expr.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
277277
ExprKind::Struct(ref qpath, fields, ref base_expr) => {
278278
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
279279
}
280-
ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
280+
ExprKind::Field(ref base, field, _) => self.check_field(expr, needs, &base, field),
281281
ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
282282
ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
283283
hir::ExprKind::Err => tcx.types.err,
@@ -1440,6 +1440,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14401440
display
14411441
}
14421442

1443+
fn complain_about_invalid_type_params(&self, args: Option<Span>) {
1444+
if let Some(args) = args {
1445+
self.tcx
1446+
.sess
1447+
.struct_span_err(args, "field expressions may not have generic arguments")
1448+
.emit();
1449+
}
1450+
}
1451+
14431452
// Check field access expressions
14441453
fn check_field(
14451454
&self,
@@ -1452,6 +1461,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14521461
let expr_t = self.structurally_resolved_type(base.span, expr_t);
14531462
let mut private_candidate = None;
14541463
let mut autoderef = self.autoderef(expr.span, expr_t);
1464+
let invalid_args = match &expr.kind {
1465+
ExprKind::Field(_, _, Some(args)) => Some(*args),
1466+
_ => None,
1467+
};
14551468
while let Some((base_t, _)) = autoderef.next() {
14561469
match base_t.kind {
14571470
ty::Adt(base_def, substs) if !base_def.is_enum() => {
@@ -1471,6 +1484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14711484
autoderef.finalize(self);
14721485

14731486
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
1487+
self.complain_about_invalid_type_params(invalid_args);
14741488
return field_ty;
14751489
}
14761490
private_candidate = Some((base_def.did, field_ty));
@@ -1486,6 +1500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14861500
autoderef.finalize(self);
14871501

14881502
self.write_field_index(expr.hir_id, index);
1503+
self.complain_about_invalid_type_params(invalid_args);
14891504
return field_ty.expect_ty();
14901505
}
14911506
}
@@ -1501,8 +1516,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15011516
return field_ty;
15021517
}
15031518

1519+
let method_exists = self.method_exists(field, expr_t, expr.hir_id, true);
1520+
if let (false, ExprKind::Field(_, _, Some(_))) = (method_exists, &expr.kind) {
1521+
// Only complain about incorrect field expressions with type parameters like
1522+
// `foo.bar::<baz>` when `bar` isn't a valid method.
1523+
self.complain_about_invalid_type_params(invalid_args);
1524+
}
15041525
if field.name == kw::Invalid {
1505-
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
1526+
} else if method_exists {
15061527
self.ban_take_value_of_method(expr, expr_t, field);
15071528
} else if !expr_t.is_primitive_ty() {
15081529
self.ban_nonexisting_field(field, base, expr, expr_t);

src/librustc_typeck/check/method/confirm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
423423

424424
loop {
425425
match exprs.last().unwrap().kind {
426-
hir::ExprKind::Field(ref expr, _)
426+
hir::ExprKind::Field(ref expr, ..)
427427
| hir::ExprKind::Index(ref expr, _)
428428
| hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
429429
_ => break,

src/librustc_typeck/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
168168
self.select_from_expr(base);
169169
}
170170

171-
hir::ExprKind::Field(ref base, _) => {
171+
hir::ExprKind::Field(ref base, ..) => {
172172
// base.f
173173
self.select_from_expr(base);
174174
}

src/librustc_typeck/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
354354
}
355355
}
356356

357-
hir::ExprKind::Field(ref base, _) => {
357+
hir::ExprKind::Field(ref base, ..) => {
358358
let base = self.cat_expr(&base)?;
359359
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
360360
Ok(self.cat_projection(expr, base, expr_ty))

src/libsyntax/ast.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,8 @@ pub enum ExprKind {
12241224
/// E.g., `a += 1`.
12251225
AssignOp(BinOp, P<Expr>, P<Expr>),
12261226
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
1227-
Field(P<Expr>, Ident),
1227+
/// The optional `Span` points at an *invalid* type parameter in the field expression.
1228+
Field(P<Expr>, Ident, Option<Span>),
12281229
/// An indexing operation (e.g., `foo[2]`).
12291230
Index(P<Expr>, P<Expr>),
12301231
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`).

src/libsyntax/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr,
11871187
vis.visit_expr(el);
11881188
vis.visit_expr(er);
11891189
}
1190-
ExprKind::Field(el, ident) => {
1190+
ExprKind::Field(el, ident, _) => {
11911191
vis.visit_expr(el);
11921192
vis.visit_ident(ident);
11931193
}

src/libsyntax/util/parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
388388
| ast::ExprKind::Unary(_, ref x)
389389
| ast::ExprKind::Cast(ref x, _)
390390
| ast::ExprKind::Type(ref x, _)
391-
| ast::ExprKind::Field(ref x, _)
391+
| ast::ExprKind::Field(ref x, ..)
392392
| ast::ExprKind::Index(ref x, _) => {
393393
// &X { y: 1 }, X { y: 1 }.y
394394
contains_exterior_struct_lit(&x)

src/libsyntax/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
773773
visitor.visit_expr(left_expression);
774774
visitor.visit_expr(right_expression);
775775
}
776-
ExprKind::Field(ref subexpression, ident) => {
776+
ExprKind::Field(ref subexpression, ident, _) => {
777777
visitor.visit_expr(subexpression);
778778
visitor.visit_ident(ident);
779779
}

src/test/ui-fulldeps/pprust-expr-roundtrip.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
132132
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
133133
},
134134
13 => {
135-
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
135+
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"), None)));
136136
},
137137
14 => {
138138
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
fn main() {
22
let _ = vec![].into_iter().collect::<usize>;
33
//~^ ERROR attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
4-
//~| ERROR field expressions may not have generic arguments
54
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
error: field expressions may not have generic arguments
2-
--> $DIR/method-missing-parentheses.rs:2:41
3-
|
4-
LL | let _ = vec![].into_iter().collect::<usize>;
5-
| ^^^^^^^
6-
71
error[E0615]: attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
82
--> $DIR/method-missing-parentheses.rs:2:32
93
|
@@ -12,6 +6,6 @@ LL | let _ = vec![].into_iter().collect::<usize>;
126
| |
137
| help: use parentheses to call the method: `collect::<usize>()`
148

15-
error: aborting due to 2 previous errors
9+
error: aborting due to previous error
1610

1711
For more information about this error, try `rustc --explain E0615`.

0 commit comments

Comments
 (0)