Skip to content

Commit

Permalink
Silence some invalid type params in field errors
Browse files Browse the repository at this point in the history
Reduce the verbosity of forgetting parentheses in methods with type
parameters by keeping that AST information until HIR type-checking.
  • Loading branch information
estebank committed Feb 9, 2020
1 parent 97d47a5 commit ce25b7c
Show file tree
Hide file tree
Showing 23 changed files with 57 additions and 43 deletions.
4 changes: 3 additions & 1 deletion src/librustc_ast_lowering/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_expr(el),
self.lower_expr(er),
),
ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident),
ExprKind::Field(ref el, ident, args) => {
hir::ExprKind::Field(self.lower_expr(el), ident, args)
}
ExprKind::Index(ref el, ref er) => {
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ast_pretty/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2025,7 +2025,7 @@ impl<'a> State<'a> {
self.word_space("=");
self.print_expr_maybe_paren(rhs, prec);
}
ast::ExprKind::Field(ref expr, ident) => {
ast::ExprKind::Field(ref expr, ident, _) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.s.word(".");
self.print_ident(ident);
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1396,7 +1396,7 @@ impl Expr<'_> {

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

ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _) => {
ExprKind::Field(ref base, ..) | ExprKind::Index(ref base, _) => {
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
}

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

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
visitor.visit_expr(right_expression);
visitor.visit_expr(left_expression);
}
ExprKind::Field(ref subexpression, ident) => {
ExprKind::Field(ref subexpression, ident, _) => {
visitor.visit_expr(subexpression);
visitor.visit_ident(ident);
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,7 @@ impl<'a> State<'a> {
self.word_space("=");
self.print_expr_maybe_paren(&rhs, prec);
}
hir::ExprKind::Field(ref expr, ident) => {
hir::ExprKind::Field(ref expr, ident, _) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.s.word(".");
self.print_ident(ident);
Expand Down Expand Up @@ -2315,7 +2315,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
hir::ExprKind::Unary(_, ref x)
| hir::ExprKind::Cast(ref x, _)
| hir::ExprKind::Type(ref x, _)
| hir::ExprKind::Field(ref x, _)
| hir::ExprKind::Field(ref x, ..)
| hir::ExprKind::Index(ref x, _) => {
// `&X { y: 1 }, X { y: 1 }.y`
contains_exterior_struct_lit(&x)
Expand Down
16 changes: 6 additions & 10 deletions src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ impl<'a> Parser<'a> {
) -> P<Expr> {
let span = self.token.span;
self.bump();
let field = ExprKind::Field(base, Ident::new(field, span));
let field = ExprKind::Field(base, Ident::new(field, span), None);
self.expect_no_suffix(span, "a tuple index", suffix);
self.mk_expr(lo.to(span), field, AttrVec::new())
}
Expand Down Expand Up @@ -825,16 +825,12 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new()))
} else {
// Field access `expr.f`
if let Some(args) = segment.args {
self.struct_span_err(
args.span(),
"field expressions may not have generic arguments",
)
.emit();
}

let span = lo.to(self.prev_span);
Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new()))
Ok(self.mk_expr(
span,
ExprKind::Field(self_arg, segment.ident, segment.args.map(|args| args.span())),
AttrVec::new(),
))
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_passes/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE)
}

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

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

match expr.kind {
hir::ExprKind::Path(_) => succ,
hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ),
hir::ExprKind::Field(ref e, ..) => self.propagate_through_expr(&e, succ),
_ => self.propagate_through_expr(expr, succ),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_passes/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ fn resolve_local<'tcx>(
match expr.kind {
hir::ExprKind::AddrOf(_, _, ref subexpr)
| hir::ExprKind::Unary(hir::UnOp::UnDeref, ref subexpr)
| hir::ExprKind::Field(ref subexpr, _)
| hir::ExprKind::Field(ref subexpr, ..)
| hir::ExprKind::Index(ref subexpr, _) => {
expr = &subexpr;
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2004,7 +2004,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),

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

fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
match expr.kind {
ExprKind::Field(_, ident) => {
ExprKind::Field(_, ident, _) => {
// FIXME(#6890): Even though you can't treat a method like a
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
let is_expected = &|res| source.is_expected(res);

let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
ExprKind::Field(_, ident) => {
ExprKind::Field(_, ident, _) => {
err.span_suggestion(
expr.span,
"use the path separator to refer to an item",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_save_analysis/dump_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,7 +1431,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), base)
}
ast::ExprKind::MethodCall(ref seg, ref args) => self.process_method_call(ex, seg, args),
ast::ExprKind::Field(ref sub_ex, _) => {
ast::ExprKind::Field(ref sub_ex, ..) => {
self.visit_expr(&sub_ex);

if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_save_analysis/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
return None;
}
match expr.kind {
ast::ExprKind::Field(ref sub_ex, ident) => {
ast::ExprKind::Field(ref sub_ex, ident, _) => {
let sub_ex_hir_id = self.tcx.hir().node_to_hir_id(sub_ex.id);
let hir_node = match self.tcx.hir().find(sub_ex_hir_id) {
Some(Node::Expr(expr)) => expr,
Expand Down
25 changes: 23 additions & 2 deletions src/librustc_typeck/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::Struct(ref qpath, fields, ref base_expr) => {
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
}
ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
ExprKind::Field(ref base, field, _) => self.check_field(expr, needs, &base, field),
ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
hir::ExprKind::Err => tcx.types.err,
Expand Down Expand Up @@ -1440,6 +1440,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
display
}

fn complain_about_invalid_type_params(&self, args: Option<Span>) {
if let Some(args) = args {
self.tcx
.sess
.struct_span_err(args, "field expressions may not have generic arguments")
.emit();
}
}

// Check field access expressions
fn check_field(
&self,
Expand All @@ -1452,6 +1461,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expr_t = self.structurally_resolved_type(base.span, expr_t);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
let invalid_args = match &expr.kind {
ExprKind::Field(_, _, Some(args)) => Some(*args),
_ => None,
};
while let Some((base_t, _)) = autoderef.next() {
match base_t.kind {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
Expand All @@ -1471,6 +1484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
autoderef.finalize(self);

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

self.write_field_index(expr.hir_id, index);
self.complain_about_invalid_type_params(invalid_args);
return field_ty.expect_ty();
}
}
Expand All @@ -1501,8 +1516,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return field_ty;
}

let method_exists = self.method_exists(field, expr_t, expr.hir_id, true);
if let (false, ExprKind::Field(_, _, Some(_))) = (method_exists, &expr.kind) {
// Only complain about incorrect field expressions with type parameters like
// `foo.bar::<baz>` when `bar` isn't a valid method.
self.complain_about_invalid_type_params(invalid_args);
}
if field.name == kw::Invalid {
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
} else if method_exists {
self.ban_take_value_of_method(expr, expr_t, field);
} else if !expr_t.is_primitive_ty() {
self.ban_nonexisting_field(field, base, expr, expr_t);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {

loop {
match exprs.last().unwrap().kind {
hir::ExprKind::Field(ref expr, _)
hir::ExprKind::Field(ref expr, ..)
| hir::ExprKind::Index(ref expr, _)
| hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
_ => break,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.select_from_expr(base);
}

hir::ExprKind::Field(ref base, _) => {
hir::ExprKind::Field(ref base, ..) => {
// base.f
self.select_from_expr(base);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
}

hir::ExprKind::Field(ref base, _) => {
hir::ExprKind::Field(ref base, ..) => {
let base = self.cat_expr(&base)?;
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
Ok(self.cat_projection(expr, base, expr_ty))
Expand Down
3 changes: 2 additions & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,8 @@ pub enum ExprKind {
/// E.g., `a += 1`.
AssignOp(BinOp, P<Expr>, P<Expr>),
/// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field.
Field(P<Expr>, Ident),
/// The optional `Span` points at an *invalid* type parameter in the field expression.
Field(P<Expr>, Ident, Option<Span>),
/// An indexing operation (e.g., `foo[2]`).
Index(P<Expr>, P<Expr>),
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr,
vis.visit_expr(el);
vis.visit_expr(er);
}
ExprKind::Field(el, ident) => {
ExprKind::Field(el, ident, _) => {
vis.visit_expr(el);
vis.visit_ident(ident);
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
| ast::ExprKind::Unary(_, ref x)
| ast::ExprKind::Cast(ref x, _)
| ast::ExprKind::Type(ref x, _)
| ast::ExprKind::Field(ref x, _)
| ast::ExprKind::Field(ref x, ..)
| ast::ExprKind::Index(ref x, _) => {
// &X { y: 1 }, X { y: 1 }.y
contains_exterior_struct_lit(&x)
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
visitor.visit_expr(left_expression);
visitor.visit_expr(right_expression);
}
ExprKind::Field(ref subexpression, ident) => {
ExprKind::Field(ref subexpression, ident, _) => {
visitor.visit_expr(subexpression);
visitor.visit_ident(ident);
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui-fulldeps/pprust-expr-roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
},
13 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"), None)));
},
14 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
Expand Down
1 change: 0 additions & 1 deletion src/test/ui/suggestions/method-missing-parentheses.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fn main() {
let _ = vec![].into_iter().collect::<usize>;
//~^ ERROR attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
//~| ERROR field expressions may not have generic arguments
}
8 changes: 1 addition & 7 deletions src/test/ui/suggestions/method-missing-parentheses.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
error: field expressions may not have generic arguments
--> $DIR/method-missing-parentheses.rs:2:41
|
LL | let _ = vec![].into_iter().collect::<usize>;
| ^^^^^^^

error[E0615]: attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
--> $DIR/method-missing-parentheses.rs:2:32
|
Expand All @@ -12,6 +6,6 @@ LL | let _ = vec![].into_iter().collect::<usize>;
| |
| help: use parentheses to call the method: `collect::<usize>()`

error: aborting due to 2 previous errors
error: aborting due to previous error

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

0 comments on commit ce25b7c

Please sign in to comment.