Skip to content

Commit

Permalink
correctly handle uninferred consts
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed May 18, 2020
1 parent 9e2a6a2 commit 5da7430
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 5 deletions.
43 changes: 42 additions & 1 deletion src/librustc_infer/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand Down
20 changes: 16 additions & 4 deletions src/librustc_typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
}
Expand All @@ -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 })
}
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/const-generics/uninferred-consts.rs
Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 20 additions & 0 deletions src/test/ui/const-generics/uninferred-consts.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 5da7430

Please sign in to comment.