From 5da74304d500d1a472f171c06c932f156f77eb9a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 10 May 2020 00:01:23 +0200 Subject: [PATCH] correctly handle uninferred consts --- .../infer/error_reporting/need_type_info.rs | 43 ++++++++++++++++++- src/librustc_typeck/check/writeback.rs | 20 +++++++-- .../ui/const-generics/uninferred-consts.rs | 12 ++++++ .../const-generics/uninferred-consts.stderr | 20 +++++++++ 4 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/const-generics/uninferred-consts.rs create mode 100644 src/test/ui/const-generics/uninferred-consts.stderr diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 0141ba8273775..dfc7177921d31 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -172,8 +172,19 @@ fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String { } pub enum TypeAnnotationNeeded { + /// ```compile_fail,E0282 + /// let x = "hello".chars().rev().collect(); + /// ``` E0282, + /// An implementation cannot be chosen unambiguously because of lack of information. + /// ```compile_fail,E0283 + /// let _ = Default::default(); + /// ``` E0283, + /// ```compile_fail,E0284 + /// let mut d: u64 = 2; + /// d = d % 1u32.into(); + /// ``` E0284, } @@ -261,7 +272,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.name_resolver = Some(Box::new(&getter)); let _ = if let ty::FnDef(..) = ty.kind { // We don't want the regular output for `fn`s because it includes its path in - // invalid pseduo-syntax, we want the `fn`-pointer output instead. + // invalid pseudo-syntax, we want the `fn`-pointer output instead. ty.fn_sig(self.tcx).print(printer) } else { ty.print(printer) @@ -518,6 +529,36 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err } + // FIXME(const_generics): We should either try and merge this with `need_type_info_err` + // or improve the errors created here. + // + // Unlike for type inference variables, we don't yet store the origin of const inference variables. + // This is needed for to get a more relevant error span. + pub fn need_type_info_err_const( + &self, + body_id: Option, + span: Span, + ct: &'tcx ty::Const<'tcx>, + error_code: TypeAnnotationNeeded, + ) -> DiagnosticBuilder<'tcx> { + let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span); + if let Some(body_id) = body_id { + let expr = self.tcx.hir().expect_expr(body_id.hir_id); + local_visitor.visit_expr(expr); + } + + let error_code = error_code.into(); + let mut err = self.tcx.sess.struct_span_err_with_code( + local_visitor.target_span, + &format!("type annotations needed"), + error_code, + ); + + err.note("unable to infer the value of a const parameter"); + + err + } + /// If the `FnSig` for the method call can be found and type arguments are identified as /// needed, suggest annotating the call, otherwise point out the resulting type of the call. fn annotate_method_call( diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index c5bf151bc1e11..154ca391aa5fd 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -647,13 +647,26 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: false } } - fn report_error(&self, t: Ty<'tcx>) { + fn report_type_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) .emit(); } } + + fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { + if !self.tcx.sess.has_errors() { + self.infcx + .need_type_info_err_const( + Some(self.body.id()), + self.span.to_span(self.tcx), + c, + E0282, + ) + .emit(); + } + } } impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { @@ -666,7 +679,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { Ok(t) => self.infcx.tcx.erase_regions(&t), Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); - self.report_error(t); + self.report_type_error(t); self.replaced_with_error = true; self.tcx().types.err } @@ -683,8 +696,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { Ok(ct) => self.infcx.tcx.erase_regions(&ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); - // FIXME: we'd like to use `self.report_error`, but it doesn't yet - // accept a &'tcx ty::Const. + self.report_const_error(ct); self.replaced_with_error = true; self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty }) } diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/uninferred-consts.rs new file mode 100644 index 0000000000000..3b2bb49197d01 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts.rs @@ -0,0 +1,12 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893 +struct Foo; +impl Foo { + fn foo(self) {} +} +fn main() { + Foo.foo(); + //~^ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/uninferred-consts.stderr b/src/test/ui/const-generics/uninferred-consts.stderr new file mode 100644 index 0000000000000..a3620084a4289 --- /dev/null +++ b/src/test/ui/const-generics/uninferred-consts.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/uninferred-consts.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0282]: type annotations needed + --> $DIR/uninferred-consts.rs:10:5 + | +LL | Foo.foo(); + | ^^^^^^^^^ + | + = note: unable to infer the value of a const parameter + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0282`.