diff --git a/src/libcore/benches/slice.rs b/src/libcore/benches/slice.rs index 484753c1a045e..711a8dff2c0b5 100644 --- a/src/libcore/benches/slice.rs +++ b/src/libcore/benches/slice.rs @@ -55,3 +55,29 @@ fn binary_search_l2_with_dups(b: &mut Bencher) { fn binary_search_l3_with_dups(b: &mut Bencher) { binary_search(b, Cache::L3, |i| i / 16 * 16); } + +macro_rules! rotate { + ($fn:ident, $n:expr, $mapper:expr) => { + #[bench] + fn $fn(b: &mut Bencher) { + let mut x = (0usize..$n).map(&$mapper).collect::>(); + b.iter(|| { + for s in 0..x.len() { + x[..].rotate_right(s); + } + black_box(x[0].clone()) + }) + } + }; +} + +#[derive(Clone)] +struct Rgb(u8, u8, u8); + +rotate!(rotate_u8, 32, |i| i as u8); +rotate!(rotate_rgb, 32, |i| Rgb(i as u8, (i as u8).wrapping_add(7), (i as u8).wrapping_add(42))); +rotate!(rotate_usize, 32, |i| i); +rotate!(rotate_16_usize_4, 16, |i| [i; 4]); +rotate!(rotate_16_usize_5, 16, |i| [i; 5]); +rotate!(rotate_64_usize_4, 64, |i| [i; 4]); +rotate!(rotate_64_usize_5, 64, |i| [i; 5]); diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 0437937d769b7..f73e14f27e092 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -2,32 +2,9 @@ use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; -/// Rotation is much faster if it has access to a little bit of memory. This -/// union provides a RawVec-like interface, but to a fixed-size stack buffer. -#[allow(unions_with_drop_fields)] -union RawArray { - /// Ensure this is appropriately aligned for T, and is big - /// enough for two elements even if T is enormous. - typed: [T; 2], - /// For normally-sized types, especially things like u8, having more - /// than 2 in the buffer is necessary for usefulness, so pad it out - /// enough to be helpful, but not so big as to risk overflow. - _extra: [usize; 32], -} - -impl RawArray { - fn capacity() -> usize { - if mem::size_of::() == 0 { - usize::max_value() - } else { - mem::size_of::() / mem::size_of::() - } - } -} - -/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` -/// becomes the first element. Equivalently, rotates the range `left` -/// elements to the left or `right` elements to the right. +/// Rotates the range `[mid-left, mid+right)` such that the element at `mid` becomes the first +/// element. Equivalently, rotates the range `left` elements to the left or `right` elements to the +/// right. /// /// # Safety /// @@ -35,55 +12,161 @@ impl RawArray { /// /// # Algorithm /// -/// For longer rotations, swap the left-most `delta = min(left, right)` -/// elements with the right-most `delta` elements. LLVM vectorizes this, -/// which is profitable as we only reach this step for a "large enough" -/// rotation. Doing this puts `delta` elements on the larger side into the -/// correct position, leaving a smaller rotate problem. Demonstration: -/// +/// Algorithm 1 is used for small values of `left + right` or for large `T`. The elements are moved +/// into their final positions one at a time starting at `mid - left` and advancing by `right` steps +/// modulo `left + right`, such that only one temporary is needed. Eventually, we arrive back at +/// `mid - left`. However, if `gcd(left + right, right)` is not 1, the above steps skipped over +/// elements. For example: /// ```text -/// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ] -/// 1 2 3 4 5 [ 11 12 13 . 6 7 8 9 10 ] -/// 1 2 3 4 5 [ 8 9 10 . 6 7 ] 11 12 13 -/// 1 2 3 4 5 6 7 [ 10 . 8 9 ] 11 12 13 -/// 1 2 3 4 5 6 7 [ 9 . 8 ] 10 11 12 13 -/// 1 2 3 4 5 6 7 8 [ . ] 9 10 11 12 13 +/// left = 10, right = 6 +/// the `^` indicates an element in its final place +/// 6 7 8 9 10 11 12 13 14 15 . 0 1 2 3 4 5 +/// after using one step of the above algorithm (The X will be overwritten at the end of the round, +/// and 12 is stored in a temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 2 3 4 5 +/// ^ +/// after using another step (now 2 is in the temporary): +/// X 7 8 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ +/// after the third step (the steps wrap around, and 8 is in the temporary): +/// X 7 2 9 10 11 6 13 14 15 . 0 1 12 3 4 5 +/// ^ ^ ^ +/// after 7 more steps, the round ends with the temporary 0 getting put in the X: +/// 0 7 2 9 4 11 6 13 8 15 . 10 1 12 3 14 5 +/// ^ ^ ^ ^ ^ ^ ^ ^ /// ``` +/// Fortunately, the number of skipped over elements between finalized elements is always equal, so +/// we can just offset our starting position and do more rounds (the total number of rounds is the +/// `gcd(left + right, right)` value). The end result is that all elements are finalized once and +/// only once. +/// +/// Algorithm 2 is used if `left + right` is large but `min(left, right)` is small enough to +/// fit onto a stack buffer. The `min(left, right)` elements are copied onto the buffer, `memmove` +/// is applied to the others, and the ones on the buffer are moved back into the hole on the +/// opposite side of where they originated. +/// +/// Algorithms that can be vectorized outperform the above once `left + right` becomes large enough. +/// Algorithm 1 can be vectorized by chunking and performing many rounds at once, but there are too +/// few rounds on average until `left + right` is enormous, and the worst case of a single +/// round is always there. Instead, algorithm 3 utilizes repeated swapping of +/// `min(left, right)` elements until a smaller rotate problem is left. /// -/// Once the rotation is small enough, copy some elements into a stack -/// buffer, `memmove` the others, and move the ones back from the buffer. -pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { +/// ```text +/// left = 11, right = 4 +/// [4 5 6 7 8 9 10 11 12 13 14 . 0 1 2 3] +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping the right most elements with elements to the left +/// [4 5 6 7 8 9 10 . 0 1 2 3] 11 12 13 14 +/// ^ ^ ^ ^ ^ ^ ^ ^ swapping these +/// [4 5 6 . 0 1 2 3] 7 8 9 10 11 12 13 14 +/// we cannot swap any more, but a smaller rotation problem is left to solve +/// ``` +/// when `left < right` the swapping happens from the left instead. +pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) { + type BufType = [usize; 32]; + if mem::size_of::() == 0 { + return; + } loop { - let delta = cmp::min(left, right); - if delta <= RawArray::::capacity() { - // We will always hit this immediately for ZST. - break; + // N.B. the below algorithms can fail if these cases are not checked + if (right == 0) || (left == 0) { + return; } - - ptr::swap_nonoverlapping( - mid.sub(left), - mid.add(right - delta), - delta); - - if left <= right { - right -= delta; + if (left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>()) { + // Algorithm 1 + // Microbenchmarks indicate that the average performance for random shifts is better all + // the way until about `left + right == 32`, but the worst case performance breaks even + // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 + // `usize`s, this algorithm also outperforms other algorithms. + let x = mid.sub(left); + // beginning of first round + let mut tmp: T = x.read(); + let mut i = right; + // `gcd` can be found before hand by calculating `gcd(left + right, right)`, + // but it is faster to do one loop which calculates the gcd as a side effect, then + // doing the rest of the chunk + let mut gcd = right; + // benchmarks reveal that it is faster to swap temporaries all the way through instead + // of reading one temporary once, copying backwards, and then writing that temporary at + // the very end. This is possibly due to the fact that swapping or replacing temporaries + // uses only one memory address in the loop instead of needing to manage two. + loop { + tmp = x.add(i).replace(tmp); + // instead of incrementing `i` and then checking if it is outside the bounds, we + // check if `i` will go outside the bounds on the next increment. This prevents + // any wrapping of pointers or `usize`. + if i >= left { + i -= left; + if i == 0 { + // end of first round + x.write(tmp); + break; + } + // this conditional must be here if `left + right >= 15` + if i < gcd { + gcd = i; + } + } else { + i += right; + } + } + // finish the chunk with more rounds + for start in 1..gcd { + tmp = x.add(start).read(); + i = start + right; + loop { + tmp = x.add(i).replace(tmp); + if i >= left { + i -= left; + if i == start { + x.add(start).write(tmp); + break; + } + } else { + i += right; + } + } + } + return; + // `T` is not a zero-sized type, so it's okay to divide by its size. + } else if cmp::min(left, right) <= mem::size_of::() / mem::size_of::() { + // Algorithm 2 + // The `[T; 0]` here is to ensure this is appropriately aligned for T + let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); + let buf = rawarray.as_mut_ptr() as *mut T; + let dim = mid.sub(left).add(right); + if left <= right { + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + ptr::copy(mid, mid.sub(left), right); + ptr::copy_nonoverlapping(buf, dim, left); + } else { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } + return; + } else if left >= right { + // Algorithm 3 + // There is an alternate way of swapping that involves finding where the last swap + // of this algorithm would be, and swapping using that last chunk instead of swapping + // adjacent chunks like this algorithm is doing, but this way is still faster. + loop { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + left -= right; + if left < right { + break; + } + } } else { - left -= delta; + // Algorithm 3, `left < right` + loop { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + right -= left; + if right < left { + break; + } + } } } - - let mut rawarray = MaybeUninit::>::uninit(); - let buf = &mut (*rawarray.as_mut_ptr()).typed as *mut [T; 2] as *mut T; - - let dim = mid.sub(left).add(right); - if left <= right { - ptr::copy_nonoverlapping(mid.sub(left), buf, left); - ptr::copy(mid, mid.sub(left), right); - ptr::copy_nonoverlapping(buf, dim, left); - } - else { - ptr::copy_nonoverlapping(mid, buf, right); - ptr::copy(mid.sub(left), dim, left); - ptr::copy_nonoverlapping(buf, mid.sub(left), right); - } } diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 04ad02766616d..1ef77f87ab7e2 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1152,6 +1152,44 @@ fn test_rotate_right() { } } +#[test] +#[cfg(not(miri))] +fn brute_force_rotate_test_0() { + // In case of edge cases involving multiple algorithms + let n = 300; + for len in 0..n { + for s in 0..len { + let mut v = Vec::with_capacity(len); + for i in 0..len { + v.push(i); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + +#[test] +fn brute_force_rotate_test_1() { + // `ptr_rotate` covers so many kinds of pointer usage, that this is just a good test for + // pointers in general. This uses a `[usize; 4]` to hit all algorithms without overwhelming miri + let n = 30; + for len in 0..n { + for s in 0..len { + let mut v: Vec<[usize; 4]> = Vec::with_capacity(len); + for i in 0..len { + v.push([i, 0, 0, 0]); + } + v[..].rotate_right(s); + for i in 0..v.len() { + assert_eq!(v[i][0], v.len().wrapping_add(i.wrapping_sub(s)) % v.len()); + } + } + } +} + #[test] #[cfg(not(target_arch = "wasm32"))] fn sort_unstable() { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 0d477ae796822..b85738dd29a6d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -287,7 +287,7 @@ impl<'hir> Map<'hir> { self.definitions.def_index_to_hir_id(def_id.to_def_id().index) } - fn def_kind(&self, hir_id: HirId) -> Option { + pub fn def_kind(&self, hir_id: HirId) -> Option { let node = if let Some(node) = self.find(hir_id) { node } else { diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 8d0ead5c8fe90..2ffcd2c4ace7b 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -662,19 +662,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } _ => { + // `last_ty` can be `!`, `expected` will have better info when present. + let t = self.resolve_vars_if_possible(&match exp_found { + Some(ty::error::ExpectedFound { expected, .. }) => expected, + _ => last_ty, + }); let msg = "`match` arms have incompatible types"; err.span_label(cause.span, msg); if prior_arms.len() <= 4 { for sp in prior_arms { - err.span_label(*sp, format!( - "this is found to be of type `{}`", - self.resolve_vars_if_possible(&last_ty), - )); + err.span_label( *sp, format!("this is found to be of type `{}`", t)); } } else if let Some(sp) = prior_arms.last() { - err.span_label(*sp, format!( - "this and all prior arms are found to be of type `{}`", last_ty, - )); + err.span_label( + *sp, + format!("this and all prior arms are found to be of type `{}`", t), + ); } } }, @@ -1143,27 +1146,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } (_, false, _) => { if let Some(exp_found) = exp_found { - let (def_id, ret_ty) = match exp_found.found.sty { - ty::FnDef(def, _) => { - (Some(def), Some(self.tcx.fn_sig(def).output())) - } - _ => (None, None), - }; - - let exp_is_struct = match exp_found.expected.sty { - ty::Adt(def, _) => def.is_struct(), - _ => false, - }; - - if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { - if exp_is_struct && &exp_found.expected == ret_ty.skip_binder() { - let message = format!( - "did you mean `{}(/* fields */)`?", - self.tcx.def_path_str(def_id) - ); - diag.span_label(span, message); - } - } self.suggest_as_ref_where_appropriate(span, &exp_found, diag); } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index d825358beaade..9680f61d69903 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -548,7 +548,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce(self, &cause, e, e_ty); } else { assert!(e_ty.is_unit()); - coerce.coerce_forced_unit(self, &cause, &mut |_| (), true); + let ty = coerce.expected_ty(); + coerce.coerce_forced_unit(self, &cause, &mut |err| { + let val = match ty.sty { + ty::Bool => "true", + ty::Char => "'a'", + ty::Int(_) | ty::Uint(_) => "42", + ty::Float(_) => "3.14159", + ty::Error | ty::Never => return, + _ => "value", + }; + let msg = "give it a value of the expected type"; + let label = destination.label + .map(|l| format!(" {}", l.ident)) + .unwrap_or_else(String::new); + let sugg = format!("break{} {}", label, val); + err.span_suggestion(expr.span, msg, sugg, Applicability::HasPlaceholders); + }, false); } } else { // If `ctxt.coerce` is `None`, we can just ignore diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 08033b46b8004..4fb28db6e94fa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3709,7 +3709,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.consider_hint_about_removing_semicolon(blk, expected_ty, err); } if let Some(fn_span) = fn_span { - err.span_label(fn_span, "this function's body doesn't return"); + err.span_label( + fn_span, + "implicitly returns `()` as its body has no tail or `return` \ + expression", + ); } }, false); } @@ -3819,6 +3823,101 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pointing_at_return_type } + /// When encountering an fn-like ctor that needs to unify with a value, check whether calling + /// the ctor would successfully solve the type mismatch and if so, suggest it: + /// ``` + /// fn foo(x: usize) -> usize { x } + /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` + /// ``` + fn suggest_fn_call( + &self, + err: &mut DiagnosticBuilder<'tcx>, + expr: &hir::Expr, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + match found.sty { + ty::FnDef(..) | ty::FnPtr(_) => {} + _ => return false, + } + let hir = self.tcx.hir(); + + let sig = found.fn_sig(self.tcx); + let sig = self + .replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig) + .0; + let sig = self.normalize_associated_types_in(expr.span, &sig); + if let Ok(_) = self.try_coerce(expr, sig.output(), expected, AllowTwoPhase::No) { + let (mut sugg_call, applicability) = if sig.inputs().is_empty() { + (String::new(), Applicability::MachineApplicable) + } else { + ("...".to_string(), Applicability::HasPlaceholders) + }; + let mut msg = "call this function"; + if let ty::FnDef(def_id, ..) = found.sty { + match hir.get_if_local(def_id) { + Some(Node::Item(hir::Item { + node: ItemKind::Fn(.., body_id), + .. + })) | + Some(Node::ImplItem(hir::ImplItem { + node: hir::ImplItemKind::Method(_, body_id), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), + .. + })) => { + let body = hir.body(*body_id); + sugg_call = body.arguments.iter() + .map(|arg| match &arg.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); + match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) { + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; + } + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} + } + } + Some(Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), + .. + })) => sugg_call = idents.iter() + .map(|ident| if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + }).collect::>() + .join(", "), + _ => {} + } + }; + if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) { + err.span_suggestion( + expr.span, + &format!("use parentheses to {}", msg), + format!("{}({})", code, sugg_call), + applicability, + ); + return true; + } + } + false + } + pub fn suggest_ref_or_into( &self, err: &mut DiagnosticBuilder<'tcx>, @@ -3833,6 +3932,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggestion, Applicability::MachineApplicable, ); + } else if let (ty::FnDef(def_id, ..), true) = ( + &found.sty, + self.suggest_fn_call(err, expr, expected, found), + ) { + if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { + let sp = self.sess().source_map().def_span(sp); + err.span_label(sp, &format!("{} defined here", found)); + } } else if !self.check_for_cast(err, expr, found, expected) { let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field( expr.hir_id, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d85c2df16a350..30e16592113b6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2052,9 +2052,23 @@ impl<'a> Parser<'a> { while self.token != token::CloseDelim(token::Paren) { es.push(match self.parse_expr() { Ok(es) => es, - Err(err) => { + Err(mut err) => { // recover from parse error in tuple list - return Ok(self.recover_seq_parse_error(token::Paren, lo, Err(err))); + match self.token.kind { + token::Ident(name, false) + if name == kw::Underscore && self.look_ahead(1, |t| { + t == &token::Comma + }) => { + // Special-case handling of `Foo<(_, _, _)>` + err.emit(); + let sp = self.token.span; + self.bump(); + self.mk_expr(sp, ExprKind::Err, ThinVec::new()) + } + _ => return Ok( + self.recover_seq_parse_error(token::Paren, lo, Err(err)), + ), + } } }); recovered = self.expect_one_of( @@ -2456,9 +2470,10 @@ impl<'a> Parser<'a> { } /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. - fn parse_dot_or_call_expr(&mut self, - already_parsed_attrs: Option>) - -> PResult<'a, P> { + fn parse_dot_or_call_expr( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let b = self.parse_bottom_expr(); @@ -2466,16 +2481,16 @@ impl<'a> Parser<'a> { self.parse_dot_or_call_expr_with(b, span, attrs) } - fn parse_dot_or_call_expr_with(&mut self, - e0: P, - lo: Span, - mut attrs: ThinVec) - -> PResult<'a, P> { + fn parse_dot_or_call_expr_with( + &mut self, + e0: P, + lo: Span, + mut attrs: ThinVec, + ) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure - self.parse_dot_or_call_expr_with_(e0, lo) - .map(|expr| + self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| expr.map(|mut expr| { attrs.extend::>(expr.attrs.into()); expr.attrs = attrs; @@ -2483,10 +2498,7 @@ impl<'a> Parser<'a> { ExprKind::If(..) if !expr.attrs.is_empty() => { // Just point to the first attribute in there... let span = expr.attrs[0].span; - - self.span_err(span, - "attributes are not yet allowed on `if` \ - expressions"); + self.span_err(span, "attributes are not yet allowed on `if` expressions"); } _ => {} } @@ -2624,7 +2636,24 @@ impl<'a> Parser<'a> { } fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { - self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r) + self.parse_paren_comma_seq(|p| { + match p.parse_expr() { + Ok(expr) => Ok(expr), + Err(mut err) => match p.token.kind { + token::Ident(name, false) + if name == kw::Underscore && p.look_ahead(1, |t| { + t == &token::Comma + }) => { + // Special-case handling of `foo(_, _, _)` + err.emit(); + let sp = p.token.span; + p.bump(); + Ok(p.mk_expr(sp, ExprKind::Err, ThinVec::new())) + } + _ => Err(err), + }, + } + }).map(|(r, _)| r) } crate fn process_potential_macro_variable(&mut self) { @@ -2806,9 +2835,10 @@ impl<'a> Parser<'a> { /// This parses an expression accounting for associativity and precedence of the operators in /// the expression. #[inline] - fn parse_assoc_expr(&mut self, - already_parsed_attrs: Option>) - -> PResult<'a, P> { + fn parse_assoc_expr( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, P> { self.parse_assoc_expr_with(0, already_parsed_attrs.into()) } diff --git a/src/llvm-project b/src/llvm-project index 9b64ca5b7e1e3..f2b0c67661f19 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 9b64ca5b7e1e3583978f9ac8af6d93b220a13d90 +Subproject commit f2b0c67661f19bb2564225d47aca424ad0449791 diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 618d020ce08b5..f4984ca446309 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn f() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; LL | "bla".to_string(); | - help: consider removing this semicolon @@ -18,7 +18,7 @@ error[E0308]: mismatched types LL | fn g() -> String { | - ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); LL | "removeme".to_string(); | - help: consider removing this semicolon diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr index d73489a602df4..cfb42c601279a 100644 --- a/src/test/ui/block-result/issue-11714.stderr +++ b/src/test/ui/block-result/issue-11714.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn blah() -> i32 { | ---- ^^^ expected i32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; | - help: consider removing this semicolon diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 18adb15c9615d..f7cafab3d773b 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn foo() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression ... LL | ; | - help: consider removing this semicolon @@ -18,7 +18,7 @@ error[E0308]: mismatched types LL | fn bar() -> String { | --- ^^^^^^ expected struct `std::string::String`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() LL | ; | - help: consider removing this semicolon diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr index 057de5b625e87..955793e8586e7 100644 --- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn plus_one(x: i32) -> i32 { | -------- ^^^ expected i32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | x + 1; | - help: consider removing this semicolon | @@ -17,7 +17,7 @@ error[E0308]: mismatched types LL | fn foo() -> Result { | --- ^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | Ok(1); | - help: consider removing this semicolon | diff --git a/src/test/ui/issues/issue-27042.stderr b/src/test/ui/issues/issue-27042.stderr index 4beb752854b9c..7678984a518ba 100644 --- a/src/test/ui/issues/issue-27042.stderr +++ b/src/test/ui/issues/issue-27042.stderr @@ -12,10 +12,13 @@ error[E0308]: mismatched types --> $DIR/issue-27042.rs:6:16 | LL | loop { break }; - | ^^^^^ expected (), found i32 + | ^^^^^ + | | + | expected i32, found () + | help: give it a value of the expected type: `break 42` | - = note: expected type `()` - found type `i32` + = note: expected type `i32` + found type `()` error[E0308]: mismatched types --> $DIR/issue-27042.rs:8:9 diff --git a/src/test/ui/issues/issue-32323.stderr b/src/test/ui/issues/issue-32323.stderr index 0339fdc55b9c8..6256dc0c55022 100644 --- a/src/test/ui/issues/issue-32323.stderr +++ b/src/test/ui/issues/issue-32323.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | pub fn f<'a, T: Tr<'a>>() -> >::Out {} | - ^^^^^^^^^^^^^^^^^^ expected associated type, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `>::Out` found type `()` diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 928d217441ef2..4457d71cbb4a7 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -5,6 +5,7 @@ fn main () { //~| ERROR mismatched types //~| ERROR invalid left-hand side expression //~| ERROR expected expression, found reserved identifier `_` + //~| ERROR expected expression, found reserved identifier `_` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR no method named `iter` found for type `()` in the current scope } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index e8386fd8de9e5..7f89caf92abe1 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -4,6 +4,12 @@ error: expected expression, found reserved identifier `_` LL | let sr: Vec<(u32, _, _) = vec![]; | ^ expected expression +error: expected expression, found reserved identifier `_` + --> $DIR/issue-34334.rs:2:26 + | +LL | let sr: Vec<(u32, _, _) = vec![]; + | ^ expected expression + error: expected one of `,` or `>`, found `=` --> $DIR/issue-34334.rs:2:29 | @@ -36,12 +42,12 @@ LL | let sr: Vec<(u32, _, _) = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^ left-hand of expression not valid error[E0599]: no method named `iter` found for type `()` in the current scope - --> $DIR/issue-34334.rs:8:36 + --> $DIR/issue-34334.rs:9:36 | LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); | ^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0070, E0308, E0423, E0599. For more information about an error, try `rustc --explain E0070`. diff --git a/src/test/ui/issues/issue-35241.stderr b/src/test/ui/issues/issue-35241.stderr index 8fda58abadb6e..586146cbaa4ee 100644 --- a/src/test/ui/issues/issue-35241.stderr +++ b/src/test/ui/issues/issue-35241.stderr @@ -1,11 +1,14 @@ error[E0308]: mismatched types --> $DIR/issue-35241.rs:3:20 | +LL | struct Foo(u32); + | ---------------- fn(u32) -> Foo {Foo} defined here +LL | LL | fn test() -> Foo { Foo } | --- ^^^ | | | | | expected struct `Foo`, found fn item - | | did you mean `Foo(/* fields */)`? + | | help: use parentheses to instantiate this tuple struct: `Foo(_)` | expected `Foo` because of return type | = note: expected type `Foo` diff --git a/src/test/ui/issues/issue-43162.stderr b/src/test/ui/issues/issue-43162.stderr index cd11959ede6cb..6d3e8b5ba2323 100644 --- a/src/test/ui/issues/issue-43162.stderr +++ b/src/test/ui/issues/issue-43162.stderr @@ -16,7 +16,7 @@ error[E0308]: mismatched types LL | fn foo() -> bool { | --- ^^^^ expected bool, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | LL | break true; | - help: consider removing this semicolon diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs new file mode 100644 index 0000000000000..b259e9e269d06 --- /dev/null +++ b/src/test/ui/issues/issue-43623.rs @@ -0,0 +1,19 @@ +pub trait Trait<'a> { + type Assoc; +} + +pub struct Type; + +impl<'a> Trait<'a> for Type { + type Assoc = (); +} + +pub fn break_me(f: F) +where T: for<'b> Trait<'b>, + F: for<'b> FnMut(>::Assoc) { + break_me::; + //~^ ERROR: type mismatch in function arguments + //~| ERROR: type mismatch resolving +} + +fn main() {} diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr new file mode 100644 index 0000000000000..b5674105f75d2 --- /dev/null +++ b/src/test/ui/issues/issue-43623.stderr @@ -0,0 +1,42 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/issue-43623.rs:14:5 + | +LL | break_me::; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected signature of `for<'b> fn(>::Assoc) -> _` + | found signature of `fn(_) -> _` + | +note: required by `break_me` + --> $DIR/issue-43623.rs:11:1 + | +LL | / pub fn break_me(f: F) +LL | | where T: for<'b> Trait<'b>, +LL | | F: for<'b> FnMut(>::Assoc) { +LL | | break_me::; +LL | | +LL | | +LL | | } + | |_^ + +error[E0271]: type mismatch resolving `for<'b> >::Assoc,)>>::Output == ()` + --> $DIR/issue-43623.rs:14:5 + | +LL | break_me::; + | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime + | +note: required by `break_me` + --> $DIR/issue-43623.rs:11:1 + | +LL | / pub fn break_me(f: F) +LL | | where T: for<'b> Trait<'b>, +LL | | F: for<'b> FnMut(>::Assoc) { +LL | | break_me::; +LL | | +LL | | +LL | | } + | |_^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-44023.stderr b/src/test/ui/issues/issue-44023.stderr index 153be363c1dea..258ffe558e9ba 100644 --- a/src/test/ui/issues/issue-44023.stderr +++ b/src/test/ui/issues/issue-44023.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn საჭმელად_გემრიელი_სადილი ( ) -> isize { | ------------------------ ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/issues/issue-44405.rs b/src/test/ui/issues/issue-44405.rs new file mode 100644 index 0000000000000..d404b9044dd6f --- /dev/null +++ b/src/test/ui/issues/issue-44405.rs @@ -0,0 +1,22 @@ +use std::ops::Index; + +struct Test; +struct Container(Test); + +impl Test { + fn test(&mut self) {} +} + +impl<'a> Index<&'a bool> for Container { + type Output = Test; + + fn index(&self, _index: &'a bool) -> &Test { + &self.0 + } +} + +fn main() { + let container = Container(Test); + let mut val = true; + container[&mut val].test(); //~ ERROR: cannot borrow data +} diff --git a/src/test/ui/issues/issue-44405.stderr b/src/test/ui/issues/issue-44405.stderr new file mode 100644 index 0000000000000..1fd69f6e77799 --- /dev/null +++ b/src/test/ui/issues/issue-44405.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow data in an index of `Container` as mutable + --> $DIR/issue-44405.rs:21:5 + | +LL | container[&mut val].test(); + | ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Container` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index 90b493e1634c4..ecf729e1032b1 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn foo(b: bool) -> Result { | --- ^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | Err("bar".to_string()); | - help: consider removing this semicolon | diff --git a/src/test/ui/liveness/liveness-forgot-ret.stderr b/src/test/ui/liveness/liveness-forgot-ret.stderr index a970b80fdbbd9..4baf351f7eb2d 100644 --- a/src/test/ui/liveness/liveness-forgot-ret.stderr +++ b/src/test/ui/liveness/liveness-forgot-ret.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } | - ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/liveness/liveness-missing-ret2.stderr b/src/test/ui/liveness/liveness-missing-ret2.stderr index ab7d411880bba..1f60560b45043 100644 --- a/src/test/ui/liveness/liveness-missing-ret2.stderr +++ b/src/test/ui/liveness/liveness-missing-ret2.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn f() -> isize { | - ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr index a5d9734c069ec..2497d93daa494 100644 --- a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr +++ b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -5,7 +5,7 @@ LL | macro_rules! test { () => { fn foo() -> i32 { 1; } } } | --- ^^^ - help: consider removing this semicolon | | | | | expected i32, found () - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression ... LL | test!(); | -------- in this macro invocation @@ -19,7 +19,7 @@ error[E0308]: mismatched types LL | fn no_return() -> i32 {} | --------- ^^^ expected i32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `i32` found type `()` @@ -30,7 +30,7 @@ error[E0308]: mismatched types LL | fn bar(x: u32) -> u32 { | --- ^^^ expected u32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression LL | x * 2; | - help: consider removing this semicolon | @@ -43,7 +43,7 @@ error[E0308]: mismatched types LL | fn baz(x: u64) -> u32 { | --- ^^^ expected u32, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `u32` found type `()` diff --git a/src/test/ui/loops/loop-break-value.stderr b/src/test/ui/loops/loop-break-value.stderr index 1e167905ec8d7..fef5b5873068f 100644 --- a/src/test/ui/loops/loop-break-value.stderr +++ b/src/test/ui/loops/loop-break-value.stderr @@ -90,10 +90,10 @@ error[E0308]: mismatched types --> $DIR/loop-break-value.rs:4:31 | LL | let val: ! = loop { break break; }; - | ^^^^^ expected (), found ! + | ^^^^^ expected !, found () | - = note: expected type `()` - found type `!` + = note: expected type `!` + found type `()` error[E0308]: mismatched types --> $DIR/loop-break-value.rs:11:19 @@ -153,10 +153,13 @@ error[E0308]: mismatched types --> $DIR/loop-break-value.rs:90:9 | LL | break; - | ^^^^^ expected (), found integer + | ^^^^^ + | | + | expected integer, found () + | help: give it a value of the expected type: `break value` | - = note: expected type `()` - found type `{integer}` + = note: expected type `{integer}` + found type `()` error: aborting due to 16 previous errors diff --git a/src/test/ui/loops/loop-labeled-break-value.stderr b/src/test/ui/loops/loop-labeled-break-value.stderr index ad7cb4b0c2e5f..8b9468cacc1f9 100644 --- a/src/test/ui/loops/loop-labeled-break-value.stderr +++ b/src/test/ui/loops/loop-labeled-break-value.stderr @@ -2,28 +2,37 @@ error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:3:29 | LL | let _: i32 = loop { break }; - | ^^^^^ expected (), found i32 + | ^^^^^ + | | + | expected i32, found () + | help: give it a value of the expected type: `break 42` | - = note: expected type `()` - found type `i32` + = note: expected type `i32` + found type `()` error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:6:37 | LL | let _: i32 = 'inner: loop { break 'inner }; - | ^^^^^^^^^^^^ expected (), found i32 + | ^^^^^^^^^^^^ + | | + | expected i32, found () + | help: give it a value of the expected type: `break 'inner 42` | - = note: expected type `()` - found type `i32` + = note: expected type `i32` + found type `()` error[E0308]: mismatched types --> $DIR/loop-labeled-break-value.rs:9:45 | LL | let _: i32 = 'inner2: loop { loop { break 'inner2 } }; - | ^^^^^^^^^^^^^ expected (), found i32 + | ^^^^^^^^^^^^^ + | | + | expected i32, found () + | help: give it a value of the expected type: `break 'inner2 42` | - = note: expected type `()` - found type `i32` + = note: expected type `i32` + found type `()` error: aborting due to 3 previous errors diff --git a/src/test/ui/loops/loop-properly-diverging-2.stderr b/src/test/ui/loops/loop-properly-diverging-2.stderr index 6293fdb058a0f..3758bbf9f6f31 100644 --- a/src/test/ui/loops/loop-properly-diverging-2.stderr +++ b/src/test/ui/loops/loop-properly-diverging-2.stderr @@ -2,10 +2,13 @@ error[E0308]: mismatched types --> $DIR/loop-properly-diverging-2.rs:2:23 | LL | let x: i32 = loop { break }; - | ^^^^^ expected (), found i32 + | ^^^^^ + | | + | expected i32, found () + | help: give it a value of the expected type: `break 42` | - = note: expected type `()` - found type `i32` + = note: expected type `i32` + found type `()` error: aborting due to previous error diff --git a/src/test/ui/match/match-arm-resolving-to-never.rs b/src/test/ui/match/match-arm-resolving-to-never.rs new file mode 100644 index 0000000000000..8f54023305e83 --- /dev/null +++ b/src/test/ui/match/match-arm-resolving-to-never.rs @@ -0,0 +1,19 @@ +enum E { + A, + B, + C, + D, + E, + F, +} + +fn main() { + match E::F { + E::A => 1, + E::B => 2, + E::C => 3, + E::D => 4, + E::E => unimplemented!(""), + E::F => "", //~ ERROR match arms have incompatible types + }; +} diff --git a/src/test/ui/match/match-arm-resolving-to-never.stderr b/src/test/ui/match/match-arm-resolving-to-never.stderr new file mode 100644 index 0000000000000..24ce97f86e760 --- /dev/null +++ b/src/test/ui/match/match-arm-resolving-to-never.stderr @@ -0,0 +1,22 @@ +error[E0308]: match arms have incompatible types + --> $DIR/match-arm-resolving-to-never.rs:17:17 + | +LL | / match E::F { +LL | | E::A => 1, +LL | | E::B => 2, +LL | | E::C => 3, +LL | | E::D => 4, +LL | | E::E => unimplemented!(""), + | | ------------------ this and all prior arms are found to be of type `{integer}` +LL | | E::F => "", + | | ^^ expected integer, found reference +LL | | }; + | |_____- `match` arms have incompatible types + | + = note: expected type `{integer}` + found type `&'static str` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/missing/missing-return.stderr b/src/test/ui/missing/missing-return.stderr index 42466e2fc6574..3c8ecdcfbcbe4 100644 --- a/src/test/ui/missing/missing-return.stderr +++ b/src/test/ui/missing/missing-return.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn f() -> isize { } | - ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/parser/issue-62881.stderr b/src/test/ui/parser/issue-62881.stderr index 85c3575fd9288..3d58b6fba0baf 100644 --- a/src/test/ui/parser/issue-62881.stderr +++ b/src/test/ui/parser/issue-62881.stderr @@ -19,7 +19,7 @@ error[E0308]: mismatched types LL | fn f() -> isize { fn f() -> isize {} pub f< | - ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/parser/issue-62895.stderr b/src/test/ui/parser/issue-62895.stderr index 7def7b562ca59..39ce980964b77 100644 --- a/src/test/ui/parser/issue-62895.stderr +++ b/src/test/ui/parser/issue-62895.stderr @@ -38,7 +38,7 @@ error[E0308]: mismatched types LL | fn v() -> isize { | - ^^^^^ expected isize, found () | | - | this function's body doesn't return + | implicitly returns `()` as its body has no tail or `return` expression | = note: expected type `isize` found type `()` diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index a1a8714ab3f38..2538bbbf8067f 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -195,8 +195,14 @@ LL | let _: Z = m::n::Z::Unit {}; error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:27:20 | +LL | Fn(u8), + | ------ fn(u8) -> m::n::Z {m::n::Z::Fn} defined here +... LL | let _: Z = Z::Fn; - | ^^^^^ expected enum `m::n::Z`, found fn item + | ^^^^^ + | | + | expected enum `m::n::Z`, found fn item + | help: use parentheses to instantiate this tuple variant: `Z::Fn(_)` | = note: expected type `m::n::Z` found type `fn(u8) -> m::n::Z {m::n::Z::Fn}` @@ -219,8 +225,14 @@ LL | let _ = Z::Unit; error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:43:16 | +LL | Fn(u8), + | ------ fn(u8) -> m::E {m::E::Fn} defined here +... LL | let _: E = m::E::Fn; - | ^^^^^^^^ expected enum `m::E`, found fn item + | ^^^^^^^^ + | | + | expected enum `m::E`, found fn item + | help: use parentheses to instantiate this tuple variant: `m::E::Fn(_)` | = note: expected type `m::E` found type `fn(u8) -> m::E {m::E::Fn}` @@ -243,8 +255,14 @@ LL | let _: E = m::E::Unit; error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:51:16 | +LL | Fn(u8), + | ------ fn(u8) -> m::E {m::E::Fn} defined here +... LL | let _: E = E::Fn; - | ^^^^^ expected enum `m::E`, found fn item + | ^^^^^ + | | + | expected enum `m::E`, found fn item + | help: use parentheses to instantiate this tuple variant: `E::Fn(_)` | = note: expected type `m::E` found type `fn(u8) -> m::E {m::E::Fn}` diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index 123dd86b90549..b3b879ef9acbe 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -1,8 +1,14 @@ error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:16:17 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- fn() {>::bar::<'static, char>} defined here +... LL | let x: () = >::bar::<'static, char>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::bar::<'static, char>()` | = note: expected type `()` found type `fn() {>::bar::<'static, char>}` @@ -10,8 +16,14 @@ LL | let x: () = >::bar::<'static, char>; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:25:17 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- fn() {>::bar::<'static, char>} defined here +... LL | let x: () = >::bar::<'static, char>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::bar::<'static, char>()` | = note: expected type `()` found type `fn() {>::bar::<'static, char>}` @@ -19,8 +31,14 @@ LL | let x: () = >::bar::<'static, char>; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:33:17 | +LL | fn baz() {} + | -------- fn() {>::baz} defined here +... LL | let x: () = >::baz; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::baz()` | = note: expected type `()` found type `fn() {>::baz}` @@ -28,8 +46,14 @@ LL | let x: () = >::baz; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:41:17 | +LL | fn foo<'z>() where &'z (): Sized { + | -------------------------------- fn() {foo::<'static>} defined here +... LL | let x: () = foo::<'static>; - | ^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `foo::<'static>()` | = note: expected type `()` found type `fn() {foo::<'static>}` diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index 9167346282bab..363018db232d8 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -1,8 +1,14 @@ error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:16:17 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- fn() {>::bar::} defined here +... LL | let x: () = >::bar::<'static, char>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::bar::<'static, char>()` | = note: expected type `()` found type `fn() {>::bar::}` @@ -10,8 +16,14 @@ LL | let x: () = >::bar::<'static, char>; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:25:17 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- fn() {>::bar::} defined here +... LL | let x: () = >::bar::<'static, char>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::bar::<'static, char>()` | = note: expected type `()` found type `fn() {>::bar::}` @@ -19,8 +31,14 @@ LL | let x: () = >::bar::<'static, char>; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:33:17 | +LL | fn baz() {} + | -------- fn() {>::baz} defined here +... LL | let x: () = >::baz; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `>::baz()` | = note: expected type `()` found type `fn() {>::baz}` @@ -28,8 +46,14 @@ LL | let x: () = >::baz; error[E0308]: mismatched types --> $DIR/substs-ppaux.rs:41:17 | +LL | fn foo<'z>() where &'z (): Sized { + | -------------------------------- fn() {foo::} defined here +... LL | let x: () = foo::<'static>; - | ^^^^^^^^^^^^^^ expected (), found fn item + | ^^^^^^^^^^^^^^ + | | + | expected (), found fn item + | help: use parentheses to call this function: `foo::<'static>()` | = note: expected type `()` found type `fn() {foo::}` diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs new file mode 100644 index 0000000000000..a8ea3faefe876 --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.rs @@ -0,0 +1,19 @@ +fn foo(a: usize, b: usize) -> usize { a } + +struct S(usize, usize); + +trait T { + fn baz(x: usize, y: usize) -> usize { x } +} + +fn main() { + let _: usize = foo(_, _); + //~^ ERROR expected expression + //~| ERROR expected expression + let _: S = S(_, _); + //~^ ERROR expected expression + //~| ERROR expected expression + let _: usize = T::baz(_, _); + //~^ ERROR expected expression + //~| ERROR expected expression +} diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr new file mode 100644 index 0000000000000..a6d1c4b859f2f --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-with-underscore-args.stderr @@ -0,0 +1,38 @@ +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:24 + | +LL | let _: usize = foo(_, _); + | ^ expected expression + +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:10:27 + | +LL | let _: usize = foo(_, _); + | ^ expected expression + +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:18 + | +LL | let _: S = S(_, _); + | ^ expected expression + +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:13:21 + | +LL | let _: S = S(_, _); + | ^ expected expression + +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:27 + | +LL | let _: usize = T::baz(_, _); + | ^ expected expression + +error: expected expression, found reserved identifier `_` + --> $DIR/fn-or-tuple-struct-with-underscore-args.rs:16:30 + | +LL | let _: usize = T::baz(_, _); + | ^ expected expression + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs new file mode 100644 index 0000000000000..9b6b10748172b --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs @@ -0,0 +1,45 @@ +fn foo(a: usize, b: usize) -> usize { a } + +fn bar() -> usize { 42 } + +struct S(usize, usize); +enum E { + A(usize), + B { a: usize }, +} +struct V(); + +trait T { + fn baz(x: usize, y: usize) -> usize { x } + fn bat(x: usize) -> usize { 42 } + fn bax(x: usize) -> usize { 42 } + fn bach(x: usize) -> usize; + fn ban(&self) -> usize { 42 } + fn bal(&self) -> usize; +} + +struct X; + +impl T for X { + fn bach(x: usize) -> usize { 42 } + fn bal(&self) -> usize { 42 } +} + +fn main() { + let _: usize = foo; //~ ERROR mismatched types + let _: S = S; //~ ERROR mismatched types + let _: usize = bar; //~ ERROR mismatched types + let _: V = V; //~ ERROR mismatched types + let _: usize = T::baz; //~ ERROR mismatched types + let _: usize = T::bat; //~ ERROR mismatched types + let _: E = E::A; //~ ERROR mismatched types + let _: E = E::B; //~ ERROR expected value, found struct variant `E::B` + let _: usize = X::baz; //~ ERROR mismatched types + let _: usize = X::bat; //~ ERROR mismatched types + let _: usize = X::bax; //~ ERROR mismatched types + let _: usize = X::bach; //~ ERROR mismatched types + let _: usize = X::ban; //~ ERROR mismatched types + let _: usize = X::bal; //~ ERROR mismatched types + let _: usize = X.ban; //~ ERROR attempted to take value of method + let _: usize = X.bal; //~ ERROR attempted to take value of method +} diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr new file mode 100644 index 0000000000000..0686b56f97ded --- /dev/null +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -0,0 +1,220 @@ +error[E0423]: expected value, found struct variant `E::B` + --> $DIR/fn-or-tuple-struct-without-args.rs:36:16 + | +LL | let _: E = E::B; + | ^^^- + | | | + | | help: a tuple variant with a similar name exists: `A` + | did you mean `E::B { /* fields */ }`? + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:29:20 + | +LL | fn foo(a: usize, b: usize) -> usize { a } + | ----------------------------------- fn(usize, usize) -> usize {foo} defined here +... +LL | let _: usize = foo; + | ^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `foo(a, b)` + | + = note: expected type `usize` + found type `fn(usize, usize) -> usize {foo}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:30:16 + | +LL | struct S(usize, usize); + | ----------------------- fn(usize, usize) -> S {S} defined here +... +LL | let _: S = S; + | ^ + | | + | expected struct `S`, found fn item + | help: use parentheses to instantiate this tuple struct: `S(_, _)` + | + = note: expected type `S` + found type `fn(usize, usize) -> S {S}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:31:20 + | +LL | fn bar() -> usize { 42 } + | ----------------- fn() -> usize {bar} defined here +... +LL | let _: usize = bar; + | ^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `bar()` + | + = note: expected type `usize` + found type `fn() -> usize {bar}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:32:16 + | +LL | struct V(); + | ----------- fn() -> V {V} defined here +... +LL | let _: V = V; + | ^ + | | + | expected struct `V`, found fn item + | help: use parentheses to instantiate this tuple struct: `V()` + | + = note: expected type `V` + found type `fn() -> V {V}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:33:20 + | +LL | fn baz(x: usize, y: usize) -> usize { x } + | ----------------------------------- fn(usize, usize) -> usize {<_ as T>::baz} defined here +... +LL | let _: usize = T::baz; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `T::baz(x, y)` + | + = note: expected type `usize` + found type `fn(usize, usize) -> usize {<_ as T>::baz}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:34:20 + | +LL | fn bat(x: usize) -> usize { 42 } + | ------------------------- fn(usize) -> usize {<_ as T>::bat} defined here +... +LL | let _: usize = T::bat; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `T::bat(x)` + | + = note: expected type `usize` + found type `fn(usize) -> usize {<_ as T>::bat}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:35:16 + | +LL | A(usize), + | -------- fn(usize) -> E {E::A} defined here +... +LL | let _: E = E::A; + | ^^^^ + | | + | expected enum `E`, found fn item + | help: use parentheses to instantiate this tuple variant: `E::A(_)` + | + = note: expected type `E` + found type `fn(usize) -> E {E::A}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:37:20 + | +LL | fn baz(x: usize, y: usize) -> usize { x } + | ----------------------------------- fn(usize, usize) -> usize {::baz} defined here +... +LL | let _: usize = X::baz; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::baz(x, y)` + | + = note: expected type `usize` + found type `fn(usize, usize) -> usize {::baz}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:38:20 + | +LL | fn bat(x: usize) -> usize { 42 } + | ------------------------- fn(usize) -> usize {::bat} defined here +... +LL | let _: usize = X::bat; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::bat(x)` + | + = note: expected type `usize` + found type `fn(usize) -> usize {::bat}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:39:20 + | +LL | fn bax(x: usize) -> usize { 42 } + | ------------------------- fn(usize) -> usize {::bax} defined here +... +LL | let _: usize = X::bax; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::bax(x)` + | + = note: expected type `usize` + found type `fn(usize) -> usize {::bax}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:40:20 + | +LL | fn bach(x: usize) -> usize; + | --------------------------- fn(usize) -> usize {::bach} defined here +... +LL | let _: usize = X::bach; + | ^^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::bach(x)` + | + = note: expected type `usize` + found type `fn(usize) -> usize {::bach}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:41:20 + | +LL | fn ban(&self) -> usize { 42 } + | ---------------------- for<'r> fn(&'r X) -> usize {::ban} defined here +... +LL | let _: usize = X::ban; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::ban(_)` + | + = note: expected type `usize` + found type `for<'r> fn(&'r X) -> usize {::ban}` + +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:42:20 + | +LL | fn bal(&self) -> usize; + | ----------------------- for<'r> fn(&'r X) -> usize {::bal} defined here +... +LL | let _: usize = X::bal; + | ^^^^^^ + | | + | expected usize, found fn item + | help: use parentheses to call this function: `X::bal(_)` + | + = note: expected type `usize` + found type `for<'r> fn(&'r X) -> usize {::bal}` + +error[E0615]: attempted to take value of method `ban` on type `X` + --> $DIR/fn-or-tuple-struct-without-args.rs:43:22 + | +LL | let _: usize = X.ban; + | ^^^ help: use parentheses to call the method: `ban()` + +error[E0615]: attempted to take value of method `bal` on type `X` + --> $DIR/fn-or-tuple-struct-without-args.rs:44:22 + | +LL | let _: usize = X.bal; + | ^^^ help: use parentheses to call the method: `bal()` + +error: aborting due to 16 previous errors + +Some errors have detailed explanations: E0308, E0423, E0615. +For more information about an error, try `rustc --explain E0308`.