diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 9c6c53abf0748..cf070eb962f09 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,9 +1,11 @@ use crate::FnCtxt; use rustc_ast::util::parser::PREC_POSTFIX; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::CtorKind; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; use rustc_infer::infer::InferOk; @@ -11,11 +13,14 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut}; +use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder}; +use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; +use rustc_middle::ty::relate::TypeRelation; +use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitable}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches; use rustc_trait_selection::traits::ObligationCause; use super::method::probe; @@ -40,7 +45,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_alternative_method_deref(err, expr, error); // Use `||` to give these suggestions a precedence - let _ = self.suggest_missing_parentheses(err, expr) + let suggested = self.suggest_missing_parentheses(err, expr) || self.suggest_remove_last_method_call(err, expr, expected) || self.suggest_associated_const(err, expr, expected) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) @@ -54,6 +59,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected); + if !suggested { + self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected); + } } pub fn emit_coerce_suggestions( @@ -205,6 +213,215 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expected, Some(err)) } + pub fn point_at_expr_source_of_inferred_type( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + found: Ty<'tcx>, + expected: Ty<'tcx>, + ) -> bool { + let map = self.tcx.hir(); + + let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; }; + let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; }; + let hir::def::Res::Local(hir_id) = p.res else { return false; }; + let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; }; + let Some(hir::Node::Local(hir::Local { + ty: None, + init: Some(init), + .. + })) = map.find_parent(pat.hir_id) else { return false; }; + let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; }; + if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() { + return false; + } + + // Locate all the usages of the relevant binding. + struct FindExprs<'hir> { + hir_id: hir::HirId, + uses: Vec<&'hir hir::Expr<'hir>>, + } + impl<'v> Visitor<'v> for FindExprs<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind + && let hir::def::Res::Local(hir_id) = path.res + && hir_id == self.hir_id + { + self.uses.push(ex); + } + hir::intravisit::walk_expr(self, ex); + } + } + + let mut expr_finder = FindExprs { hir_id, uses: vec![] }; + let id = map.get_parent_item(hir_id); + let hir_id: hir::HirId = id.into(); + + let Some(node) = map.find(hir_id) else { return false; }; + let Some(body_id) = node.body_id() else { return false; }; + let body = map.body(body_id); + expr_finder.visit_expr(body.value); + // Hack to make equality checks on types with inference variables and regions useful. + let mut eraser = BottomUpFolder { + tcx: self.tcx, + lt_op: |_| self.tcx.lifetimes.re_erased, + ct_op: |c| c, + ty_op: |t| match *t.kind() { + ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))), + ty::Infer(ty::IntVar(_)) => { + self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 })) + } + ty::Infer(ty::FloatVar(_)) => { + self.tcx.mk_ty_infer(ty::FloatVar(ty::FloatVid { index: 0 })) + } + _ => t, + }, + }; + let mut prev = eraser.fold_ty(ty); + let mut prev_span = None; + + for binding in expr_finder.uses { + // In every expression where the binding is referenced, we will look at that + // expression's type and see if it is where the incorrect found type was fully + // "materialized" and point at it. We will also try to provide a suggestion there. + if let Some(hir::Node::Expr(expr) + | hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr), + .. + })) = &map.find_parent(binding.hir_id) + && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind + && rcvr.hir_id == binding.hir_id + && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id) + { + // We special case methods, because they can influence inference through the + // call's arguments and we can provide a more explicit span. + let sig = self.tcx.fn_sig(def_id); + let def_self_ty = sig.input(0).skip_binder(); + let rcvr_ty = self.node_ty(rcvr.hir_id); + // Get the evaluated type *after* calling the method call, so that the influence + // of the arguments can be reflected in the receiver type. The receiver + // expression has the type *before* theis analysis is done. + let ty = match self.lookup_probe( + segment.ident, + rcvr_ty, + expr, + probe::ProbeScope::TraitsInScope, + ) { + Ok(pick) => pick.self_ty, + Err(_) => rcvr_ty, + }; + // Remove one layer of references to account for `&mut self` and + // `&self`, so that we can compare it against the binding. + let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) { + (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty), + _ => (ty, def_self_ty), + }; + let mut param_args = FxHashMap::default(); + let mut param_expected = FxHashMap::default(); + let mut param_found = FxHashMap::default(); + if self.can_eq(self.param_env, ty, found).is_ok() { + // We only point at the first place where the found type was inferred. + for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() { + if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() { + // We found an argument that references a type parameter in `Self`, + // so we assume that this is the argument that caused the found + // type, which we know already because of `can_eq` above was first + // inferred in this method call. + let arg = &args[i]; + let arg_ty = self.node_ty(arg.hir_id); + err.span_label( + arg.span, + &format!( + "this is of type `{arg_ty}`, which causes `{ident}` to be \ + inferred as `{ty}`", + ), + ); + param_args.insert(param_ty, (arg, arg_ty)); + } + } + } + + // Here we find, for a type param `T`, the type that `T` is in the current + // method call *and* in the original expected type. That way, we can see if we + // can give any structured suggestion for the function argument. + let mut c = CollectAllMismatches { + infcx: &self.infcx, + param_env: self.param_env, + errors: vec![], + }; + let _ = c.relate(def_self_ty, ty); + for error in c.errors { + if let TypeError::Sorts(error) = error { + param_found.insert(error.expected, error.found); + } + } + c.errors = vec![]; + let _ = c.relate(def_self_ty, expected); + for error in c.errors { + if let TypeError::Sorts(error) = error { + param_expected.insert(error.expected, error.found); + } + } + for (param, (arg, arg_ty)) in param_args.iter() { + let Some(expected) = param_expected.get(param) else { continue; }; + let Some(found) = param_found.get(param) else { continue; }; + if self.can_eq(self.param_env, *arg_ty, *found).is_err() { continue; } + self.emit_coerce_suggestions(err, arg, *found, *expected, None, None); + } + + let ty = eraser.fold_ty(ty); + if ty.references_error() { + break; + } + if ty != prev + && param_args.is_empty() + && self.can_eq(self.param_env, ty, found).is_ok() + { + // We only point at the first place where the found type was inferred. + err.span_label( + segment.ident.span, + with_forced_trimmed_paths!(format!( + "here the type of `{ident}` is inferred to be `{ty}`", + )), + ); + break; + } else if !param_args.is_empty() { + break; + } + prev = ty; + } else { + let ty = eraser.fold_ty(self.node_ty(binding.hir_id)); + if ty.references_error() { + break; + } + if ty != prev + && let Some(span) = prev_span + && self.can_eq(self.param_env, ty, found).is_ok() + { + // We only point at the first place where the found type was inferred. + // We use the *previous* span because if the type is known *here* it means + // it was *evaluated earlier*. We don't do this for method calls because we + // evaluate the method's self type eagerly, but not in any other case. + err.span_label( + span, + with_forced_trimmed_paths!(format!( + "here the type of `{ident}` is inferred to be `{ty}`", + )), + ); + break; + } + prev = ty; + } + if binding.hir_id == expr.hir_id { + // Do not look at expressions that come after the expression we were originally + // evaluating and had a type error. + break; + } + prev_span = Some(binding.span); + } + true + } + fn annotate_expected_due_to_let_ty( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 631749fcc0fa4..6ed1bc051a5fa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -234,6 +234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) => self.check_expr_path(qpath, expr, args), _ => self.check_expr_kind(expr, expected), }); + let ty = self.resolve_vars_if_possible(ty); // Warn for non-block expressions with diverging children. match expr.kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 55280487adda4..7d6b4aaebf4ea 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -798,6 +798,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { full_call_span, format!("arguments to this {} are incorrect", call_name), ); + if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) = + (callee_ty, &call_expr.kind) + { + // Type that would have accepted this argument if it hadn't been inferred earlier. + // FIXME: We leave an inference variable for now, but it'd be nice to get a more + // specific type to increase the accuracy of the diagnostic. + let expected = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: full_call_span, + }); + self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty); + } // Call out where the function is defined self.label_fn_like( &mut err, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0143901f2d7a7..e0304fa2d3b98 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -553,6 +553,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs), _ => span_bug!(span, "Impossible, verified above."), } + if (lhs, rhs).references_error() { + err.downgrade_to_delayed_bug(); + } if self.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "In a match expression, only numbers and characters can be matched \ diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index a130fde47ed5c..749e960bfd030 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -61,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> { .as_local() .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some()) }; - let value = value.fold_with(&mut ty::fold::BottomUpFolder { + let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 6996ddd872994..1d39cf60e2616 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1407,7 +1407,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.note_obligation_cause(&mut err, &obligation); self.point_at_returns_when_relevant(&mut err, &obligation); - err.emit(); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8c2c182877496..aa98ab801587b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -248,7 +248,7 @@ pub trait TypeErrCtxtExt<'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, obligation: &PredicateObligation<'tcx>, ); @@ -1685,7 +1685,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn point_at_returns_when_relevant( &self, - err: &mut Diagnostic, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, obligation: &PredicateObligation<'tcx>, ) { match obligation.cause.code().peel_derives() { @@ -1707,7 +1707,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { for expr in &visitor.returns { if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { let ty = self.resolve_vars_if_possible(returned_ty); - err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); + if ty.references_error() { + // don't print out the [type error] here + err.delay_as_bug(); + } else { + err.span_label( + expr.span, + &format!("this returned value is of type `{}`", ty), + ); + } } } } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 2203bfca4e5f7..05a12d3d4d4a2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -538,8 +538,6 @@ ul.block, .block li { overflow: initial; text-align: right; -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; padding: 14px 8px; color: var(--src-line-numbers-span-color); diff --git a/src/test/ui/type/issue-58355.rs b/src/test/ui/type/issue-58355.rs new file mode 100644 index 0000000000000..3b62fdece403b --- /dev/null +++ b/src/test/ui/type/issue-58355.rs @@ -0,0 +1,7 @@ +#![crate_type = "lib"] + +pub fn foo(callback: fn() -> dyn ToString) { + let mut x: Option dyn ToString>> = None; + x = Some(Box::new(callback)); + //~^ ERROR: the size for values of type `dyn ToString` cannot be known at compilation time +} diff --git a/src/test/ui/type/issue-58355.stderr b/src/test/ui/type/issue-58355.stderr new file mode 100644 index 0000000000000..6f89a7b004999 --- /dev/null +++ b/src/test/ui/type/issue-58355.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time + --> $DIR/issue-58355.rs:5:14 + | +LL | x = Some(Box::new(callback)); + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString` + = note: required because it appears within the type `fn() -> dyn ToString` + = note: required for the cast from `fn() -> dyn ToString` to the object type `dyn Fn() -> (dyn ToString + 'static)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr index 9f4558adab150..de133e5599cf9 100644 --- a/src/test/ui/type/type-check/assignment-in-if.stderr +++ b/src/test/ui/type/type-check/assignment-in-if.stderr @@ -67,6 +67,9 @@ LL | x == 5 error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:18 | +LL | if y = (Foo { foo: x }) { + | - here the type of `x` is inferred to be `usize` +... LL | if x == x && x = x && x == x { | ------ ^ expected `bool`, found `usize` | | @@ -75,6 +78,9 @@ LL | if x == x && x = x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:22 | +LL | if y = (Foo { foo: x }) { + | - here the type of `x` is inferred to be `usize` +... LL | if x == x && x = x && x == x { | ^ expected `bool`, found `usize` @@ -92,6 +98,9 @@ LL | if x == x && x == x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:51:28 | +LL | if y = (Foo { foo: x }) { + | - here the type of `x` is inferred to be `usize` +... LL | if x == x && x == x && x = x { | ---------------- ^ expected `bool`, found `usize` | | diff --git a/src/test/ui/type/type-check/point-at-inference-2.rs b/src/test/ui/type/type-check/point-at-inference-2.rs new file mode 100644 index 0000000000000..6557d7fa1911a --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference-2.rs @@ -0,0 +1,13 @@ +fn bar(_: Vec) {} +fn baz(_: &Vec<&i32>) {} +fn main() { + let v = vec![&1]; + bar(v); //~ ERROR E0308 + let v = vec![]; + baz(&v); + baz(&v); + bar(v); //~ ERROR E0308 + let v = vec![]; + baz(&v); + bar(v); //~ ERROR E0308 +} diff --git a/src/test/ui/type/type-check/point-at-inference-2.stderr b/src/test/ui/type/type-check/point-at-inference-2.stderr new file mode 100644 index 0000000000000..13227c5e245bd --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference-2.stderr @@ -0,0 +1,56 @@ +error[E0308]: mismatched types + --> $DIR/point-at-inference-2.rs:5:9 + | +LL | bar(v); + | --- ^ expected `i32`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec<&{integer}>` +note: function defined here + --> $DIR/point-at-inference-2.rs:1:4 + | +LL | fn bar(_: Vec) {} + | ^^^ ----------- + +error[E0308]: mismatched types + --> $DIR/point-at-inference-2.rs:9:9 + | +LL | baz(&v); + | - here the type of `v` is inferred to be `Vec<&i32>` +LL | baz(&v); +LL | bar(v); + | --- ^ expected `i32`, found `&i32` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec<&i32>` +note: function defined here + --> $DIR/point-at-inference-2.rs:1:4 + | +LL | fn bar(_: Vec) {} + | ^^^ ----------- + +error[E0308]: mismatched types + --> $DIR/point-at-inference-2.rs:12:9 + | +LL | baz(&v); + | - here the type of `v` is inferred to be `Vec<&i32>` +LL | bar(v); + | --- ^ expected `i32`, found `&i32` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec<&i32>` +note: function defined here + --> $DIR/point-at-inference-2.rs:1:4 + | +LL | fn bar(_: Vec) {} + | ^^^ ----------- + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type/type-check/point-at-inference-3.fixed b/src/test/ui/type/type-check/point-at-inference-3.fixed new file mode 100644 index 0000000000000..1a960133ceba9 --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference-3.fixed @@ -0,0 +1,12 @@ +// run-rustfix +fn main() { + let mut v = Vec::new(); + v.push(0i32); + //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` + v.push(0); + v.push(1i32); //~ ERROR mismatched types + //~^ NOTE expected `i32`, found `u32` + //~| NOTE arguments to this method are incorrect + //~| NOTE associated function defined here + //~| HELP change the type of the numeric literal from `u32` to `i32` +} diff --git a/src/test/ui/type/type-check/point-at-inference-3.rs b/src/test/ui/type/type-check/point-at-inference-3.rs new file mode 100644 index 0000000000000..92910ae1a3114 --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference-3.rs @@ -0,0 +1,12 @@ +// run-rustfix +fn main() { + let mut v = Vec::new(); + v.push(0i32); + //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` + v.push(0); + v.push(1u32); //~ ERROR mismatched types + //~^ NOTE expected `i32`, found `u32` + //~| NOTE arguments to this method are incorrect + //~| NOTE associated function defined here + //~| HELP change the type of the numeric literal from `u32` to `i32` +} diff --git a/src/test/ui/type/type-check/point-at-inference-3.stderr b/src/test/ui/type/type-check/point-at-inference-3.stderr new file mode 100644 index 0000000000000..999c3148362f6 --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference-3.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/point-at-inference-3.rs:7:12 + | +LL | v.push(0i32); + | ---- this is of type `i32`, which causes `v` to be inferred as `Vec` +... +LL | v.push(1u32); + | ---- ^^^^ expected `i32`, found `u32` + | | + | arguments to this method are incorrect + | +note: associated function defined here + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL +help: change the type of the numeric literal from `u32` to `i32` + | +LL | v.push(1i32); + | ~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type/type-check/point-at-inference.fixed b/src/test/ui/type/type-check/point-at-inference.fixed new file mode 100644 index 0000000000000..f41fbe59fba6c --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference.fixed @@ -0,0 +1,13 @@ +// run-rustfix +fn bar(_: Vec) {} +fn baz(_: &impl std::any::Any) {} +fn main() { + let v = vec![1, 2, 3, 4, 5]; + let mut foo = vec![]; + baz(&foo); + for i in &v { + foo.push(*i); + } + baz(&foo); + bar(foo); //~ ERROR E0308 +} diff --git a/src/test/ui/type/type-check/point-at-inference.rs b/src/test/ui/type/type-check/point-at-inference.rs new file mode 100644 index 0000000000000..6419e42e70d12 --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference.rs @@ -0,0 +1,13 @@ +// run-rustfix +fn bar(_: Vec) {} +fn baz(_: &impl std::any::Any) {} +fn main() { + let v = vec![1, 2, 3, 4, 5]; + let mut foo = vec![]; + baz(&foo); + for i in &v { + foo.push(i); + } + baz(&foo); + bar(foo); //~ ERROR E0308 +} diff --git a/src/test/ui/type/type-check/point-at-inference.stderr b/src/test/ui/type/type-check/point-at-inference.stderr new file mode 100644 index 0000000000000..70428fe841b9c --- /dev/null +++ b/src/test/ui/type/type-check/point-at-inference.stderr @@ -0,0 +1,26 @@ +error[E0308]: mismatched types + --> $DIR/point-at-inference.rs:12:9 + | +LL | foo.push(i); + | - this is of type `&{integer}`, which causes `foo` to be inferred as `Vec<&{integer}>` +... +LL | bar(foo); + | --- ^^^ expected `i32`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected struct `Vec` + found struct `Vec<&{integer}>` +note: function defined here + --> $DIR/point-at-inference.rs:2:4 + | +LL | fn bar(_: Vec) {} + | ^^^ ----------- +help: consider dereferencing the borrow + | +LL | foo.push(*i); + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/typeck/issue-105946.rs b/src/test/ui/typeck/issue-105946.rs new file mode 100644 index 0000000000000..bf01751d5f6ee --- /dev/null +++ b/src/test/ui/typeck/issue-105946.rs @@ -0,0 +1,12 @@ +fn digit() -> str { + return {}; + //~^ ERROR: mismatched types [E0308] +} +fn main() { + let [_y..] = [box 1, box 2]; + //~^ ERROR: cannot find value `_y` in this scope [E0425] + //~| ERROR: `X..` patterns in slices are experimental [E0658] + //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658] + //~| ERROR: box expression syntax is experimental; you can call `Box::new` instead [E0658] + //~| ERROR: pattern requires 1 element but array has 2 [E0527] +} diff --git a/src/test/ui/typeck/issue-105946.stderr b/src/test/ui/typeck/issue-105946.stderr new file mode 100644 index 0000000000000..d803de4df4727 --- /dev/null +++ b/src/test/ui/typeck/issue-105946.stderr @@ -0,0 +1,49 @@ +error[E0425]: cannot find value `_y` in this scope + --> $DIR/issue-105946.rs:6:10 + | +LL | let [_y..] = [box 1, box 2]; + | ^^ not found in this scope + +error[E0658]: `X..` patterns in slices are experimental + --> $DIR/issue-105946.rs:6:10 + | +LL | let [_y..] = [box 1, box 2]; + | ^^^^ + | + = note: see issue #67264 for more information + = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable + +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead + --> $DIR/issue-105946.rs:6:19 + | +LL | let [_y..] = [box 1, box 2]; + | ^^^^^ + | + = note: see issue #49733 for more information + = help: add `#![feature(box_syntax)]` to the crate attributes to enable + +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead + --> $DIR/issue-105946.rs:6:26 + | +LL | let [_y..] = [box 1, box 2]; + | ^^^^^ + | + = note: see issue #49733 for more information + = help: add `#![feature(box_syntax)]` to the crate attributes to enable + +error[E0308]: mismatched types + --> $DIR/issue-105946.rs:2:10 + | +LL | return {}; + | ^^ expected `str`, found `()` + +error[E0527]: pattern requires 1 element but array has 2 + --> $DIR/issue-105946.rs:6:9 + | +LL | let [_y..] = [box 1, box 2]; + | ^^^^^^ expected 2 elements + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0425, E0527, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/tools/error_index_generator/book_config.toml b/src/tools/error_index_generator/book_config.toml index 885100ae3a449..2701ad917bb09 100644 --- a/src/tools/error_index_generator/book_config.toml +++ b/src/tools/error_index_generator/book_config.toml @@ -7,6 +7,7 @@ src = "" git-repository-url = "https://github.com/rust-lang/rust/" additional-css = ["error-index.css"] additional-js = ["error-index.js"] +input-404 = "" [output.html.search] enable = true diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 1bde8e007826d..98eda97e236cb 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -98,8 +98,7 @@ fn add_rust_attribute_on_codeblock(explanation: &str) -> String { fn render_html(output_path: &Path) -> Result<(), Box> { let mut introduction = format!( - " -# Rust error codes index + "# Rust error codes index This page lists all the error codes emitted by the Rust compiler. @@ -149,7 +148,12 @@ This page lists all the error codes emitted by the Rust compiler. book.book.sections.push(BookItem::Chapter(chapter)); book.build()?; - // We can't put this content into another file, otherwise `mbdbook` will also put it into the + // The error-index used to be generated manually (without mdbook), and the + // index was located at the top level. Now that it is generated with + // mdbook, error-index.html has moved to error_codes/error-index.html. + // This adds a redirect so that old links go to the new location. + // + // We can't put this content into another file, otherwise `mdbook` will also put it into the // output directory, making a duplicate. fs::write( output_path.join("error-index.html"), @@ -163,14 +167,10 @@ This page lists all the error codes emitted by the Rust compiler.
If you are not automatically redirected to the error code index, please here. - "#, )?; - // No need for a 404 file, it's already handled by the server. - fs::remove_file(output_path.join("error_codes/404.html"))?; - Ok(()) } diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js index 8c907f5795d32..c80cbf297afff 100644 --- a/src/tools/error_index_generator/redirect.js +++ b/src/tools/error_index_generator/redirect.js @@ -3,14 +3,10 @@ let code = window.location.hash.replace(/^#/, ''); // We have to make sure this pattern matches to avoid inadvertently creating an // open redirect. - if (!/^E[0-9]+$/.test(code)) { + if (/^E[0-9]+$/.test(code)) { + window.location.replace('./error_codes/' + code + '.html'); return; } - if (window.location.pathname.indexOf("/error_codes/") !== -1) { - // We're not at the top level, so we don't prepend with "./error_codes/". - window.location = './' + code + '.html'; - } else { - window.location = './error_codes/' + code + '.html'; - } } + window.location.replace('./error_codes/error-index.html'); })()