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 😅

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

r? @varkor
This commit is contained in:
Dylan DPC 2020-05-19 13:53:41 +02:00 committed by GitHub
commit 12040cf665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 5 deletions

View File

@ -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(

View File

@ -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 })
}

View File

@ -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
}

View File

@ -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`.