Auto merge of #97622 - JohnTitor:rollup-4qoxrjn, r=JohnTitor

Rollup of 9 pull requests

Successful merges:

 - #94647 (Expose `get_many_mut` and `get_many_unchecked_mut` to HashMap)
 - #97216 (Ensure we never consider the null pointer dereferencable)
 - #97399 (simplify code of finding arg index in `opt_const_param_of`)
 - #97470 (rustdoc: add more test coverage)
 - #97498 (Corrected EBNF grammar for from_str)
 - #97562 (Fix comment in `poly_project_and_unify_type`)
 - #97580 (Add regression test for #71546)
 - #97611 (Tweak insert docs)
 - #97616 (Remove an unnecessary `Option`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-06-01 14:44:20 +00:00
commit 8256e97231
15 changed files with 257 additions and 59 deletions

View File

@ -441,6 +441,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
msg, msg,
}) })
} }
// Ensure we never consider the null pointer dereferencable.
if M::PointerTag::OFFSET_IS_ADDR {
assert_ne!(ptr.addr(), Size::ZERO);
}
// Test align. Check this last; if both bounds and alignment are violated // Test align. Check this last; if both bounds and alignment are violated
// we want the error to be about the bounds. // we want the error to be about the bounds.
if let Some(align) = align { if let Some(align) = align {

View File

@ -126,9 +126,10 @@ impl<T: Eq + Hash> SsoHashSet<T> {
/// Adds a value to the set. /// Adds a value to the set.
/// ///
/// If the set did not have this value present, `true` is returned. /// Returns whether the value was newly inserted. That is:
/// ///
/// If the set did have this value present, `false` is returned. /// - If the set did not previously contain this value, `true` is returned.
/// - If the set already contained this value, `false` is returned.
#[inline] #[inline]
pub fn insert(&mut self, elem: T) -> bool { pub fn insert(&mut self, elem: T) -> bool {
self.map.insert(elem, ()).is_none() self.map.insert(elem, ()).is_none()

View File

@ -145,15 +145,28 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
} }
} }
/// Takes the place of a /// States returned from `poly_project_and_unify_type`. Takes the place
/// of the old return type, which was:
/// ```ignore (not-rust)
/// Result< /// Result<
/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, /// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
/// MismatchedProjectionTypes<'tcx>, /// MismatchedProjectionTypes<'tcx>,
/// > /// >
/// ```
pub(super) enum ProjectAndUnifyResult<'tcx> { pub(super) enum ProjectAndUnifyResult<'tcx> {
/// The projection bound holds subject to the given obligations. If the
/// projection cannot be normalized because the required trait bound does
/// not hold, this is returned, with `obligations` being a predicate that
/// cannot be proven.
Holds(Vec<PredicateObligation<'tcx>>), Holds(Vec<PredicateObligation<'tcx>>),
/// The projection cannot be normalized due to ambiguity. Resolving some
/// inference variables in the projection may fix this.
FailedNormalization, FailedNormalization,
/// The project cannot be normalized because `poly_project_and_unify_type`
/// is called recursively while normalizing the same projection.
Recursive, Recursive,
// the projection can be normalized, but is not equal to the expected type.
// Returns the type error that arose from the mismatch.
MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
} }
@ -163,19 +176,6 @@ pub(super) enum ProjectAndUnifyResult<'tcx> {
/// ``` /// ```
/// If successful, this may result in additional obligations. Also returns /// If successful, this may result in additional obligations. Also returns
/// the projection cache key used to track these additional obligations. /// the projection cache key used to track these additional obligations.
///
/// ## Returns
///
/// - `Err(_)`: the projection can be normalized, but is not equal to the
/// expected type.
/// - `Ok(Err(InProgress))`: this is called recursively while normalizing
/// the same projection.
/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity
/// (resolving some inference variables in the projection may fix this).
/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to
/// the given obligations. If the projection cannot be normalized because
/// the required trait bound doesn't hold this returned with `obligations`
/// being a predicate that cannot be proven.
#[instrument(level = "debug", skip(selcx))] #[instrument(level = "debug", skip(selcx))]
pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>, selcx: &mut SelectionContext<'cx, 'tcx>,

View File

@ -81,10 +81,17 @@ pub fn trait_obligations<'a, 'tcx>(
body_id: hir::HirId, body_id: hir::HirId,
trait_ref: &ty::TraitRef<'tcx>, trait_ref: &ty::TraitRef<'tcx>,
span: Span, span: Span,
item: Option<&'tcx hir::Item<'tcx>>, item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> { ) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = let mut wf = WfPredicates {
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item }; infcx,
param_env,
body_id,
span,
out: vec![],
recursion_depth: 0,
item: Some(item),
};
wf.compute_trait_ref(trait_ref, Elaborate::All); wf.compute_trait_ref(trait_ref, Elaborate::All);
debug!(obligations = ?wf.out); debug!(obligations = ?wf.out);
wf.normalize() wf.normalize()

View File

@ -1228,7 +1228,7 @@ fn check_impl<'tcx>(
fcx.body_id, fcx.body_id,
&trait_ref, &trait_ref,
ast_trait_ref.path.span, ast_trait_ref.path.span,
Some(item), item,
); );
debug!(?obligations); debug!(?obligations);
for obligation in obligations { for obligation in obligations {

View File

@ -161,38 +161,23 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// We've encountered an `AnonConst` in some path, so we need to // We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return // figure out which generic parameter it corresponds to and return
// the relevant type. // the relevant type.
let filtered = path.segments.iter().find_map(|seg| { let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
seg.args? let args = seg.args?;
.args args.args
.iter()
.filter(|arg| arg.is_ty_or_const())
.position(|arg| arg.id() == hir_id)
.map(|index| (index, seg)).or_else(|| args.bindings
.iter() .iter()
.filter(|arg| arg.is_ty_or_const()) .filter_map(TypeBinding::opt_const)
.position(|arg| arg.id() == hir_id) .position(|ct| ct.hir_id == hir_id)
.map(|index| (index, seg)) .map(|idx| (idx, seg)))
}); }) else {
tcx.sess.delay_span_bug(
// FIXME(associated_const_generics): can we blend this with iteration above? tcx.def_span(def_id),
let (arg_index, segment) = match filtered { "no arg matching AnonConst in path",
None => { );
let binding_filtered = path.segments.iter().find_map(|seg| { return None;
seg.args?
.bindings
.iter()
.filter_map(TypeBinding::opt_const)
.position(|ct| ct.hir_id == hir_id)
.map(|idx| (idx, seg))
});
match binding_filtered {
Some(inner) => inner,
None => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
"no arg matching AnonConst in path",
);
return None;
}
}
}
Some(inner) => inner,
}; };
// Try to use the segment resolution if it is valid, otherwise we // Try to use the segment resolution if it is valid, otherwise we

View File

@ -770,10 +770,14 @@ impl<T> BTreeSet<T> {
/// Adds a value to the set. /// Adds a value to the set.
/// ///
/// If the set did not have an equal element present, `true` is returned. /// Returns whether the value was newly inserted. That is:
/// ///
/// If the set did have an equal element present, `false` is returned, and /// - If the set did not previously contain an equal value, `true` is
/// the entry is not updated. See the [module-level documentation] for more. /// returned.
/// - If the set already contained an equal value, `false` is returned, and
/// the entry is not updated.
///
/// See the [module-level documentation] for more.
/// ///
/// [module-level documentation]: index.html#insert-and-complex-keys /// [module-level documentation]: index.html#insert-and-complex-keys
/// ///

View File

@ -126,7 +126,6 @@ macro_rules! from_str_float_impl {
/// ```txt /// ```txt
/// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
/// Number ::= ( Digit+ | /// Number ::= ( Digit+ |
/// '.' Digit* |
/// Digit+ '.' Digit* | /// Digit+ '.' Digit* |
/// Digit* '.' Digit+ ) Exp? /// Digit* '.' Digit+ ) Exp?
/// Exp ::= 'e' Sign? Digit+ /// Exp ::= 'e' Sign? Digit+

View File

@ -896,6 +896,119 @@ where
self.base.get_key_value(k) self.base.get_key_value(k)
} }
/// Attempts to get mutable references to `N` values in the map at once.
///
/// Returns an array of length `N` with the results of each query. For soundness, at most one
/// mutable reference will be returned to any value. `None` will be returned if any of the
/// keys are duplicates or missing.
///
/// # Examples
///
/// ```
/// #![feature(map_many_mut)]
/// use std::collections::HashMap;
///
/// let mut libraries = HashMap::new();
/// libraries.insert("Bodleian Library".to_string(), 1602);
/// libraries.insert("Athenæum".to_string(), 1807);
/// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
/// libraries.insert("Library of Congress".to_string(), 1800);
///
/// let got = libraries.get_many_mut([
/// "Athenæum",
/// "Library of Congress",
/// ]);
/// assert_eq!(
/// got,
/// Some([
/// &mut 1807,
/// &mut 1800,
/// ]),
/// );
///
/// // Missing keys result in None
/// let got = libraries.get_many_mut([
/// "Athenæum",
/// "New York Public Library",
/// ]);
/// assert_eq!(got, None);
///
/// // Duplicate keys result in None
/// let got = libraries.get_many_mut([
/// "Athenæum",
/// "Athenæum",
/// ]);
/// assert_eq!(got, None);
/// ```
#[inline]
#[unstable(feature = "map_many_mut", issue = "97601")]
pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.base.get_many_mut(ks)
}
/// Attempts to get mutable references to `N` values in the map at once, without validating that
/// the values are unique.
///
/// Returns an array of length `N` with the results of each query. `None` will be returned if
/// any of the keys are missing.
///
/// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
///
/// # Safety
///
/// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
/// references are not used.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// #![feature(map_many_mut)]
/// use std::collections::HashMap;
///
/// let mut libraries = HashMap::new();
/// libraries.insert("Bodleian Library".to_string(), 1602);
/// libraries.insert("Athenæum".to_string(), 1807);
/// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
/// libraries.insert("Library of Congress".to_string(), 1800);
///
/// let got = libraries.get_many_mut([
/// "Athenæum",
/// "Library of Congress",
/// ]);
/// assert_eq!(
/// got,
/// Some([
/// &mut 1807,
/// &mut 1800,
/// ]),
/// );
///
/// // Missing keys result in None
/// let got = libraries.get_many_mut([
/// "Athenæum",
/// "New York Public Library",
/// ]);
/// assert_eq!(got, None);
/// ```
#[inline]
#[unstable(feature = "map_many_mut", issue = "97601")]
pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
&mut self,
ks: [&Q; N],
) -> Option<[&'_ mut V; N]>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.base.get_many_unchecked_mut(ks)
}
/// Returns `true` if the map contains a value for the specified key. /// Returns `true` if the map contains a value for the specified key.
/// ///
/// The key may be any borrowed form of the map's key type, but /// The key may be any borrowed form of the map's key type, but

View File

@ -858,9 +858,10 @@ where
/// Adds a value to the set. /// Adds a value to the set.
/// ///
/// If the set did not have this value present, `true` is returned. /// Returns whether the value was newly inserted. That is:
/// ///
/// If the set did have this value present, `false` is returned. /// - If the set did not previously contain this value, `true` is returned.
/// - If the set already contained this value, `false` is returned.
/// ///
/// # Examples /// # Examples
/// ///

View File

@ -0,0 +1,18 @@
pub mod my_trait {
pub trait MyTrait {
fn my_fn(&self) -> Self;
}
}
pub mod prelude {
#[doc(inline)]
pub use crate::my_trait::MyTrait;
}
pub struct SomeStruct;
impl my_trait::MyTrait for SomeStruct {
fn my_fn(&self) -> SomeStruct {
SomeStruct
}
}

View File

@ -0,0 +1,25 @@
// aux-build:implementors_inline.rs
// build-aux-docs
// ignore-cross-compile
extern crate implementors_inline;
// @!has implementors/implementors_js/trait.MyTrait.js
// @has implementors/implementors_inline/my_trait/trait.MyTrait.js
// @!has implementors/implementors_inline/prelude/trait.MyTrait.js
// @has implementors_inline/my_trait/trait.MyTrait.html
// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js'
// @has implementors_js/trait.MyTrait.html
// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js'
/// When re-exporting this trait, the HTML will be inlined,
/// but, vitally, the JavaScript will be located only at the
/// one canonical path.
pub use implementors_inline::prelude::MyTrait;
pub struct OtherStruct;
impl MyTrait for OtherStruct {
fn my_fn(&self) -> OtherStruct {
OtherStruct
}
}

View File

@ -1,8 +1,10 @@
#![allow(rustdoc::broken_intra_doc_links)] #![forbid(rustdoc::broken_intra_doc_links)]
//! Email me at <hello@example.com>. //! Email me at <hello@example.com>.
//! Email me at <hello-world@example.com>. //! Email me at <hello-world@example.com>.
//! Email me at <hello@localhost> (this warns but will still become a link). //! Email me at <hello@localhost>.
//! Email me at <prim@i32>.
// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com' // @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com' // @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost' // @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32'

View File

@ -0,0 +1,19 @@
// Regression test for #71546.
// ignore-compare-mode-nll
// NLL stderr is different from the original one.
pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str>
where
V: 'static,
for<'a> &'a V: IntoIterator,
for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
{
let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
.into_iter()
.map(|elem| elem.to_string())
.collect::<String>();
Ok(csv_str)
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough
--> $DIR/issue-71546.rs:12:27
|
LL | let csv_str: String = value
| ___________________________^
LL | | .into_iter()
LL | | .map(|elem| elem.to_string())
| |_____________________________________^
|
= help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`...
= note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds...
note: ...that is required by this bound
--> $DIR/issue-71546.rs:10:55
|
LL | for<'a> <&'a V as IntoIterator>::Item: ToString + 'static,
| ^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0310`.