diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 14bfa8bab8939..13a569e81d0f2 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1243,7 +1243,7 @@ pub(crate) mod builtin { /// be disabled. See [`debug_assert!`] for assertions that are not enabled in /// release builds by default. /// - /// Unsafe code relies on `assert!` to enforce run-time invariants that, if + /// Unsafe code may rely on `assert!` to enforce run-time invariants that, if /// violated could lead to unsafety. /// /// Other use-cases of `assert!` include testing and enforcing run-time diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 9e1971c9a945b..c164e893b4fbf 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1165,8 +1165,7 @@ instead of overflowing. Basic usage: ``` -", $Feature, "#![feature(saturating_neg)] -assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), "::MAX); @@ -1175,7 +1174,7 @@ assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT) $EndFeature, " ```"), - #[unstable(feature = "saturating_neg", issue = "59983")] + #[stable(feature = "saturating_neg", since = "1.45.0")] #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[inline] pub const fn saturating_neg(self) -> Self { @@ -1192,8 +1191,7 @@ MIN` instead of overflowing. Basic usage: ``` -", $Feature, "#![feature(saturating_neg)] -assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), "::MAX); @@ -1202,7 +1200,7 @@ assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($ $EndFeature, " ```"), - #[unstable(feature = "saturating_neg", issue = "59983")] + #[stable(feature = "saturating_neg", since = "1.45.0")] #[rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718")] #[inline] pub const fn saturating_abs(self) -> Self { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index d636542d699f9..6a8e908b9c618 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -17,7 +17,6 @@ #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] -#![feature(saturating_neg)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] #![feature(specialization)] 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_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8ae6853210f18..43fd2b1853011 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -620,7 +620,11 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } pub fn get_path_res(&self, id: NodeId) -> Res { - let hir_id = self.tcx.hir().node_id_to_hir_id(id); + // FIXME(#71104) + let hir_id = match self.tcx.hir().opt_node_id_to_hir_id(id) { + Some(id) => id, + None => return Res::Err, + }; match self.tcx.hir().get(hir_id) { Node::TraitRef(tr) => tr.path.res, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 64dc34ab3b0a7..c4805c54a7d43 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -468,7 +468,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { match expr.kind { hir::ExprKind::Index(ref base_expr, ref index_expr) => { - let index_expr_ty = self.node_ty(index_expr.hir_id); + // We need to get the final type in case dereferences were needed for the trait + // to apply (#72002). + let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr); self.convert_place_op_to_mutable( PlaceOp::Index, expr, 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`. diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs index 2c3421b7a8d0b..ab24abeba32fe 100644 --- a/src/test/ui/consts/const-int-arithmetic.rs +++ b/src/test/ui/consts/const-int-arithmetic.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(saturating_neg)] #![feature(const_checked_int_methods)] #![feature(const_euclidean_int_methods)] #![feature(const_overflowing_int_methods)] diff --git a/src/test/ui/issues/issue-72002.rs b/src/test/ui/issues/issue-72002.rs new file mode 100644 index 0000000000000..54ff89355ff3a --- /dev/null +++ b/src/test/ui/issues/issue-72002.rs @@ -0,0 +1,29 @@ +// check-pass +struct Indexable; + +impl Indexable { + fn boo(&mut self) {} +} + +impl std::ops::Index<&str> for Indexable { + type Output = Indexable; + + fn index(&self, field: &str) -> &Indexable { + self + } +} + +impl std::ops::IndexMut<&str> for Indexable { + fn index_mut(&mut self, field: &str) -> &mut Indexable { + self + } +} + +fn main() { + let mut v = Indexable; + let field = "hello".to_string(); + + v[field.as_str()].boo(); + + v[&field].boo(); // < This should work +} diff --git a/src/test/ui/save-analysis/issue-72267.rs b/src/test/ui/save-analysis/issue-72267.rs new file mode 100644 index 0000000000000..eea0a7fea0cef --- /dev/null +++ b/src/test/ui/save-analysis/issue-72267.rs @@ -0,0 +1,7 @@ +// compile-flags: -Z save-analysis + +fn main() { + let _: Box<(dyn ?Sized)>; + //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR at least one trait is required for an object type +} diff --git a/src/test/ui/save-analysis/issue-72267.stderr b/src/test/ui/save-analysis/issue-72267.stderr new file mode 100644 index 0000000000000..76fc6c57cbc36 --- /dev/null +++ b/src/test/ui/save-analysis/issue-72267.stderr @@ -0,0 +1,15 @@ +error: `?Trait` is not permitted in trait object types + --> $DIR/issue-72267.rs:4:21 + | +LL | let _: Box<(dyn ?Sized)>; + | ^^^^^^ + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-72267.rs:4:17 + | +LL | let _: Box<(dyn ?Sized)>; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0224`.