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:
commit
12040cf665
@ -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(
|
||||
|
@ -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 })
|
||||
}
|
||||
|
12
src/test/ui/const-generics/uninferred-consts.rs
Normal file
12
src/test/ui/const-generics/uninferred-consts.rs
Normal 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
|
||||
}
|
20
src/test/ui/const-generics/uninferred-consts.stderr
Normal file
20
src/test/ui/const-generics/uninferred-consts.stderr
Normal 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`.
|
Loading…
x
Reference in New Issue
Block a user