Merge from rustc
This commit is contained in:
commit
3ef558ec15
174 changed files with 9862 additions and 3253 deletions
|
|
@ -2541,9 +2541,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "miropt-test-tools"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
#![allow(internal_features)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![cfg_attr(bootstrap, feature(min_specialization))]
|
||||
#![feature(never_type)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -57,6 +57,7 @@ use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
|||
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
|
|
@ -190,16 +191,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
trait ResolverAstLoweringExt {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
|
||||
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
|
||||
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
|
||||
}
|
||||
|
||||
impl ResolverAstLoweringExt for ResolverAstLowering {
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
|
||||
if let ExprKind::Path(None, path) = &expr.kind {
|
||||
// Don't perform legacy const generics rewriting if the path already
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
seen_spans.insert(move_span);
|
||||
}
|
||||
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
|
||||
if !is_loop_move {
|
||||
err.span_label(
|
||||
|
|
@ -291,18 +291,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if needs_note {
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +563,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
E0381,
|
||||
"{used} binding {desc}{isnt_initialized}"
|
||||
);
|
||||
use_spans.var_path_only_subdiag(&mut err, desired_action);
|
||||
use_spans.var_path_only_subdiag(self.dcx(), &mut err, desired_action);
|
||||
|
||||
if let InitializationRequiringAction::PartialAssignment
|
||||
| InitializationRequiringAction::Assignment = desired_action
|
||||
|
|
@ -848,9 +854,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
&value_msg,
|
||||
);
|
||||
|
||||
borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
|
||||
borrow_spans.var_path_only_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
crate::InitializationRequiringAction::Borrow,
|
||||
);
|
||||
|
||||
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
|
||||
move_spans.var_subdiag(self.dcx(), &mut err, None, |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span },
|
||||
|
|
@ -895,7 +905,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
borrow_span,
|
||||
&self.describe_any_place(borrow.borrowed_place.as_ref()),
|
||||
);
|
||||
borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| {
|
||||
borrow_spans.var_subdiag(self.dcx(), &mut err, Some(borrow.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
let place = &borrow.borrowed_place;
|
||||
let desc_place = self.describe_any_place(place.as_ref());
|
||||
|
|
@ -1043,7 +1053,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"mutably borrow",
|
||||
);
|
||||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }),
|
||||
|kind, var_span| {
|
||||
|
|
@ -1131,22 +1141,31 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
if issued_spans == borrow_spans {
|
||||
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
|
||||
borrow_spans.var_subdiag(
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
},
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUsePlaceClosure {
|
||||
place: desc_place,
|
||||
var_span,
|
||||
is_single_var: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
} else {
|
||||
issued_spans.var_subdiag(
|
||||
Some(self.dcx()),
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(issued_borrow.kind),
|
||||
|kind, var_span| {
|
||||
|
|
@ -1165,7 +1184,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
borrow_spans.var_subdiag(
|
||||
Some(self.dcx()),
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(gen_borrow_kind),
|
||||
|kind, var_span| {
|
||||
|
|
@ -2217,7 +2236,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
|
|
@ -2476,7 +2495,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
None,
|
||||
);
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
borrow_spans.args_subdiag(self.dcx(), &mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
is_within: borrow_spans.for_coroutine(),
|
||||
args_span,
|
||||
|
|
@ -2935,7 +2954,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
"assign",
|
||||
);
|
||||
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
|
|
@ -2953,7 +2972,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
|
||||
|
||||
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
|
||||
loan_spans.var_subdiag(self.dcx(), &mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
|
|
@ -146,7 +146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.eager_subdiagnostic(
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
|
|
@ -587,11 +587,12 @@ impl UseSpans<'_> {
|
|||
/// Add a span label to the arguments of the closure, if it exists.
|
||||
pub(super) fn args_subdiag(
|
||||
self,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diagnostic,
|
||||
f: impl FnOnce(Span) -> CaptureArgLabel,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { args_span, .. } = self {
|
||||
err.subdiagnostic(f(args_span));
|
||||
err.subdiagnostic(dcx, f(args_span));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -599,6 +600,7 @@ impl UseSpans<'_> {
|
|||
/// only adds label to the `path_span`
|
||||
pub(super) fn var_path_only_subdiag(
|
||||
self,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diagnostic,
|
||||
action: crate::InitializationRequiringAction,
|
||||
) {
|
||||
|
|
@ -607,20 +609,26 @@ impl UseSpans<'_> {
|
|||
if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self {
|
||||
match closure_kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
});
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInCoroutine { path_span },
|
||||
MatchOn | Use => UseInCoroutine { path_span },
|
||||
Assignment => AssignInCoroutine { path_span },
|
||||
PartialAssignment => AssignPartInCoroutine { path_span },
|
||||
},
|
||||
);
|
||||
}
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
err.subdiagnostic(match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
});
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match action {
|
||||
Borrow => BorrowInClosure { path_span },
|
||||
MatchOn | Use => UseInClosure { path_span },
|
||||
Assignment => AssignInClosure { path_span },
|
||||
PartialAssignment => AssignPartInClosure { path_span },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -629,32 +637,32 @@ impl UseSpans<'_> {
|
|||
/// Add a subdiagnostic to the use of the captured variable, if it exists.
|
||||
pub(super) fn var_subdiag(
|
||||
self,
|
||||
dcx: Option<&rustc_errors::DiagCtxt>,
|
||||
dcx: &rustc_errors::DiagCtxt,
|
||||
err: &mut Diagnostic,
|
||||
kind: Option<rustc_middle::mir::BorrowKind>,
|
||||
f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause,
|
||||
) {
|
||||
if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self {
|
||||
if capture_kind_span != path_span {
|
||||
err.subdiagnostic(match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
err.subdiagnostic(
|
||||
dcx,
|
||||
match kind {
|
||||
Some(kd) => match kd {
|
||||
rustc_middle::mir::BorrowKind::Shared
|
||||
| rustc_middle::mir::BorrowKind::Fake => {
|
||||
CaptureVarKind::Immut { kind_span: capture_kind_span }
|
||||
}
|
||||
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
rustc_middle::mir::BorrowKind::Mut { .. } => {
|
||||
CaptureVarKind::Mut { kind_span: capture_kind_span }
|
||||
}
|
||||
},
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
},
|
||||
None => CaptureVarKind::Move { kind_span: capture_kind_span },
|
||||
});
|
||||
);
|
||||
};
|
||||
let diag = f(closure_kind, path_span);
|
||||
match dcx {
|
||||
Some(hd) => err.eager_subdiagnostic(hd, diag),
|
||||
None => err.subdiagnostic(diag),
|
||||
};
|
||||
err.subdiagnostic(dcx, diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1025,26 +1033,33 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
CallKind::FnCall { fn_trait_id, .. }
|
||||
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
|
||||
{
|
||||
err.subdiagnostic(CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Call {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
err.subdiagnostic(self.dcx(), CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
}
|
||||
CallKind::Operator { self_arg, .. } => {
|
||||
let self_arg = self_arg.unwrap();
|
||||
err.subdiagnostic(CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::OperatorUse {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
|
||||
span: self_arg.span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::LhsMoveByOperator { span: self_arg.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
CallKind::Normal { self_arg, desugaring, method_did, method_args } => {
|
||||
|
|
@ -1061,11 +1076,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
|
||||
let func = tcx.def_path_str(method_did);
|
||||
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonNote::FuncTakeSelf {
|
||||
func,
|
||||
place_name: place_name.clone(),
|
||||
span: self_arg.span,
|
||||
},
|
||||
);
|
||||
}
|
||||
let parent_did = tcx.parent(method_did);
|
||||
let parent_self_ty =
|
||||
|
|
@ -1079,7 +1097,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::BorrowContent { var_span },
|
||||
);
|
||||
}
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
|
|
@ -1093,18 +1114,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
_ => false,
|
||||
};
|
||||
if suggest {
|
||||
err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::IterateSlice {
|
||||
ty,
|
||||
span: move_span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::ImplicitCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
// If the moved place was a `&mut` ref, then we can
|
||||
// suggest to reborrow it where it was moved, so it
|
||||
// will still be valid by the time we get to the usage.
|
||||
|
|
@ -1128,19 +1155,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
if let Some((CallDesugaringKind::Await, _)) = desugaring {
|
||||
err.subdiagnostic(CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::Await {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
err.subdiagnostic(CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MethodCall {
|
||||
fn_call_span,
|
||||
place_name: &place_name,
|
||||
is_partial,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
}
|
||||
// Erase and shadow everything that could be passed to the new infcx.
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
|
|
@ -1155,7 +1188,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
)
|
||||
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
||||
{
|
||||
err.eager_subdiagnostic(
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonSuggest::FreshReborrow {
|
||||
span: move_span.shrink_to_hi(),
|
||||
|
|
@ -1239,17 +1272,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
if move_span != span || is_loop_message {
|
||||
err.subdiagnostic(CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CaptureReasonLabel::MovedHere {
|
||||
move_span,
|
||||
is_partial,
|
||||
is_move_msg,
|
||||
is_loop_message,
|
||||
},
|
||||
);
|
||||
}
|
||||
// If the move error occurs due to a loop, don't show
|
||||
// another message for the same span
|
||||
if !is_loop_message {
|
||||
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
|
||||
move_spans.var_subdiag(self.dcx(), err, None, |kind, var_span| match kind {
|
||||
hir::ClosureKind::Coroutine(_) => {
|
||||
CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -448,12 +448,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
None => "value".to_string(),
|
||||
};
|
||||
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
binds_to.sort();
|
||||
binds_to.dedup();
|
||||
|
|
@ -475,14 +478,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
Some(desc) => format!("`{desc}`"),
|
||||
None => "value".to_string(),
|
||||
};
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: place_ty,
|
||||
place: &place_desc,
|
||||
span,
|
||||
},
|
||||
);
|
||||
|
||||
use_spans.args_subdiag(err, |args_span| {
|
||||
use_spans.args_subdiag(self.dcx(), err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
|
||||
place: place_desc,
|
||||
args_span,
|
||||
|
|
@ -580,12 +586,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
if binds_to.len() == 1 {
|
||||
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
ty: bind_to.ty,
|
||||
place: place_desc,
|
||||
span: binding_span,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
if suggest {
|
||||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
self.dcx(),
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
|
|
|
|||
|
|
@ -616,13 +616,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap();
|
||||
let upvar_def_span = self.infcx.tcx.hir().span(def_hir);
|
||||
let upvar_span = upvars_map.get(&def_hir).unwrap().span;
|
||||
diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::Defined { span: upvar_def_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::Captured { span: upvar_span });
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
|
||||
diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span });
|
||||
diag.subdiagnostic(self.dcx(), VarHereDenote::FnMutInferred { span: fr_span });
|
||||
}
|
||||
|
||||
self.suggest_move_on_borrowing_closure(&mut diag);
|
||||
|
|
@ -788,7 +788,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
},
|
||||
};
|
||||
|
||||
diag.subdiagnostic(err_category);
|
||||
diag.subdiagnostic(self.dcx(), err_category);
|
||||
|
||||
self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr);
|
||||
self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr);
|
||||
|
|
@ -979,7 +979,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
ident.span,
|
||||
"calling this method introduces the `impl`'s `'static` requirement",
|
||||
);
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"consider relaxing the implicit `'static` requirement",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use crate::location::{LocationIndex, LocationTable};
|
|||
use crate::BorrowIndex;
|
||||
use polonius_engine::AllFacts as PoloniusFacts;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::Local;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
||||
|
|
@ -24,20 +25,10 @@ impl polonius_engine::FactTypes for RustcFacts {
|
|||
|
||||
pub type AllFacts = PoloniusFacts<RustcFacts>;
|
||||
|
||||
pub(crate) trait AllFactsExt {
|
||||
#[extension(pub(crate) trait AllFactsExt)]
|
||||
impl AllFacts {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
/// current `-Z` flags.
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool;
|
||||
|
||||
fn write_to_dir(
|
||||
&self,
|
||||
dir: impl AsRef<Path>,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl AllFactsExt for AllFacts {
|
||||
/// Return
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||
tcx.sess.opts.unstable_opts.nll_facts
|
||||
|| tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled()
|
||||
|
|
|
|||
|
|
@ -1,24 +1,16 @@
|
|||
use crate::borrow_set::LocalsStateAtExit;
|
||||
use rustc_hir as hir;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::ProjectionElem;
|
||||
use rustc_middle::mir::{Body, Mutability, Place};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
/// Extension methods for the `Place` type.
|
||||
pub trait PlaceExt<'tcx> {
|
||||
#[extension(pub trait PlaceExt<'tcx>)]
|
||||
impl<'tcx> Place<'tcx> {
|
||||
/// Returns `true` if we can safely ignore borrows of this place.
|
||||
/// This is true whenever there is no action that the user can do
|
||||
/// to the place `self` that would invalidate the borrow. This is true
|
||||
/// for borrows of raw pointer dereferents as well as shared references.
|
||||
fn ignore_borrow(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
locals_state_at_exit: &LocalsStateAtExit,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
||||
fn ignore_borrow(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_hir::OpaqueTyOrigin;
|
|||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::infer::TyCtxtInferExt as _;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
|
||||
|
|
@ -225,15 +226,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Given the fully resolved, instantiated type for an opaque
|
||||
/// type, i.e., the value of an inference variable like C1 or C2
|
||||
/// (*), computes the "definition type" for an opaque type
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem;
|
|||
use rustc_hir::BodyOwnerKind;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt};
|
||||
|
|
@ -793,27 +794,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
trait InferCtxtExt<'tcx> {
|
||||
fn replace_free_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
value: T,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
all_outlive_scope: LocalDefId,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
||||
#[extension(trait InferCtxtExt<'tcx>)]
|
||||
impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn replace_free_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -233,11 +233,11 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
_outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
Ok(ongoing_codegen
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
ongoing_codegen
|
||||
.downcast::<driver::aot::OngoingCodegen>()
|
||||
.unwrap()
|
||||
.join(sess, self.config.borrow().as_ref().unwrap()))
|
||||
.join(sess, self.config.borrow().as_ref().unwrap())
|
||||
}
|
||||
|
||||
fn link(
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
|
|||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
diag.subdiagnostic(dcx, missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
|
|
|
|||
|
|
@ -217,13 +217,11 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
Box::new(res)
|
||||
}
|
||||
|
||||
fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
let (codegen_results, work_products) = ongoing_codegen
|
||||
fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
ongoing_codegen
|
||||
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
|
||||
.expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
.join(sess);
|
||||
|
||||
Ok((codegen_results, work_products))
|
||||
.join(sess)
|
||||
}
|
||||
|
||||
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorGuaranteed> {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for TargetFeatureDisableOrEnabl
|
|||
diag.span(span);
|
||||
};
|
||||
if let Some(missing_features) = self.missing_features {
|
||||
diag.subdiagnostic(missing_features);
|
||||
diag.subdiagnostic(dcx, missing_features);
|
||||
}
|
||||
diag.arg("features", self.features.join(", "));
|
||||
diag
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let (codegen_results, work_products) = ongoing_codegen
|
||||
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
|
||||
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
|
|
@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
});
|
||||
}
|
||||
|
||||
Ok((codegen_results, work_products))
|
||||
(codegen_results, work_products)
|
||||
}
|
||||
|
||||
fn link(
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ pub trait CodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed>;
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>);
|
||||
|
||||
/// This is called on the returned `CodegenResults` from `join_codegen`
|
||||
fn link(
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
visitor.visit_ty(ty);
|
||||
}
|
||||
|
||||
fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
|
||||
fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) {
|
||||
match self.const_kind() {
|
||||
// In a const fn all borrows are transient or point to the places given via
|
||||
// references in the arguments (so we already checked them with
|
||||
|
|
@ -355,10 +355,19 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
// to mutable memory.
|
||||
hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
|
||||
_ => {
|
||||
// For indirect places, we are not creating a new permanent borrow, it's just as
|
||||
// transient as the already existing one. For reborrowing references this is handled
|
||||
// at the top of `visit_rvalue`, but for raw pointers we handle it here.
|
||||
// Pointers/references to `static mut` and cases where the `*` is not the first
|
||||
// projection also end up here.
|
||||
// Locals with StorageDead do not live beyond the evaluation and can
|
||||
// thus safely be borrowed without being able to be leaked to the final
|
||||
// value of the constant.
|
||||
if self.local_has_storage_dead(local) {
|
||||
// Note: This is only sound if every local that has a `StorageDead` has a
|
||||
// `StorageDead` in every control flow path leading to a `return` terminator.
|
||||
// The good news is that interning will detect if any unexpected mutable
|
||||
// pointer slips through.
|
||||
if place.is_indirect() || self.local_has_storage_dead(place.local) {
|
||||
self.check_op(ops::TransientMutBorrow(kind));
|
||||
} else {
|
||||
self.check_op(ops::MutBorrow(kind));
|
||||
|
|
@ -390,6 +399,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
|
||||
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
// FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost
|
||||
// projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`.
|
||||
// All those cases are handled below with shared/mutable borrows.
|
||||
// Once `const_mut_refs` is stable, we should be able to entirely remove this special case.
|
||||
// (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.)
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_, kind, place) => {
|
||||
if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
|
||||
|
|
@ -460,7 +474,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
|
||||
if !is_allowed {
|
||||
self.check_mut_borrow(
|
||||
place.local,
|
||||
place,
|
||||
if matches!(rvalue, Rvalue::Ref(..)) {
|
||||
hir::BorrowKind::Ref
|
||||
} else {
|
||||
|
|
@ -478,7 +492,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
// If the place is indirect, this is basically a reborrow. We have a reborrow
|
||||
// special case above, but for raw pointers and pointers/references to `static` and
|
||||
// when the `*` is not the first projection, `place_as_reborrow` does not recognize
|
||||
// them as such, so we end up here. This should probably be considered a
|
||||
// `TransientCellBorrow` (we consider the equivalent mutable case a
|
||||
// `TransientMutBorrow`), but such reborrows got accidentally stabilized already and
|
||||
// it is too much of a breaking change to take back.
|
||||
if borrowed_place_has_mut_interior && !place.is_indirect() {
|
||||
match self.const_kind() {
|
||||
// In a const fn all borrows are transient or point to the places given via
|
||||
// references in the arguments (so we already checked them with
|
||||
|
|
@ -495,6 +516,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// final value.
|
||||
// Note: This is only sound if every local that has a `StorageDead` has a
|
||||
// `StorageDead` in every control flow path leading to a `return` terminator.
|
||||
// The good news is that interning will detect if any unexpected mutable
|
||||
// pointer slips through.
|
||||
if self.local_has_storage_dead(place.local) {
|
||||
self.check_op(ops::TransientCellBorrow);
|
||||
} else {
|
||||
|
|
@ -948,6 +971,12 @@ fn place_as_reborrow<'tcx>(
|
|||
) -> Option<PlaceRef<'tcx>> {
|
||||
match place.as_ref().last_projection() {
|
||||
Some((place_base, ProjectionElem::Deref)) => {
|
||||
// FIXME: why do statics and raw pointers get excluded here? This makes
|
||||
// some code involving mutable pointers unstable, but it is unclear
|
||||
// why that code is treated differently from mutable references.
|
||||
// Once TransientMutBorrow and TransientCellBorrow are stable,
|
||||
// this can probably be cleaned up without any behavioral changes.
|
||||
|
||||
// A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
|
||||
// that points to the allocation for the static. Don't treat these as reborrows.
|
||||
if body.local_decls[place_base.local].is_ref_to_static() {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
// FIXME(effects) revisit this
|
||||
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
|
||||
let span = tcx.def_span(data.impl_def_id);
|
||||
err.subdiagnostic(errors::NonConstImplNote { span });
|
||||
err.subdiagnostic(tcx.dcx(), errors::NonConstImplNote { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,13 @@ pub trait Qualif {
|
|||
adt: AdtDef<'tcx>,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
/// Returns `true` if this `Qualif` behaves sructurally for pointers and references:
|
||||
/// the pointer/reference qualifies if and only if the pointee qualifies.
|
||||
///
|
||||
/// (This is currently `false` for all our instances, but that may change in the future. Also,
|
||||
/// by keeping it abstract, the handling of `Deref` in `in_place` becomes more clear.)
|
||||
fn deref_structural<'tcx>(cx: &ConstCx<'_, 'tcx>) -> bool;
|
||||
}
|
||||
|
||||
/// Constant containing interior mutability (`UnsafeCell<T>`).
|
||||
|
|
@ -103,6 +110,10 @@ impl Qualif for HasMutInterior {
|
|||
// It arises structurally for all other types.
|
||||
adt.is_unsafe_cell()
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Constant containing an ADT that implements `Drop`.
|
||||
|
|
@ -131,6 +142,10 @@ impl Qualif for NeedsDrop {
|
|||
) -> bool {
|
||||
adt.has_dtor(cx.tcx)
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Constant containing an ADT that implements non-const `Drop`.
|
||||
|
|
@ -210,6 +225,10 @@ impl Qualif for NeedsNonConstDrop {
|
|||
) -> bool {
|
||||
adt.has_non_const_dtor(cx.tcx)
|
||||
}
|
||||
|
||||
fn deref_structural<'tcx>(_cx: &ConstCx<'_, 'tcx>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
|
||||
|
|
@ -303,6 +322,11 @@ where
|
|||
return false;
|
||||
}
|
||||
|
||||
if matches!(elem, ProjectionElem::Deref) && !Q::deref_structural(cx) {
|
||||
// We have to assume that this qualifies.
|
||||
return true;
|
||||
}
|
||||
|
||||
place = place_base;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -263,14 +263,10 @@ pub enum SubdiagnosticMessage {
|
|||
/// Translatable message which has already been translated eagerly.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
Eager(Cow<'static, str>),
|
||||
/// be instantiated multiple times with different values. These subdiagnostics' messages
|
||||
/// are translated when they are added to the parent diagnostic, producing this variant of
|
||||
/// `DiagnosticMessage`.
|
||||
Translated(Cow<'static, str>),
|
||||
/// Identifier of a Fluent message. Instances of this variant are generated by the
|
||||
/// `Subdiagnostic` derive.
|
||||
FluentIdentifier(FluentId),
|
||||
|
|
@ -307,19 +303,15 @@ impl From<Cow<'static, str>> for SubdiagnosticMessage {
|
|||
pub enum DiagnosticMessage {
|
||||
/// Non-translatable diagnostic message.
|
||||
Str(Cow<'static, str>),
|
||||
/// Translatable message which has already been translated eagerly.
|
||||
/// Translatable message which has been already translated.
|
||||
///
|
||||
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
|
||||
/// be instantiated multiple times with different values. As translation normally happens
|
||||
/// immediately prior to emission, after the diagnostic and subdiagnostic derive logic has run,
|
||||
/// the setting of diagnostic arguments in the derived code will overwrite previous variable
|
||||
/// values and only the final value will be set when translation occurs - resulting in
|
||||
/// incorrect diagnostics. Eager translation results in translation for a subdiagnostic
|
||||
/// happening immediately after the subdiagnostic derive's logic has been run. This variant
|
||||
/// stores messages which have been translated eagerly.
|
||||
Eager(Cow<'static, str>),
|
||||
/// be instantiated multiple times with different values. These subdiagnostics' messages
|
||||
/// are translated when they are added to the parent diagnostic, producing this variant of
|
||||
/// `DiagnosticMessage`.
|
||||
Translated(Cow<'static, str>),
|
||||
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
|
||||
/// message.
|
||||
/// message. Yet to be translated.
|
||||
///
|
||||
/// <https://projectfluent.org/fluent/guide/hello.html>
|
||||
/// <https://projectfluent.org/fluent/guide/attributes.html>
|
||||
|
|
@ -336,7 +328,7 @@ impl DiagnosticMessage {
|
|||
pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self {
|
||||
let attr = match sub {
|
||||
SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s),
|
||||
SubdiagnosticMessage::Eager(s) => return DiagnosticMessage::Eager(s),
|
||||
SubdiagnosticMessage::Translated(s) => return DiagnosticMessage::Translated(s),
|
||||
SubdiagnosticMessage::FluentIdentifier(id) => {
|
||||
return DiagnosticMessage::FluentIdentifier(id, None);
|
||||
}
|
||||
|
|
@ -345,7 +337,7 @@ impl DiagnosticMessage {
|
|||
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()),
|
||||
DiagnosticMessage::Eager(s) => DiagnosticMessage::Eager(s.clone()),
|
||||
DiagnosticMessage::Translated(s) => DiagnosticMessage::Translated(s.clone()),
|
||||
DiagnosticMessage::FluentIdentifier(id, _) => {
|
||||
DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr))
|
||||
}
|
||||
|
|
@ -354,7 +346,7 @@ impl DiagnosticMessage {
|
|||
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
DiagnosticMessage::Eager(s) | DiagnosticMessage::Str(s) => Some(s),
|
||||
DiagnosticMessage::Translated(s) | DiagnosticMessage::Str(s) => Some(s),
|
||||
DiagnosticMessage::FluentIdentifier(_, _) => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -396,7 +388,7 @@ impl Into<SubdiagnosticMessage> for DiagnosticMessage {
|
|||
fn into(self) -> SubdiagnosticMessage {
|
||||
match self {
|
||||
DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s),
|
||||
DiagnosticMessage::Eager(s) => SubdiagnosticMessage::Eager(s),
|
||||
DiagnosticMessage::Translated(s) => SubdiagnosticMessage::Translated(s),
|
||||
DiagnosticMessage::FluentIdentifier(id, None) => {
|
||||
SubdiagnosticMessage::FluentIdentifier(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -851,18 +851,11 @@ impl Diagnostic {
|
|||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]).
|
||||
pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
|
||||
subdiagnostic.add_to_diagnostic(self);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
|
||||
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
|
||||
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
|
||||
/// interpolated variables).
|
||||
pub fn eager_subdiagnostic(
|
||||
pub fn subdiagnostic(
|
||||
&mut self,
|
||||
dcx: &crate::DiagCtxt,
|
||||
subdiagnostic: impl AddToDiagnostic,
|
||||
|
|
@ -918,7 +911,7 @@ impl Diagnostic {
|
|||
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
|
||||
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
|
||||
/// passes the user's string along).
|
||||
fn subdiagnostic_message_to_diagnostic_message(
|
||||
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
|
||||
&self,
|
||||
attr: impl Into<SubdiagnosticMessage>,
|
||||
) -> DiagnosticMessage {
|
||||
|
|
|
|||
|
|
@ -404,9 +404,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
|||
name: impl Into<Cow<'static, str>>, arg: impl IntoDiagnosticArg,
|
||||
));
|
||||
forward!((subdiagnostic, with_subdiagnostic)(
|
||||
subdiagnostic: impl crate::AddToDiagnostic,
|
||||
));
|
||||
forward!((eager_subdiagnostic, with_eager_subdiagnostic)(
|
||||
dcx: &DiagCtxt,
|
||||
subdiagnostic: impl crate::AddToDiagnostic,
|
||||
));
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileLines, FileName, SourceFile, Span};
|
||||
|
||||
use crate::error::TranslateError;
|
||||
use crate::snippet::{
|
||||
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
|
||||
};
|
||||
|
|
@ -559,6 +560,18 @@ pub struct SilentEmitter {
|
|||
pub fatal_note: String,
|
||||
}
|
||||
|
||||
pub fn silent_translate<'a>(
|
||||
message: &'a DiagnosticMessage,
|
||||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
match message {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => Ok(Cow::Borrowed(msg)),
|
||||
DiagnosticMessage::FluentIdentifier(identifier, _) => {
|
||||
// Any value works here.
|
||||
Ok(identifier.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Translate for SilentEmitter {
|
||||
fn fluent_bundle(&self) -> Option<&Lrc<FluentBundle>> {
|
||||
None
|
||||
|
|
@ -567,6 +580,16 @@ impl Translate for SilentEmitter {
|
|||
fn fallback_fluent_bundle(&self) -> &FluentBundle {
|
||||
panic!("silent emitter attempted to translate message")
|
||||
}
|
||||
|
||||
// Override `translate_message` for the silent emitter because eager translation of
|
||||
// subdiagnostics result in a call to this.
|
||||
fn translate_message<'a>(
|
||||
&'a self,
|
||||
message: &'a DiagnosticMessage,
|
||||
_: &'a FluentArgs<'_>,
|
||||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
silent_translate(message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Emitter for SilentEmitter {
|
||||
|
|
|
|||
|
|
@ -643,7 +643,8 @@ impl DiagCtxt {
|
|||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
SubdiagnosticMessage::Eager(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
let inner = self.inner.borrow();
|
||||
inner.eagerly_translate(message, args)
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
|
|
@ -653,8 +654,7 @@ impl DiagCtxt {
|
|||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> String {
|
||||
let inner = self.inner.borrow();
|
||||
let args = crate::translation::to_fluent_args(args);
|
||||
inner.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
|
||||
inner.eagerly_translate_to_string(message, args)
|
||||
}
|
||||
|
||||
// This is here to not allow mutation of flags;
|
||||
|
|
@ -1464,6 +1464,25 @@ impl DiagCtxtInner {
|
|||
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `SubdiagnosticMessage::Eager`.
|
||||
pub fn eagerly_translate<'a>(
|
||||
&self,
|
||||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> SubdiagnosticMessage {
|
||||
SubdiagnosticMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
|
||||
}
|
||||
|
||||
/// Translate `message` eagerly with `args` to `String`.
|
||||
pub fn eagerly_translate_to_string<'a>(
|
||||
&self,
|
||||
message: DiagnosticMessage,
|
||||
args: impl Iterator<Item = DiagnosticArg<'a>>,
|
||||
) -> String {
|
||||
let args = crate::translation::to_fluent_args(args);
|
||||
self.emitter.translate_message(&message, &args).map_err(Report::new).unwrap().to_string()
|
||||
}
|
||||
|
||||
fn flush_delayed(&mut self) {
|
||||
if self.delayed_bugs.is_empty() {
|
||||
return;
|
||||
|
|
@ -1502,15 +1521,22 @@ impl DiagCtxtInner {
|
|||
}
|
||||
|
||||
let mut bug =
|
||||
if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
|
||||
if backtrace || self.ice_file.is_none() { bug.decorate(self) } else { bug.inner };
|
||||
|
||||
// "Undelay" the delayed bugs (into plain `Bug`s).
|
||||
if bug.level != DelayedBug {
|
||||
// NOTE(eddyb) not panicking here because we're already producing
|
||||
// an ICE, and the more information the merrier.
|
||||
bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
|
||||
let subdiag = InvalidFlushedDelayedDiagnosticLevel {
|
||||
span: bug.span.primary_span().unwrap(),
|
||||
level: bug.level,
|
||||
};
|
||||
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
|
||||
// just uses `DiagCtxtInner` functions.
|
||||
subdiag.add_to_diagnostic_with(&mut bug, |diag, msg| {
|
||||
let args = diag.args();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
self.eagerly_translate(msg, args)
|
||||
});
|
||||
}
|
||||
bug.level = Bug;
|
||||
|
|
@ -1545,25 +1571,35 @@ impl DelayedDiagnostic {
|
|||
DelayedDiagnostic { inner: diagnostic, note: backtrace }
|
||||
}
|
||||
|
||||
fn decorate(mut self) -> Diagnostic {
|
||||
fn decorate(mut self, dcx: &DiagCtxtInner) -> Diagnostic {
|
||||
// FIXME: Cannot use `Diagnostic::subdiagnostic` which takes `DiagCtxt`, but it
|
||||
// just uses `DiagCtxtInner` functions.
|
||||
let subdiag_with = |diag: &mut Diagnostic, msg| {
|
||||
let args = diag.args();
|
||||
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
|
||||
dcx.eagerly_translate(msg, args)
|
||||
};
|
||||
|
||||
match self.note.status() {
|
||||
BacktraceStatus::Captured => {
|
||||
let inner = &self.inner;
|
||||
self.inner.subdiagnostic(DelayedAtWithNewline {
|
||||
let subdiag = DelayedAtWithNewline {
|
||||
span: inner.span.primary_span().unwrap_or(DUMMY_SP),
|
||||
emitted_at: inner.emitted_at.clone(),
|
||||
note: self.note,
|
||||
});
|
||||
};
|
||||
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
|
||||
}
|
||||
// Avoid the needless newline when no backtrace has been captured,
|
||||
// the display impl should just be a single line.
|
||||
_ => {
|
||||
let inner = &self.inner;
|
||||
self.inner.subdiagnostic(DelayedAtWithoutNewline {
|
||||
let subdiag = DelayedAtWithoutNewline {
|
||||
span: inner.span.primary_span().unwrap_or(DUMMY_SP),
|
||||
emitted_at: inner.emitted_at.clone(),
|
||||
note: self.note,
|
||||
});
|
||||
};
|
||||
subdiag.add_to_diagnostic_with(&mut self.inner, subdiag_with);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1709,15 +1745,15 @@ impl Level {
|
|||
}
|
||||
|
||||
// FIXME(eddyb) this doesn't belong here AFAICT, should be moved to callsite.
|
||||
pub fn add_elided_lifetime_in_path_suggestion(
|
||||
pub fn add_elided_lifetime_in_path_suggestion<E: EmissionGuarantee>(
|
||||
source_map: &SourceMap,
|
||||
diag: &mut Diagnostic,
|
||||
diag: &mut DiagnosticBuilder<'_, E>,
|
||||
n: usize,
|
||||
path_span: Span,
|
||||
incl_angl_brckt: bool,
|
||||
insertion_span: Span,
|
||||
) {
|
||||
diag.subdiagnostic(ExpectedLifetimeParameter { span: path_span, count: n });
|
||||
diag.subdiagnostic(diag.dcx, ExpectedLifetimeParameter { span: path_span, count: n });
|
||||
if !source_map.is_span_accessible(insertion_span) {
|
||||
// Do not try to suggest anything if generated by a proc-macro.
|
||||
return;
|
||||
|
|
@ -1726,11 +1762,10 @@ pub fn add_elided_lifetime_in_path_suggestion(
|
|||
let suggestion =
|
||||
if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
|
||||
|
||||
diag.subdiagnostic(IndicateAnonymousLifetime {
|
||||
span: insertion_span.shrink_to_hi(),
|
||||
count: n,
|
||||
suggestion,
|
||||
});
|
||||
diag.subdiagnostic(
|
||||
diag.dcx,
|
||||
IndicateAnonymousLifetime { span: insertion_span.shrink_to_hi(), count: n, suggestion },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind};
|
|||
use crate::snippet::Style;
|
||||
use crate::{DiagnosticArg, DiagnosticMessage, FluentBundle};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_error_messages::FluentArgs;
|
||||
pub use rustc_error_messages::FluentArgs;
|
||||
use std::borrow::Cow;
|
||||
use std::env;
|
||||
use std::error::Report;
|
||||
|
|
@ -61,7 +61,7 @@ pub trait Translate {
|
|||
) -> Result<Cow<'_, str>, TranslateError<'_>> {
|
||||
trace!(?message, ?args);
|
||||
let (identifier, attr) = match message {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => {
|
||||
DiagnosticMessage::Str(msg) | DiagnosticMessage::Translated(msg) => {
|
||||
return Ok(Cow::Borrowed(msg));
|
||||
}
|
||||
DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl Annotatable {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {
|
||||
match self {
|
||||
Annotatable::Item(item) => visitor.visit_item(item),
|
||||
Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ use rustc_ast::mut_visit::*;
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult};
|
||||
use rustc_ast::{try_visit, walk_list};
|
||||
use rustc_ast::{AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind};
|
||||
use rustc_ast::{ForeignItemKind, HasAttrs, HasNodeId};
|
||||
use rustc_ast::{Inline, ItemKind, MacStmtStyle, MetaItemKind, ModKind};
|
||||
|
|
@ -143,16 +144,15 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
|
||||
pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) -> V::Result {
|
||||
match self {
|
||||
AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
|
||||
AstFragment::OptExpr(Some(expr)) => try_visit!(visitor.visit_expr(expr)),
|
||||
AstFragment::OptExpr(None) => {}
|
||||
AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
|
||||
$($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
|
||||
$($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
|
||||
visitor.$visit_ast_elt(ast_elt, $($args)*);
|
||||
})?)*
|
||||
AstFragment::MethodReceiverExpr(expr) => try_visit!(visitor.visit_method_receiver_expr(expr)),
|
||||
$($(AstFragment::$Kind(ast) => try_visit!(visitor.$visit_ast(ast)),)?)*
|
||||
$($(AstFragment::$Kind(ast) => walk_list!(visitor, $visit_ast_elt, &ast[..], $($args)*),)?)*
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::mbe::{
|
|||
use rustc_ast::token::{self, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
|
||||
use rustc_errors::{Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
|
||||
use rustc_parse::parser::{Parser, Recovery};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -58,7 +58,7 @@ pub(super) fn failed_to_match_macro<'cx>(
|
|||
err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
|
||||
}
|
||||
|
||||
annotate_doc_comment(&mut err, sess.source_map(), span);
|
||||
annotate_doc_comment(cx.sess.dcx(), &mut err, sess.source_map(), span);
|
||||
|
||||
if let Some(span) = remaining_matcher.span() {
|
||||
err.span_note(span, format!("while trying to match {remaining_matcher}"));
|
||||
|
|
@ -311,12 +311,17 @@ enum ExplainDocComment {
|
|||
},
|
||||
}
|
||||
|
||||
pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
|
||||
pub(super) fn annotate_doc_comment(
|
||||
dcx: &DiagCtxt,
|
||||
err: &mut Diagnostic,
|
||||
sm: &SourceMap,
|
||||
span: Span,
|
||||
) {
|
||||
if let Ok(src) = sm.span_to_snippet(span) {
|
||||
if src.starts_with("///") || src.starts_with("/**") {
|
||||
err.subdiagnostic(ExplainDocComment::Outer { span });
|
||||
err.subdiagnostic(dcx, ExplainDocComment::Outer { span });
|
||||
} else if src.starts_with("//!") || src.starts_with("/*!") {
|
||||
err.subdiagnostic(ExplainDocComment::Inner { span });
|
||||
err.subdiagnostic(dcx, ExplainDocComment::Inner { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ pub fn compile_declarative_macro(
|
|||
let sp = token.span.substitute_dummy(def.span);
|
||||
let mut err = sess.dcx().struct_span_err(sp, s);
|
||||
err.span_label(sp, msg);
|
||||
annotate_doc_comment(&mut err, sess.source_map(), sp);
|
||||
annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp);
|
||||
err.emit();
|
||||
return dummy_syn_ext();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -407,9 +407,9 @@ pub fn check_intrinsic_type(
|
|||
}
|
||||
sym::float_to_int_unchecked => (2, 0, vec![param(0)], param(1)),
|
||||
|
||||
sym::assume => (0, 0, vec![tcx.types.bool], Ty::new_unit(tcx)),
|
||||
sym::likely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
|
||||
sym::unlikely => (0, 0, vec![tcx.types.bool], tcx.types.bool),
|
||||
sym::assume => (0, 1, vec![tcx.types.bool], Ty::new_unit(tcx)),
|
||||
sym::likely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
|
||||
sym::unlikely => (0, 1, vec![tcx.types.bool], tcx.types.bool),
|
||||
|
||||
sym::read_via_copy => (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)),
|
||||
sym::write_via_move => {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_bound_vars::*;
|
||||
|
|
@ -27,17 +28,8 @@ use std::fmt;
|
|||
|
||||
use crate::errors;
|
||||
|
||||
trait RegionExt {
|
||||
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
|
||||
|
||||
fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
|
||||
|
||||
fn id(&self) -> Option<DefId>;
|
||||
|
||||
fn shifted(self, amount: u32) -> ResolvedArg;
|
||||
}
|
||||
|
||||
impl RegionExt for ResolvedArg {
|
||||
#[extension(trait RegionExt)]
|
||||
impl ResolvedArg {
|
||||
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
|
||||
debug!("ResolvedArg::early: def_id={:?}", param.def_id);
|
||||
(param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let semi = expr.span.shrink_to_hi().with_hi(semi_span.hi());
|
||||
let sugg = crate::errors::RemoveSemiForCoerce { expr: expr.span, ret, semi };
|
||||
diag.subdiagnostic(sugg);
|
||||
diag.subdiagnostic(self.dcx(), sugg);
|
||||
}
|
||||
|
||||
/// When the previously checked expression (the scrutinee) diverges,
|
||||
|
|
@ -311,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
error: &mut bool,
|
||||
) {
|
||||
if let Some((if_span, msg)) = ret_reason {
|
||||
err.span_label(if_span, msg.clone());
|
||||
err.span_label(if_span, msg);
|
||||
} else if let ExprKind::Block(block, _) = then_expr.kind
|
||||
&& let Some(expr) = block.expr
|
||||
{
|
||||
|
|
|
|||
|
|
@ -993,19 +993,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
if let Some((deref_ty, _)) = derefed {
|
||||
// Give a note about what the expr derefs to.
|
||||
if deref_ty != self.expr_ty.peel_refs() {
|
||||
err.subdiagnostic(errors::DerefImplsIsEmpty {
|
||||
span: self.expr_span,
|
||||
deref_ty: fcx.ty_to_string(deref_ty),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
fcx.dcx(),
|
||||
errors::DerefImplsIsEmpty {
|
||||
span: self.expr_span,
|
||||
deref_ty: fcx.ty_to_string(deref_ty),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Create a multipart suggestion: add `!` and `.is_empty()` in
|
||||
// place of the cast.
|
||||
err.subdiagnostic(errors::UseIsEmpty {
|
||||
lo: self.expr_span.shrink_to_lo(),
|
||||
hi: self.span.with_lo(self.expr_span.hi()),
|
||||
expr_ty: fcx.ty_to_string(self.expr_ty),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
fcx.dcx(),
|
||||
errors::UseIsEmpty {
|
||||
lo: self.expr_span.shrink_to_lo(),
|
||||
hi: self.span.with_lo(self.expr_span.hi()),
|
||||
expr_ty: fcx.ty_to_string(self.expr_ty),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let Some(sp) =
|
||||
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
|
||||
{
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
}
|
||||
oprnd_t = Ty::new_error(tcx, err.emit());
|
||||
}
|
||||
|
|
@ -2048,7 +2048,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.shrink_to_hi()
|
||||
.to(range_end.span);
|
||||
|
||||
err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1269,7 +1269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
// The user provided `ptr::null()`, but the function expects
|
||||
// `ptr::null_mut()`.
|
||||
err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
|
||||
err.subdiagnostic(self.dcx(), SuggestPtrNullMut { span: arg.span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -458,13 +458,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// but those checks need to be a bit more delicate and the benefit is diminishing.
|
||||
if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
|
||||
let sugg = prefix_wrap(".as_ref()");
|
||||
err.subdiagnostic(errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
},
|
||||
);
|
||||
return true;
|
||||
} else if let Some((deref_ty, _)) =
|
||||
self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1)
|
||||
|
|
@ -472,13 +475,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&& error_tys_equate_as_ref
|
||||
{
|
||||
let sugg = prefix_wrap(".as_deref()");
|
||||
err.subdiagnostic(errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg,
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
},
|
||||
);
|
||||
return true;
|
||||
} else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
|
||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||
|
|
@ -565,7 +571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
end: span.shrink_to_hi(),
|
||||
},
|
||||
};
|
||||
err.subdiagnostic(suggest_boxing);
|
||||
err.subdiagnostic(self.dcx(), suggest_boxing);
|
||||
|
||||
true
|
||||
} else {
|
||||
|
|
@ -799,29 +805,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match &fn_decl.output {
|
||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
|
||||
// `fn main()` must return `()`, do not suggest changing return type
|
||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
|
||||
err.subdiagnostic(self.dcx(), errors::ExpectedReturnTypeLabel::Unit { span });
|
||||
return true;
|
||||
}
|
||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
||||
if let Some(found) = found.make_suggestable(self.tcx, false) {
|
||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||
span,
|
||||
found: found.to_string(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
|
||||
);
|
||||
return true;
|
||||
} else if let ty::Closure(_, args) = found.kind()
|
||||
// FIXME(compiler-errors): Get better at printing binders...
|
||||
&& let closure = args.as_closure()
|
||||
&& closure.sig().is_suggestable(self.tcx, false)
|
||||
{
|
||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||
span,
|
||||
found: closure.print_as_impl_trait().to_string(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::Add {
|
||||
span,
|
||||
found: closure.print_as_impl_trait().to_string(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::MissingHere { span },
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -843,16 +855,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!(?found);
|
||||
if found.is_suggestable(self.tcx, false) {
|
||||
if term.span.is_empty() {
|
||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||
span: term.span,
|
||||
found: found.to_string(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::AddReturnTypeSuggestion::Add {
|
||||
span: term.span,
|
||||
found: found.to_string(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||
span: term.span,
|
||||
expected,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::ExpectedReturnTypeLabel::Other {
|
||||
span: term.span,
|
||||
expected,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -867,10 +885,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let ty = self.normalize(hir_ty.span, ty);
|
||||
let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
|
||||
if self.can_coerce(expected, ty) {
|
||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||
span: hir_ty.span,
|
||||
expected,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected },
|
||||
);
|
||||
self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1106,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let sp = self.tcx.sess.source_map().start_point(expr.span).with_parent(None);
|
||||
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
|
||||
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
@ -1220,7 +1238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
return false;
|
||||
};
|
||||
diag.subdiagnostic(subdiag);
|
||||
diag.subdiagnostic(self.dcx(), subdiag);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3269,19 +3269,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if impls_trait(trait_info.def_id) {
|
||||
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
|
||||
} else {
|
||||
err.subdiagnostic(CandidateTraitNote {
|
||||
span: self.tcx.def_span(trait_info.def_id),
|
||||
trait_name: self.tcx.def_path_str(trait_info.def_id),
|
||||
item_name,
|
||||
action_or_ty: if trait_missing_method {
|
||||
"NONE".to_string()
|
||||
} else {
|
||||
param_type.map_or_else(
|
||||
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|
||||
ToString::to_string,
|
||||
)
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
CandidateTraitNote {
|
||||
span: self.tcx.def_span(trait_info.def_id),
|
||||
trait_name: self.tcx.def_path_str(trait_info.def_id),
|
||||
item_name,
|
||||
action_or_ty: if trait_missing_method {
|
||||
"NONE".to_string()
|
||||
} else {
|
||||
param_type.map_or_else(
|
||||
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|
||||
ToString::to_string,
|
||||
)
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
}
|
||||
trait_infos => {
|
||||
|
|
|
|||
|
|
@ -824,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// If the previous expression was a block expression, suggest parentheses
|
||||
// (turning this into a binary subtraction operation instead.)
|
||||
// for example, `{2} - 2` -> `({2}) - 2` (see src\test\ui\parser\expr-as-stmt.rs)
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
} else {
|
||||
match actual.kind() {
|
||||
Uint(_) if op == hir::UnOp::Neg => {
|
||||
|
|
|
|||
|
|
@ -13,30 +13,10 @@ use rustc_middle::ty::{self, TyCtxt};
|
|||
|
||||
/// FIXME(-Znext-solver): This or public because it is shared with the
|
||||
/// new trait solver implementation. We should deduplicate canonicalization.
|
||||
pub trait CanonicalExt<'tcx, V> {
|
||||
#[extension(pub trait CanonicalExt<'tcx, V>)]
|
||||
impl<'tcx, V> Canonical<'tcx, V> {
|
||||
/// Instantiate the wrapped value, replacing each canonical value
|
||||
/// with the value given in `var_values`.
|
||||
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>;
|
||||
|
||||
/// Allows one to apply a instantiation to some subset of
|
||||
/// `self.value`. Invoke `projection_fn` with `self.value` to get
|
||||
/// a value V that is expressed in terms of the same canonical
|
||||
/// variables bound in `self` (usually this extracts from subset
|
||||
/// of `self`). Apply the instantiation `var_values` to this value
|
||||
/// V, replacing each of the canonical variables.
|
||||
fn instantiate_projected<T>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
var_values: &CanonicalVarValues<'tcx>,
|
||||
projection_fn: impl FnOnce(&V) -> T,
|
||||
) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
|
||||
fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
@ -44,6 +24,12 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> {
|
|||
self.instantiate_projected(tcx, var_values, |value| value.clone())
|
||||
}
|
||||
|
||||
/// Allows one to apply a instantiation to some subset of
|
||||
/// `self.value`. Invoke `projection_fn` with `self.value` to get
|
||||
/// a value V that is expressed in terms of the same canonical
|
||||
/// variables bound in `self` (usually this extracts from subset
|
||||
/// of `self`). Apply the instantiation `var_values` to this value
|
||||
/// V, replacing each of the canonical variables.
|
||||
fn instantiate_projected<T>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -845,7 +845,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
arm_ty,
|
||||
arm_span,
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
err.subdiagnostic(self.dcx(), subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// Get return type span and point to it.
|
||||
|
|
@ -882,7 +882,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
else_ty,
|
||||
else_span,
|
||||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
err.subdiagnostic(self.dcx(), subdiag);
|
||||
}
|
||||
// don't suggest wrapping either blocks in `if .. {} else {}`
|
||||
let is_empty_arm = |id| {
|
||||
|
|
@ -2786,19 +2786,8 @@ pub enum FailureCode {
|
|||
Error0644,
|
||||
}
|
||||
|
||||
pub trait ObligationCauseExt<'tcx> {
|
||||
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
|
||||
|
||||
fn as_failure_code_diag(
|
||||
&self,
|
||||
terr: TypeError<'tcx>,
|
||||
span: Span,
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
) -> ObligationCauseFailureCode;
|
||||
fn as_requirement_str(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
#[extension(pub trait ObligationCauseExt<'tcx>)]
|
||||
impl<'tcx> ObligationCause<'tcx> {
|
||||
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
|
||||
use self::FailureCode::*;
|
||||
use crate::traits::ObligationCauseCode::*;
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
trait_predicates: trait_predicates.join(", "),
|
||||
}
|
||||
};
|
||||
err.subdiagnostic(suggestion);
|
||||
err.subdiagnostic(self.dcx(), suggestion);
|
||||
}
|
||||
|
||||
pub(super) fn report_placeholder_failure(
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)),
|
||||
end_sp: return_sp.shrink_to_hi(),
|
||||
};
|
||||
err.subdiagnostic(sugg);
|
||||
err.subdiagnostic(self.dcx(), sugg);
|
||||
|
||||
let mut starts = Vec::new();
|
||||
let mut ends = Vec::new();
|
||||
|
|
@ -93,7 +93,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
ends.push(span.shrink_to_hi());
|
||||
}
|
||||
let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends };
|
||||
err.subdiagnostic(sugg);
|
||||
err.subdiagnostic(self.dcx(), sugg);
|
||||
}
|
||||
|
||||
pub(super) fn suggest_tuple_pattern(
|
||||
|
|
@ -138,7 +138,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
span_low: cause.span.shrink_to_lo(),
|
||||
span_high: cause.span.shrink_to_hi(),
|
||||
};
|
||||
diag.subdiagnostic(sugg);
|
||||
diag.subdiagnostic(self.dcx(), sugg);
|
||||
}
|
||||
_ => {
|
||||
// More than one matching variant.
|
||||
|
|
@ -147,7 +147,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
cause_span: cause.span,
|
||||
compatible_variants,
|
||||
};
|
||||
diag.subdiagnostic(sugg);
|
||||
diag.subdiagnostic(self.dcx(), sugg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -219,9 +219,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
},
|
||||
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
|
||||
// FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic
|
||||
diag.subdiagnostic(ConsiderAddingAwait::FutureSugg {
|
||||
span: exp_span.shrink_to_hi(),
|
||||
});
|
||||
diag.subdiagnostic(
|
||||
self.dcx(),
|
||||
ConsiderAddingAwait::FutureSugg { span: exp_span.shrink_to_hi() },
|
||||
);
|
||||
Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span })
|
||||
}
|
||||
(Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
|
||||
|
|
@ -249,7 +250,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(subdiag) = subdiag {
|
||||
diag.subdiagnostic(subdiag);
|
||||
diag.subdiagnostic(self.dcx(), subdiag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +286,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
} else {
|
||||
return;
|
||||
};
|
||||
diag.subdiagnostic(suggestion);
|
||||
diag.subdiagnostic(self.dcx(), suggestion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -325,15 +326,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
(true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
|
||||
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
|
||||
(true, true) => {
|
||||
diag.subdiagnostic(FnItemsAreDistinct);
|
||||
diag.subdiagnostic(self.dcx(), FnItemsAreDistinct);
|
||||
FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig }
|
||||
}
|
||||
(false, false) => {
|
||||
diag.subdiagnostic(FnItemsAreDistinct);
|
||||
diag.subdiagnostic(self.dcx(), FnItemsAreDistinct);
|
||||
FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig }
|
||||
}
|
||||
};
|
||||
diag.subdiagnostic(sugg);
|
||||
diag.subdiagnostic(self.dcx(), sugg);
|
||||
}
|
||||
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
|
||||
let expected_sig =
|
||||
|
|
@ -342,7 +343,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).instantiate(self.tcx, args2));
|
||||
|
||||
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
|
||||
diag.subdiagnostic(FnUniqTypes);
|
||||
diag.subdiagnostic(self.dcx(), FnUniqTypes);
|
||||
}
|
||||
|
||||
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|
||||
|
|
@ -371,7 +372,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
diag.subdiagnostic(sug);
|
||||
diag.subdiagnostic(self.dcx(), sug);
|
||||
}
|
||||
(ty::FnDef(did, args), ty::FnPtr(sig)) => {
|
||||
let expected_sig =
|
||||
|
|
@ -390,7 +391,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
format!("{fn_name} as {found_sig}")
|
||||
};
|
||||
|
||||
diag.subdiagnostic(FnConsiderCasting { casting });
|
||||
diag.subdiagnostic(self.dcx(), FnConsiderCasting { casting });
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
|
|
@ -822,7 +823,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
let diag = self.consider_returning_binding_diag(blk, expected_ty);
|
||||
match diag {
|
||||
Some(diag) => {
|
||||
err.subdiagnostic(diag);
|
||||
err.subdiagnostic(self.dcx(), diag);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
|
|
|
|||
|
|
@ -626,11 +626,8 @@ pub struct InferCtxtBuilder<'tcx> {
|
|||
next_trait_solver: bool,
|
||||
}
|
||||
|
||||
pub trait TyCtxtInferExt<'tcx> {
|
||||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
||||
#[extension(pub trait TyCtxtInferExt<'tcx>)]
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
|
|
|
|||
|
|
@ -52,18 +52,8 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
|||
) -> Vec<PredicateObligation<'tcx>>;
|
||||
}
|
||||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn register_predicate_obligations(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||
);
|
||||
|
||||
#[must_use]
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||
#[extension(pub trait TraitEngineExt<'tcx>)]
|
||||
impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T {
|
||||
fn register_predicate_obligations(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
|
|
@ -74,6 +64,7 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
let errors = self.select_where_possible(infcx);
|
||||
if !errors.is_empty() {
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ pub struct Linker {
|
|||
impl Linker {
|
||||
pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> {
|
||||
let (codegen_results, work_products) =
|
||||
codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)?;
|
||||
codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames);
|
||||
|
||||
sess.compile_status()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1757,7 +1757,7 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
|
|||
diag.note(note.to_string());
|
||||
}
|
||||
if let Some(sugg) = self.suggestion {
|
||||
diag.subdiagnostic(sugg);
|
||||
diag.subdiagnostic(diag.dcx, sugg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -331,44 +331,7 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
}
|
||||
}
|
||||
(Meta::Path(_), "subdiagnostic") => {
|
||||
if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() {
|
||||
let DiagnosticDeriveKind::Diagnostic = self.kind else {
|
||||
// No eager translation for lints.
|
||||
return Ok(quote! { diag.subdiagnostic(#binding); });
|
||||
};
|
||||
return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); });
|
||||
} else {
|
||||
return Ok(quote! { diag.subdiagnostic(#binding); });
|
||||
}
|
||||
}
|
||||
(Meta::List(meta_list), "subdiagnostic") => {
|
||||
let err = || {
|
||||
span_err(
|
||||
meta_list.span().unwrap(),
|
||||
"`eager` is the only supported nested attribute for `subdiagnostic`",
|
||||
)
|
||||
.emit();
|
||||
};
|
||||
|
||||
let Ok(p): Result<Path, _> = meta_list.parse_args() else {
|
||||
err();
|
||||
return Ok(quote! {});
|
||||
};
|
||||
|
||||
if !p.is_ident("eager") {
|
||||
err();
|
||||
return Ok(quote! {});
|
||||
}
|
||||
|
||||
match &self.kind {
|
||||
DiagnosticDeriveKind::Diagnostic => {}
|
||||
DiagnosticDeriveKind::LintDiagnostic => {
|
||||
throw_invalid_attr!(attr, |diag| {
|
||||
diag.help("eager subdiagnostics are not supported on lints")
|
||||
})
|
||||
}
|
||||
};
|
||||
return Ok(quote! { diag.eager_subdiagnostic(dcx, #binding); });
|
||||
return Ok(quote! { diag.subdiagnostic(diag.dcx, #binding); });
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
154
compiler/rustc_macros/src/extension.rs
Normal file
154
compiler/rustc_macros/src/extension.rs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature,
|
||||
Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility,
|
||||
};
|
||||
|
||||
pub(crate) fn extension(
|
||||
attr: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr);
|
||||
let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl);
|
||||
let headers: Vec<_> = items
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn {
|
||||
attrs: scrub_attrs(&f.attrs),
|
||||
sig: scrub_header(f.sig.clone()),
|
||||
default: None,
|
||||
semi_token: Some(Token)),
|
||||
}),
|
||||
ImplItem::Const(ct) => TraitItem::Const(TraitItemConst {
|
||||
attrs: scrub_attrs(&ct.attrs),
|
||||
const_token: ct.const_token,
|
||||
ident: ct.ident.clone(),
|
||||
generics: ct.generics.clone(),
|
||||
colon_token: ct.colon_token,
|
||||
ty: ct.ty.clone(),
|
||||
default: None,
|
||||
semi_token: ct.semi_token,
|
||||
}),
|
||||
ImplItem::Type(ty) => TraitItem::Type(TraitItemType {
|
||||
attrs: scrub_attrs(&ty.attrs),
|
||||
type_token: ty.type_token,
|
||||
ident: ty.ident.clone(),
|
||||
generics: ty.generics.clone(),
|
||||
colon_token: None,
|
||||
bounds: Punctuated::new(),
|
||||
default: None,
|
||||
semi_token: ty.semi_token,
|
||||
}),
|
||||
ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro {
|
||||
attrs: scrub_attrs(&mac.attrs),
|
||||
mac: mac.mac.clone(),
|
||||
semi_token: mac.semi_token,
|
||||
}),
|
||||
ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()),
|
||||
_ => unimplemented!(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
#(#attrs)*
|
||||
#vis trait #trait_ {
|
||||
#(#headers)*
|
||||
}
|
||||
|
||||
impl #generics #trait_ for #self_ty {
|
||||
#(#items)*
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Only keep `#[doc]` attrs.
|
||||
fn scrub_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
|
||||
attrs
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.filter(|attr| {
|
||||
let ident = &attr.path().segments[0].ident;
|
||||
ident == "doc" || ident == "must_use"
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Scrub arguments so that they're valid for trait signatures.
|
||||
fn scrub_header(mut sig: Signature) -> Signature {
|
||||
for (idx, input) in sig.inputs.iter_mut().enumerate() {
|
||||
match input {
|
||||
syn::FnArg::Receiver(rcvr) => {
|
||||
// `mut self` -> `self`
|
||||
if rcvr.reference.is_none() {
|
||||
rcvr.mutability.take();
|
||||
}
|
||||
}
|
||||
syn::FnArg::Typed(arg) => match &mut *arg.pat {
|
||||
Pat::Ident(arg) => {
|
||||
// `ref mut ident @ pat` -> `ident`
|
||||
arg.by_ref.take();
|
||||
arg.mutability.take();
|
||||
arg.subpat.take();
|
||||
}
|
||||
_ => {
|
||||
// `pat` -> `__arg0`
|
||||
arg.pat = Box::new(
|
||||
PatIdent {
|
||||
attrs: vec![],
|
||||
by_ref: None,
|
||||
mutability: None,
|
||||
ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()),
|
||||
subpat: None,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
sig
|
||||
}
|
||||
|
||||
struct ExtensionAttr {
|
||||
vis: Visibility,
|
||||
trait_: Path,
|
||||
}
|
||||
|
||||
impl Parse for ExtensionAttr {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let vis = input.parse()?;
|
||||
let _: Token![trait] = input.parse()?;
|
||||
let trait_ = input.parse()?;
|
||||
Ok(ExtensionAttr { vis, trait_ })
|
||||
}
|
||||
}
|
||||
|
||||
struct Impl {
|
||||
attrs: Vec<Attribute>,
|
||||
generics: Generics,
|
||||
self_ty: Type,
|
||||
items: Vec<ImplItem>,
|
||||
}
|
||||
|
||||
impl Parse for Impl {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
let _: Token![impl] = input.parse()?;
|
||||
let generics = input.parse()?;
|
||||
let self_ty = input.parse()?;
|
||||
|
||||
let content;
|
||||
let _brace_token = braced!(content in input);
|
||||
let mut items = Vec::new();
|
||||
while !content.is_empty() {
|
||||
items.push(content.parse()?);
|
||||
}
|
||||
|
||||
Ok(Impl { attrs, generics, self_ty, items })
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ use proc_macro::TokenStream;
|
|||
|
||||
mod current_version;
|
||||
mod diagnostics;
|
||||
mod extension;
|
||||
mod hash_stable;
|
||||
mod lift;
|
||||
mod query;
|
||||
|
|
@ -40,6 +41,11 @@ pub fn symbols(input: TokenStream) -> TokenStream {
|
|||
symbols::symbols(input.into()).into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn extension(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
extension::extension(attr, input)
|
||||
}
|
||||
|
||||
decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
|
||||
decl_derive!(
|
||||
[HashStable_Generic, attributes(stable_hasher)] =>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
|
|||
use crate::query::LocalCrate;
|
||||
use crate::ty::TyCtxt;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::VisitorResult;
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::svh::Svh;
|
||||
|
|
@ -431,23 +433,28 @@ impl<'hir> Map<'hir> {
|
|||
}
|
||||
|
||||
/// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
|
||||
pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
|
||||
pub fn walk_toplevel_module<V>(self, visitor: &mut V) -> V::Result
|
||||
where
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let (top_mod, span, hir_id) = self.get_module(LocalModDefId::CRATE_DEF_ID);
|
||||
visitor.visit_mod(top_mod, span, hir_id);
|
||||
visitor.visit_mod(top_mod, span, hir_id)
|
||||
}
|
||||
|
||||
/// Walks the attributes in a crate.
|
||||
pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
|
||||
pub fn walk_attributes<V>(self, visitor: &mut V) -> V::Result
|
||||
where
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let krate = self.krate();
|
||||
for info in krate.owners.iter() {
|
||||
if let MaybeOwner::Owner(info) = info {
|
||||
for attrs in info.attrs.map.values() {
|
||||
for a in *attrs {
|
||||
visitor.visit_attribute(a)
|
||||
}
|
||||
walk_list!(visitor, visit_attribute, *attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
/// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
|
||||
|
|
@ -460,52 +467,38 @@ impl<'hir> Map<'hir> {
|
|||
/// provided by `tcx.hir_crate_items(())`.
|
||||
///
|
||||
/// Please see the notes in `intravisit.rs` for more information.
|
||||
pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V)
|
||||
pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V) -> V::Result
|
||||
where
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let krate = self.tcx.hir_crate_items(());
|
||||
|
||||
for id in krate.items() {
|
||||
visitor.visit_item(self.item(id));
|
||||
}
|
||||
|
||||
for id in krate.trait_items() {
|
||||
visitor.visit_trait_item(self.trait_item(id));
|
||||
}
|
||||
|
||||
for id in krate.impl_items() {
|
||||
visitor.visit_impl_item(self.impl_item(id));
|
||||
}
|
||||
|
||||
for id in krate.foreign_items() {
|
||||
visitor.visit_foreign_item(self.foreign_item(id));
|
||||
}
|
||||
walk_list!(visitor, visit_item, krate.items().map(|id| self.item(id)));
|
||||
walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id)));
|
||||
walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id)));
|
||||
walk_list!(
|
||||
visitor,
|
||||
visit_foreign_item,
|
||||
krate.foreign_items().map(|id| self.foreign_item(id))
|
||||
);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
/// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
|
||||
/// item-likes in a single module.
|
||||
pub fn visit_item_likes_in_module<V>(self, module: LocalModDefId, visitor: &mut V)
|
||||
pub fn visit_item_likes_in_module<V>(self, module: LocalModDefId, visitor: &mut V) -> V::Result
|
||||
where
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let module = self.tcx.hir_module_items(module);
|
||||
|
||||
for id in module.items() {
|
||||
visitor.visit_item(self.item(id));
|
||||
}
|
||||
|
||||
for id in module.trait_items() {
|
||||
visitor.visit_trait_item(self.trait_item(id));
|
||||
}
|
||||
|
||||
for id in module.impl_items() {
|
||||
visitor.visit_impl_item(self.impl_item(id));
|
||||
}
|
||||
|
||||
for id in module.foreign_items() {
|
||||
visitor.visit_foreign_item(self.foreign_item(id));
|
||||
}
|
||||
walk_list!(visitor, visit_item, module.items().map(|id| self.item(id)));
|
||||
walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id)));
|
||||
walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id)));
|
||||
walk_list!(
|
||||
visitor,
|
||||
visit_foreign_item,
|
||||
module.foreign_items().map(|id| self.foreign_item(id))
|
||||
);
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub fn for_each_module(self, mut f: impl FnMut(LocalModDefId)) {
|
||||
|
|
|
|||
|
|
@ -23,20 +23,8 @@ use std::fmt;
|
|||
use std::num::NonZero;
|
||||
use std::ops::Bound;
|
||||
|
||||
pub trait IntegerExt {
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
|
||||
fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
|
||||
fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
|
||||
fn repr_discr<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
repr: &ReprOptions,
|
||||
min: i128,
|
||||
max: i128,
|
||||
) -> (Integer, bool);
|
||||
}
|
||||
|
||||
impl IntegerExt for Integer {
|
||||
#[extension(pub trait IntegerExt)]
|
||||
impl Integer {
|
||||
#[inline]
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
|
||||
match (*self, signed) {
|
||||
|
|
@ -123,12 +111,8 @@ impl IntegerExt for Integer {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait PrimitiveExt {
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
|
||||
fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl PrimitiveExt for Primitive {
|
||||
#[extension(pub trait PrimitiveExt)]
|
||||
impl Primitive {
|
||||
#[inline]
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
match *self {
|
||||
|
|
|
|||
|
|
@ -96,13 +96,8 @@ impl<'tcx> Discr<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait IntTypeExt {
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
|
||||
fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>;
|
||||
fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>;
|
||||
}
|
||||
|
||||
impl IntTypeExt for IntegerType {
|
||||
#[extension(pub trait IntTypeExt)]
|
||||
impl IntegerType {
|
||||
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
match self {
|
||||
IntegerType::Pointer(true) => tcx.types.isize,
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
|
|||
|
||||
let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
|
||||
if !is_empty_match && all_arms_have_guards {
|
||||
err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
|
||||
err.subdiagnostic(cx.tcx.dcx(), NonExhaustiveMatchAllArmsGuarded);
|
||||
}
|
||||
if let Some((span, sugg)) = suggestion {
|
||||
err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint {
|
|||
return;
|
||||
}
|
||||
|
||||
// will be evaluated by miri and produce its errors there
|
||||
if body.source.promoted.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let def_id = body.source.def_id().expect_local();
|
||||
let def_kind = tcx.def_kind(def_id);
|
||||
let is_fn_like = def_kind.is_fn_like();
|
||||
|
|
|
|||
|
|
@ -132,18 +132,23 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
|
|||
bcb_data.basic_blocks.iter().flat_map(move |&bb| {
|
||||
let data = &mir_body[bb];
|
||||
|
||||
let unexpand = move |expn_span| {
|
||||
unexpand_into_body_span_with_visible_macro(expn_span, body_span)
|
||||
// Discard any spans that fill the entire body, because they tend
|
||||
// to represent compiler-inserted code, e.g. implicitly returning `()`.
|
||||
.filter(|(span, _)| !span.source_equal(body_span))
|
||||
};
|
||||
|
||||
let statement_spans = data.statements.iter().filter_map(move |statement| {
|
||||
let expn_span = filtered_statement_span(statement)?;
|
||||
let (span, visible_macro) =
|
||||
unexpand_into_body_span_with_visible_macro(expn_span, body_span)?;
|
||||
let (span, visible_macro) = unexpand(expn_span)?;
|
||||
|
||||
Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement)))
|
||||
});
|
||||
|
||||
let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| {
|
||||
let expn_span = filtered_terminator_span(terminator)?;
|
||||
let (span, visible_macro) =
|
||||
unexpand_into_body_span_with_visible_macro(expn_span, body_span)?;
|
||||
let (span, visible_macro) = unexpand(expn_span)?;
|
||||
|
||||
Some(SpanFromMir::new(span, visible_macro, bcb, false))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> {
|
|||
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
|
||||
diag.span_label(self.yield_sp, fluent::_subdiag::label);
|
||||
if let Some(reason) = self.reason {
|
||||
diag.subdiagnostic(reason);
|
||||
diag.subdiagnostic(diag.dcx, reason);
|
||||
}
|
||||
diag.span_help(self.src_sp, fluent::_subdiag::help);
|
||||
diag.arg("pre", self.pre);
|
||||
|
|
|
|||
|
|
@ -452,7 +452,6 @@ impl<'a> Parser<'a> {
|
|||
let mut expected = self
|
||||
.expected_tokens
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|token| {
|
||||
// Filter out suggestions that suggest the same token which was found and deemed incorrect.
|
||||
fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
|
||||
|
|
@ -464,7 +463,7 @@ impl<'a> Parser<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
if *token != parser::TokenType::Token(self.token.kind.clone()) {
|
||||
if **token != parser::TokenType::Token(self.token.kind.clone()) {
|
||||
let eq = is_ident_eq_keyword(&self.token.kind, &token);
|
||||
// If the suggestion is a keyword and the found token is an ident,
|
||||
// the content of which are equal to the suggestion's content,
|
||||
|
|
@ -483,6 +482,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
expected.sort_by_cached_key(|x| x.to_string());
|
||||
expected.dedup();
|
||||
|
|
@ -2350,7 +2350,7 @@ impl<'a> Parser<'a> {
|
|||
let mut err = self.dcx().struct_span_err(span, msg);
|
||||
let sp = self.sess.source_map().start_point(self.token.span);
|
||||
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
}
|
||||
err.span_label(span, "expected expression");
|
||||
|
||||
|
|
|
|||
|
|
@ -1433,7 +1433,7 @@ impl<'a> Parser<'a> {
|
|||
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
|
||||
// then suggest parens around the lhs.
|
||||
if let Some(sp) = this.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(this.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
}
|
||||
err
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1933,7 +1933,7 @@ impl<'a> Parser<'a> {
|
|||
if self.token.kind == token::Not {
|
||||
if let Err(mut err) = self.unexpected::<FieldDef>() {
|
||||
// Encounter the macro invocation
|
||||
err.subdiagnostic(MacroExpandsToAdtField { adt_ty });
|
||||
err.subdiagnostic(self.dcx(), MacroExpandsToAdtField { adt_ty });
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -2352,10 +2352,13 @@ impl<'a> Parser<'a> {
|
|||
.into_iter()
|
||||
.any(|s| self.prev_token.is_ident_named(s));
|
||||
|
||||
err.subdiagnostic(errors::FnTraitMissingParen {
|
||||
span: self.prev_token.span,
|
||||
machine_applicable,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
errors::FnTraitMissingParen {
|
||||
span: self.prev_token.span,
|
||||
machine_applicable,
|
||||
},
|
||||
);
|
||||
}
|
||||
return Err(err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -843,7 +843,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
let sp = self.sess.source_map().start_point(self.token.span);
|
||||
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
|
||||
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
|
||||
err.subdiagnostic(self.dcx(), ExprParenthesesNeeded::surrounding(*sp));
|
||||
}
|
||||
|
||||
Err(err)
|
||||
|
|
|
|||
|
|
@ -893,7 +893,7 @@ impl<'a> Parser<'a> {
|
|||
ParseError {
|
||||
description: "expected format parameter to occur after `:`".to_owned(),
|
||||
note: None,
|
||||
label: format!("expected `{}` to occur after `:`", alignment).to_owned(),
|
||||
label: format!("expected `{}` to occur after `:`", alignment),
|
||||
span: pos.to(pos),
|
||||
secondary_label: None,
|
||||
suggestion: Suggestion::None,
|
||||
|
|
|
|||
|
|
@ -403,9 +403,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion });
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
ChangeImportBindingSuggestion { span: binding_span, suggestion },
|
||||
);
|
||||
} else {
|
||||
err.subdiagnostic(ChangeImportBinding { span: binding_span });
|
||||
err.subdiagnostic(self.dcx(), ChangeImportBinding { span: binding_span });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1430,17 +1433,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
);
|
||||
|
||||
if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
|
||||
err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span });
|
||||
err.subdiagnostic(self.dcx(), MaybeMissingMacroRulesName { span: ident.span });
|
||||
return;
|
||||
}
|
||||
|
||||
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
|
||||
err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
|
||||
err.subdiagnostic(self.dcx(), ExplicitUnsafeTraits { span: ident.span, ident });
|
||||
return;
|
||||
}
|
||||
|
||||
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
|
||||
err.subdiagnostic(AddedMacroUse);
|
||||
err.subdiagnostic(self.dcx(), AddedMacroUse);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1450,10 +1453,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let span = self.def_span(def_id);
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let head_span = source_map.guess_head_span(span);
|
||||
err.subdiagnostic(ConsiderAddingADerive {
|
||||
span: head_span.shrink_to_lo(),
|
||||
suggestion: "#[derive(Default)]\n".to_string(),
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.dcx(),
|
||||
ConsiderAddingADerive {
|
||||
span: head_span.shrink_to_lo(),
|
||||
suggestion: "#[derive(Default)]\n".to_string(),
|
||||
},
|
||||
);
|
||||
}
|
||||
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
|
||||
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
|
||||
|
|
|
|||
|
|
@ -1262,12 +1262,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// exclude decl_macro
|
||||
if self.get_macro_by_def_id(def_id).macro_rules =>
|
||||
{
|
||||
err.subdiagnostic(ConsiderAddingMacroExport {
|
||||
err.subdiagnostic(self.dcx(), ConsiderAddingMacroExport {
|
||||
span: binding.span,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
err.subdiagnostic(ConsiderMarkingAsPub {
|
||||
err.subdiagnostic(self.dcx(), ConsiderMarkingAsPub {
|
||||
span: import.span,
|
||||
ident,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1111,11 +1111,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
Side::Start => (segment.ident.span.between(range.span), " @ ".into()),
|
||||
Side::End => (range.span.to(segment.ident.span), format!("{} @ ..", segment.ident)),
|
||||
};
|
||||
err.subdiagnostic(errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
|
||||
span,
|
||||
ident: segment.ident,
|
||||
snippet,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.r.dcx(),
|
||||
errors::UnexpectedResUseAtOpInSlicePatWithRangeSugg {
|
||||
span,
|
||||
ident: segment.ident,
|
||||
snippet,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
enum Side {
|
||||
|
|
@ -1207,10 +1210,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
});
|
||||
|
||||
if let Some(param) = param {
|
||||
err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
|
||||
span: param.shrink_to_lo(),
|
||||
applicability,
|
||||
});
|
||||
err.subdiagnostic(
|
||||
self.r.dcx(),
|
||||
errors::UnexpectedResChangeTyToConstParamSugg {
|
||||
span: param.shrink_to_lo(),
|
||||
applicability,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,21 +173,21 @@ pub fn add_feature_diagnostics_for_issue(
|
|||
feature_from_cli: bool,
|
||||
) {
|
||||
if let Some(n) = find_feature_issue(feature, issue) {
|
||||
err.subdiagnostic(FeatureDiagnosticForIssue { n });
|
||||
err.subdiagnostic(sess.dcx(), FeatureDiagnosticForIssue { n });
|
||||
}
|
||||
|
||||
// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
|
||||
if sess.parse_sess.unstable_features.is_nightly_build() {
|
||||
if feature_from_cli {
|
||||
err.subdiagnostic(CliFeatureDiagnosticHelp { feature });
|
||||
err.subdiagnostic(sess.dcx(), CliFeatureDiagnosticHelp { feature });
|
||||
} else {
|
||||
err.subdiagnostic(FeatureDiagnosticHelp { feature });
|
||||
err.subdiagnostic(sess.dcx(), FeatureDiagnosticHelp { feature });
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.ui_testing {
|
||||
err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
|
||||
err.subdiagnostic(sess.dcx(), SuggestUpgradeCompiler::ui_testing());
|
||||
} else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
|
||||
err.subdiagnostic(suggestion);
|
||||
err.subdiagnostic(sess.dcx(), suggestion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub enum Arch {
|
|||
Arm64e,
|
||||
Arm64_32,
|
||||
I386,
|
||||
I386_sim,
|
||||
I686,
|
||||
X86_64,
|
||||
X86_64h,
|
||||
|
|
@ -34,7 +35,7 @@ impl Arch {
|
|||
Arm64 | Arm64_macabi | Arm64_sim => "arm64",
|
||||
Arm64e => "arm64e",
|
||||
Arm64_32 => "arm64_32",
|
||||
I386 => "i386",
|
||||
I386 | I386_sim => "i386",
|
||||
I686 => "i686",
|
||||
X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
|
||||
X86_64h => "x86_64h",
|
||||
|
|
@ -45,7 +46,7 @@ impl Arch {
|
|||
Cow::Borrowed(match self {
|
||||
Armv7k | Armv7s => "arm",
|
||||
Arm64 | Arm64e | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64",
|
||||
I386 | I686 => "x86",
|
||||
I386 | I386_sim | I686 => "x86",
|
||||
X86_64 | X86_64_sim | X86_64_macabi | X86_64h => "x86_64",
|
||||
})
|
||||
}
|
||||
|
|
@ -54,9 +55,7 @@ impl Arch {
|
|||
match self {
|
||||
Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => "",
|
||||
X86_64_macabi | Arm64_macabi => "macabi",
|
||||
// x86_64-apple-ios is a simulator target, even though it isn't
|
||||
// declared that way in the target like the other ones...
|
||||
Arm64_sim | X86_64_sim => "sim",
|
||||
I386_sim | Arm64_sim | X86_64_sim => "sim",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +69,7 @@ impl Arch {
|
|||
// Only macOS 10.12+ is supported, which means
|
||||
// all x86_64/x86 CPUs must be running at least penryn
|
||||
// https://github.com/llvm/llvm-project/blob/01f924d0e37a5deae51df0d77e10a15b63aa0c0f/clang/lib/Driver/ToolChains/Arch/X86.cpp#L79-L82
|
||||
I386 | I686 => "penryn",
|
||||
I386 | I386_sim | I686 => "penryn",
|
||||
X86_64 | X86_64_sim => "penryn",
|
||||
X86_64_macabi => "penryn",
|
||||
// Note: `core-avx2` is slightly more advanced than `x86_64h`, see
|
||||
|
|
@ -85,7 +84,7 @@ impl Arch {
|
|||
fn stack_probes(self) -> StackProbeType {
|
||||
match self {
|
||||
Armv7k | Armv7s => StackProbeType::None,
|
||||
Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h | X86_64_sim
|
||||
Arm64 | Arm64e | Arm64_32 | I386 | I386_sim | I686 | X86_64 | X86_64h | X86_64_sim
|
||||
| X86_64_macabi | Arm64_macabi | Arm64_sim => StackProbeType::Inline,
|
||||
}
|
||||
}
|
||||
|
|
@ -302,8 +301,8 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]>
|
|||
// Otherwise if cross-compiling for a different OS/SDK, remove any part
|
||||
// of the linking environment that's wrong and reversed.
|
||||
match arch {
|
||||
Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
|
||||
| X86_64h | Arm64_sim => {
|
||||
Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I386_sim | I686 | X86_64
|
||||
| X86_64_sim | X86_64h | Arm64_sim => {
|
||||
cvs!["MACOSX_DEPLOYMENT_TARGET"]
|
||||
}
|
||||
X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
|
|||
use crate::spec::{Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
let arch = Arch::I386;
|
||||
// i386-apple-ios is a simulator target, even though it isn't declared
|
||||
// that way in the target name like the other ones...
|
||||
let arch = Arch::I386_sim;
|
||||
Target {
|
||||
// Clang automatically chooses a more specific target based on
|
||||
// IPHONEOS_DEPLOYMENT_TARGET.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
|
|||
use crate::spec::{SanitizerSet, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
// x86_64-apple-ios is a simulator target, even though it isn't declared
|
||||
// that way in the target name like the other ones...
|
||||
let arch = Arch::X86_64_sim;
|
||||
let mut base = opts("ios", arch);
|
||||
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch};
|
|||
use crate::spec::{Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
// x86_64-apple-tvos is a simulator target, even though it isn't declared
|
||||
// that way in the target name like the other ones...
|
||||
let arch = Arch::X86_64_sim;
|
||||
Target {
|
||||
llvm_target: tvos_sim_llvm_target(arch).into(),
|
||||
|
|
|
|||
|
|
@ -17,49 +17,8 @@ use std::fmt::Debug;
|
|||
|
||||
pub use rustc_infer::infer::*;
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
|
||||
|
||||
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool;
|
||||
|
||||
/// Check whether a `ty` implements given trait(trait_def_id) without side-effects.
|
||||
///
|
||||
/// The inputs are:
|
||||
///
|
||||
/// - the def-id of the trait
|
||||
/// - the type parameters of the trait, including the self-type
|
||||
/// - the parameter environment
|
||||
///
|
||||
/// Invokes `evaluate_obligation`, so in the event that evaluating
|
||||
/// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
|
||||
/// (or EvaluatedToAmbigStackDependent) will be returned.
|
||||
fn type_implements_trait(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> traits::EvaluationResult;
|
||||
|
||||
/// Returns `Some` if a type implements a trait shallowly, without side-effects,
|
||||
/// along with any errors that would have been reported upon further obligation
|
||||
/// processing.
|
||||
///
|
||||
/// - If this returns `Some([])`, then the trait holds modulo regions.
|
||||
/// - If this returns `Some([errors..])`, then the trait has an impl for
|
||||
/// the self type, but some nested obligations do not hold.
|
||||
/// - If this returns `None`, no implementation that applies could be found.
|
||||
///
|
||||
/// FIXME(-Znext-solver): Due to the recursive nature of the new solver,
|
||||
/// this will probably only ever return `Some([])` or `None`.
|
||||
fn type_implements_trait_shallow(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<Vec<traits::FulfillmentError<'tcx>>>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
|
||||
|
|
@ -81,6 +40,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
|
||||
}
|
||||
|
||||
/// Check whether a `ty` implements given trait(trait_def_id) without side-effects.
|
||||
///
|
||||
/// The inputs are:
|
||||
///
|
||||
/// - the def-id of the trait
|
||||
/// - the type parameters of the trait, including the self-type
|
||||
/// - the parameter environment
|
||||
///
|
||||
/// Invokes `evaluate_obligation`, so in the event that evaluating
|
||||
/// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
|
||||
/// (or EvaluatedToAmbigStackDependent) will be returned.
|
||||
#[instrument(level = "debug", skip(self, params), ret)]
|
||||
fn type_implements_trait(
|
||||
&self,
|
||||
|
|
@ -99,6 +69,17 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
|
||||
}
|
||||
|
||||
/// Returns `Some` if a type implements a trait shallowly, without side-effects,
|
||||
/// along with any errors that would have been reported upon further obligation
|
||||
/// processing.
|
||||
///
|
||||
/// - If this returns `Some([])`, then the trait holds modulo regions.
|
||||
/// - If this returns `Some([errors..])`, then the trait has an impl for
|
||||
/// the self type, but some nested obligations do not hold.
|
||||
/// - If this returns `None`, no implementation that applies could be found.
|
||||
///
|
||||
/// FIXME(-Znext-solver): Due to the recursive nature of the new solver,
|
||||
/// this will probably only ever return `Some([])` or `None`.
|
||||
fn type_implements_trait_shallow(
|
||||
&self,
|
||||
trait_def_id: DefId,
|
||||
|
|
@ -124,19 +105,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtBuilderExt<'tcx> {
|
||||
fn enter_canonical_trait_query<K, R>(
|
||||
self,
|
||||
canonical_key: &Canonical<'tcx, K>,
|
||||
operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
|
||||
) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
|
||||
where
|
||||
K: TypeFoldable<TyCtxt<'tcx>>,
|
||||
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
|
||||
#[extension(pub trait InferCtxtBuilderExt<'tcx>)]
|
||||
impl<'tcx> InferCtxtBuilder<'tcx> {
|
||||
/// The "main method" for a canonicalized trait query. Given the
|
||||
/// canonical key `canonical_key`, this method will create a new
|
||||
/// inference context, instantiate the key, and run your operation
|
||||
|
|
|
|||
|
|
@ -3,20 +3,14 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError};
|
|||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
|
||||
pub trait InferCtxtRegionExt<'tcx> {
|
||||
#[extension(pub trait InferCtxtRegionExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Resolve regions, using the deep normalizer to normalize any type-outlives
|
||||
/// obligations in the process. This is in `rustc_trait_selection` because
|
||||
/// we need to normalize.
|
||||
///
|
||||
/// Prefer this method over `resolve_regions_with_normalize`, unless you are
|
||||
/// doing something specific for normalization.
|
||||
fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Vec<RegionResolutionError<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
|
||||
fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
|
|
|
|||
|
|
@ -131,22 +131,12 @@ pub enum GenerateProofTree {
|
|||
Never,
|
||||
}
|
||||
|
||||
pub trait InferCtxtEvalExt<'tcx> {
|
||||
#[extension(pub trait InferCtxtEvalExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Evaluates a goal from **outside** of the trait solver.
|
||||
///
|
||||
/// Using this while inside of the solver is wrong as it uses a new
|
||||
/// search graph which would break cycle detection.
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (
|
||||
Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<'tcx>>,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -17,14 +17,8 @@ use crate::solve::inspect::ProofTreeBuilder;
|
|||
use crate::traits::StructurallyNormalizeExt;
|
||||
use crate::traits::TraitEngineExt;
|
||||
|
||||
pub trait InferCtxtSelectExt<'tcx> {
|
||||
fn select_in_new_trait_solver(
|
||||
&self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtSelectExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn select_in_new_trait_solver(
|
||||
&self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
|
|
|
|||
|
|
@ -216,22 +216,17 @@ pub trait ProofTreeVisitor<'tcx> {
|
|||
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow<Self::BreakTy>;
|
||||
}
|
||||
|
||||
pub trait ProofTreeInferCtxtExt<'tcx> {
|
||||
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
visitor: &mut V,
|
||||
) -> ControlFlow<V::BreakTy>;
|
||||
}
|
||||
|
||||
impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
visitor: &mut V,
|
||||
) -> ControlFlow<V::BreakTy> {
|
||||
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
|
||||
let proof_tree = proof_tree.unwrap();
|
||||
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
|
||||
self.probe(|_| {
|
||||
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
|
||||
let proof_tree = proof_tree.unwrap();
|
||||
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,11 +61,8 @@ enum GoalEvaluationKind {
|
|||
Nested { is_normalizes_to_hack: IsNormalizesToHack },
|
||||
}
|
||||
|
||||
trait CanonicalResponseExt {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
|
||||
#[extension(trait CanonicalResponseExt)]
|
||||
impl<'tcx> Canonical<'tcx, Response<'tcx>> {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool {
|
||||
self.value.external_constraints.region_constraints.is_empty()
|
||||
&& self.value.var_values.is_identity()
|
||||
|
|
|
|||
|
|
@ -8,23 +8,21 @@ use crate::infer::outlives::env::OutlivesEnvironment;
|
|||
use crate::infer::InferOk;
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::traits::engine::TraitEngineExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect, FulfillmentCtxt};
|
||||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
use crate::traits::structural_normalize::StructurallyNormalizeExt;
|
||||
use crate::traits::NormalizeExt;
|
||||
use crate::traits::SkipLeakCheck;
|
||||
use crate::traits::{
|
||||
Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
|
||||
SelectionContext,
|
||||
Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext,
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{util, TraitEngine};
|
||||
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||
|
|
@ -310,29 +308,35 @@ fn equate_impl_headers<'tcx>(
|
|||
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligations: &'a [PredicateObligation<'tcx>],
|
||||
) -> Option<&'a PredicateObligation<'tcx>> {
|
||||
) -> Option<PredicateObligation<'tcx>> {
|
||||
let infcx = selcx.infcx;
|
||||
|
||||
obligations.iter().find(|obligation| {
|
||||
let evaluation_result = if infcx.next_trait_solver() {
|
||||
infcx.evaluate_obligation(obligation)
|
||||
} else {
|
||||
if infcx.next_trait_solver() {
|
||||
let mut fulfill_cx = FulfillmentCtxt::new(infcx);
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations.iter().cloned());
|
||||
|
||||
// We only care about the obligations that are *definitely* true errors.
|
||||
// Ambiguities do not prove the disjointness of two impls.
|
||||
let mut errors = fulfill_cx.select_where_possible(infcx);
|
||||
errors.pop().map(|err| err.obligation)
|
||||
} else {
|
||||
obligations.iter().cloned().find(|obligation| {
|
||||
// We use `evaluate_root_obligation` to correctly track intercrate
|
||||
// ambiguity clauses. We cannot use this in the new solver.
|
||||
selcx.evaluate_root_obligation(obligation)
|
||||
};
|
||||
let evaluation_result = selcx.evaluate_root_obligation(obligation);
|
||||
|
||||
match evaluation_result {
|
||||
Ok(result) => !result.may_apply(),
|
||||
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
|
||||
// since there can be instantiations of this goal that don't overflow and result in
|
||||
// success. This isn't much of a problem in the old solver, since we treat overflow
|
||||
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
|
||||
// but in the new solver, this is very important for correctness, since overflow
|
||||
// *must* be treated as ambiguity for completeness.
|
||||
Err(_overflow) => false,
|
||||
}
|
||||
})
|
||||
match evaluation_result {
|
||||
Ok(result) => !result.may_apply(),
|
||||
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
|
||||
// since there can be instantiations of this goal that don't overflow and result in
|
||||
// success. This isn't much of a problem in the old solver, since we treat overflow
|
||||
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
|
||||
// but in the new solver, this is very important for correctness, since overflow
|
||||
// *must* be treated as ambiguity for completeness.
|
||||
Err(_overflow) => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if both impls can be satisfied by a common type by considering whether
|
||||
|
|
@ -522,15 +526,13 @@ fn try_prove_negated_where_clause<'tcx>(
|
|||
// Without this, we over-eagerly register coherence ambiguity candidates when
|
||||
// impl candidates do exist.
|
||||
let ref infcx = root_infcx.fork_with_intercrate(false);
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
let mut fulfill_cx = FulfillmentCtxt::new(infcx);
|
||||
|
||||
ocx.register_obligation(Obligation::new(
|
||||
infcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
negative_predicate,
|
||||
));
|
||||
if !ocx.select_all_or_error().is_empty() {
|
||||
fulfill_cx.register_predicate_obligation(
|
||||
infcx,
|
||||
Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, negative_predicate),
|
||||
);
|
||||
if !fulfill_cx.select_all_or_error(infcx).is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,11 +27,8 @@ use rustc_middle::ty::TypeFoldable;
|
|||
use rustc_middle::ty::Variance;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
|
||||
}
|
||||
|
||||
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||
#[extension(pub trait TraitEngineExt<'tcx>)]
|
||||
impl<'tcx> dyn TraitEngine<'tcx> {
|
||||
fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> {
|
||||
if infcx.next_trait_solver() {
|
||||
Box::new(NextFulfillmentCtxt::new(infcx))
|
||||
|
|
|
|||
|
|
@ -11,38 +11,8 @@ use super::ArgKind;
|
|||
|
||||
pub use rustc_infer::traits::error_reporting::*;
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
/// `report_arg_count_mismatch`.
|
||||
fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
|
||||
|
||||
/// Reports an error when the number of arguments needed by a
|
||||
/// trait match doesn't match the number that the expression
|
||||
/// provides.
|
||||
fn report_arg_count_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected_args: Vec<ArgKind>,
|
||||
found_args: Vec<ArgKind>,
|
||||
is_closure: bool,
|
||||
closure_pipe_span: Option<Span>,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
|
||||
/// in that order, and returns the generic type corresponding to the
|
||||
/// argument of that trait (corresponding to the closure arguments).
|
||||
fn type_implements_fn_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Given some node representing a fn-like thing in the HIR map,
|
||||
/// returns a span and `ArgKind` information that describes the
|
||||
/// arguments it expects. This can be supplied to
|
||||
|
|
@ -229,6 +199,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
|
||||
/// in that order, and returns the generic type corresponding to the
|
||||
/// argument of that trait (corresponding to the closure arguments).
|
||||
fn type_implements_fn_trait(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -23,24 +23,6 @@ use crate::errors::{
|
|||
|
||||
use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
|
||||
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
/*private*/
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Option<(DefId, GenericArgsRef<'tcx>)>;
|
||||
|
||||
/*private*/
|
||||
fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>;
|
||||
|
||||
fn on_unimplemented_note(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> OnUnimplementedNote;
|
||||
}
|
||||
|
||||
/// The symbols which are always allowed in a format string
|
||||
static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
|
||||
kw::SelfUpper,
|
||||
|
|
@ -56,7 +38,8 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
|
|||
sym::Trait,
|
||||
];
|
||||
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
|
|
|||
|
|
@ -106,279 +106,6 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// This trait is public to expose the diagnostics methods to clippy.
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
associated_item: Option<(&'static str, Ty<'tcx>)>,
|
||||
body_id: LocalDefId,
|
||||
);
|
||||
|
||||
fn suggest_dereferences(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn get_closure_name(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
err: &mut Diagnostic,
|
||||
msg: Cow<'static, str>,
|
||||
) -> Option<Symbol>;
|
||||
|
||||
fn suggest_fn_call(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn check_for_binding_assigned_block_without_tail_expression(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_add_clone_to_arg(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn extract_callable_info(
|
||||
&self,
|
||||
body_id: LocalDefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)>;
|
||||
|
||||
fn suggest_add_reference_to_arg(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
has_custom_message: bool,
|
||||
) -> bool;
|
||||
|
||||
fn suggest_borrowing_for_object_cast(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
object_ty: Ty<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_remove_reference(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic);
|
||||
|
||||
fn suggest_change_mut(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_semicolon_removal(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
|
||||
|
||||
fn suggest_impl_trait(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn point_at_returns_when_relevant(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
);
|
||||
|
||||
fn report_closure_arg_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
found: ty::PolyTraitRef<'tcx>,
|
||||
expected: ty::PolyTraitRef<'tcx>,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
found_node: Option<Node<'_>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn note_conflicting_fn_args(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
);
|
||||
|
||||
fn note_conflicting_closure_bounds(
|
||||
&self,
|
||||
cause: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_fully_qualified_path(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
item_def_id: DefId,
|
||||
span: Span,
|
||||
trait_ref: DefId,
|
||||
);
|
||||
|
||||
fn maybe_note_obligation_cause_for_async_await(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn note_obligation_cause_for_async_await(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
interior_or_upvar_span: CoroutineInteriorOrUpvar,
|
||||
is_async: bool,
|
||||
outer_coroutine: Option<DefId>,
|
||||
trait_pred: ty::TraitPredicate<'tcx>,
|
||||
target_ty: Ty<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
next_code: Option<&ObligationCauseCode<'tcx>>,
|
||||
);
|
||||
|
||||
fn note_obligation_cause_code<T>(
|
||||
&self,
|
||||
body_id: LocalDefId,
|
||||
err: &mut Diagnostic,
|
||||
predicate: T,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cause_code: &ObligationCauseCode<'tcx>,
|
||||
obligated_types: &mut Vec<Ty<'tcx>>,
|
||||
seen_requirements: &mut FxHashSet<DefId>,
|
||||
) where
|
||||
T: ToPredicate<'tcx>;
|
||||
|
||||
/// Suggest to await before try: future? => future.await?
|
||||
fn suggest_await_before_try(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
);
|
||||
|
||||
fn suggest_floating_point_literal(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_derive(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_dereferencing_index(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_option_method_if_applicable(
|
||||
&self,
|
||||
failed_pred: ty::Predicate<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
);
|
||||
|
||||
fn note_function_argument_obligation(
|
||||
&self,
|
||||
body_id: LocalDefId,
|
||||
err: &mut Diagnostic,
|
||||
arg_hir_id: HirId,
|
||||
parent_code: &ObligationCauseCode<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
call_hir_id: HirId,
|
||||
);
|
||||
|
||||
fn look_for_iterator_item_mistakes(
|
||||
&self,
|
||||
assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
|
||||
typeck_results: &TypeckResults<'tcx>,
|
||||
type_diffs: &[TypeError<'tcx>],
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
path_segment: &hir::PathSegment<'_>,
|
||||
args: &[hir::Expr<'_>],
|
||||
err: &mut Diagnostic,
|
||||
);
|
||||
|
||||
fn point_at_chain(
|
||||
&self,
|
||||
expr: &hir::Expr<'_>,
|
||||
typeck_results: &TypeckResults<'tcx>,
|
||||
type_diffs: Vec<TypeError<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
);
|
||||
|
||||
fn probe_assoc_types_at_expr(
|
||||
&self,
|
||||
type_diffs: &[TypeError<'tcx>],
|
||||
span: Span,
|
||||
prev_ty: Ty<'tcx>,
|
||||
body_id: hir::HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Vec<Option<(Span, (DefId, Ty<'tcx>))>>;
|
||||
|
||||
fn suggest_convert_to_slice(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
candidate_impls: &[ImplCandidate<'tcx>],
|
||||
span: Span,
|
||||
);
|
||||
|
||||
fn explain_hrtb_projection(
|
||||
&self,
|
||||
diag: &mut Diagnostic,
|
||||
pred: ty::PolyTraitPredicate<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
);
|
||||
|
||||
fn suggest_desugaring_async_fn_in_trait(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
);
|
||||
}
|
||||
|
||||
fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) {
|
||||
(
|
||||
generics.tail_span_for_predicate_suggestion(),
|
||||
|
|
@ -509,7 +236,8 @@ pub fn suggest_restriction<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
@ -4830,11 +4558,14 @@ fn hint_missing_borrow<'tcx>(
|
|||
}
|
||||
|
||||
if !to_borrow.is_empty() {
|
||||
err.subdiagnostic(errors::AdjustSignatureBorrow::Borrow { to_borrow });
|
||||
err.subdiagnostic(infcx.dcx(), errors::AdjustSignatureBorrow::Borrow { to_borrow });
|
||||
}
|
||||
|
||||
if !remove_borrow.is_empty() {
|
||||
err.subdiagnostic(errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow });
|
||||
err.subdiagnostic(
|
||||
infcx.dcx(),
|
||||
errors::AdjustSignatureBorrow::RemoveBorrow { remove_borrow },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,78 +57,8 @@ use super::{
|
|||
|
||||
pub use rustc_infer::traits::error_reporting::*;
|
||||
|
||||
pub trait TypeErrCtxtExt<'tcx> {
|
||||
fn build_overflow_error<T>(
|
||||
&self,
|
||||
predicate: &T,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> DiagnosticBuilder<'tcx>
|
||||
where
|
||||
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
|
||||
|
||||
fn report_overflow_error<T>(
|
||||
&self,
|
||||
predicate: &T,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
mutate: impl FnOnce(&mut Diagnostic),
|
||||
) -> !
|
||||
where
|
||||
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
|
||||
|
||||
fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
|
||||
|
||||
fn report_fulfillment_errors(&self, errors: Vec<FulfillmentError<'tcx>>) -> ErrorGuaranteed;
|
||||
|
||||
fn report_overflow_obligation<T>(
|
||||
&self,
|
||||
obligation: &Obligation<'tcx, T>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> !
|
||||
where
|
||||
T: ToPredicate<'tcx> + Clone;
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
|
||||
|
||||
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
|
||||
|
||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||
/// then it should be the same as `obligation`.
|
||||
fn report_selection_error(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
root_obligation: &PredicateObligation<'tcx>,
|
||||
error: &SelectionError<'tcx>,
|
||||
) -> ErrorGuaranteed;
|
||||
|
||||
fn emit_specialized_closure_kind_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Option<ErrorGuaranteed>;
|
||||
|
||||
fn fn_arg_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed>;
|
||||
|
||||
fn try_conversion_context(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool;
|
||||
|
||||
fn report_const_param_not_wf(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
&self,
|
||||
mut errors: Vec<FulfillmentError<'tcx>>,
|
||||
|
|
@ -382,6 +312,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||
/// then it should be the same as `obligation`.
|
||||
fn report_selection_error(
|
||||
&self,
|
||||
mut obligation: PredicateObligation<'tcx>,
|
||||
|
|
@ -1393,209 +1326,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) trait InferCtxtPrivExt<'tcx> {
|
||||
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
|
||||
// `error` occurring implies that `cond` occurs.
|
||||
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
|
||||
|
||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed;
|
||||
|
||||
fn report_projection_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
error: &MismatchedProjectionTypes<'tcx>,
|
||||
) -> ErrorGuaranteed;
|
||||
|
||||
fn maybe_detailed_projection_msg(
|
||||
&self,
|
||||
pred: ty::ProjectionPredicate<'tcx>,
|
||||
normalized_ty: ty::Term<'tcx>,
|
||||
expected_ty: ty::Term<'tcx>,
|
||||
) -> Option<String>;
|
||||
|
||||
fn fuzzy_match_tys(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
ignoring_lifetimes: bool,
|
||||
) -> Option<CandidateSimilarity>;
|
||||
|
||||
fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str;
|
||||
|
||||
fn find_similar_impl_candidates(
|
||||
&self,
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> Vec<ImplCandidate<'tcx>>;
|
||||
|
||||
fn report_similar_impl_candidates(
|
||||
&self,
|
||||
impl_candidates: &[ImplCandidate<'tcx>],
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
body_def_id: LocalDefId,
|
||||
err: &mut Diagnostic,
|
||||
other: bool,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn report_similar_impl_candidates_for_root_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
||||
body_def_id: LocalDefId,
|
||||
err: &mut Diagnostic,
|
||||
);
|
||||
|
||||
/// Gets the parent trait chain start
|
||||
fn get_parent_trait_ref(
|
||||
&self,
|
||||
code: &ObligationCauseCode<'tcx>,
|
||||
) -> Option<(Ty<'tcx>, Option<Span>)>;
|
||||
|
||||
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
|
||||
/// with the same path as `trait_ref`, a help message about
|
||||
/// a probable version mismatch is added to `err`
|
||||
fn note_version_mismatch(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
trait_ref: &ty::PolyTraitRef<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
|
||||
/// `trait_ref`.
|
||||
///
|
||||
/// For this to work, `new_self_ty` must have no escaping bound variables.
|
||||
fn mk_trait_obligation_with_new_self_ty(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||
) -> PredicateObligation<'tcx>;
|
||||
|
||||
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed;
|
||||
|
||||
fn predicate_can_apply(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
pred: ty::PolyTraitPredicate<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
|
||||
|
||||
fn suggest_unsized_bound_if_applicable(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
);
|
||||
|
||||
fn annotate_source_of_ambiguity(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
impls: &[ambiguity::Ambiguity],
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
);
|
||||
|
||||
fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
|
||||
|
||||
fn maybe_indirection_for_unsized(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
item: &'tcx Item<'tcx>,
|
||||
param: &'tcx GenericParam<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn is_recursive_obligation(
|
||||
&self,
|
||||
obligated_types: &mut Vec<Ty<'tcx>>,
|
||||
cause_code: &ObligationCauseCode<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn get_standard_error_message(
|
||||
&self,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
message: Option<String>,
|
||||
predicate_is_const: bool,
|
||||
append_const_msg: Option<AppendConstMessage>,
|
||||
post_message: String,
|
||||
) -> String;
|
||||
|
||||
fn get_safe_transmute_error_and_reason(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
) -> GetSafeTransmuteErrorAndReason;
|
||||
|
||||
fn add_tuple_trait_message(
|
||||
&self,
|
||||
obligation_cause_code: &ObligationCauseCode<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
);
|
||||
|
||||
fn try_to_add_help_message(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
is_fn_trait: bool,
|
||||
suggested: bool,
|
||||
unsatisfied_const: bool,
|
||||
);
|
||||
|
||||
fn add_help_message_for_fn_trait(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
implemented_kind: ty::ClosureKind,
|
||||
params: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
);
|
||||
|
||||
fn maybe_add_note_for_unsatisfied_const(
|
||||
&self,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
) -> UnsatisfiedConst;
|
||||
|
||||
fn report_closure_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
closure_def_id: DefId,
|
||||
found_kind: ty::ClosureKind,
|
||||
kind: ty::ClosureKind,
|
||||
trait_prefix: &'static str,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn report_cyclic_signature_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
terr: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn report_opaque_type_auto_trait_leakage(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn report_signature_mismatch_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
span: Span,
|
||||
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
|
||||
|
||||
fn report_not_const_evaluatable_error(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)]
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
|
||||
// `error` occurring implies that `cond` occurs.
|
||||
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
|
||||
|
|
@ -2414,6 +2146,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
suggested
|
||||
}
|
||||
|
||||
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
|
||||
/// `trait_ref`.
|
||||
///
|
||||
/// For this to work, `new_self_ty` must have no escaping bound variables.
|
||||
fn mk_trait_obligation_with_new_self_ty(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -11,25 +11,6 @@ pub use rustc_middle::traits::query::OutlivesBound;
|
|||
|
||||
pub type BoundsCompat<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
|
||||
pub trait InferCtxtExt<'a, 'tcx> {
|
||||
/// Do *NOT* call this directly.
|
||||
fn implied_bounds_tys_compat(
|
||||
&'a self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
compat: bool,
|
||||
) -> BoundsCompat<'a, 'tcx>;
|
||||
|
||||
/// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
|
||||
/// with `compat` set to `true`, otherwise `false`.
|
||||
fn implied_bounds_tys(
|
||||
&'a self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: LocalDefId,
|
||||
tys: &'a FxIndexSet<Ty<'tcx>>,
|
||||
) -> Bounds<'a, 'tcx>;
|
||||
}
|
||||
|
||||
/// Implied bounds are region relationships that we deduce
|
||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||
|
|
@ -130,7 +111,9 @@ fn implied_outlives_bounds<'a, 'tcx>(
|
|||
bounds
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'a, 'tcx>)]
|
||||
impl<'a, 'tcx: 'a> InferCtxt<'tcx> {
|
||||
/// Do *NOT* call this directly.
|
||||
fn implied_bounds_tys_compat(
|
||||
&'a self,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
|
|
@ -142,6 +125,8 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
|
|||
.flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, *ty, compat))
|
||||
}
|
||||
|
||||
/// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
|
||||
/// with `compat` set to `true`, otherwise `false`.
|
||||
fn implied_bounds_tys(
|
||||
&'a self,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
|
|
|
|||
|
|
@ -52,12 +52,22 @@ pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>;
|
|||
|
||||
pub(super) struct InProgress;
|
||||
|
||||
pub trait NormalizeExt<'tcx> {
|
||||
#[extension(pub trait NormalizeExt<'tcx>)]
|
||||
impl<'tcx> At<'_, 'tcx> {
|
||||
/// Normalize a value using the `AssocTypeNormalizer`.
|
||||
///
|
||||
/// This normalization should be used when the type contains inference variables or the
|
||||
/// projection may be fallible.
|
||||
fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> InferOk<'tcx, T>;
|
||||
fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
|
||||
if self.infcx.next_trait_solver() {
|
||||
InferOk { value, obligations: Vec::new() }
|
||||
} else {
|
||||
let mut selcx = SelectionContext::new(self.infcx);
|
||||
let Normalized { value, obligations } =
|
||||
normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
|
||||
InferOk { value, obligations }
|
||||
}
|
||||
}
|
||||
|
||||
/// Deeply normalizes `value`, replacing all aliases which can by normalized in
|
||||
/// the current environment. In the new solver this errors in case normalization
|
||||
|
|
@ -73,25 +83,6 @@ pub trait NormalizeExt<'tcx> {
|
|||
/// existing fulfillment context in the old solver. Once we also eagerly prove goals with
|
||||
/// the old solver or have removed the old solver, remove `traits::fully_normalize` and
|
||||
/// rename this function to `At::fully_normalize`.
|
||||
fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
value: T,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
) -> Result<T, Vec<FulfillmentError<'tcx>>>;
|
||||
}
|
||||
|
||||
impl<'tcx> NormalizeExt<'tcx> for At<'_, 'tcx> {
|
||||
fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
|
||||
if self.infcx.next_trait_solver() {
|
||||
InferOk { value, obligations: Vec::new() }
|
||||
} else {
|
||||
let mut selcx = SelectionContext::new(self.infcx);
|
||||
let Normalized { value, obligations } =
|
||||
normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
|
||||
InferOk { value, obligations }
|
||||
}
|
||||
}
|
||||
|
||||
fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
value: T,
|
||||
|
|
|
|||
|
|
@ -4,32 +4,8 @@ use crate::infer::canonical::OriginalQueryValues;
|
|||
use crate::infer::InferCtxt;
|
||||
use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
|
||||
|
||||
fn predicate_must_hold_considering_regions(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
|
||||
|
||||
fn evaluate_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError>;
|
||||
|
||||
// Helper function that canonicalizes and runs the query. If an
|
||||
// overflow results, we re-run it in the local context so we can
|
||||
// report a nice error.
|
||||
/*crate*/
|
||||
fn evaluate_obligation_no_overflow(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> EvaluationResult;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
#[extension(pub trait InferCtxtExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
/// Evaluates whether the predicate can be satisfied (by any means)
|
||||
/// in the given `ParamEnv`.
|
||||
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||
|
|
@ -114,9 +90,9 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper function that canonicalizes and runs the query. If an
|
||||
// overflow results, we re-run it in the local context so we can
|
||||
// report a nice error.
|
||||
/// Helper function that canonicalizes and runs the query. If an
|
||||
/// overflow results, we re-run it in the local context so we can
|
||||
/// report a nice error.
|
||||
fn evaluate_obligation_no_overflow(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
|
|
|||
|
|
@ -22,20 +22,8 @@ use super::NoSolution;
|
|||
|
||||
pub use rustc_middle::traits::query::NormalizationResult;
|
||||
|
||||
pub trait QueryNormalizeExt<'tcx> {
|
||||
/// Normalize a value using the `QueryNormalizer`.
|
||||
///
|
||||
/// This normalization should *only* be used when the projection does not
|
||||
/// have possible ambiguity or may not be well-formed.
|
||||
///
|
||||
/// After codegen, when lifetimes do not matter, it is preferable to instead
|
||||
/// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
|
||||
fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
|
||||
#[extension(pub trait QueryNormalizeExt<'tcx>)]
|
||||
impl<'cx, 'tcx> At<'cx, 'tcx> {
|
||||
/// Normalize `value` in the context of the inference context,
|
||||
/// yielding a resulting type, or an error if `value` cannot be
|
||||
/// normalized. If you don't care about regions, you should prefer
|
||||
|
|
@ -49,6 +37,12 @@ impl<'cx, 'tcx> QueryNormalizeExt<'tcx> for At<'cx, 'tcx> {
|
|||
/// normalizing, but for now should be used only when we actually
|
||||
/// know that normalization will succeed, since error reporting
|
||||
/// and other details are still "under development".
|
||||
///
|
||||
/// This normalization should *only* be used when the projection does not
|
||||
/// have possible ambiguity or may not be well-formed.
|
||||
///
|
||||
/// After codegen, when lifetimes do not matter, it is preferable to instead
|
||||
/// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure.
|
||||
fn query_normalize<T>(self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -33,20 +33,8 @@ enum Inserted<'tcx> {
|
|||
ShouldRecurseOn(DefId),
|
||||
}
|
||||
|
||||
trait ChildrenExt<'tcx> {
|
||||
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
|
||||
fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
|
||||
|
||||
fn insert(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
simplified_self: Option<SimplifiedType>,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Inserted<'tcx>, OverlapError<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx> ChildrenExt<'tcx> for Children {
|
||||
#[extension(trait ChildrenExt<'tcx>)]
|
||||
impl<'tcx> Children {
|
||||
/// Insert an impl into this set of children without comparing to any existing impls.
|
||||
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
|
||||
|
|
@ -247,22 +235,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub trait GraphExt<'tcx> {
|
||||
/// Insert a local impl into the specialization graph. If an existing impl
|
||||
/// conflicts with it (has overlap, but neither specializes the other),
|
||||
/// information about the area of overlap is returned in the `Err`.
|
||||
fn insert(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
overlap_mode: OverlapMode,
|
||||
) -> Result<Option<FutureCompatOverlapError<'tcx>>, OverlapError<'tcx>>;
|
||||
|
||||
/// Insert cached metadata mapping from a child impl back to its parent.
|
||||
fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId);
|
||||
}
|
||||
|
||||
impl<'tcx> GraphExt<'tcx> for Graph {
|
||||
#[extension(pub trait GraphExt<'tcx>)]
|
||||
impl<'tcx> Graph {
|
||||
/// Insert a local impl into the specialization graph. If an existing impl
|
||||
/// conflicts with it (has overlap, but neither specializes the other),
|
||||
/// information about the area of overlap is returned in the `Err`.
|
||||
|
|
|
|||
|
|
@ -5,15 +5,8 @@ use rustc_middle::ty::{self, Ty};
|
|||
|
||||
use crate::traits::{NormalizeExt, Obligation};
|
||||
|
||||
pub trait StructurallyNormalizeExt<'tcx> {
|
||||
fn structurally_normalize(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
fulfill_cx: &mut dyn TraitEngine<'tcx>,
|
||||
) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>;
|
||||
}
|
||||
|
||||
impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
|
||||
#[extension(pub trait StructurallyNormalizeExt<'tcx>)]
|
||||
impl<'tcx> At<'_, 'tcx> {
|
||||
fn structurally_normalize(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
|
|||
4
configure
vendored
4
configure
vendored
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
script="$(dirname $0)"/src/bootstrap/configure.py
|
||||
script="$(dirname "$0")"/src/bootstrap/configure.py
|
||||
|
||||
try() {
|
||||
cmd=$1
|
||||
|
|
@ -15,4 +15,4 @@ try python3 "$@"
|
|||
try python2.7 "$@"
|
||||
try python27 "$@"
|
||||
try python2 "$@"
|
||||
exec python $script "$@"
|
||||
exec python "$script" "$@"
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ pub struct Drain<
|
|||
drain_len: usize,
|
||||
// index into the logical array, not the physical one (always lies in [0..deque.len))
|
||||
idx: usize,
|
||||
// number of elements after the drain range
|
||||
tail_len: usize,
|
||||
// number of elements remaining after dropping the drain
|
||||
new_len: usize,
|
||||
remaining: usize,
|
||||
// Needed to make Drain covariant over T
|
||||
_marker: PhantomData<&'a T>,
|
||||
|
|
@ -41,12 +41,12 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
|
|||
drain_len: usize,
|
||||
) -> Self {
|
||||
let orig_len = mem::replace(&mut deque.len, drain_start);
|
||||
let tail_len = orig_len - drain_start - drain_len;
|
||||
let new_len = orig_len - drain_len;
|
||||
Drain {
|
||||
deque: NonNull::from(deque),
|
||||
drain_len,
|
||||
idx: drain_start,
|
||||
tail_len,
|
||||
new_len,
|
||||
remaining: drain_len,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
|
|||
f.debug_tuple("Drain")
|
||||
.field(&self.drain_len)
|
||||
.field(&self.idx)
|
||||
.field(&self.tail_len)
|
||||
.field(&self.new_len)
|
||||
.field(&self.remaining)
|
||||
.finish()
|
||||
}
|
||||
|
|
@ -95,70 +95,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
|||
fn drop(&mut self) {
|
||||
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
|
||||
|
||||
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
|
||||
fn drop(&mut self) {
|
||||
if self.0.remaining != 0 {
|
||||
unsafe {
|
||||
// SAFETY: We just checked that `self.remaining != 0`.
|
||||
let (front, back) = self.0.as_slices();
|
||||
ptr::drop_in_place(front);
|
||||
ptr::drop_in_place(back);
|
||||
}
|
||||
}
|
||||
|
||||
let source_deque = unsafe { self.0.deque.as_mut() };
|
||||
|
||||
let drain_start = source_deque.len();
|
||||
let drain_len = self.0.drain_len;
|
||||
let drain_end = drain_start + drain_len;
|
||||
|
||||
let orig_len = self.0.tail_len + drain_end;
|
||||
|
||||
if T::IS_ZST {
|
||||
// no need to copy around any memory if T is a ZST
|
||||
source_deque.len = orig_len - drain_len;
|
||||
return;
|
||||
}
|
||||
|
||||
let head_len = drain_start;
|
||||
let tail_len = self.0.tail_len;
|
||||
|
||||
match (head_len, tail_len) {
|
||||
(0, 0) => {
|
||||
source_deque.head = 0;
|
||||
source_deque.len = 0;
|
||||
}
|
||||
(0, _) => {
|
||||
source_deque.head = source_deque.to_physical_idx(drain_len);
|
||||
source_deque.len = orig_len - drain_len;
|
||||
}
|
||||
(_, 0) => {
|
||||
source_deque.len = orig_len - drain_len;
|
||||
}
|
||||
_ => unsafe {
|
||||
if head_len <= tail_len {
|
||||
source_deque.wrap_copy(
|
||||
source_deque.head,
|
||||
source_deque.to_physical_idx(drain_len),
|
||||
head_len,
|
||||
);
|
||||
source_deque.head = source_deque.to_physical_idx(drain_len);
|
||||
source_deque.len = orig_len - drain_len;
|
||||
} else {
|
||||
source_deque.wrap_copy(
|
||||
source_deque.to_physical_idx(head_len + drain_len),
|
||||
source_deque.to_physical_idx(head_len),
|
||||
tail_len,
|
||||
);
|
||||
source_deque.len = orig_len - drain_len;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let guard = DropGuard(self);
|
||||
if guard.0.remaining != 0 {
|
||||
|
||||
if mem::needs_drop::<T>() && guard.0.remaining != 0 {
|
||||
unsafe {
|
||||
// SAFETY: We just checked that `self.remaining != 0`.
|
||||
let (front, back) = guard.0.as_slices();
|
||||
|
|
@ -172,6 +111,125 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
|||
}
|
||||
|
||||
// Dropping `guard` handles moving the remaining elements into place.
|
||||
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if mem::needs_drop::<T>() && self.0.remaining != 0 {
|
||||
unsafe {
|
||||
// SAFETY: We just checked that `self.remaining != 0`.
|
||||
let (front, back) = self.0.as_slices();
|
||||
ptr::drop_in_place(front);
|
||||
ptr::drop_in_place(back);
|
||||
}
|
||||
}
|
||||
|
||||
let source_deque = unsafe { self.0.deque.as_mut() };
|
||||
|
||||
let drain_len = self.0.drain_len;
|
||||
let new_len = self.0.new_len;
|
||||
|
||||
if T::IS_ZST {
|
||||
// no need to copy around any memory if T is a ZST
|
||||
source_deque.len = new_len;
|
||||
return;
|
||||
}
|
||||
|
||||
let head_len = source_deque.len; // #elements in front of the drain
|
||||
let tail_len = new_len - head_len; // #elements behind the drain
|
||||
|
||||
// Next, we will fill the hole left by the drain with as few writes as possible.
|
||||
// The code below handles the following control flow and reduces the amount of
|
||||
// branches under the assumption that `head_len == 0 || tail_len == 0`, i.e.
|
||||
// draining at the front or at the back of the dequeue is especially common.
|
||||
//
|
||||
// H = "head index" = `deque.head`
|
||||
// h = elements in front of the drain
|
||||
// d = elements in the drain
|
||||
// t = elements behind the drain
|
||||
//
|
||||
// Note that the buffer may wrap at any point and the wrapping is handled by
|
||||
// `wrap_copy` and `to_physical_idx`.
|
||||
//
|
||||
// Case 1: if `head_len == 0 && tail_len == 0`
|
||||
// Everything was drained, reset the head index back to 0.
|
||||
// H
|
||||
// [ . . . . . d d d d . . . . . ]
|
||||
// H
|
||||
// [ . . . . . . . . . . . . . . ]
|
||||
//
|
||||
// Case 2: else if `tail_len == 0`
|
||||
// Don't move data or the head index.
|
||||
// H
|
||||
// [ . . . h h h h d d d d . . . ]
|
||||
// H
|
||||
// [ . . . h h h h . . . . . . . ]
|
||||
//
|
||||
// Case 3: else if `head_len == 0`
|
||||
// Don't move data, but move the head index.
|
||||
// H
|
||||
// [ . . . d d d d t t t t . . . ]
|
||||
// H
|
||||
// [ . . . . . . . t t t t . . . ]
|
||||
//
|
||||
// Case 4: else if `tail_len <= head_len`
|
||||
// Move data, but not the head index.
|
||||
// H
|
||||
// [ . . h h h h d d d d t t . . ]
|
||||
// H
|
||||
// [ . . h h h h t t . . . . . . ]
|
||||
//
|
||||
// Case 5: else
|
||||
// Move data and the head index.
|
||||
// H
|
||||
// [ . . h h d d d d t t t t . . ]
|
||||
// H
|
||||
// [ . . . . . . h h t t t t . . ]
|
||||
|
||||
// When draining at the front (`.drain(..n)`) or at the back (`.drain(n..)`),
|
||||
// we don't need to copy any data. The number of elements copied would be 0.
|
||||
if head_len != 0 && tail_len != 0 {
|
||||
join_head_and_tail_wrapping(source_deque, drain_len, head_len, tail_len);
|
||||
// Marking this function as cold helps LLVM to eliminate it entirely if
|
||||
// this branch is never taken.
|
||||
// We use `#[cold]` instead of `#[inline(never)]`, because inlining this
|
||||
// function into the general case (`.drain(n..m)`) is fine.
|
||||
// See `tests/codegen/vecdeque-drain.rs` for a test.
|
||||
#[cold]
|
||||
fn join_head_and_tail_wrapping<T, A: Allocator>(
|
||||
source_deque: &mut VecDeque<T, A>,
|
||||
drain_len: usize,
|
||||
head_len: usize,
|
||||
tail_len: usize,
|
||||
) {
|
||||
// Pick whether to move the head or the tail here.
|
||||
let (src, dst, len);
|
||||
if head_len < tail_len {
|
||||
src = source_deque.head;
|
||||
dst = source_deque.to_physical_idx(drain_len);
|
||||
len = head_len;
|
||||
} else {
|
||||
src = source_deque.to_physical_idx(head_len + drain_len);
|
||||
dst = source_deque.to_physical_idx(head_len);
|
||||
len = tail_len;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
source_deque.wrap_copy(src, dst, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if new_len == 0 {
|
||||
// Special case: If the entire dequeue was drained, reset the head back to 0,
|
||||
// like `.clear()` does.
|
||||
source_deque.head = 0;
|
||||
} else if head_len < tail_len {
|
||||
// If we moved the head above, then we need to adjust the head index here.
|
||||
source_deque.head = source_deque.to_physical_idx(drain_len);
|
||||
}
|
||||
source_deque.len = new_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -485,10 +485,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
|||
// H := head
|
||||
// L := last element (`self.to_physical_idx(self.len - 1)`)
|
||||
//
|
||||
// H L
|
||||
// [o o o o o o o . ]
|
||||
// H L
|
||||
// A [o o o o o o o . . . . . . . . . ]
|
||||
// H L
|
||||
// [o o o o o o o o ]
|
||||
// H L
|
||||
// A [o o o o o o o o . . . . . . . . ]
|
||||
// L H
|
||||
// [o o o o o o o o ]
|
||||
// H L
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use core::iter::{
|
|||
TrustedRandomAccessNoCoerce,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||
use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||
use core::num::NonZero;
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
use core::ops::Deref;
|
||||
|
|
@ -200,27 +200,23 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
if T::IS_ZST {
|
||||
if self.ptr.as_ptr() == self.end as *mut _ {
|
||||
None
|
||||
} else {
|
||||
// `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
|
||||
// reducing the `end`.
|
||||
self.end = self.end.wrapping_byte_sub(1);
|
||||
|
||||
// Make up a value of this ZST.
|
||||
Some(unsafe { mem::zeroed() })
|
||||
let ptr = if T::IS_ZST {
|
||||
if self.ptr.as_ptr() == self.end as *mut T {
|
||||
return None;
|
||||
}
|
||||
// `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
|
||||
// reducing the `end`.
|
||||
self.end = self.end.wrapping_byte_sub(1);
|
||||
self.ptr
|
||||
} else {
|
||||
if self.ptr == non_null!(self.end, T) {
|
||||
None
|
||||
} else {
|
||||
let old = self.ptr;
|
||||
self.ptr = unsafe { old.add(1) };
|
||||
|
||||
Some(unsafe { ptr::read(old.as_ptr()) })
|
||||
return None;
|
||||
}
|
||||
}
|
||||
let old = self.ptr;
|
||||
self.ptr = unsafe { old.add(1) };
|
||||
old
|
||||
};
|
||||
Some(unsafe { ptr.read() })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -305,7 +301,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||
// Also note the implementation of `Self: TrustedRandomAccess` requires
|
||||
// that `T: Copy` so reading elements from the buffer doesn't invalidate
|
||||
// them for `Drop`.
|
||||
unsafe { if T::IS_ZST { mem::zeroed() } else { self.ptr.add(i).read() } }
|
||||
unsafe { self.ptr.add(i).read() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -314,23 +310,22 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
if T::IS_ZST {
|
||||
if self.end as *mut _ == self.ptr.as_ptr() {
|
||||
None
|
||||
} else {
|
||||
// See above for why 'ptr.offset' isn't used
|
||||
self.end = self.end.wrapping_byte_sub(1);
|
||||
|
||||
// Make up a value of this ZST.
|
||||
Some(unsafe { mem::zeroed() })
|
||||
if self.ptr.as_ptr() == self.end as *mut _ {
|
||||
return None;
|
||||
}
|
||||
// See above for why 'ptr.offset' isn't used
|
||||
self.end = self.end.wrapping_byte_sub(1);
|
||||
// Note that even though this is next_back() we're reading from `self.ptr`, not
|
||||
// `self.end`. We track our length using the byte offset from `self.ptr` to `self.end`,
|
||||
// so the end pointer may not be suitably aligned for T.
|
||||
Some(unsafe { ptr::read(self.ptr.as_ptr()) })
|
||||
} else {
|
||||
if non_null!(self.end, T) == self.ptr {
|
||||
None
|
||||
} else {
|
||||
let new_end = unsafe { non_null!(self.end, T).sub(1) };
|
||||
*non_null!(mut self.end, T) = new_end;
|
||||
|
||||
Some(unsafe { ptr::read(new_end.as_ptr()) })
|
||||
if self.ptr == non_null!(self.end, T) {
|
||||
return None;
|
||||
}
|
||||
unsafe {
|
||||
self.end = self.end.sub(1);
|
||||
Some(ptr::read(self.end))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -937,52 +937,68 @@ extern "rust-intrinsic" {
|
|||
#[rustc_nounwind]
|
||||
pub fn unreachable() -> !;
|
||||
|
||||
/// Informs the optimizer that a condition is always true.
|
||||
/// If the condition is false, the behavior is undefined.
|
||||
///
|
||||
/// No code is generated for this intrinsic, but the optimizer will try
|
||||
/// to preserve it (and its condition) between passes, which may interfere
|
||||
/// with optimization of surrounding code and reduce performance. It should
|
||||
/// not be used if the invariant can be discovered by the optimizer on its
|
||||
/// own, or if it does not enable any significant optimizations.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
|
||||
#[rustc_nounwind]
|
||||
pub fn assume(b: bool);
|
||||
}
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn likely(b: bool) -> bool;
|
||||
/// Informs the optimizer that a condition is always true.
|
||||
/// If the condition is false, the behavior is undefined.
|
||||
///
|
||||
/// No code is generated for this intrinsic, but the optimizer will try
|
||||
/// to preserve it (and its condition) between passes, which may interfere
|
||||
/// with optimization of surrounding code and reduce performance. It should
|
||||
/// not be used if the invariant can be discovered by the optimizer on its
|
||||
/// own, or if it does not enable any significant optimizations.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_stable(feature = "const_assume", since = "1.77.0")]
|
||||
#[rustc_nounwind]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||
pub const unsafe fn assume(b: bool) {
|
||||
if !b {
|
||||
// SAFETY: the caller must guarantee the argument is never `false`
|
||||
unsafe { unreachable() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn unlikely(b: bool) -> bool;
|
||||
/// Hints to the compiler that branch condition is likely to be true.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||
#[rustc_nounwind]
|
||||
pub const fn likely(b: bool) -> bool {
|
||||
b
|
||||
}
|
||||
|
||||
/// Hints to the compiler that branch condition is likely to be false.
|
||||
/// Returns the value passed to it.
|
||||
///
|
||||
/// Any use other than with `if` statements will probably not have an effect.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_const_unstable(feature = "const_likely", issue = "none")]
|
||||
#[unstable(feature = "core_intrinsics", issue = "none")]
|
||||
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
|
||||
#[rustc_nounwind]
|
||||
pub const fn unlikely(b: bool) -> bool {
|
||||
b
|
||||
}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
/// Executes a breakpoint trap, for inspection by a debugger.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::iter::{
|
|||
Cloned, Copied, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable, Map, TrustedFused,
|
||||
TrustedLen,
|
||||
};
|
||||
use crate::iter::{Once, OnceWith};
|
||||
use crate::iter::{Empty, Once, OnceWith};
|
||||
use crate::num::NonZero;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
use crate::result;
|
||||
|
|
@ -593,6 +593,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// See also the `OneShot` specialization below.
|
||||
impl<I, U> Iterator for FlattenCompat<I, U>
|
||||
where
|
||||
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
|
||||
|
|
@ -601,7 +602,7 @@ where
|
|||
type Item = U::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<U::Item> {
|
||||
default fn next(&mut self) -> Option<U::Item> {
|
||||
loop {
|
||||
if let elt @ Some(_) = and_then_or_clear(&mut self.frontiter, Iterator::next) {
|
||||
return elt;
|
||||
|
|
@ -614,7 +615,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
default fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
|
||||
let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
|
||||
let lo = flo.saturating_add(blo);
|
||||
|
|
@ -636,7 +637,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
default fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
Fold: FnMut(Acc, Self::Item) -> R,
|
||||
|
|
@ -653,7 +654,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where
|
||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
|
|
@ -669,7 +670,7 @@ where
|
|||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
default fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance<U: Iterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
|
||||
|
|
@ -686,7 +687,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
default fn count(self) -> usize {
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn count<U: Iterator>(acc: usize, iter: U) -> usize {
|
||||
|
|
@ -697,7 +698,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
default fn last(self) -> Option<Self::Item> {
|
||||
#[inline]
|
||||
fn last<U: Iterator>(last: Option<U::Item>, iter: U) -> Option<U::Item> {
|
||||
iter.last().or(last)
|
||||
|
|
@ -707,13 +708,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// See also the `OneShot` specialization below.
|
||||
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
|
||||
where
|
||||
I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
|
||||
U: DoubleEndedIterator,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<U::Item> {
|
||||
default fn next_back(&mut self) -> Option<U::Item> {
|
||||
loop {
|
||||
if let elt @ Some(_) = and_then_or_clear(&mut self.backiter, |b| b.next_back()) {
|
||||
return elt;
|
||||
|
|
@ -726,7 +728,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
default fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
Fold: FnMut(Acc, Self::Item) -> R,
|
||||
|
|
@ -743,7 +745,7 @@ where
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where
|
||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
|
|
@ -759,7 +761,7 @@ where
|
|||
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
default fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn advance<U: DoubleEndedIterator>(n: usize, iter: &mut U) -> ControlFlow<(), usize> {
|
||||
|
|
@ -841,3 +843,198 @@ fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option
|
|||
}
|
||||
x
|
||||
}
|
||||
|
||||
/// Specialization trait for iterator types that never return more than one item.
|
||||
///
|
||||
/// Note that we still have to deal with the possibility that the iterator was
|
||||
/// already exhausted before it came into our control.
|
||||
#[rustc_specialization_trait]
|
||||
trait OneShot {}
|
||||
|
||||
// These all have exactly one item, if not already consumed.
|
||||
impl<T> OneShot for Once<T> {}
|
||||
impl<F> OneShot for OnceWith<F> {}
|
||||
impl<T> OneShot for array::IntoIter<T, 1> {}
|
||||
impl<T> OneShot for option::IntoIter<T> {}
|
||||
impl<T> OneShot for option::Iter<'_, T> {}
|
||||
impl<T> OneShot for option::IterMut<'_, T> {}
|
||||
impl<T> OneShot for result::IntoIter<T> {}
|
||||
impl<T> OneShot for result::Iter<'_, T> {}
|
||||
impl<T> OneShot for result::IterMut<'_, T> {}
|
||||
|
||||
// These are always empty, which is fine to optimize too.
|
||||
impl<T> OneShot for Empty<T> {}
|
||||
impl<T> OneShot for array::IntoIter<T, 0> {}
|
||||
|
||||
// These adaptors never increase the number of items.
|
||||
// (There are more possible, but for now this matches BoundedSize above.)
|
||||
impl<I: OneShot> OneShot for Cloned<I> {}
|
||||
impl<I: OneShot> OneShot for Copied<I> {}
|
||||
impl<I: OneShot, P> OneShot for Filter<I, P> {}
|
||||
impl<I: OneShot, P> OneShot for FilterMap<I, P> {}
|
||||
impl<I: OneShot, F> OneShot for Map<I, F> {}
|
||||
|
||||
// Blanket impls pass this property through as well
|
||||
// (but we can't do `Box<I>` unless we expose this trait to alloc)
|
||||
impl<I: OneShot> OneShot for &mut I {}
|
||||
|
||||
#[inline]
|
||||
fn into_item<I>(inner: I) -> Option<I::Item>
|
||||
where
|
||||
I: IntoIterator<IntoIter: OneShot>,
|
||||
{
|
||||
inner.into_iter().next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flatten_one<I: IntoIterator<IntoIter: OneShot>, Acc>(
|
||||
mut fold: impl FnMut(Acc, I::Item) -> Acc,
|
||||
) -> impl FnMut(Acc, I) -> Acc {
|
||||
move |acc, inner| match inner.into_iter().next() {
|
||||
Some(item) => fold(acc, item),
|
||||
None => acc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_flatten_one<I: IntoIterator<IntoIter: OneShot>, Acc, R: Try<Output = Acc>>(
|
||||
mut fold: impl FnMut(Acc, I::Item) -> R,
|
||||
) -> impl FnMut(Acc, I) -> R {
|
||||
move |acc, inner| match inner.into_iter().next() {
|
||||
Some(item) => fold(acc, item),
|
||||
None => try { acc },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by_one<I>(n: NonZero<usize>, inner: I) -> Option<NonZero<usize>>
|
||||
where
|
||||
I: IntoIterator<IntoIter: OneShot>,
|
||||
{
|
||||
match inner.into_iter().next() {
|
||||
Some(_) => NonZero::new(n.get() - 1),
|
||||
None => Some(n),
|
||||
}
|
||||
}
|
||||
|
||||
// Specialization: When the inner iterator `U` never returns more than one item, the `frontiter` and
|
||||
// `backiter` states are a waste, because they'll always have already consumed their item. So in
|
||||
// this impl, we completely ignore them and just focus on `self.iter`, and we only call the inner
|
||||
// `U::next()` one time.
|
||||
//
|
||||
// It's mostly fine if we accidentally mix this with the more generic impls, e.g. by forgetting to
|
||||
// specialize one of the methods. If the other impl did set the front or back, we wouldn't see it
|
||||
// here, but it would be empty anyway; and if the other impl looked for a front or back that we
|
||||
// didn't bother setting, it would just see `None` (or a previous empty) and move on.
|
||||
//
|
||||
// An exception to that is `advance_by(0)` and `advance_back_by(0)`, where the generic impls may set
|
||||
// `frontiter` or `backiter` without consuming the item, so we **must** override those.
|
||||
impl<I, U> Iterator for FlattenCompat<I, U>
|
||||
where
|
||||
I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
|
||||
U: Iterator + OneShot,
|
||||
{
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<U::Item> {
|
||||
while let Some(inner) = self.iter.next() {
|
||||
if let item @ Some(_) = inner.into_iter().next() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (lower, upper) = self.iter.size_hint();
|
||||
match <I::Item as ConstSizeIntoIterator>::size() {
|
||||
Some(0) => (0, Some(0)),
|
||||
Some(1) => (lower, upper),
|
||||
_ => (0, upper),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
Fold: FnMut(Acc, Self::Item) -> R,
|
||||
R: Try<Output = Acc>,
|
||||
{
|
||||
self.iter.try_fold(init, try_flatten_one(fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where
|
||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.fold(init, flatten_one(fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
if let Some(n) = NonZero::new(n) {
|
||||
self.iter.try_fold(n, advance_by_one).map_or(Ok(()), Err)
|
||||
} else {
|
||||
// Just advance the outer iterator
|
||||
self.iter.advance_by(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.iter.filter_map(into_item).count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last(self) -> Option<Self::Item> {
|
||||
self.iter.filter_map(into_item).last()
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We don't actually care about `U: DoubleEndedIterator`, since forward and backward are the
|
||||
// same for a one-shot iterator, but we have to keep that to match the default specialization.
|
||||
impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
|
||||
where
|
||||
I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
|
||||
U: DoubleEndedIterator + OneShot,
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<U::Item> {
|
||||
while let Some(inner) = self.iter.next_back() {
|
||||
if let item @ Some(_) = inner.into_iter().next() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
Fold: FnMut(Acc, Self::Item) -> R,
|
||||
R: Try<Output = Acc>,
|
||||
{
|
||||
self.iter.try_rfold(init, try_flatten_one(fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
|
||||
where
|
||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||
{
|
||||
self.iter.rfold(init, flatten_one(fold))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||
if let Some(n) = NonZero::new(n) {
|
||||
self.iter.try_rfold(n, advance_by_one).map_or(Ok(()), Err)
|
||||
} else {
|
||||
// Just advance the outer iterator
|
||||
self.iter.advance_back_by(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3016,8 +3016,13 @@ impl<T> [T] {
|
|||
/// ```
|
||||
/// let mut v = [-5i32, 4, 2, -3, 1];
|
||||
///
|
||||
/// // Find the median
|
||||
/// v.select_nth_unstable(2);
|
||||
/// // Find the items less than or equal to the median, the median, and greater than or equal to
|
||||
/// // the median.
|
||||
/// let (lesser, median, greater) = v.select_nth_unstable(2);
|
||||
///
|
||||
/// assert!(lesser == [-3, -5] || lesser == [-5, -3]);
|
||||
/// assert_eq!(median, &mut 1);
|
||||
/// assert!(greater == [4, 2] || greater == [2, 4]);
|
||||
///
|
||||
/// // We are only guaranteed the slice will be one of the following, based on the way we sort
|
||||
/// // about the specified index.
|
||||
|
|
@ -3067,8 +3072,13 @@ impl<T> [T] {
|
|||
/// ```
|
||||
/// let mut v = [-5i32, 4, 2, -3, 1];
|
||||
///
|
||||
/// // Find the median as if the slice were sorted in descending order.
|
||||
/// v.select_nth_unstable_by(2, |a, b| b.cmp(a));
|
||||
/// // Find the items less than or equal to the median, the median, and greater than or equal to
|
||||
/// // the median as if the slice were sorted in descending order.
|
||||
/// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a));
|
||||
///
|
||||
/// assert!(lesser == [4, 2] || lesser == [2, 4]);
|
||||
/// assert_eq!(median, &mut 1);
|
||||
/// assert!(greater == [-3, -5] || greater == [-5, -3]);
|
||||
///
|
||||
/// // We are only guaranteed the slice will be one of the following, based on the way we sort
|
||||
/// // about the specified index.
|
||||
|
|
@ -3122,8 +3132,13 @@ impl<T> [T] {
|
|||
/// ```
|
||||
/// let mut v = [-5i32, 4, 1, -3, 2];
|
||||
///
|
||||
/// // Return the median as if the array were sorted according to absolute value.
|
||||
/// v.select_nth_unstable_by_key(2, |a| a.abs());
|
||||
/// // Find the items less than or equal to the median, the median, and greater than or equal to
|
||||
/// // the median as if the slice were sorted according to absolute value.
|
||||
/// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs());
|
||||
///
|
||||
/// assert!(lesser == [1, 2] || lesser == [2, 1]);
|
||||
/// assert_eq!(median, &mut -3);
|
||||
/// assert!(greater == [4, -5] || greater == [-5, 4]);
|
||||
///
|
||||
/// // We are only guaranteed the slice will be one of the following, based on the way we sort
|
||||
/// // about the specified index.
|
||||
|
|
|
|||
|
|
@ -212,3 +212,69 @@ fn test_flatten_last() {
|
|||
assert_eq!(it.advance_by(3), Ok(())); // 22..22
|
||||
assert_eq!(it.clone().last(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatten_one_shot() {
|
||||
// This could be `filter_map`, but people often do flatten options.
|
||||
let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7));
|
||||
assert_eq!(it.size_hint(), (0, Some(10)));
|
||||
assert_eq!(it.clone().count(), 8);
|
||||
assert_eq!(it.clone().last(), NonZero::new(2));
|
||||
|
||||
// sum -> fold
|
||||
let sum: i8 = it.clone().map(|n| n.get()).sum();
|
||||
assert_eq!(sum, 24);
|
||||
|
||||
// the product overflows at 6, remaining are 7,8,9 -> 1,2
|
||||
let one = NonZero::new(1i8).unwrap();
|
||||
let product = it.try_fold(one, |acc, x| acc.checked_mul(x));
|
||||
assert_eq!(product, None);
|
||||
assert_eq!(it.size_hint(), (0, Some(3)));
|
||||
assert_eq!(it.clone().count(), 2);
|
||||
|
||||
assert_eq!(it.advance_by(0), Ok(()));
|
||||
assert_eq!(it.clone().next(), NonZero::new(1));
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.clone().next(), NonZero::new(2));
|
||||
assert_eq!(it.advance_by(100), Err(NonZero::new(99).unwrap()));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatten_one_shot_rev() {
|
||||
let mut it = (0i8..10).flat_map(|i| NonZero::new(i % 7)).rev();
|
||||
assert_eq!(it.size_hint(), (0, Some(10)));
|
||||
assert_eq!(it.clone().count(), 8);
|
||||
assert_eq!(it.clone().last(), NonZero::new(1));
|
||||
|
||||
// sum -> Rev fold -> rfold
|
||||
let sum: i8 = it.clone().map(|n| n.get()).sum();
|
||||
assert_eq!(sum, 24);
|
||||
|
||||
// Rev try_fold -> try_rfold
|
||||
// the product overflows at 4, remaining are 3,2,1,0 -> 3,2,1
|
||||
let one = NonZero::new(1i8).unwrap();
|
||||
let product = it.try_fold(one, |acc, x| acc.checked_mul(x));
|
||||
assert_eq!(product, None);
|
||||
assert_eq!(it.size_hint(), (0, Some(4)));
|
||||
assert_eq!(it.clone().count(), 3);
|
||||
|
||||
// Rev advance_by -> advance_back_by
|
||||
assert_eq!(it.advance_by(0), Ok(()));
|
||||
assert_eq!(it.clone().next(), NonZero::new(3));
|
||||
assert_eq!(it.advance_by(1), Ok(()));
|
||||
assert_eq!(it.clone().next(), NonZero::new(2));
|
||||
assert_eq!(it.advance_by(100), Err(NonZero::new(98).unwrap()));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatten_one_shot_arrays() {
|
||||
let it = (0..10).flat_map(|i| [i]);
|
||||
assert_eq!(it.size_hint(), (10, Some(10)));
|
||||
assert_eq!(it.sum::<i32>(), 45);
|
||||
|
||||
let mut it = (0..10).flat_map(|_| -> [i32; 0] { [] });
|
||||
assert_eq!(it.size_hint(), (0, Some(0)));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,13 +318,33 @@ pub fn temp_dir() -> PathBuf {
|
|||
super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(target_vendor = "uwp"))]
|
||||
#[cfg(all(not(target_vendor = "uwp"), not(target_vendor = "win7")))]
|
||||
fn home_dir_crt() -> Option<PathBuf> {
|
||||
unsafe {
|
||||
// Defined in processthreadsapi.h.
|
||||
const CURRENT_PROCESS_TOKEN: usize = -4_isize as usize;
|
||||
|
||||
super::fill_utf16_buf(
|
||||
|buf, mut sz| {
|
||||
match c::GetUserProfileDirectoryW(
|
||||
ptr::invalid_mut(CURRENT_PROCESS_TOKEN),
|
||||
buf,
|
||||
&mut sz,
|
||||
) {
|
||||
0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0,
|
||||
0 => sz,
|
||||
_ => sz - 1, // sz includes the null terminator
|
||||
}
|
||||
},
|
||||
super::os2path,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "win7")]
|
||||
fn home_dir_crt() -> Option<PathBuf> {
|
||||
unsafe {
|
||||
// The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
|
||||
// instead of us having to go through these multiple steps to get a token. However this is
|
||||
// not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
|
||||
// we can simplify this code. See #90144 for details.
|
||||
use crate::sys::handle::Handle;
|
||||
|
||||
let me = c::GetCurrentProcess();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue