Auto merge of #67356 - Centril:rollup-paaw3ju, r=Centril
Rollup of 8 pull requests Successful merges: - #67249 (Improve code generated for `starts_with(<literal char>)`) - #67308 (Delete flaky test net::tcp::tests::fast_rebind) - #67318 (Improve typeck & lowering docs for slice patterns) - #67322 (use Self alias in place of macros) - #67323 (make transparent enums more ordinary) - #67336 (Fix JS error when loading page with search) - #67344 (.gitignore: Don't ignore a file that exists in the repository) - #67349 (Minor: update Unsize docs for dyn syntax) Failed merges: r? @ghost
This commit is contained in:
commit
99b89533d4
13 changed files with 134 additions and 70 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -55,5 +55,6 @@ config.mk
|
|||
config.stamp
|
||||
Session.vim
|
||||
.cargo
|
||||
!/src/test/run-make/thumb-none-qemu/example/.cargo
|
||||
no_llvm_build
|
||||
# Before adding new lines, see the comment at the top.
|
||||
|
|
|
|||
|
|
@ -11,4 +11,5 @@ mod hash;
|
|||
mod iter;
|
||||
mod num;
|
||||
mod ops;
|
||||
mod pattern;
|
||||
mod slice;
|
||||
|
|
|
|||
43
src/libcore/benches/pattern.rs
Normal file
43
src/libcore/benches/pattern.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use test::black_box;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn starts_with_char(b: &mut Bencher) {
|
||||
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
black_box(text.starts_with('k'));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn starts_with_str(b: &mut Bencher) {
|
||||
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
black_box(text.starts_with("k"));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn ends_with_char(b: &mut Bencher) {
|
||||
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
black_box(text.ends_with('k'));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ends_with_str(b: &mut Bencher) {
|
||||
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
|
||||
b.iter(|| {
|
||||
for _ in 0..1024 {
|
||||
black_box(text.ends_with("k"));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ pub trait Sized {
|
|||
/// Types that can be "unsized" to a dynamically-sized type.
|
||||
///
|
||||
/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
|
||||
/// `Unsize<fmt::Debug>`.
|
||||
/// `Unsize<dyn fmt::Debug>`.
|
||||
///
|
||||
/// All implementations of `Unsize` are provided automatically by the compiler.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
|
|||
)]
|
||||
#[inline]
|
||||
pub const unsafe fn new_unchecked(n: $Int) -> Self {
|
||||
$Ty(n)
|
||||
Self(n)
|
||||
}
|
||||
|
||||
/// Creates a non-zero if the given value is not zero.
|
||||
|
|
@ -76,7 +76,7 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
|
|||
pub fn new(n: $Int) -> Option<Self> {
|
||||
if n != 0 {
|
||||
// SAFETY: we just checked that there's no `0`
|
||||
Some(unsafe { $Ty(n) })
|
||||
Some(unsafe { Self(n) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -445,21 +445,13 @@ impl<'a> Pattern<'a> for char {
|
|||
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
if let Some(ch) = haystack.chars().next() {
|
||||
self == ch
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>
|
||||
{
|
||||
if let Some(ch) = haystack.chars().next_back() {
|
||||
self == ch
|
||||
} else {
|
||||
false
|
||||
}
|
||||
self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -710,16 +702,13 @@ impl<'a, 'b> Pattern<'a> for &'b str {
|
|||
/// Checks whether the pattern matches at the front of the haystack
|
||||
#[inline]
|
||||
fn is_prefix_of(self, haystack: &'a str) -> bool {
|
||||
haystack.is_char_boundary(self.len()) &&
|
||||
self == &haystack[..self.len()]
|
||||
haystack.as_bytes().starts_with(self.as_bytes())
|
||||
}
|
||||
|
||||
/// Checks whether the pattern matches at the back of the haystack
|
||||
#[inline]
|
||||
fn is_suffix_of(self, haystack: &'a str) -> bool {
|
||||
self.len() <= haystack.len() &&
|
||||
haystack.is_char_boundary(haystack.len() - self.len()) &&
|
||||
self == &haystack[haystack.len() - self.len()..]
|
||||
haystack.as_bytes().ends_with(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,7 @@ let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
|
|||
#[$stable]
|
||||
#[cfg_attr(not(bootstrap), $const_stable)]
|
||||
pub const fn new(v: $int_type) -> Self {
|
||||
$atomic_type {v: UnsafeCell::new(v)}
|
||||
Self {v: UnsafeCell::new(v)}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2852,19 +2852,23 @@ impl<'a> LoweringContext<'a> {
|
|||
let mut rest = None;
|
||||
|
||||
let mut iter = pats.iter().enumerate();
|
||||
while let Some((idx, pat)) = iter.next() {
|
||||
// Interpret the first `..` pattern as a subtuple pattern.
|
||||
for (idx, pat) in iter.by_ref() {
|
||||
// Interpret the first `..` pattern as a sub-tuple pattern.
|
||||
// Note that unlike for slice patterns,
|
||||
// where `xs @ ..` is a legal sub-slice pattern,
|
||||
// it is not a legal sub-tuple pattern.
|
||||
if pat.is_rest() {
|
||||
rest = Some((idx, pat.span));
|
||||
break;
|
||||
}
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
// It was not a sub-tuple pattern so lower it normally.
|
||||
elems.push(self.lower_pat(pat));
|
||||
}
|
||||
|
||||
while let Some((_, pat)) = iter.next() {
|
||||
// There was a previous subtuple pattern; make sure we don't allow more.
|
||||
for (_, pat) in iter {
|
||||
// There was a previous sub-tuple pattern; make sure we don't allow more...
|
||||
if pat.is_rest() {
|
||||
// ...but there was one again, so error.
|
||||
self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
|
||||
} else {
|
||||
elems.push(self.lower_pat(pat));
|
||||
|
|
@ -2874,6 +2878,12 @@ impl<'a> LoweringContext<'a> {
|
|||
(elems.into(), rest.map(|(ddpos, _)| ddpos))
|
||||
}
|
||||
|
||||
/// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
|
||||
/// `hir::PatKind::Slice(before, slice, after)`.
|
||||
///
|
||||
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
|
||||
/// this is interpreted as a sub-slice pattern semantically.
|
||||
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
|
||||
fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
|
||||
let mut before = Vec::new();
|
||||
let mut after = Vec::new();
|
||||
|
|
@ -2881,14 +2891,17 @@ impl<'a> LoweringContext<'a> {
|
|||
let mut prev_rest_span = None;
|
||||
|
||||
let mut iter = pats.iter();
|
||||
while let Some(pat) = iter.next() {
|
||||
// Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
|
||||
// Lower all the patterns until the first occurence of a sub-slice pattern.
|
||||
for pat in iter.by_ref() {
|
||||
match pat.kind {
|
||||
// Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
|
||||
PatKind::Rest => {
|
||||
prev_rest_span = Some(pat.span);
|
||||
slice = Some(self.pat_wild_with_node_id_of(pat));
|
||||
break;
|
||||
},
|
||||
// Found a sub-slice pattern `$binding_mode $ident @ ..`.
|
||||
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
|
||||
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
|
||||
prev_rest_span = Some(sub.span);
|
||||
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
|
||||
|
|
@ -2896,14 +2909,13 @@ impl<'a> LoweringContext<'a> {
|
|||
slice = Some(self.pat_with_node_id_of(pat, node));
|
||||
break;
|
||||
},
|
||||
_ => {}
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
_ => before.push(self.lower_pat(pat)),
|
||||
}
|
||||
|
||||
// It was not a subslice pattern so lower it normally.
|
||||
before.push(self.lower_pat(pat));
|
||||
}
|
||||
|
||||
while let Some(pat) = iter.next() {
|
||||
// Lower all the patterns after the first sub-slice pattern.
|
||||
for pat in iter {
|
||||
// There was a previous subslice pattern; make sure we don't allow more.
|
||||
let rest_span = match pat.kind {
|
||||
PatKind::Rest => Some(pat.span),
|
||||
|
|
@ -2915,8 +2927,10 @@ impl<'a> LoweringContext<'a> {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(rest_span) = rest_span {
|
||||
// We have e.g., `[a, .., b, ..]`. That's no good, error!
|
||||
self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
|
||||
} else {
|
||||
// Lower the pattern normally.
|
||||
after.push(self.lower_pat(pat));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1048,8 +1048,15 @@ pub enum PatKind {
|
|||
/// A range pattern (e.g., `1..=2` or `1..2`).
|
||||
Range(P<Expr>, P<Expr>, RangeEnd),
|
||||
|
||||
/// `[a, b, ..i, y, z]` is represented as:
|
||||
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`.
|
||||
/// A slice pattern, `[before_0, ..., before_n, (slice, after_0, ..., after_n)?]`.
|
||||
///
|
||||
/// Here, `slice` is lowered from the syntax `($binding_mode $ident @)? ..`.
|
||||
/// If `slice` exists, then `after` can be non-empty.
|
||||
///
|
||||
/// The representation for e.g., `[a, b, .., c, d]` is:
|
||||
/// ```
|
||||
/// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)])
|
||||
/// ```
|
||||
Slice(HirVec<P<Pat>>, Option<P<Pat>>, HirVec<P<Pat>>),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2330,7 +2330,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, d
|
|||
);
|
||||
let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
|
||||
err.span_label(sp, &msg);
|
||||
if let &[ref start @ .., ref end] = &variant_spans[..] {
|
||||
if let [start @ .., end] = &*variant_spans {
|
||||
for variant_span in start {
|
||||
err.span_label(*variant_span, "");
|
||||
}
|
||||
|
|
@ -2372,23 +2372,14 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
|
|||
}
|
||||
let sp = tcx.sess.source_map().def_span(sp);
|
||||
|
||||
if adt.is_enum() {
|
||||
if !tcx.features().transparent_enums {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::transparent_enums,
|
||||
sp,
|
||||
"transparent enums are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
if adt.variants.len() != 1 {
|
||||
bad_variant_count(tcx, adt, sp, def_id);
|
||||
if adt.variants.is_empty() {
|
||||
// Don't bother checking the fields. No variants (and thus no fields) exist.
|
||||
return;
|
||||
}
|
||||
}
|
||||
if adt.is_enum() && !tcx.features().transparent_enums {
|
||||
feature_err(
|
||||
&tcx.sess.parse_sess,
|
||||
sym::transparent_enums,
|
||||
sp,
|
||||
"transparent enums are unstable",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
if adt.is_union() && !tcx.features().transparent_unions {
|
||||
|
|
@ -2401,6 +2392,14 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
|
|||
.emit();
|
||||
}
|
||||
|
||||
if adt.variants.len() != 1 {
|
||||
bad_variant_count(tcx, adt, sp, def_id);
|
||||
if adt.variants.is_empty() {
|
||||
// Don't bother checking the fields. No variants (and thus no fields) exist.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// For each field, figure out if it's known to be a ZST and align(1)
|
||||
let field_infos = adt.all_fields().map(|field| {
|
||||
let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
|
||||
|
|
@ -5351,9 +5350,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
directly, not through a function pointer");
|
||||
}
|
||||
|
||||
// Resolves `typ` by a single level if `typ` is a type variable.
|
||||
// If no resolution is possible, then an error is reported.
|
||||
// Numeric inference variables may be left unresolved.
|
||||
/// Resolves `typ` by a single level if `typ` is a type variable.
|
||||
/// If no resolution is possible, then an error is reported.
|
||||
/// Numeric inference variables may be left unresolved.
|
||||
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let ty = self.resolve_vars_with_obligations(ty);
|
||||
if !ty.is_ty_var() {
|
||||
|
|
|
|||
|
|
@ -1154,6 +1154,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.mk_ref(region, mt)
|
||||
}
|
||||
|
||||
/// Type check a slice pattern.
|
||||
///
|
||||
/// Syntactically, these look like `[pat_0, ..., pat_n]`.
|
||||
/// Semantically, we are type checking a pattern with structure:
|
||||
/// ```
|
||||
/// [before_0, ..., before_n, (slice, after_0, ... after_n)?]
|
||||
/// ```
|
||||
/// The type of `slice`, if it is present, depends on the `expected` type.
|
||||
/// If `slice` is missing, then so is `after_i`.
|
||||
/// If `slice` is present, it can still represent 0 elements.
|
||||
fn check_pat_slice(
|
||||
&self,
|
||||
span: Span,
|
||||
|
|
@ -1167,27 +1177,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let tcx = self.tcx;
|
||||
let expected_ty = self.structurally_resolved_type(span, expected);
|
||||
let (inner_ty, slice_ty) = match expected_ty.kind {
|
||||
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
|
||||
ty::Array(inner_ty, size) => {
|
||||
let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) {
|
||||
// Now we know the length...
|
||||
let min_len = before.len() as u64 + after.len() as u64;
|
||||
if slice.is_none() {
|
||||
// ...and since there is no variable-length pattern,
|
||||
// we require an exact match between the number of elements
|
||||
// in the array pattern and as provided by the matched type.
|
||||
if min_len != size {
|
||||
self.error_scrutinee_inconsistent_length(span, min_len, size)
|
||||
}
|
||||
tcx.types.err
|
||||
} else if let Some(rest) = size.checked_sub(min_len) {
|
||||
// The variable-length pattern was there,
|
||||
// so it has an array type with the remaining elements left as its size...
|
||||
tcx.mk_array(inner_ty, rest)
|
||||
} else {
|
||||
// ...however, in this case, there were no remaining elements.
|
||||
// That is, the slice pattern requires more than the array type offers.
|
||||
self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size);
|
||||
tcx.types.err
|
||||
}
|
||||
} else {
|
||||
// No idea what the length is, which happens if we have e.g.,
|
||||
// `let [a, b] = arr` where `arr: [T; N]` where `const N: usize`.
|
||||
self.error_scrutinee_unfixed_length(span);
|
||||
tcx.types.err
|
||||
};
|
||||
(inner_ty, slice_ty)
|
||||
}
|
||||
ty::Slice(inner_ty) => (inner_ty, expected_ty),
|
||||
// The expected type must be an array or slice, but was neither, so error.
|
||||
_ => {
|
||||
if !expected_ty.references_error() {
|
||||
self.error_expected_array_or_slice(span, expected_ty);
|
||||
|
|
@ -1196,12 +1218,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// Type check all the patterns before `slice`.
|
||||
for elt in before {
|
||||
self.check_pat(&elt, inner_ty, def_bm, discrim_span);
|
||||
}
|
||||
// Type check the `slice`, if present, against its expected type.
|
||||
if let Some(slice) = slice {
|
||||
self.check_pat(&slice, slice_ty, def_bm, discrim_span);
|
||||
}
|
||||
// Type check the elements after `slice`, if present.
|
||||
for elt in after {
|
||||
self.check_pat(&elt, inner_ty, def_bm, discrim_span);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2683,7 +2683,7 @@ function getSearchElement() {
|
|||
insertAfter(popup, getSearchElement());
|
||||
}
|
||||
|
||||
onHashChange();
|
||||
onHashChange(null);
|
||||
window.onhashchange = onHashChange;
|
||||
|
||||
buildHelperPopup();
|
||||
|
|
|
|||
|
|
@ -1312,21 +1312,6 @@ mod tests {
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fast_rebind() {
|
||||
each_ip(&mut |addr| {
|
||||
let acceptor = t!(TcpListener::bind(&addr));
|
||||
|
||||
let _t = thread::spawn(move || {
|
||||
t!(TcpStream::connect(&addr));
|
||||
});
|
||||
|
||||
t!(acceptor.accept());
|
||||
drop(acceptor);
|
||||
t!(TcpListener::bind(&addr));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tcp_clone_smoke() {
|
||||
each_ip(&mut |addr| {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue