From 468bbb815096f0a82e79bfab4a8c04dd09ccc531 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 13 Mar 2019 17:10:27 +0100 Subject: [PATCH] Introduce `ArgSource` for diagnostics. This commit introduces an `ArgSource` enum that is lowered into the HIR so that diagnostics can correctly refer to the argument pattern's original name rather than the generated pattern. --- src/librustc/hir/intravisit.rs | 10 ++++++++++ src/librustc/hir/lowering.rs | 8 ++++++++ src/librustc/hir/mod.rs | 20 +++++++++++++++++++ .../nice_region_error/different_lifetimes.rs | 15 ++++++-------- .../nice_region_error/named_anon_conflict.rs | 9 ++++----- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc_typeck/check/writeback.rs | 6 ++++++ src/libsyntax/ast.rs | 11 ++++++++++ src/libsyntax/ext/build.rs | 3 ++- src/libsyntax/mut_visit.rs | 14 ++++++++++++- src/libsyntax/parse/parser.rs | 10 ++++++---- src/libsyntax/visit.rs | 3 +++ 12 files changed, 90 insertions(+), 21 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 977830315e23e..2ee64ca22d416 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -254,6 +254,9 @@ pub trait Visitor<'v> : Sized { fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) } + fn visit_argument_source(&mut self, s: &'v ArgSource) { + walk_argument_source(self, s) + } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -391,10 +394,17 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { for argument in &body.arguments { visitor.visit_id(argument.hir_id); visitor.visit_pat(&argument.pat); + visitor.visit_argument_source(&argument.source); } visitor.visit_expr(&body.value); } +pub fn walk_argument_source<'v, V: Visitor<'v>>(visitor: &mut V, source: &'v ArgSource) { + if let ArgSource::AsyncFn(pat) = source { + visitor.visit_pat(pat); + } +} + pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e775076fd5874..525fe1a236a4a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2048,6 +2048,14 @@ impl<'a> LoweringContext<'a> { hir::Arg { hir_id, pat: self.lower_pat(&arg.pat), + source: self.lower_arg_source(&arg.source), + } + } + + fn lower_arg_source(&mut self, source: &ArgSource) -> hir::ArgSource { + match source { + ArgSource::Normal => hir::ArgSource::Normal, + ArgSource::AsyncFn(pat) => hir::ArgSource::AsyncFn(self.lower_pat(pat)), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c7b7548a16c19..8dcb3601b33a7 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1882,6 +1882,26 @@ pub struct InlineAsm { pub struct Arg { pub pat: P, pub hir_id: HirId, + pub source: ArgSource, +} + +impl Arg { + /// Returns the pattern representing the original binding for this argument. + pub fn original_pat(&self) -> &P { + match &self.source { + ArgSource::Normal => &self.pat, + ArgSource::AsyncFn(pat) => &pat, + } + } +} + +/// Represents the source of an argument in a function header. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum ArgSource { + /// Argument as specified by the user. + Normal, + /// Generated argument from `async fn` lowering, contains the original binding pattern. + AsyncFn(P), } /// Represents the header (not the body) of a function declaration. diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 86d7a19bc8309..944cc8a8b1999 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -86,19 +86,16 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = if let Some(simple_ident) = anon_arg_sup.pat.simple_ident() { - format!(" from `{}`", simple_ident) - } else { - String::new() + let span_label_var1 = match anon_arg_sup.original_pat().simple_ident() { + Some(simple_ident) => format!(" from `{}`", simple_ident), + None => String::new(), }; - let span_label_var2 = if let Some(simple_ident) = anon_arg_sub.pat.simple_ident() { - format!(" into `{}`", simple_ident) - } else { - String::new() + let span_label_var2 = match anon_arg_sub.original_pat().simple_ident() { + Some(simple_ident) => format!(" into `{}`", simple_ident), + None => String::new(), }; - let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) { (None, None) => { let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id { diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 3821484d38e5f..ada18d7af73af 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -86,13 +86,12 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } } - let (error_var, span_label_var) = if let Some(simple_ident) = arg.pat.simple_ident() { - ( + let (error_var, span_label_var) = match arg.original_pat().simple_ident() { + Some(simple_ident) => ( format!("the type of `{}`", simple_ident), format!("the type of `{}`", simple_ident), - ) - } else { - ("parameter type".to_owned(), "type".to_owned()) + ), + None => ("parameter type".to_owned(), "type".to_owned()), }; let mut diag = struct_span_err!( diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ab10536038872..51ae6eec32a32 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2420,7 +2420,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let help_name = if let Some(body) = parent { let arg = &self.tcx.hir().body(body).arguments[index]; - format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.pat.hir_id)) + format!("`{}`", self.tcx.hir().hir_to_pretty_string(arg.original_pat().hir_id)) } else { format!("argument {}", index + 1) }; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index c2404917fa7a7..b48f87a09c4ab 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -297,6 +297,12 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { let ty = self.resolve(&ty, &hir_ty.span); self.write_ty_to_tables(hir_ty.hir_id, ty); } + + fn visit_argument_source(&mut self, _: &'gcx hir::ArgSource) { + // Don't visit the argument source, in `async fn`s it can contain a pattern which has a + // `NodeId` w/out a type, as it is only used for getting the name of the original pattern + // for diagnostics where only an `hir::Arg` is present. + } } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b24a4a22f08c1..c740bf7d6f0af 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1724,6 +1724,16 @@ pub struct Arg { pub ty: P, pub pat: P, pub id: NodeId, + pub source: ArgSource, +} + +/// The source of an argument in a function header. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum ArgSource { + /// Argument as written by the user. + Normal, + /// Argument from `async fn` lowering, contains the original binding pattern. + AsyncFn(P), } /// Alternative representation for `Arg`s describing `self` parameter of methods. @@ -1783,6 +1793,7 @@ impl Arg { }), ty, id: DUMMY_NODE_ID, + source: ArgSource::Normal, }; match eself.node { SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 75d30a7b4c98a..82d0bdeb81f9f 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -979,7 +979,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ast::Arg { ty, pat: arg_pat, - id: ast::DUMMY_NODE_ID + id: ast::DUMMY_NODE_ID, + source: ast::ArgSource::Normal, } } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 3f74c5153cefd..6779e7e61f4cb 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -235,6 +235,10 @@ pub trait MutVisitor: Sized { noop_visit_arg(a, self); } + fn visit_arg_source(&mut self, a: &mut ArgSource) { + noop_visit_arg_source(a, self); + } + fn visit_generics(&mut self, generics: &mut Generics) { noop_visit_generics(generics, self); } @@ -563,10 +567,18 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { id, pat, ty }: &mut Arg, vis: &mut T) { +pub fn noop_visit_arg(Arg { id, pat, ty, source }: &mut Arg, vis: &mut T) { vis.visit_id(id); vis.visit_pat(pat); vis.visit_ty(ty); + vis.visit_arg_source(source); +} + +pub fn noop_visit_arg_source(source: &mut ArgSource, vis: &mut T) { + match source { + ArgSource::Normal => {}, + ArgSource::AsyncFn(pat) => vis.visit_pat(pat), + } } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f16bdf449ae7e..0360a92ba5d92 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,7 +1,7 @@ use crate::ast::{AngleBracketedArgs, AsyncArgument, ParenthesizedArgs, AttrStyle, BareFnTy}; use crate::ast::{GenericBound, TraitBoundModifier}; use crate::ast::Unsafety; -use crate::ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind}; +use crate::ast::{Mod, AnonConst, Arg, ArgSource, Arm, Guard, Attribute, BindingMode, TraitItemKind}; use crate::ast::Block; use crate::ast::{BlockCheckMode, CaptureBy, Movability}; use crate::ast::{Constness, Crate}; @@ -550,7 +550,7 @@ fn dummy_arg(span: Span) -> Arg { span, id: ast::DUMMY_NODE_ID }; - Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal } } #[derive(Copy, Clone, Debug)] @@ -2101,7 +2101,7 @@ impl<'a> Parser<'a> { } }; - Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID }) + Ok(Arg { ty, pat, id: ast::DUMMY_NODE_ID, source: ast::ArgSource::Normal }) } /// Parses a single function argument. @@ -2124,7 +2124,8 @@ impl<'a> Parser<'a> { Ok(Arg { ty: t, pat, - id: ast::DUMMY_NODE_ID + id: ast::DUMMY_NODE_ID, + source: ast::ArgSource::Normal, }) } @@ -8689,6 +8690,7 @@ impl<'a> Parser<'a> { ), span, }), + source: ArgSource::AsyncFn(input.pat.clone()), }; // Construct a `let = __argN;` statement to insert at the top of the diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 6b3a30ccb54b7..cbcf7cffc1f19 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -534,6 +534,9 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { for argument in &function_declaration.inputs { visitor.visit_pat(&argument.pat); + if let ArgSource::AsyncFn(pat) = &argument.source { + visitor.visit_pat(pat); + } visitor.visit_ty(&argument.ty) } visitor.visit_fn_ret_ty(&function_declaration.output)