mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
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:
commit
6b3cd03fdb
1
.mailmap
1
.mailmap
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 don’t take self as a parameter and
|
||||
// they are not methods because they don’t 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,
|
||||
);
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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:
|
||||
///
|
||||
|
@ -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`")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 isn’t 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]> {
|
||||
|
@ -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"));
|
||||
|
@ -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),
|
||||
|
20
tests/ui/generic-associated-types/issue-88360.fixed
Normal file
20
tests/ui/generic-associated-types/issue-88360.fixed
Normal 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() {}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
|
||||
trait GatTrait {
|
||||
type Gat<'a> where Self: 'a;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
11
tests/ui/methods/method-not-found-but-doc-alias.rs
Normal file
11
tests/ui/methods/method-not-found-but-doc-alias.rs
Normal 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
|
||||
}
|
12
tests/ui/methods/method-not-found-but-doc-alias.stderr
Normal file
12
tests/ui/methods/method-not-found-but-doc-alias.stderr
Normal 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`.
|
28
tests/ui/suggestions/suggest-remove-deref.fixed
Normal file
28
tests/ui/suggestions/suggest-remove-deref.fixed
Normal 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();
|
||||
}
|
28
tests/ui/suggestions/suggest-remove-deref.rs
Normal file
28
tests/ui/suggestions/suggest-remove-deref.rs
Normal 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();
|
||||
}
|
43
tests/ui/suggestions/suggest-remove-deref.stderr
Normal file
43
tests/ui/suggestions/suggest-remove-deref.stderr
Normal 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`.
|
@ -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) {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user