Auto merge of #107215 - Dylan-DPC:rollup-zqtiufk, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #104926 (Move relationships from FulfillmentContext to Inherited)
 - #106854 (Add `Arc::into_inner` for safely discarding `Arc`s without calling the destructor on the inner type.)
 - #107108 (Consider doc(alias) when providing typo suggestions)
 - #107186 (rustdoc: Use correct pseudo-element selector)
 - #107192 (Add myself to the mailmap)
 - #107195 (Fix typo in universal_regions.rs comment)
 - #107203 (Suggest remove deref for type mismatch)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-01-23 07:32:07 +00:00
commit 6b3cd03fdb
27 changed files with 465 additions and 136 deletions

View File

@ -325,6 +325,7 @@ Lennart Kudling <github@kudling.de>
Léo Lanteri Thauvin <leseulartichaut@gmail.com>
Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
Léo Testard <leo.testard@gmail.com>
León Orell Valerian Liehr <me@fmease.dev> <liehr.exchange@gmx.net>
Leonardo Yvens <leoyvens@gmail.com>
Liigo Zhuang <liigo@qq.com>
Lily Ballard <lily@ballards.net> <kevin@sb.org>

View File

@ -162,7 +162,7 @@ struct UniversalRegionIndices<'tcx> {
/// `ty::Region` to the internal `RegionVid` we are using. This is
/// used because trait matching and type-checking will feed us
/// region constraints that reference those regions and we need to
/// be able to map them our internal `RegionVid`. This is
/// be able to map them to our internal `RegionVid`. This is
/// basically equivalent to an `InternalSubsts`, except that it also
/// contains an entry for `ReStatic` -- it might be nice to just
/// use a substs, and then handle `ReStatic` another way.

View File

@ -1233,6 +1233,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg_sp = receiver.span;
}
}
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
&& let Some(1) = self.deref_steps(expected, checked_ty) {
// We have `*&T`, check if what was expected was `&T`.
// If so, we may want to suggest removing a `*`.
sugg_sp = sugg_sp.with_hi(inner.span.lo());
return Some((
sugg_sp,
"consider removing deref here".to_string(),
"".to_string(),
Applicability::MachineApplicable,
true,
false,
));
}
if let Ok(src) = sm.span_to_snippet(sugg_sp) {
let needs_parens = match expr.kind {
// parenthesize if needed (Issue #46756)

View File

@ -196,8 +196,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
) -> FxHashMap<Ty<'tcx>, Ty<'tcx>> {
debug!("calculate_diverging_fallback({:?})", unsolved_variables);
let relationships = self.fulfillment_cx.borrow_mut().relationships().clone();
// Construct a coercion graph where an edge `A -> B` indicates
// a type variable is that is coerced
let coercion_graph = self.create_coercion_graph();
@ -281,9 +279,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
roots_reachable_from_non_diverging,
);
debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations());
debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
debug!("relationships: {:#?}", relationships);
// For each diverging variable, figure out whether it can
// reach a member of N. If so, it falls back to `()`. Else
@ -297,16 +293,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
.depth_first_search(root_vid)
.any(|n| roots_reachable_from_non_diverging.visited(n));
let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
let mut found_infer_var_info = ty::InferVarInfo { self_in_trait: false, output: false };
for (vid, rel) in relationships.iter() {
if self.root_var(*vid) == root_vid {
relationship.self_in_trait |= rel.self_in_trait;
relationship.output |= rel.output;
for (vid, info) in self.inh.infer_var_info.borrow().iter() {
if self.infcx.root_var(*vid) == root_vid {
found_infer_var_info.self_in_trait |= info.self_in_trait;
found_infer_var_info.output |= info.output;
}
}
if relationship.self_in_trait && relationship.output {
if found_infer_var_info.self_in_trait && found_infer_var_info.output {
// This case falls back to () to ensure that the code pattern in
// tests/ui/never_type/fallback-closure-ret.rs continues to
// compile when never_type_fallback is enabled.

View File

@ -1,6 +1,6 @@
use super::callee::DeferredCallResolution;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
@ -10,7 +10,8 @@ use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
use rustc_span::{self, Span};
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _};
use std::cell::RefCell;
use std::ops::Deref;
@ -63,6 +64,8 @@ pub struct Inherited<'tcx> {
/// we record that type variable here. This is later used to inform
/// fallback. See the `fallback` module for details.
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
pub(super) infer_var_info: RefCell<FxHashMap<ty::TyVid, ty::InferVarInfo>>,
}
impl<'tcx> Deref for Inherited<'tcx> {
@ -128,6 +131,7 @@ impl<'tcx> Inherited<'tcx> {
deferred_generator_interiors: RefCell::new(Vec::new()),
diverging_type_vars: RefCell::new(Default::default()),
body_id,
infer_var_info: RefCell::new(Default::default()),
}
}
@ -136,6 +140,9 @@ impl<'tcx> Inherited<'tcx> {
if obligation.has_escaping_bound_vars() {
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
}
self.update_infer_var_info(&obligation);
self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation);
}
@ -152,4 +159,43 @@ impl<'tcx> Inherited<'tcx> {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}
pub fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
let infer_var_info = &mut self.infer_var_info.borrow_mut();
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
&& self.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
{
let new_self_ty = self.tcx.types.unit;
// Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = obligation.with(self.tcx,
obligation
.predicate
.kind()
.rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(self.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() {
infer_var_info.entry(ty).or_default().self_in_trait = true;
}
}
if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("infer_var_info: {:?}.output = true", vid);
infer_var_info.entry(vid).or_default().output = true;
}
}
}
}

View File

@ -76,7 +76,7 @@ pub struct NoMatchData<'tcx> {
pub unsatisfied_predicates:
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
pub out_of_scope_traits: Vec<DefId>,
pub lev_candidate: Option<ty::AssocItem>,
pub similar_candidate: Option<ty::AssocItem>,
pub mode: probe::Mode,
}

View File

@ -461,7 +461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
static_candidates: Vec::new(),
unsatisfied_predicates: Vec::new(),
out_of_scope_traits: Vec::new(),
lev_candidate: None,
similar_candidate: None,
mode,
}));
}
@ -1076,13 +1076,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if let Some((kind, def_id)) = private_candidate {
return Err(MethodError::PrivateMatch(kind, def_id, out_of_scope_traits));
}
let lev_candidate = self.probe_for_lev_candidate()?;
let similar_candidate = self.probe_for_similar_candidate()?;
Err(MethodError::NoMatch(NoMatchData {
static_candidates,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
similar_candidate,
mode: self.mode,
}))
}
@ -1787,7 +1787,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// Similarly to `probe_for_return_type`, this method attempts to find the best matching
/// candidate method where the method name may have been misspelled. Similarly to other
/// Levenshtein based suggestions, we provide at most one such suggestion.
fn probe_for_lev_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
fn probe_for_similar_candidate(&mut self) -> Result<Option<ty::AssocItem>, MethodError<'tcx>> {
debug!("probing for method names similar to {:?}", self.method_name);
let steps = self.steps.clone();
@ -1831,6 +1831,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
None,
)
}
.or_else(|| {
applicable_close_candidates
.iter()
.find(|cand| self.matches_by_doc_alias(cand.def_id))
.map(|cand| cand.name)
})
.unwrap();
Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
}
@ -1981,6 +1987,38 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
}
/// Determine if the associated item withe the given DefId matches
/// the desired name via a doc alias.
fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
let Some(name) = self.method_name else { return false; };
let Some(local_def_id) = def_id.as_local() else { return false; };
let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id);
let attrs = self.fcx.tcx.hir().attrs(hir_id);
for attr in attrs {
let sym::doc = attr.name_or_empty() else { continue; };
let Some(values) = attr.meta_item_list() else { continue; };
for v in values {
if v.name_or_empty() != sym::alias {
continue;
}
if let Some(nested) = v.meta_item_list() {
// #[doc(alias("foo", "bar"))]
for n in nested {
if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() {
return true;
}
}
} else if let Some(meta) = v.meta_item()
&& let Some(lit) = meta.name_value_literal()
&& name.as_str() == lit.symbol.as_str() {
// #[doc(alias = "foo")]
return true;
}
}
}
false
}
/// Finds the method with the appropriate name (or return type, as the case may be). If
/// `allow_similar_names` is set, find methods with close-matching names.
// The length of the returned iterator is nearly always 0 or 1 and this
@ -1996,6 +2034,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
if !self.is_relevant_kind_for_mode(x.kind) {
return false;
}
if self.matches_by_doc_alias(x.def_id) {
return true;
}
match lev_distance_with_substrings(name.as_str(), x.name.as_str(), max_dist)
{
Some(d) => d > 0,

View File

@ -262,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty_str = with_forced_trimmed_paths!(self.ty_to_string(rcvr_ty));
let is_method = mode == Mode::MethodCall;
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
let lev_candidate = no_match_data.lev_candidate;
let similar_candidate = no_match_data.similar_candidate;
let item_kind = if is_method {
"method"
} else if rcvr_ty.is_enum() {
@ -937,7 +937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
&& lev_candidate.is_none()
&& similar_candidate.is_none()
&& !custom_span_label
{
label_span_not_found(&mut err);
@ -1015,20 +1015,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if fallback_span {
err.span_label(span, msg);
}
} else if let Some(lev_candidate) = lev_candidate {
} else if let Some(similar_candidate) = similar_candidate {
// Don't emit a suggestion if we found an actual method
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty() {
let def_kind = lev_candidate.kind.as_def_kind();
let def_kind = similar_candidate.kind.as_def_kind();
// Methods are defined within the context of a struct and their first parameter is always self,
// which represents the instance of the struct the method is being called on
// Associated functions dont take self as a parameter and
// they are not methods because they dont have an instance of the struct to work with.
if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
if def_kind == DefKind::AssocFn && similar_candidate.fn_has_self_parameter {
err.span_suggestion(
span,
"there is a method with a similar name",
lev_candidate.name,
similar_candidate.name,
Applicability::MaybeIncorrect,
);
} else {
@ -1037,9 +1037,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&format!(
"there is {} {} with a similar name",
def_kind.article(),
def_kind.descr(lev_candidate.def_id),
def_kind.descr(similar_candidate.def_id),
),
lev_candidate.name,
similar_candidate.name,
Applicability::MaybeIncorrect,
);
}

View File

@ -1,6 +1,5 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty};
@ -42,8 +41,6 @@ pub trait TraitEngine<'tcx>: 'tcx {
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships>;
}
pub trait TraitEngineExt<'tcx> {

View File

@ -2619,7 +2619,7 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
}
#[derive(Debug, Default, Copy, Clone)]
pub struct FoundRelationships {
pub struct InferVarInfo {
/// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo`
/// obligation, where:
///

View File

@ -1,6 +1,5 @@
use std::mem;
use rustc_data_structures::fx::FxHashMap;
use rustc_infer::{
infer::InferCtxt,
traits::{
@ -8,7 +7,6 @@ use rustc_infer::{
SelectionError, TraitEngine,
},
};
use rustc_middle::ty;
use super::{search_graph, Certainty, EvalCtxt};
@ -102,8 +100,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.clone()
}
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
unimplemented!("Should be moved out of `TraitEngine`")
}
}

View File

@ -7,24 +7,18 @@ use crate::traits::{
ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
SelectionError, TraitEngine,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::ty::{self, TypeVisitable};
use rustc_data_structures::fx::FxIndexSet;
use rustc_middle::ty::TypeVisitable;
pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
usable_in_snapshot: bool,
}
impl FulfillmentContext<'_> {
pub(super) fn new() -> Self {
FulfillmentContext {
obligations: FxIndexSet::default(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
FulfillmentContext { obligations: FxIndexSet::default(), usable_in_snapshot: false }
}
pub(crate) fn new_in_snapshot() -> Self {
@ -43,8 +37,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
}
let obligation = infcx.resolve_vars_if_possible(obligation);
super::relationships::update(self, infcx, &obligation);
self.obligations.insert(obligation);
}
@ -154,8 +146,4 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.iter().cloned().collect()
}
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
}

View File

@ -1,5 +1,4 @@
use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@ -54,8 +53,6 @@ pub struct FulfillmentContext<'tcx> {
// fulfillment context.
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
// Is it OK to register obligations into this infcx inside
// an infcx snapshot?
//
@ -85,19 +82,11 @@ static_assert_size!(PendingPredicateObligation<'_>, 72);
impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
pub(super) fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: false,
}
FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: false }
}
pub(super) fn new_in_snapshot() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
relationships: FxHashMap::default(),
usable_in_snapshot: true,
}
FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: true }
}
/// Attempts to select obligations using `selcx`.
@ -139,8 +128,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
super::relationships::update(self, infcx, &obligation);
self.predicates
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
@ -164,10 +151,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}
fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
&mut self.relationships
}
}
struct FulfillProcessor<'a, 'tcx> {

View File

@ -14,7 +14,6 @@ mod object_safety;
pub mod outlives_bounds;
mod project;
pub mod query;
pub(crate) mod relationships;
mod select;
mod specialize;
mod structural_match;

View File

@ -1,48 +0,0 @@
use crate::infer::InferCtxt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::PredicateObligation;
use rustc_infer::traits::TraitEngine;
use rustc_middle::ty;
pub(crate) fn update<'tcx, T>(
engine: &mut T,
infcx: &InferCtxt<'tcx>,
obligation: &PredicateObligation<'tcx>,
) where
T: TraitEngine<'tcx>,
{
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t))
&& infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
{
let new_self_ty = infcx.tcx.types.unit;
// Then construct a new obligation with Self = () added
// to the ParamEnv, and see if it holds.
let o = obligation.with(infcx.tcx,
obligation
.predicate
.kind()
.rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::Clause::Trait(tpred.with_self_ty(infcx.tcx, new_self_ty)))
),
);
// Don't report overflow errors. Otherwise equivalent to may_hold.
if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() {
engine.relationships().entry(ty).or_default().self_in_trait = true;
}
}
if let ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}
}
}

View File

@ -654,6 +654,20 @@ impl<T> Arc<T> {
///
/// This will succeed even if there are outstanding weak references.
///
// FIXME: when `Arc::into_inner` is stabilized, add this paragraph:
/*
/// It is strongly recommended to use [`Arc::into_inner`] instead if you don't
/// want to keep the `Arc` in the [`Err`] case.
/// Immediately dropping the [`Err`] payload, like in the expression
/// `Arc::try_unwrap(this).ok()`, can still cause the strong count to
/// drop to zero and the inner value of the `Arc` to be dropped:
/// For instance if two threads execute this expression in parallel, then
/// there is a race condition. The threads could first both check whether they
/// have the last clone of their `Arc` via `Arc::try_unwrap`, and then
/// both drop their `Arc` in the call to [`ok`][`Result::ok`],
/// taking the strong count from two down to zero.
///
*/
/// # Examples
///
/// ```
@ -685,6 +699,137 @@ impl<T> Arc<T> {
Ok(elem)
}
}
/// Returns the inner value, if the `Arc` has exactly one strong reference.
///
/// Otherwise, [`None`] is returned and the `Arc` is dropped.
///
/// This will succeed even if there are outstanding weak references.
///
/// If `Arc::into_inner` is called on every clone of this `Arc`,
/// it is guaranteed that exactly one of the calls returns the inner value.
/// This means in particular that the inner value is not dropped.
///
/// The similar expression `Arc::try_unwrap(this).ok()` does not
/// offer such a guarantee. See the last example below.
//
// FIXME: when `Arc::into_inner` is stabilized, add this to end
// of the previous sentence:
/*
/// and the documentation of [`Arc::try_unwrap`].
*/
///
/// # Examples
///
/// Minimal example demonstrating the guarantee that `Arc::into_inner` gives.
/// ```
/// #![feature(arc_into_inner)]
///
/// use std::sync::Arc;
///
/// let x = Arc::new(3);
/// let y = Arc::clone(&x);
///
/// // Two threads calling `Arc::into_inner` on both clones of an `Arc`:
/// let x_thread = std::thread::spawn(|| Arc::into_inner(x));
/// let y_thread = std::thread::spawn(|| Arc::into_inner(y));
///
/// let x_inner_value = x_thread.join().unwrap();
/// let y_inner_value = y_thread.join().unwrap();
///
/// // One of the threads is guaranteed to receive the inner value:
/// assert!(matches!(
/// (x_inner_value, y_inner_value),
/// (None, Some(3)) | (Some(3), None)
/// ));
/// // The result could also be `(None, None)` if the threads called
/// // `Arc::try_unwrap(x).ok()` and `Arc::try_unwrap(y).ok()` instead.
/// ```
///
/// A more practical example demonstrating the need for `Arc::into_inner`:
/// ```
/// #![feature(arc_into_inner)]
///
/// use std::sync::Arc;
///
/// // Definition of a simple singly linked list using `Arc`:
/// #[derive(Clone)]
/// struct LinkedList<T>(Option<Arc<Node<T>>>);
/// struct Node<T>(T, Option<Arc<Node<T>>>);
///
/// // Dropping a long `LinkedList<T>` relying on the destructor of `Arc`
/// // can cause a stack overflow. To prevent this, we can provide a
/// // manual `Drop` implementation that does the destruction in a loop:
/// impl<T> Drop for LinkedList<T> {
/// fn drop(&mut self) {
/// let mut link = self.0.take();
/// while let Some(arc_node) = link.take() {
/// if let Some(Node(_value, next)) = Arc::into_inner(arc_node) {
/// link = next;
/// }
/// }
/// }
/// }
///
/// // Implementation of `new` and `push` omitted
/// impl<T> LinkedList<T> {
/// /* ... */
/// # fn new() -> Self {
/// # LinkedList(None)
/// # }
/// # fn push(&mut self, x: T) {
/// # self.0 = Some(Arc::new(Node(x, self.0.take())));
/// # }
/// }
///
/// // The following code could have still caused a stack overflow
/// // despite the manual `Drop` impl if that `Drop` impl had used
/// // `Arc::try_unwrap(arc).ok()` instead of `Arc::into_inner(arc)`.
///
/// // Create a long list and clone it
/// let mut x = LinkedList::new();
/// for i in 0..100000 {
/// x.push(i); // Adds i to the front of x
/// }
/// let y = x.clone();
///
/// // Drop the clones in parallel
/// let x_thread = std::thread::spawn(|| drop(x));
/// let y_thread = std::thread::spawn(|| drop(y));
/// x_thread.join().unwrap();
/// y_thread.join().unwrap();
/// ```
// FIXME: when `Arc::into_inner` is stabilized, adjust above documentation
// and the documentation of `Arc::try_unwrap` according to the `FIXME`s. Also
// open an issue on rust-lang/rust-clippy, asking for a lint against
// `Arc::try_unwrap(...).ok()`.
#[inline]
#[unstable(feature = "arc_into_inner", issue = "106894")]
pub fn into_inner(this: Self) -> Option<T> {
// Make sure that the ordinary `Drop` implementation isnt called as well
let mut this = mem::ManuallyDrop::new(this);
// Following the implementation of `drop` and `drop_slow`
if this.inner().strong.fetch_sub(1, Release) != 1 {
return None;
}
acquire!(this.inner().strong);
// SAFETY: This mirrors the line
//
// unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
//
// in `drop_slow`. Instead of dropping the value behind the pointer,
// it is read and eventually returned; `ptr::read` has the same
// safety conditions as `ptr::drop_in_place`.
let inner = unsafe { ptr::read(Self::get_mut_unchecked(&mut this)) };
drop(Weak { ptr: this.ptr });
Some(inner)
}
}
impl<T> Arc<[T]> {

View File

@ -101,6 +101,38 @@ fn try_unwrap() {
assert_eq!(Arc::try_unwrap(x), Ok(5));
}
#[test]
fn into_inner() {
for _ in 0..100
// ^ Increase chances of hitting potential race conditions
{
let x = Arc::new(3);
let y = Arc::clone(&x);
let r_thread = std::thread::spawn(|| Arc::into_inner(x));
let s_thread = std::thread::spawn(|| Arc::into_inner(y));
let r = r_thread.join().expect("r_thread panicked");
let s = s_thread.join().expect("s_thread panicked");
assert!(
matches!((r, s), (None, Some(3)) | (Some(3), None)),
"assertion failed: unexpected result `{:?}`\
\n expected `(None, Some(3))` or `(Some(3), None)`",
(r, s),
);
}
let x = Arc::new(3);
assert_eq!(Arc::into_inner(x), Some(3));
let x = Arc::new(4);
let y = Arc::clone(&x);
assert_eq!(Arc::into_inner(x), None);
assert_eq!(Arc::into_inner(y), Some(4));
let x = Arc::new(5);
let _w = Arc::downgrade(&x);
assert_eq!(Arc::into_inner(x), Some(5));
}
#[test]
fn into_from_raw() {
let x = Arc::new(Box::new("hello"));

View File

@ -1897,21 +1897,21 @@ in storage.js
right: 0.25em;
}
.scraped-example:not(.expanded) .code-wrapper:before,
.scraped-example:not(.expanded) .code-wrapper:after {
.scraped-example:not(.expanded) .code-wrapper::before,
.scraped-example:not(.expanded) .code-wrapper::after {
content: " ";
width: 100%;
height: 5px;
position: absolute;
z-index: 1;
}
.scraped-example:not(.expanded) .code-wrapper:before {
.scraped-example:not(.expanded) .code-wrapper::before {
top: 0;
background: linear-gradient(to bottom,
var(--scrape-example-code-wrapper-background-start),
var(--scrape-example-code-wrapper-background-end));
}
.scraped-example:not(.expanded) .code-wrapper:after {
.scraped-example:not(.expanded) .code-wrapper::after {
bottom: 0;
background: linear-gradient(to top,
var(--scrape-example-code-wrapper-background-start),

View File

@ -0,0 +1,20 @@
// run-rustfix
trait GatTrait {
type Gat<'a> where Self: 'a;
fn test(&self) -> Self::Gat<'_>;
}
trait SuperTrait<T>
where
Self: 'static,
for<'a> Self: GatTrait<Gat<'a> = &'a T>,
{
fn copy(&self) -> Self::Gat<'_> where T: Copy {
self.test()
//~^ mismatched types
}
}
fn main() {}

View File

@ -1,3 +1,5 @@
// run-rustfix
trait GatTrait {
type Gat<'a> where Self: 'a;

View File

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/issue-88360.rs:13:9
--> $DIR/issue-88360.rs:15:9
|
LL | trait SuperTrait<T>
| - this type parameter
@ -7,13 +7,15 @@ LL | trait SuperTrait<T>
LL | fn copy(&self) -> Self::Gat<'_> where T: Copy {
| ------------- expected `&T` because of return type
LL | *self.test()
| ^^^^^^^^^^^^
| |
| expected `&T`, found type parameter `T`
| help: consider borrowing here: `&*self.test()`
| ^^^^^^^^^^^^ expected `&T`, found type parameter `T`
|
= note: expected reference `&T`
found type parameter `T`
help: consider removing deref here
|
LL - *self.test()
LL + self.test()
|
error: aborting due to previous error

View File

@ -0,0 +1,11 @@
struct Foo;
impl Foo {
#[doc(alias = "quux")]
fn bar(&self) {}
}
fn main() {
Foo.quux();
//~^ ERROR no method named `quux` found for struct `Foo` in the current scope
}

View File

@ -0,0 +1,12 @@
error[E0599]: no method named `quux` found for struct `Foo` in the current scope
--> $DIR/method-not-found-but-doc-alias.rs:9:9
|
LL | struct Foo;
| ---------- method `quux` not found for this struct
...
LL | Foo.quux();
| ^^^^ help: there is a method with a similar name: `bar`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.

View File

@ -0,0 +1,28 @@
// run-rustfix
//issue #106496
struct S;
trait X {}
impl X for S {}
fn foo<T: X>(_: &T) {}
fn test_foo() {
let hello = &S;
foo(hello);
//~^ ERROR mismatched types
}
fn bar(_: &String) {}
fn test_bar() {
let v = String::from("hello");
let s = &v;
bar(s);
//~^ ERROR mismatched types
}
fn main() {
test_foo();
test_bar();
}

View File

@ -0,0 +1,28 @@
// run-rustfix
//issue #106496
struct S;
trait X {}
impl X for S {}
fn foo<T: X>(_: &T) {}
fn test_foo() {
let hello = &S;
foo(*hello);
//~^ ERROR mismatched types
}
fn bar(_: &String) {}
fn test_bar() {
let v = String::from("hello");
let s = &v;
bar(*s);
//~^ ERROR mismatched types
}
fn main() {
test_foo();
test_bar();
}

View File

@ -0,0 +1,43 @@
error[E0308]: mismatched types
--> $DIR/suggest-remove-deref.rs:13:9
|
LL | foo(*hello);
| --- ^^^^^^ expected reference, found struct `S`
| |
| arguments to this function are incorrect
|
= note: expected reference `&_`
found struct `S`
note: function defined here
--> $DIR/suggest-remove-deref.rs:10:4
|
LL | fn foo<T: X>(_: &T) {}
| ^^^ -----
help: consider removing deref here
|
LL - foo(*hello);
LL + foo(hello);
|
error[E0308]: mismatched types
--> $DIR/suggest-remove-deref.rs:21:9
|
LL | bar(*s);
| --- ^^ expected `&String`, found struct `String`
| |
| arguments to this function are incorrect
|
note: function defined here
--> $DIR/suggest-remove-deref.rs:17:4
|
LL | fn bar(_: &String) {}
| ^^^ ----------
help: consider removing deref here
|
LL - bar(*s);
LL + bar(s);
|
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,12 +1,5 @@
// compile-flags: -Ztrait-solver=next
// known-bug: unknown
// failure-status: 101
// dont-check-compiler-stderr
// This test will fail until we fix `FulfillmentCtxt::relationships`. That's
// because we create a type variable for closure upvar types, which is not
// constrained until after we try to do fallback on diverging type variables.
// Thus, we will call that function, which is unimplemented.
// check-pass
fn require_fn(_: impl Fn() -> i32) {}