Minor cleanup of UX guidelines.
I think this fixes https://github.com/rust-lang/rust/issues/34808. It covers the [long error code explanations normalization] by linking to the RFC, and cleaning up the list where long diagnostics are defined. While the [error message overhaul] isn't covered directly, I'm not really sure that more than the [existing section] on the error/warning/help messages is warranted; the overhaul linked didn't really specify any new guidelines, primarily just changing the output format.
[Long error code explanations normalization]: https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md
[Error message overhaul]: https://github.com/rust-lang/rust/issues/33240
[existing section]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc-ux-guidelines.md#error-warning-help-note-messages
# Save tagged docker images we created and load them if they're available
# Travis saves caches whether the build failed or not, nuke rustsrc if
-# the failure was while updating it (as it may be in an bad state)
+# the failure was while updating it (as it may be in a bad state)
# https://github.com/travis-ci/travis-ci/issues/4472
before_cache:
- docker history -q rust-ci |
///
/// The length of `src` must be the same as `self`.
///
+ /// If `src` implements `Copy`, it can be more performant to use
+ /// [`copy_from_slice`].
+ ///
/// # Panics
///
/// This function will panic if the two slices have different lengths.
/// dst.clone_from_slice(&src);
/// assert!(dst == [1, 2, 3]);
/// ```
+ ///
+ /// [`copy_from_slice`]: #method.copy_from_slice
#[stable(feature = "clone_from_slice", since = "1.7.0")]
pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
core_slice::SliceExt::clone_from_slice(self, src)
///
/// The length of `src` must be the same as `self`.
///
+ /// If `src` does not implement `Copy`, use [`clone_from_slice`].
+ ///
/// # Panics
///
/// This function will panic if the two slices have different lengths.
/// dst.copy_from_slice(&src);
/// assert_eq!(src, dst);
/// ```
+ ///
+ /// [`clone_from_slice`]: #method.clone_from_slice
#[stable(feature = "copy_from_slice", since = "1.9.0")]
pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
core_slice::SliceExt::copy_from_slice(self, src)
#![allow(dead_code)]
#![cfg(windows)]
-use libc::{c_long, c_ulong, c_ulonglong, c_void};
+use libc::{c_long, c_ulong, c_void};
pub type DWORD = c_ulong;
pub type LONG = c_long;
-pub type ULONG_PTR = c_ulonglong;
+pub type ULONG_PTR = usize;
pub type LPVOID = *mut c_void;
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
///
/// The ordering of the cases is significant. They are sorted so that cmp::max
/// will keep the "more erroneous" of two values.
-#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
+#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
pub enum Representability {
Representable,
ContainsRecursive,
- SelfRecursive,
+ SelfRecursive(Vec<Span>),
}
impl<'tcx> ParameterEnvironment<'tcx> {
/// Check whether a type is representable. This means it cannot contain unboxed
/// structural recursion. This check is needed for structs and enums.
- pub fn is_representable(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span)
+ pub fn is_representable(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ sp: Span)
-> Representability {
// Iterate until something non-representable is found
- fn find_nonrepresentable<'a, 'tcx, It>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- sp: Span,
- seen: &mut Vec<Ty<'tcx>>,
- iter: It)
- -> Representability
- where It: Iterator<Item=Ty<'tcx>> {
- iter.fold(Representability::Representable,
- |r, ty| cmp::max(r, is_type_structurally_recursive(tcx, sp, seen, ty)))
+ fn fold_repr<It: Iterator<Item=Representability>>(iter: It) -> Representability {
+ iter.fold(Representability::Representable, |r1, r2| {
+ match (r1, r2) {
+ (Representability::SelfRecursive(v1),
+ Representability::SelfRecursive(v2)) => {
+ Representability::SelfRecursive(v1.iter().map(|s| *s).chain(v2).collect())
+ }
+ (r1, r2) => cmp::max(r1, r2)
+ }
+ })
}
fn are_inner_types_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span,
-> Representability {
match ty.sty {
TyTuple(ref ts, _) => {
- find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
+ // Find non representable
+ fold_repr(ts.iter().map(|ty| {
+ is_type_structurally_recursive(tcx, sp, seen, ty)
+ }))
}
// Fixed-length vectors.
// FIXME(#11924) Behavior undecided for zero-length vectors.
is_type_structurally_recursive(tcx, sp, seen, ty)
}
TyAdt(def, substs) => {
- find_nonrepresentable(tcx,
- sp,
- seen,
- def.all_fields().map(|f| f.ty(tcx, substs)))
+ // Find non representable fields with their spans
+ fold_repr(def.all_fields().map(|field| {
+ let ty = field.ty(tcx, substs);
+ let span = tcx.hir.span_if_local(field.did).unwrap_or(sp);
+ match is_type_structurally_recursive(tcx, span, seen, ty) {
+ Representability::SelfRecursive(_) => {
+ Representability::SelfRecursive(vec![span])
+ }
+ x => x,
+ }
+ }))
}
TyClosure(..) => {
// this check is run on type definitions, so we don't expect
sp: Span,
seen: &mut Vec<Ty<'tcx>>,
ty: Ty<'tcx>) -> Representability {
- debug!("is_type_structurally_recursive: {:?}", ty);
+ debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
match ty.sty {
TyAdt(def, _) => {
debug!("SelfRecursive: {:?} contains {:?}",
seen_type,
ty);
- return Representability::SelfRecursive;
+ return Representability::SelfRecursive(vec![sp]);
}
}
use std::os::windows::raw::HANDLE;
use std::path::Path;
use std::fs::{File, OpenOptions};
- use std::os::raw::{c_ulong, c_ulonglong, c_int};
+ use std::os::raw::{c_ulong, c_int};
type DWORD = c_ulong;
type BOOL = c_int;
- type ULONG_PTR = c_ulonglong;
+ type ULONG_PTR = usize;
type LPOVERLAPPED = *mut OVERLAPPED;
const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
line: &Line,
width_offset: usize,
code_offset: usize) -> Vec<(usize, Style)> {
- let source_string = file.get_line(line.line_index - 1)
- .unwrap_or("");
+ let source_string = match file.get_line(line.line_index - 1) {
+ Some(s) => s,
+ None => return Vec::new(),
+ };
let line_offset = buffer.num_lines();
// Print out the annotate source lines that correspond with the error
for annotated_file in annotated_files {
+ // we can't annotate anything if the source is unavailable.
+ if annotated_file.file.src.is_none() {
+ continue;
+ }
+
// print out the span location and spacer before we print the annotated source
// to do this, we need to know if this span will be primary
let is_primary = primary_lo.file.name == annotated_file.file.name;
// contain themselves. For case 2, there must be an inner type that will be
// caught by case 1.
match rty.is_representable(tcx, sp) {
- Representability::SelfRecursive => {
- tcx.recursive_type_with_infinite_size_error(item_def_id).emit();
+ Representability::SelfRecursive(spans) => {
+ let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
+ for span in spans {
+ err.span_label(span, &"recursive without indirection");
+ }
+ err.emit();
return false
}
Representability::Representable | Representability::ContainsRecursive => (),
/// A unit struct like `Markdown`, that renders only the first paragraph.
pub struct MarkdownSummaryLine<'a>(pub &'a str);
-/// Returns Some(code) if `s` is a line that should be stripped from
-/// documentation but used in example code. `code` is the portion of
-/// `s` that should be used in tests. (None for lines that should be
-/// left as-is.)
-fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
+/// Controls whether a line will be hidden or shown in HTML output.
+///
+/// All lines are used in documentation tests.
+enum Line<'a> {
+ Hidden(&'a str),
+ Shown(&'a str),
+}
+
+impl<'a> Line<'a> {
+ fn for_html(self) -> Option<&'a str> {
+ match self {
+ Line::Shown(l) => Some(l),
+ Line::Hidden(_) => None,
+ }
+ }
+
+ fn for_code(self) -> &'a str {
+ match self {
+ Line::Shown(l) |
+ Line::Hidden(l) => l,
+ }
+ }
+}
+
+// FIXME: There is a minor inconsistency here. For lines that start with ##, we
+// have no easy way of removing a potential single space after the hashes, which
+// is done in the single # case. This inconsistency seems okay, if non-ideal. In
+// order to fix it we'd have to iterate to find the first non-# character, and
+// then reallocate to remove it; which would make us return a String.
+fn map_line(s: &str) -> Line {
let trimmed = s.trim();
- if trimmed == "#" {
- Some("")
+ if trimmed.starts_with("##") {
+ Line::Shown(&trimmed[1..])
} else if trimmed.starts_with("# ") {
- Some(&trimmed[2..])
+ // # text
+ Line::Hidden(&trimmed[2..])
+ } else if trimmed == "#" {
+ // We cannot handle '#text' because it could be #[attr].
+ Line::Hidden("")
} else {
- None
+ Line::Shown(s)
}
}
_ => {}
}
}
- let lines = origtext.lines().filter(|l| {
- stripped_filtered_line(*l).is_none()
- });
+ let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<&str>>().join("\n");
PLAYGROUND.with(|play| {
// insert newline to clearly separate it from the
if url.is_empty() {
return None;
}
- let test = origtext.lines().map(|l| {
- stripped_filtered_line(l).unwrap_or(l)
- }).collect::<Vec<&str>>().join("\n");
+ let test = origtext.lines()
+ .map(|l| map_line(l).for_code())
+ .collect::<Vec<&str>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let test = test::maketest(&test, krate, false,
&Default::default());
}
};
- let lines = origtext.lines().filter(|l| {
- stripped_filtered_line(*l).is_none()
- });
+ let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
let text = lines.collect::<Vec<&str>>().join("\n");
if rendered { return }
PLAYGROUND.with(|play| {
if url.is_empty() {
return None;
}
- let test = origtext.lines().map(|l| {
- stripped_filtered_line(l).unwrap_or(l)
- }).collect::<Vec<&str>>().join("\n");
+ let test = origtext.lines()
+ .map(|l| map_line(l).for_code())
+ .collect::<Vec<&str>>().join("\n");
let krate = krate.as_ref().map(|s| &**s);
let test = test::maketest(&test, krate, false,
&Default::default());
let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
let tests = &mut *((*opaque).opaque as *mut ::test::Collector);
let text = str::from_utf8(text).unwrap();
- let lines = text.lines().map(|l| {
- stripped_filtered_line(l).unwrap_or(l)
- });
+ let lines = text.lines().map(|l| map_line(l).for_code());
let text = lines.collect::<Vec<&str>>().join("\n");
let filename = tests.get_filename();
}
}
let offset = offset.unwrap_or(0);
- let lines = test_s.lines().map(|l| {
- stripped_filtered_line(l).unwrap_or(l)
- });
+ let lines = test_s.lines().map(|l| map_line(l).for_code());
let text = lines.collect::<Vec<&str>>().join("\n");
nb_lines += doc[prev_offset..offset].lines().count();
let line = tests.get_line() + (nb_lines - 1);
#![cfg_attr(test, allow(dead_code))]
#![unstable(issue = "0", feature = "windows_c")]
-use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,};
-use os::raw::{c_char, c_ulonglong};
+use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char};
+#[cfg(target_arch = "x86_64")]
+use os::raw::c_ulonglong;
use libc::{wchar_t, size_t, c_void};
use ptr;
pub type WORD = u16;
pub type CHAR = c_char;
pub type HCRYPTPROV = LONG_PTR;
-pub type ULONG_PTR = c_ulonglong;
+pub type ULONG_PTR = usize;
pub type ULONG = c_ulong;
#[cfg(target_arch = "x86_64")]
pub type ULONGLONG = u64;
ExpansionConfig {
crate_name: crate_name,
features: None,
- recursion_limit: 64,
+ recursion_limit: 1024,
trace_mac: false,
should_test: false,
single_step: false,
let (span, e) = self.interpolated_or_expr_span(e)?;
let span_of_tilde = lo;
let mut err = self.diagnostic().struct_span_err(span_of_tilde,
- "`~` can not be used as an unary operator");
+ "`~` can not be used as a unary operator");
err.span_label(span_of_tilde, &"did you mean `!`?");
err.help("use `!` instead of `~` if you meant to perform bitwise negation");
err.emit();
# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2017-04-26
+2017-05-06
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-enum foo { foo_(bar) }
-enum bar { bar_none, bar_some(bar) }
-//~^ ERROR recursive type `bar` has infinite size
+enum Foo {
+ Foo_(Bar)
+}
+
+enum Bar {
+ //~^ ERROR recursive type `Bar` has infinite size
+ //~| NOTE recursive type has infinite size
+ BarNone,
+ BarSome(Bar) //~ NOTE recursive without indirection
+}
fn main() {
}
struct bar { x: bar }
//~^ ERROR E0072
//~| NOTE recursive type has infinite size
+//~| NOTE recursive without indirection
fn main() {
}
enum Expr { //~ ERROR E0072
//~| NOTE recursive type has infinite size
Plus(Expr, Expr),
+ //~^ NOTE recursive without indirection
+ //~| NOTE recursive without indirection
Literal(i64),
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-struct S { //~ ERROR E0072
- //~| NOTE recursive type has infinite size
+struct S {
+ //~^ ERROR E0072
+ //~| NOTE recursive type has infinite size
element: Option<S>
+ //~^ NOTE recursive without indirection
}
fn main() {
struct t1 { //~ ERROR E0072
//~| NOTE recursive type has infinite size
foo: isize,
- foolish: t1
+ foolish: t1 //~ NOTE recursive without indirection
}
fn main() { }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// @has issue_41783/struct.Foo.html
+// @!has - 'space'
+// @!has - 'comment'
+// @has - '# <span class="ident">single'
+// @has - '#<span class="attribute"># <span class="ident">double</span>'
+// @has - '#<span class="attribute">#<span class="attribute"># <span class="ident">triple</span>'
+
+/// ```no_run
+/// # # space
+/// # comment
+/// ## single
+/// ### double
+/// #### triple
+/// ```
+pub struct Foo;
-error: `~` can not be used as an unary operator
+error: `~` can not be used as a unary operator
--> $DIR/issue-41679.rs:12:13
|
12 | let x = ~1;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Tr {
+ // Note: The function needs to be declared over multiple lines to reproduce
+ // the crash. DO NOT reformat.
+ fn f()
+ where Self: Sized;
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue_41652_b.rs
+
+extern crate issue_41652_b;
+
+struct S;
+
+impl issue_41652_b::Tr for S {
+ fn f() {
+ 3.f()
+ //~^ ERROR no method named `f` found for type `{integer}` in the current scope
+ //~| NOTE found the following associated functions
+ //~| NOTE candidate #1 is defined in the trait `issue_41652_b::Tr`
+ }
+}
+
+fn main() {}
--- /dev/null
+error: no method named `f` found for type `{integer}` in the current scope
+ --> $DIR/issue_41652.rs:19:11
+ |
+19 | 3.f()
+ | ^
+ |
+ = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in the trait `issue_41652_b::Tr`
+ = help: to disambiguate the method call, write `issue_41652_b::Tr::f(3)` instead
+
+error: aborting due to previous error
+
|
11 | struct ListNode {
| ^^^^^^^^^^^^^^^ recursive type has infinite size
+12 | head: u8,
+13 | tail: Option<ListNode>,
+ | ---------------------- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
14 | | {
15 | | head: u8,
16 | | tail: Option<ListNode>,
+ | | ---------------------- recursive without indirection
17 | | }
| |_^ recursive type has infinite size
|
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+
+struct Foo<'a> {
+ bar: Bar<'a>,
+ b: Rc<Bar<'a>>,
+}
+
+struct Bar<'a> {
+ y: (Foo<'a>, Foo<'a>),
+ z: Option<Bar<'a>>,
+ a: &'a Foo<'a>,
+ c: &'a [Bar<'a>],
+ d: [Bar<'a>; 1],
+ e: Foo<'a>,
+ x: Bar<'a>,
+}
+
+fn main() {}
--- /dev/null
+error[E0072]: recursive type `Foo` has infinite size
+ --> $DIR/recursive-type-field.rs:13:1
+ |
+13 | struct Foo<'a> {
+ | ^^^^^^^^^^^^^^ recursive type has infinite size
+14 | bar: Bar<'a>,
+ | ------------ recursive without indirection
+ |
+ = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
+
+error[E0072]: recursive type `Bar` has infinite size
+ --> $DIR/recursive-type-field.rs:18:1
+ |
+18 | struct Bar<'a> {
+ | ^^^^^^^^^^^^^^ recursive type has infinite size
+19 | y: (Foo<'a>, Foo<'a>),
+ | --------------------- recursive without indirection
+20 | z: Option<Bar<'a>>,
+ | ------------------ recursive without indirection
+...
+23 | d: [Bar<'a>; 1],
+ | --------------- recursive without indirection
+24 | e: Foo<'a>,
+ | ---------- recursive without indirection
+25 | x: Bar<'a>,
+ | ---------- recursive without indirection
+ |
+ = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
+
+error: aborting due to 2 previous errors
+