From e5430e5306a2f3706797d5e453860875abe463ed Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 24 Sep 2020 22:01:46 +0200 Subject: [PATCH] the two hardest things in programming, names and... --- .../infer/error_reporting/need_type_info.rs | 188 +++++++++++------- .../borrow_check/diagnostics/region_name.rs | 6 +- 2 files changed, 115 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b00adec822e5..ce249404e8ea 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -178,7 +178,7 @@ fn closure_return_type_suggestion( ); err.span_label( span, - InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr), ); } @@ -220,12 +220,23 @@ impl Into for TypeAnnotationNeeded { } } +/// Information about a constant or a type containing inference variables. +pub struct InferDiagnosticsData { + pub name: String, + pub span: Option, + pub description: Cow<'static, str>, + pub parent_name: Option, + pub parent_description: Option<&'static str>, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn extract_type_name( + /// Extracts data used by diagnostic for either types or constants + /// which were stuck during inference. + pub fn extract_infer_data( &self, arg: GenericArg<'tcx>, highlight: Option, - ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { + ) -> InferDiagnosticsData { match arg.unpack() { GenericArgKind::Type(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { @@ -236,32 +247,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { var_origin.kind { let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id - { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); - ( - parent_name, - Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), - ) - } else { - (None, None) - }; + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), + return InferDiagnosticsData { + name: name.to_string(), + span: Some(var_origin.span), + description: "type parameter".into(), parent_name, - parent_desc, - ); + parent_description, + }; } } } @@ -272,56 +283,67 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) + InferDiagnosticsData { + name: s, + span: None, + description: ty.prefix_string(), + parent_name: None, + parent_description: None, + } } GenericArgKind::Const(ct) => { - let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = origin.kind { let parent_def_id = self.tcx.parent(def_id); - let (parent_name, parent_descr) = if let Some(parent_def_id) = parent_def_id - { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); - ( - parent_name, - Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), - ) - } else { - (None, None) - }; + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; - return ( - name.to_string(), - Some(origin.span), - "const parameter".into(), + return InferDiagnosticsData { + name: name.to_string(), + span: Some(origin.span), + description: "const parameter".into(), parent_name, - parent_descr, - ); + parent_description, + }; } debug_assert!(!origin.span.is_dummy()); - Some(origin.span) + let mut s = String::new(); + let mut printer = + ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ct.print(printer); + InferDiagnosticsData { + name: s, + span: Some(origin.span), + description: "the constant".into(), + parent_name: None, + parent_description: None, + } } else { bug!("unexpect const: {:?}", ct); - }; - - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; } - let _ = ct.print(printer); - (s, span, "the constant".into(), None, None) } GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } @@ -331,18 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, body_id: Option, span: Span, - ty: GenericArg<'tcx>, + arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, None); + let ty = self.resolve_vars_if_possible(&arg); + let arg_data = self.extract_infer_data(arg, None); let kind_str = match ty.unpack() { GenericArgKind::Type(_) => "type", GenericArgKind::Const(_) => "the value", GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), }; - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); + let mut local_visitor = FindHirNodeVisitor::new(&self, arg.into(), span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -372,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { pattern.span - } else if let Some(span) = name_sp { + } else if let Some(span) = arg_data.span { // `span` here lets us point at `sum` instead of the entire right hand side expr: // error[E0282]: type annotations needed // --> file2.rs:3:15 @@ -419,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; - // When `name` corresponds to a type argument, show the path of the full type we're + // When `arg_data.name` corresponds to a type argument, show the path of the full type we're // trying to infer. In the following example, `ty_msg` contains // " in `std::result::Result`": // ``` @@ -458,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &mut err, &decl.output, self.tcx.hir().body(body_id), - &descr, - &name, + &arg_data.description, + &arg_data.name, &ret, - parent_name, - parent_descr, + arg_data.parent_name, + arg_data.parent_description, ); // We don't want to give the other suggestions when the problem is the // closure return type. @@ -476,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // nudge them in the right direction. format!("a boxed closure type like `Box {}>`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { + Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => { let ty = ty_to_string(ty); format!("the explicit type `{}`, with the type parameters specified", ty) } - Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { + Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { let ty = ty_to_string(ty); format!( "the explicit type `{}`, where the type parameter `{}` is specified", - ty, name, + ty, arg_data.name, ) } _ => "a type".to_string(), @@ -601,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | ^^^ cannot infer type for `S` // | // = note: type must be known at this point - let span = name_sp.unwrap_or(err_span); + let span = arg_data.span.unwrap_or(err_span); if !err .span .span_labels() @@ -612,7 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(kind_str, &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + kind_str, + &arg_data.name, + &arg_data.description, + arg_data.parent_name, + arg_data.parent_description, + ), ); } @@ -672,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(ty.into(), None); + let data = self.extract_infer_data(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, @@ -683,12 +711,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); err.span_label( span, - InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + "type", + &data.name, + &data.description, + data.parent_name, + data.parent_description, + ), ); err } - fn missing_type_msg( + fn cannot_infer_msg( kind_str: &str, type_name: &str, descr: &str, @@ -710,6 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; + // FIXME: We really shouldn't be dealing with strings here + // but instead use a sensible enum for cases like this. let preposition = if "the value" == kind_str { "of" } else { "for" }; // For example: "cannot infer type for type parameter `T`" format!( diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index d96020fe3610..e7ab97515b66 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_type_name(ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(ty.into(), Some(highlight)).name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -646,7 +646,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(return_ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(return_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -698,7 +698,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(yield_ty.into(), Some(highlight)).0; + let type_name = self.infcx.extract_infer_data(yield_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);