about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-05-19 13:53:41 +0200
committerGitHub <noreply@github.com>2020-05-19 13:53:41 +0200
commit12040cf665b55f10a68818d116265eeea3b082e6 (patch)
tree0982f934e05907f4aae4b4436e163f2b5e428771 /src
parent4c48f5ab692c640ef9d644efa1989ed67db297d5 (diff)
parent5da74304d500d1a472f171c06c932f156f77eb9a (diff)
Rollup merge of #72066 - lcnr:const-type-info-err, r=varkor
correctly handle uninferred consts

fixes the ICE mentioned in https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893

I originally tried to generalize `need_type_info_err` to also work with consts which was not as much fun as I hoped :sweat_smile:

It might be easier to have some duplication here and handle consts separately.

r? @varkor
Diffstat (limited to 'src')
-rw-r--r--src/librustc_infer/infer/error_reporting/need_type_info.rs43
-rw-r--r--src/librustc_typeck/check/writeback.rs20
-rw-r--r--src/test/ui/const-generics/uninferred-consts.rs12
-rw-r--r--src/test/ui/const-generics/uninferred-consts.stderr20
4 files changed, 90 insertions, 5 deletions
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 0141ba82737..dfc7177921d 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<hir::BodyId>,
+        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 c5bf151bc1e..154ca391aa5 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 00000000000..3b2bb49197d
--- /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<const N: usize>(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 00000000000..a3620084a42
--- /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 <https://github.com/rust-lang/rust/issues/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`.