mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #140702 - GuillaumeGomez:rollup-rpyxs20, r=GuillaumeGomez
Rollup of 4 pull requests Successful merges: - #140135 (Unify sidebar buttons to use the same image) - #140632 (add a test for issue rust-lang/rust#81317) - #140658 (`deref_patterns`: let string and byte string literal patterns peel references and smart pointers before matching) - #140681 (Don't ignore compiler stderr in `lib-defaults.rs`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -177,16 +177,20 @@ enum PeelKind {
|
||||
/// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference
|
||||
/// any number of `&`/`&mut` references, plus a single smart pointer.
|
||||
ExplicitDerefPat,
|
||||
/// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer
|
||||
/// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt`
|
||||
/// field contains the ADT def that the pattern is a constructor for, if applicable, so that we
|
||||
/// don't peel it. See [`ResolvedPat`] for more information.
|
||||
Implicit { until_adt: Option<DefId> },
|
||||
/// Implicitly peel references, and if `deref_patterns` is enabled, smart pointer ADTs.
|
||||
Implicit {
|
||||
/// The ADT the pattern is a constructor for, if applicable, so that we don't peel it. See
|
||||
/// [`ResolvedPat`] for more information.
|
||||
until_adt: Option<DefId>,
|
||||
/// The number of references at the head of the pattern's type, so we can leave that many
|
||||
/// untouched. This is `1` for string literals, and `0` for most patterns.
|
||||
pat_ref_layers: usize,
|
||||
},
|
||||
}
|
||||
|
||||
impl AdjustMode {
|
||||
const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
|
||||
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } }
|
||||
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } }
|
||||
}
|
||||
const fn peel_all() -> AdjustMode {
|
||||
AdjustMode::peel_until_adt(None)
|
||||
@@ -488,9 +492,10 @@ fn check_pat_inner(
|
||||
match pat.kind {
|
||||
// Peel off a `&` or `&mut` from the scrutinee type. See the examples in
|
||||
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
|
||||
_ if let AdjustMode::Peel { .. } = adjust_mode
|
||||
_ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
|
||||
&& pat.default_binding_modes
|
||||
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() =>
|
||||
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
|
||||
&& self.should_peel_ref(peel_kind, expected) =>
|
||||
{
|
||||
debug!("inspecting {:?}", expected);
|
||||
|
||||
@@ -531,24 +536,9 @@ fn check_pat_inner(
|
||||
// If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
|
||||
// examples in `tests/ui/pattern/deref_patterns/`.
|
||||
_ if self.tcx.features().deref_patterns()
|
||||
&& let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode
|
||||
&& let AdjustMode::Peel { kind: peel_kind } = adjust_mode
|
||||
&& pat.default_binding_modes
|
||||
// For simplicity, only apply overloaded derefs if `expected` is a known ADT.
|
||||
// FIXME(deref_patterns): we'll get better diagnostics for users trying to
|
||||
// implicitly deref generics if we allow them here, but primitives, tuples, and
|
||||
// inference vars definitely should be stopped. Figure out what makes most sense.
|
||||
&& let ty::Adt(scrutinee_adt, _) = *expected.kind()
|
||||
// Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
|
||||
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
|
||||
&& until_adt != Some(scrutinee_adt.did())
|
||||
// At this point, the pattern isn't able to match `expected` without peeling. Check
|
||||
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
|
||||
// type error instead of a missing impl error if not. This only checks for `Deref`,
|
||||
// not `DerefPure`: we require that too, but we want a trait error if it's missing.
|
||||
&& let Some(deref_trait) = self.tcx.lang_items().deref_trait()
|
||||
&& self
|
||||
.type_implements_trait(deref_trait, [expected], self.param_env)
|
||||
.may_apply() =>
|
||||
&& self.should_peel_smart_pointer(peel_kind, expected) =>
|
||||
{
|
||||
debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
|
||||
// The scrutinee is a smart pointer; implicitly dereference it. This adds a
|
||||
@@ -680,21 +670,32 @@ fn calc_adjust_mode(
|
||||
|
||||
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
|
||||
// All other literals result in non-reference types.
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
|
||||
//
|
||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
|
||||
ty::Ref(..) => AdjustMode::Pass,
|
||||
_ => {
|
||||
// Path patterns have already been handled, and inline const blocks currently
|
||||
// aren't possible to write, so any handling for them would be untested.
|
||||
if cfg!(debug_assertions)
|
||||
&& self.tcx.features().deref_patterns()
|
||||
&& !matches!(lt.kind, PatExprKind::Lit { .. })
|
||||
{
|
||||
span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
|
||||
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}` unless
|
||||
// `deref_patterns` is enabled.
|
||||
PatKind::Expr(lt) => {
|
||||
// Path patterns have already been handled, and inline const blocks currently
|
||||
// aren't possible to write, so any handling for them would be untested.
|
||||
if cfg!(debug_assertions)
|
||||
&& self.tcx.features().deref_patterns()
|
||||
&& !matches!(lt.kind, PatExprKind::Lit { .. })
|
||||
{
|
||||
span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
|
||||
}
|
||||
// Call `resolve_vars_if_possible` here for inline const blocks.
|
||||
let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
|
||||
// If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`.
|
||||
if self.tcx.features().deref_patterns() {
|
||||
let mut peeled_ty = lit_ty;
|
||||
let mut pat_ref_layers = 0;
|
||||
while let ty::Ref(_, inner_ty, mutbl) = *peeled_ty.kind() {
|
||||
// We rely on references at the head of constants being immutable.
|
||||
debug_assert!(mutbl.is_not());
|
||||
pat_ref_layers += 1;
|
||||
peeled_ty = inner_ty;
|
||||
}
|
||||
AdjustMode::peel_all()
|
||||
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: None, pat_ref_layers } }
|
||||
} else {
|
||||
if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
|
||||
}
|
||||
},
|
||||
|
||||
@@ -720,6 +721,67 @@ fn calc_adjust_mode(
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming `expected` is a reference type, determine whether to peel it before matching.
|
||||
fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
|
||||
debug_assert!(expected.is_ref());
|
||||
let pat_ref_layers = match peel_kind {
|
||||
PeelKind::ExplicitDerefPat => 0,
|
||||
PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
|
||||
};
|
||||
|
||||
// Most patterns don't have reference types, so we'll want to peel all references from the
|
||||
// scrutinee before matching. To optimize for the common case, return early.
|
||||
if pat_ref_layers == 0 {
|
||||
return true;
|
||||
}
|
||||
debug_assert!(
|
||||
self.tcx.features().deref_patterns(),
|
||||
"Peeling for patterns with reference types is gated by `deref_patterns`."
|
||||
);
|
||||
|
||||
// If the pattern has as many or more layers of reference as the expected type, we can match
|
||||
// without peeling more, unless we find a smart pointer or `&mut` that we also need to peel.
|
||||
// We don't treat `&` and `&mut` as interchangeable, but by peeling `&mut`s before matching,
|
||||
// we can still, e.g., match on a `&mut str` with a string literal pattern. This is because
|
||||
// string literal patterns may be used where `str` is expected.
|
||||
let mut expected_ref_layers = 0;
|
||||
while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
|
||||
if mutbl.is_mut() {
|
||||
// Mutable references can't be in the final value of constants, thus they can't be
|
||||
// at the head of their types, thus we should always peel `&mut`.
|
||||
return true;
|
||||
}
|
||||
expected_ref_layers += 1;
|
||||
expected = inner_ty;
|
||||
}
|
||||
pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
|
||||
}
|
||||
|
||||
/// Determine whether `expected` is a smart pointer type that should be peeled before matching.
|
||||
fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
|
||||
// Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case.
|
||||
if let PeelKind::Implicit { until_adt, .. } = peel_kind
|
||||
// For simplicity, only apply overloaded derefs if `expected` is a known ADT.
|
||||
// FIXME(deref_patterns): we'll get better diagnostics for users trying to
|
||||
// implicitly deref generics if we allow them here, but primitives, tuples, and
|
||||
// inference vars definitely should be stopped. Figure out what makes most sense.
|
||||
&& let ty::Adt(scrutinee_adt, _) = *expected.kind()
|
||||
// Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
|
||||
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
|
||||
&& until_adt != Some(scrutinee_adt.did())
|
||||
// At this point, the pattern isn't able to match `expected` without peeling. Check
|
||||
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
|
||||
// type error instead of a missing impl error if not. This only checks for `Deref`,
|
||||
// not `DerefPure`: we require that too, but we want a trait error if it's missing.
|
||||
&& let Some(deref_trait) = self.tcx.lang_items().deref_trait()
|
||||
&& self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
|
||||
let ty = match <.kind {
|
||||
rustc_hir::PatExprKind::Lit { lit, negated } => {
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.20.3
|
||||
0.20.6
|
||||
@@ -65,15 +65,26 @@ let deref!(x) = Box::new(NoCopy) else { unreachable!() };
|
||||
drop::<NoCopy>(x);
|
||||
```
|
||||
|
||||
Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str`
|
||||
is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is
|
||||
expected. This lets them be used in `deref!(_)` patterns:
|
||||
Additionally, `deref_patterns` implements changes to string and byte string literal patterns,
|
||||
allowing then to be used in deref patterns:
|
||||
|
||||
```rust
|
||||
# #![feature(deref_patterns)]
|
||||
# #![allow(incomplete_features)]
|
||||
match ("test".to_string(), b"test".to_vec()) {
|
||||
(deref!("test"), deref!(b"test")) => {}
|
||||
match ("test".to_string(), Box::from("test"), b"test".to_vec()) {
|
||||
("test", "test", b"test") => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
// This works through multiple layers of reference and smart pointer:
|
||||
match (&Box::new(&"test".to_string()), &&&"test") {
|
||||
("test", "test") => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
// `deref!("...")` syntax may also be used:
|
||||
match "test".to_string() {
|
||||
deref!("test") => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
@@ -82,10 +93,16 @@ match *"test" {
|
||||
"test" => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
match *b"test" {
|
||||
b"test" => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
match *(b"test" as &[u8]) {
|
||||
b"test" => {}
|
||||
_ => panic!(),
|
||||
}
|
||||
```
|
||||
|
||||
Implicit deref pattern syntax is not yet supported for string or byte string literals.
|
||||
|
||||
[`box_patterns`]: ./box-patterns.md
|
||||
[`string_deref_patterns`]: ./string-deref-patterns.md
|
||||
[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors
|
||||
|
||||
@@ -55,6 +55,9 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
|
||||
--collapse-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
|
||||
enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
|
||||
d="M3,8l4,4l4,-4m-4,4M3,4l4,4l4,-4" stroke="black" stroke-width="2"/></svg>');
|
||||
--hamburger-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
|
||||
viewBox="0 0 22 22" fill="none" stroke="black">\
|
||||
<path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>');
|
||||
}
|
||||
|
||||
:root.sans-serif {
|
||||
@@ -2001,9 +2004,11 @@ a.tooltip:hover::after {
|
||||
display: flex;
|
||||
margin-right: 4px;
|
||||
position: fixed;
|
||||
left: 6px;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
}
|
||||
.hide-sidebar #sidebar-button {
|
||||
left: 6px;
|
||||
background-color: var(--main-background-color);
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -2019,6 +2024,8 @@ a.tooltip:hover::after {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
#settings-menu > a, #help-button > a, button#toggle-all-docs {
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--button-border-radius);
|
||||
color: var(--main-color);
|
||||
@@ -2031,14 +2038,15 @@ a.tooltip:hover::after {
|
||||
min-width: 0;
|
||||
}
|
||||
#sidebar-button > a {
|
||||
background-color: var(--button-background-color);
|
||||
border-color: var(--border-color);
|
||||
background-color: var(--sidebar-background-color);
|
||||
width: 33px;
|
||||
}
|
||||
#sidebar-button > a:hover, #sidebar-button > a:focus-visible {
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
|
||||
#settings-menu > a:hover, #settings-menu > a:focus-visible,
|
||||
#help-button > a:hover, #help-button > a:focus-visible,
|
||||
#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
|
||||
button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
|
||||
border-color: var(--settings-button-border-focus);
|
||||
text-decoration: none;
|
||||
@@ -2405,10 +2413,9 @@ However, it's not needed with smaller screen width because the doc/code block is
|
||||
use hamburger button */
|
||||
.src #sidebar-button > a::before, .sidebar-menu-toggle::before {
|
||||
/* hamburger button image */
|
||||
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
|
||||
viewBox="0 0 22 22" fill="none" stroke="black">\
|
||||
<path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>');
|
||||
content: var(--hamburger-image);
|
||||
opacity: 0.75;
|
||||
filter: var(--mobile-sidebar-menu-filter);
|
||||
}
|
||||
.sidebar-menu-toggle:hover::before,
|
||||
.sidebar-menu-toggle:active::before,
|
||||
@@ -2416,17 +2423,6 @@ However, it's not needed with smaller screen width because the doc/code block is
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* src sidebar button opens a folder view */
|
||||
.src #sidebar-button > a::before {
|
||||
/* folder image */
|
||||
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
|
||||
viewBox="0 0 22 22" fill="none" stroke="black">\
|
||||
<path d="M16,9v-4h-6v-1l-2,-2h-4l-2,2v16h13L21,9h-15L2,19" stroke-width="1.25"/>\
|
||||
<path d="M15,7h-11v3" stroke-width="0.75"/>\
|
||||
<path d="M3.75,10v1.25" stroke-width="0.375"/></svg>');
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
/* Media Queries */
|
||||
|
||||
/* Make sure all the buttons line wrap at the same time */
|
||||
@@ -2611,9 +2607,6 @@ in src-script.js and main.js
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
.sidebar-menu-toggle::before {
|
||||
filter: var(--mobile-sidebar-menu-filter);
|
||||
}
|
||||
.sidebar-menu-toggle:hover {
|
||||
background: var(--main-background-color);
|
||||
}
|
||||
@@ -2671,6 +2664,14 @@ in src-script.js and main.js
|
||||
margin: 0 0 -25px 0;
|
||||
padding: var(--nav-sub-mobile-padding);
|
||||
}
|
||||
|
||||
html:not(.src-sidebar-expanded) .src #sidebar-button > a {
|
||||
background-color: var(--main-background-color);
|
||||
}
|
||||
html:not(.src-sidebar-expanded) .src #sidebar-button > a:hover,
|
||||
html:not(.src-sidebar-expanded) .src #sidebar-button > a:focus-visible {
|
||||
background-color: var(--sidebar-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -199,6 +199,42 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3})
|
||||
drag-and-drop: ((205, 100), (108, 100))
|
||||
assert-position: (".sidebar-crate > h2 > a", {"x": -3})
|
||||
|
||||
// Check that the mobile sidebar and the source sidebar use the same icon.
|
||||
store-css: (".mobile-topbar .sidebar-menu-toggle::before", {"content": image_url})
|
||||
// Then we go to a source page.
|
||||
click: ".main-heading .src"
|
||||
assert-css: ("#sidebar-button a::before", {"content": |image_url|})
|
||||
// Check that hover events work as expected.
|
||||
store-css: ("#sidebar-button a", {"background-color": sidebar_background})
|
||||
move-cursor-to: "#sidebar-button a"
|
||||
store-css: ("#sidebar-button a:hover", {"background-color": sidebar_background_hover})
|
||||
assert: |sidebar_background| != |sidebar_background_hover|
|
||||
click: "#sidebar-button a"
|
||||
wait-for: "html.src-sidebar-expanded"
|
||||
assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|})
|
||||
move-cursor-to: "#settings-menu"
|
||||
assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|})
|
||||
// Closing sidebar.
|
||||
click: "#sidebar-button a"
|
||||
wait-for: "html:not(.src-sidebar-expanded)"
|
||||
// Now we check the same when the sidebar button is moved alongside the search.
|
||||
set-window-size: (500, 500)
|
||||
store-css: ("#sidebar-button a:hover", {"background-color": not_sidebar_background_hover})
|
||||
move-cursor-to: "#settings-menu"
|
||||
store-css: ("#sidebar-button a:not(:hover)", {"background-color": not_sidebar_background})
|
||||
// The sidebar background is supposed to be the same as the main background.
|
||||
assert-css: ("body", {"background-color": |not_sidebar_background|})
|
||||
assert: |not_sidebar_background| != |not_sidebar_background_hover| && |not_sidebar_background| != |sidebar_background|
|
||||
// The hover background is supposed to be the same as the sidebar background.
|
||||
assert: |not_sidebar_background_hover| == |sidebar_background|
|
||||
click: "#sidebar-button a"
|
||||
wait-for: "html.src-sidebar-expanded"
|
||||
// And now the background colors are supposed to be the same as the sidebar since the sidebar has
|
||||
// been open.
|
||||
assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|})
|
||||
move-cursor-to: "h2"
|
||||
assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|})
|
||||
|
||||
// Configuration option to show TOC in sidebar.
|
||||
set-local-storage: {"rustdoc-hide-toc": "true"}
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
//@ run-pass
|
||||
//@ dont-check-compiler-stderr (rust-lang/rust#54222)
|
||||
|
||||
//@ compile-flags: -lrust_test_helpers
|
||||
|
||||
#[link(name = "rust_test_helpers", kind = "static")]
|
||||
extern "C" {
|
||||
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
rust_dbg_extern_identity_u32(42);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//! By default, `-l NAME` without an explicit kind will default to dylib. However, if there's also
|
||||
//! an `#[link(name = NAME, kind = KIND)]` attribute with an explicit `KIND`, it should override the
|
||||
//! CLI flag. In particular, this should not result in any duplicate flag warnings from the linker.
|
||||
|
||||
//@ run-pass
|
||||
//@ compile-flags: -lrust_test_helpers
|
||||
|
||||
#[link(name = "rust_test_helpers", kind = "static")]
|
||||
extern "C" {
|
||||
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
rust_dbg_extern_identity_u32(42);
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,23 @@ fn main() {
|
||||
if let b"test" = *b"this array is too long" {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
// Test matching on `&mut T`: we peel the `&mut` before applying the usual special cases.
|
||||
// No special cases apply to `()`, so the "found" type is the type of the literal.
|
||||
if let b"test" = &mut () {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected `()`, found `&[u8; 4]`
|
||||
|
||||
// If the pointee is an array or slice, the usual special cases will apply to the "found" type:
|
||||
if let b"test" = &mut [] as &mut [i8] {}
|
||||
//~^ ERROR mismatched type
|
||||
//~| NOTE expected `[i8]`, found `[u8]`
|
||||
|
||||
if let b"test" = &mut [()] {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| NOTE expected `[(); 1]`, found `[u8; 4]`
|
||||
|
||||
if let b"test" = &mut *b"this array is too long" {}
|
||||
//~^ ERROR mismatched type
|
||||
//~| NOTE expected an array with a size of 22, found one with a size of 4
|
||||
}
|
||||
|
||||
@@ -47,6 +47,44 @@ LL | if let b"test" = *b"this array is too long" {}
|
||||
| |
|
||||
| expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:39:12
|
||||
|
|
||||
LL | if let b"test" = &mut () {}
|
||||
| ^^^^^^^ ------- this expression has type `&mut ()`
|
||||
| |
|
||||
| expected `()`, found `&[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:44:12
|
||||
|
|
||||
LL | if let b"test" = &mut [] as &mut [i8] {}
|
||||
| ^^^^^^^ -------------------- this expression has type `&mut [i8]`
|
||||
| |
|
||||
| expected `[i8]`, found `[u8]`
|
||||
|
|
||||
= note: expected slice `[i8]`
|
||||
found slice `[u8]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:48:12
|
||||
|
|
||||
LL | if let b"test" = &mut [()] {}
|
||||
| ^^^^^^^ --------- this expression has type `&mut [(); 1]`
|
||||
| |
|
||||
| expected `[(); 1]`, found `[u8; 4]`
|
||||
|
|
||||
= note: expected array `[(); 1]`
|
||||
found array `[u8; 4]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/byte-string-type-errors.rs:52:12
|
||||
|
|
||||
LL | if let b"test" = &mut *b"this array is too long" {}
|
||||
| ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]`
|
||||
| |
|
||||
| expected an array with a size of 22, found one with a size of 4
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//@ revisions: stable deref_patterns
|
||||
//@[deref_patterns] check-pass
|
||||
//! `deref_patterns` allows string and byte string literal patterns to implicitly peel references
|
||||
//! and smart pointers from the scrutinee before matching. Since strings and byte strings themselves
|
||||
//! have reference types, we need to make sure we don't peel too much. By leaving the type of the
|
||||
//! match scrutinee partially uninferred, these tests make sure we only peel as much as needed in
|
||||
//! order to match. In particular, when peeling isn't needed, the results should be the same was
|
||||
//! we'd get without `deref_patterns` enabled.
|
||||
|
||||
#![cfg_attr(deref_patterns, feature(deref_patterns))]
|
||||
#![cfg_attr(deref_patterns, expect(incomplete_features))]
|
||||
|
||||
fn uninferred<T>() -> T { unimplemented!() }
|
||||
|
||||
// Assert type equality without allowing coercions.
|
||||
trait Is<T> {}
|
||||
impl<T> Is<T> for T {}
|
||||
fn has_type<T>(_: impl Is<T>) {}
|
||||
|
||||
fn main() {
|
||||
// We don't need to peel anything to unify the type of `x` with `&str`, so `x: &str`.
|
||||
let x = uninferred();
|
||||
if let "..." = x {}
|
||||
has_type::<&str>(x);
|
||||
|
||||
// We don't need to peel anything to unify the type of `&x` with `&[u8; 3]`, so `x: [u8; 3]`.
|
||||
let x = uninferred();
|
||||
if let b"..." = &x {}
|
||||
has_type::<[u8; 3]>(x);
|
||||
|
||||
// Peeling a single `&` lets us unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`.
|
||||
let x = uninferred();
|
||||
if let b"..." = &&x {}
|
||||
//[stable]~^ ERROR: mismatched types
|
||||
has_type::<[u8; 3]>(x);
|
||||
|
||||
// We have to peel both the `&` and the box before unifying the type of `x` with `&str`.
|
||||
let x = uninferred();
|
||||
if let "..." = &Box::new(x) {}
|
||||
//[stable]~^ ERROR mismatched types
|
||||
has_type::<&str>(x);
|
||||
|
||||
// After peeling the box, we can unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`.
|
||||
let x = uninferred();
|
||||
if let b"..." = Box::new(&x) {}
|
||||
//[stable]~^ ERROR mismatched types
|
||||
has_type::<[u8; 3]>(x);
|
||||
|
||||
// `&` and `&mut` aren't interchangeable: `&mut`s need to be peeled before unifying, like boxes:
|
||||
let mut x = uninferred();
|
||||
if let "..." = &mut x {}
|
||||
//[stable]~^ ERROR mismatched types
|
||||
has_type::<&str>(x);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-pats-do-not-mislead-inference.rs:33:12
|
||||
|
|
||||
LL | if let b"..." = &&x {}
|
||||
| ^^^^^^ --- this expression has type `&&_`
|
||||
| |
|
||||
| expected `&&_`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&&_`
|
||||
found reference `&'static [u8; 3]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-pats-do-not-mislead-inference.rs:39:12
|
||||
|
|
||||
LL | if let "..." = &Box::new(x) {}
|
||||
| ^^^^^ ------------ this expression has type `&Box<_>`
|
||||
| |
|
||||
| expected `&Box<_>`, found `&str`
|
||||
|
|
||||
= note: expected reference `&Box<_>`
|
||||
found reference `&'static str`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | if let "..." = &*Box::new(x) {}
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-pats-do-not-mislead-inference.rs:45:12
|
||||
|
|
||||
LL | if let b"..." = Box::new(&x) {}
|
||||
| ^^^^^^ ------------ this expression has type `Box<&_>`
|
||||
| |
|
||||
| expected `Box<&_>`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected struct `Box<&_>`
|
||||
found reference `&'static [u8; 3]`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | if let b"..." = *Box::new(&x) {}
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/const-pats-do-not-mislead-inference.rs:51:12
|
||||
|
|
||||
LL | if let "..." = &mut x {}
|
||||
| ^^^^^ ------ this expression has type `&mut _`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static str`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
@@ -29,4 +29,30 @@ fn main() {
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// `deref_patterns` allows string and byte string patterns to implicitly peel references.
|
||||
match &"str" {
|
||||
"str" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
match &b"str" {
|
||||
b"str" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
match "str".to_owned() {
|
||||
"str" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// `deref_patterns` allows string and byte string patterns to match on mutable references.
|
||||
// See also `tests/ui/pattern/byte-string-mutability-mismatch.rs`.
|
||||
if let "str" = &mut *"str".to_string() {}
|
||||
//~^ ERROR mismatched types
|
||||
if let b"str" = &mut b"str".clone() {}
|
||||
//~^ ERROR mismatched types
|
||||
if let b"str" = &mut b"str".clone()[..] {}
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
@@ -47,7 +47,70 @@ LL | match *(b"test" as &[u8]) {
|
||||
LL | b"test" => {}
|
||||
| ^^^^^^^ expected `[u8]`, found `&[u8; 4]`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:35:9
|
||||
|
|
||||
LL | match &"str" {
|
||||
| ------ this expression has type `&&str`
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected `&&str`, found `&str`
|
||||
|
|
||||
= note: expected reference `&&_`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:40:9
|
||||
|
|
||||
LL | match &b"str" {
|
||||
| ------- this expression has type `&&[u8; 3]`
|
||||
LL | b"str" => {}
|
||||
| ^^^^^^ expected `&&[u8; 3]`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&&_`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:45:9
|
||||
|
|
||||
LL | match "str".to_owned() {
|
||||
| ---------------- this expression has type `String`
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected `String`, found `&str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:52:12
|
||||
|
|
||||
LL | if let "str" = &mut *"str".to_string() {}
|
||||
| ^^^^^ ----------------------- this expression has type `&mut str`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:54:12
|
||||
|
|
||||
LL | if let b"str" = &mut b"str".clone() {}
|
||||
| ^^^^^^ ------------------- this expression has type `&mut [u8; 3]`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/needs-gate.rs:56:12
|
||||
|
|
||||
LL | if let b"str" = &mut b"str".clone()[..] {}
|
||||
| ^^^^^^ ----------------------- this expression has type `&mut [u8]`
|
||||
| |
|
||||
| types differ in mutability
|
||||
|
|
||||
= note: expected mutable reference `&mut _`
|
||||
found reference `&'static _`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0658.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
||||
@@ -14,10 +14,26 @@ fn main() {
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test string literals in explicit `deref!(_)` patterns.
|
||||
// Test matching on `&mut str`.
|
||||
let test_actual = match &mut *test_in.to_string() {
|
||||
"zero" => 0,
|
||||
"one" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test string literals in deref patterns.
|
||||
let test_actual = match test_in.to_string() {
|
||||
deref!("zero") => 0,
|
||||
deref!("one") => 1,
|
||||
"one" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test peeling references in addition to smart pointers.
|
||||
let test_actual = match &test_in.to_string() {
|
||||
deref!("zero") => 0,
|
||||
"one" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
@@ -47,18 +63,34 @@ fn main() {
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as arrays in explicit `deref!(_)` patterns.
|
||||
let test_actual = match Box::new(*test_in) {
|
||||
deref!(b"0") => 0,
|
||||
deref!(b"1") => 1,
|
||||
// Test matching on `&mut [u8; N]`.
|
||||
let test_actual = match &mut test_in.clone() {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as slices in explicit `deref!(_)` patterns.
|
||||
// Test matching on `&mut [u8]`.
|
||||
let test_actual = match &mut test_in.clone()[..] {
|
||||
b"0" => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as arrays in deref patterns.
|
||||
let test_actual = match Box::new(*test_in) {
|
||||
deref!(b"0") => 0,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
// Test byte string literals used as slices in deref patterns.
|
||||
let test_actual = match test_in.to_vec() {
|
||||
deref!(b"0") => 0,
|
||||
deref!(b"1") => 1,
|
||||
b"1" => 1,
|
||||
_ => 2,
|
||||
};
|
||||
assert_eq!(test_actual, test_expect);
|
||||
|
||||
@@ -2,19 +2,6 @@
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
// FIXME(deref_patterns): fails to typecheck because string literal patterns don't peel
|
||||
// references from the scrutinee.
|
||||
match "foo".to_string() {
|
||||
"foo" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
match &"foo".to_string() {
|
||||
"foo" => {}
|
||||
//~^ ERROR: mismatched types
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Make sure we don't try implicitly dereferncing any ADT.
|
||||
match Some(0) {
|
||||
Ok(0) => {}
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/typeck_fail.rs:8:9
|
||||
|
|
||||
LL | match "foo".to_string() {
|
||||
| ----------------- this expression has type `String`
|
||||
LL | "foo" => {}
|
||||
| ^^^^^ expected `String`, found `&str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/typeck_fail.rs:13:9
|
||||
|
|
||||
LL | match &"foo".to_string() {
|
||||
| ------------------ this expression has type `&String`
|
||||
LL | "foo" => {}
|
||||
| ^^^^^ expected `&String`, found `&str`
|
||||
|
|
||||
= note: expected reference `&String`
|
||||
found reference `&'static str`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/typeck_fail.rs:20:9
|
||||
--> $DIR/typeck_fail.rs:7:9
|
||||
|
|
||||
LL | match Some(0) {
|
||||
| ------- this expression has type `Option<{integer}>`
|
||||
@@ -28,6 +9,6 @@ LL | Ok(0) => {}
|
||||
= note: expected enum `Option<{integer}>`
|
||||
found enum `Result<_, _>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Regression test for #81317: type can no longer be infered as of 1.49
|
||||
//
|
||||
// The problem is that the xor operator and the index.into() call
|
||||
// each have two candidate impls that could apply
|
||||
// { S as BitXor<S>, S as BitXor<&'a S> } for xor and
|
||||
// { T::I as Into<u64>, T::I as Into<S> } for index.into()
|
||||
// previously inference was able to infer that the only valid combination was
|
||||
// S as BitXor<S> and T::I as Into<S>
|
||||
//
|
||||
// after rust-lang/rust#73905 this is no longer infered
|
||||
//
|
||||
// the error message could be better e.g.
|
||||
// when iv is unused or has an an explicitly specified type S
|
||||
// there is currently the following help message
|
||||
//
|
||||
// error[E0284]: type annotations needed
|
||||
// --> src/main.rs:13:24
|
||||
// |
|
||||
// 44 | let iv = S ^ index.into();
|
||||
// | - ^^^^
|
||||
// | |
|
||||
// | type must be known at this point
|
||||
// |
|
||||
// = note: cannot satisfy `<S as BitXor<_>>::Output == _`
|
||||
// help: try using a fully qualified path to specify the expected types
|
||||
// |
|
||||
// 44 - let iv = S ^ index.into();
|
||||
// 44 + let iv = S ^ <<T as P>::I as Into<T>>::into(index);
|
||||
//
|
||||
// this is better as it's actually sufficent to fix the problem,
|
||||
// while just specifying the type of iv as currently suggested is insufficent
|
||||
//
|
||||
//@ check-fail
|
||||
|
||||
use std::ops::BitXor;
|
||||
|
||||
pub struct S;
|
||||
|
||||
pub trait P {
|
||||
type I: Into<u64> + Into<S>;
|
||||
}
|
||||
|
||||
pub fn decrypt_portion<T: P>(index: T::I) {
|
||||
let iv = S ^ index.into();
|
||||
//~^ ERROR type annotations needed
|
||||
&iv.to_bytes_be();
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn to_bytes_be(&self) -> &[u8] {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
impl BitXor for S {
|
||||
type Output = S;
|
||||
|
||||
fn bitxor(self, _rhs: Self) -> Self::Output {
|
||||
S
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BitXor<&'a S> for S {
|
||||
type Output = S;
|
||||
|
||||
fn bitxor(self, _rhs: &'a S) -> Self::Output {
|
||||
S
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,17 @@
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/regression-issue-81317.rs:44:9
|
||||
|
|
||||
LL | let iv = S ^ index.into();
|
||||
| ^^
|
||||
LL |
|
||||
LL | &iv.to_bytes_be();
|
||||
| -- type must be known at this point
|
||||
|
|
||||
help: consider giving `iv` an explicit type
|
||||
|
|
||||
LL | let iv: /* Type */ = S ^ index.into();
|
||||
| ++++++++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
Reference in New Issue
Block a user