Skip to content

Commit 5572759

Browse files
committed
Auto merge of #127796 - tgross35:rollup-ubo5hzb, r=tgross35
Rollup of 6 pull requests Successful merges: - #120990 (Suggest a borrow when using dbg) - #127047 (fix least significant digits of f128 associated constants) - #127709 (match lowering: Move `MatchPair` tree creation to its own module) - #127770 (Update books) - #127780 (Make sure trait def ids match before zipping args in `note_function_argument_obligation`) - #127795 (Fix typos in RELEASES.md) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2823cfb + 658a13d commit 5572759

File tree

19 files changed

+635
-280
lines changed

19 files changed

+635
-280
lines changed

RELEASES.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Stabilized APIs
6767
- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
6868
- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
6969
- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
70-
- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
70+
- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
7171
- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
7272
- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
7373
- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
@@ -91,9 +91,9 @@ Stabilized APIs
9191
- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
9292
- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
9393
- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
94-
- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
95-
- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
96-
- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
94+
- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
95+
- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
96+
- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
9797
- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
9898
- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
9999
- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+63-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![allow(rustc::untranslatable_diagnostic)]
55

66
use either::Either;
7-
use hir::ClosureKind;
7+
use hir::{ClosureKind, Path};
88
use rustc_data_structures::captures::Captures;
99
use rustc_data_structures::fx::FxIndexSet;
1010
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
1616
use rustc_middle::bug;
1717
use rustc_middle::hir::nested_filter::OnlyBodies;
1818
use rustc_middle::mir::tcx::PlaceTy;
19+
use rustc_middle::mir::VarDebugInfoContents;
1920
use rustc_middle::mir::{
2021
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
2122
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
546547
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
547548
}
548549
}
549-
if let Some(pat) = finder.pat {
550+
551+
self.suggest_ref_for_dbg_args(expr, place, move_span, err);
552+
553+
// it's useless to suggest inserting `ref` when the span don't comes from local code
554+
if let Some(pat) = finder.pat
555+
&& !move_span.is_dummy()
556+
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
557+
{
550558
*in_pattern = true;
551559
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
552560
if let Some(pat) = finder.parent_pat {
@@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
561569
}
562570
}
563571

572+
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
573+
// but here we actually do not check whether the macro name is `dbg!`
574+
// so that we may extend the scope a bit larger to cover more cases
575+
fn suggest_ref_for_dbg_args(
576+
&self,
577+
body: &hir::Expr<'_>,
578+
place: &Place<'tcx>,
579+
move_span: Span,
580+
err: &mut Diag<'infcx>,
581+
) {
582+
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
583+
VarDebugInfoContents::Place(ref p) => p == place,
584+
_ => false,
585+
});
586+
let arg_name = if let Some(var_info) = var_info {
587+
var_info.name
588+
} else {
589+
return;
590+
};
591+
struct MatchArgFinder {
592+
expr_span: Span,
593+
match_arg_span: Option<Span>,
594+
arg_name: Symbol,
595+
}
596+
impl Visitor<'_> for MatchArgFinder {
597+
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
598+
// dbg! is expanded into a match pattern, we need to find the right argument span
599+
if let hir::ExprKind::Match(expr, ..) = &e.kind
600+
&& let hir::ExprKind::Path(hir::QPath::Resolved(
601+
_,
602+
path @ Path { segments: [seg], .. },
603+
)) = &expr.kind
604+
&& seg.ident.name == self.arg_name
605+
&& self.expr_span.source_callsite().contains(expr.span)
606+
{
607+
self.match_arg_span = Some(path.span);
608+
}
609+
hir::intravisit::walk_expr(self, e);
610+
}
611+
}
612+
613+
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
614+
finder.visit_expr(body);
615+
if let Some(macro_arg_span) = finder.match_arg_span {
616+
err.span_suggestion_verbose(
617+
macro_arg_span.shrink_to_lo(),
618+
"consider borrowing instead of transferring ownership",
619+
"&",
620+
Applicability::MachineApplicable,
621+
);
622+
}
623+
}
624+
564625
fn report_use_of_uninitialized(
565626
&self,
566627
mpi: MovePathIndex,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
use rustc_middle::mir::*;
2+
use rustc_middle::thir::{self, *};
3+
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
4+
5+
use crate::build::expr::as_place::{PlaceBase, PlaceBuilder};
6+
use crate::build::matches::{FlatPat, MatchPair, TestCase};
7+
use crate::build::Builder;
8+
9+
impl<'a, 'tcx> Builder<'a, 'tcx> {
10+
/// Builds and returns [`MatchPair`] trees, one for each pattern in
11+
/// `subpatterns`, representing the fields of a [`PatKind::Variant`] or
12+
/// [`PatKind::Leaf`].
13+
///
14+
/// Used internally by [`MatchPair::new`].
15+
fn field_match_pairs<'pat>(
16+
&mut self,
17+
place: PlaceBuilder<'tcx>,
18+
subpatterns: &'pat [FieldPat<'tcx>],
19+
) -> Vec<MatchPair<'pat, 'tcx>> {
20+
subpatterns
21+
.iter()
22+
.map(|fieldpat| {
23+
let place =
24+
place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty));
25+
MatchPair::new(place, &fieldpat.pattern, self)
26+
})
27+
.collect()
28+
}
29+
30+
/// Builds [`MatchPair`] trees for the prefix/middle/suffix parts of an
31+
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
32+
///
33+
/// Used internally by [`MatchPair::new`].
34+
fn prefix_slice_suffix<'pat>(
35+
&mut self,
36+
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
37+
place: &PlaceBuilder<'tcx>,
38+
prefix: &'pat [Box<Pat<'tcx>>],
39+
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
40+
suffix: &'pat [Box<Pat<'tcx>>],
41+
) {
42+
let tcx = self.tcx;
43+
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
44+
match place_resolved.ty(&self.local_decls, tcx).ty.kind() {
45+
ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true),
46+
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
47+
}
48+
} else {
49+
((prefix.len() + suffix.len()).try_into().unwrap(), false)
50+
};
51+
52+
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
53+
let elem =
54+
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
55+
MatchPair::new(place.clone_project(elem), subpattern, self)
56+
}));
57+
58+
if let Some(subslice_pat) = opt_slice {
59+
let suffix_len = suffix.len() as u64;
60+
let subslice = place.clone_project(PlaceElem::Subslice {
61+
from: prefix.len() as u64,
62+
to: if exact_size { min_length - suffix_len } else { suffix_len },
63+
from_end: !exact_size,
64+
});
65+
match_pairs.push(MatchPair::new(subslice, subslice_pat, self));
66+
}
67+
68+
match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| {
69+
let end_offset = (idx + 1) as u64;
70+
let elem = ProjectionElem::ConstantIndex {
71+
offset: if exact_size { min_length - end_offset } else { end_offset },
72+
min_length,
73+
from_end: !exact_size,
74+
};
75+
let place = place.clone_project(elem);
76+
MatchPair::new(place, subpattern, self)
77+
}));
78+
}
79+
}
80+
81+
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
82+
/// Recursively builds a `MatchPair` tree for the given pattern and its
83+
/// subpatterns.
84+
pub(in crate::build) fn new(
85+
mut place_builder: PlaceBuilder<'tcx>,
86+
pattern: &'pat Pat<'tcx>,
87+
cx: &mut Builder<'_, 'tcx>,
88+
) -> MatchPair<'pat, 'tcx> {
89+
// Force the place type to the pattern's type.
90+
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
91+
if let Some(resolved) = place_builder.resolve_upvar(cx) {
92+
place_builder = resolved;
93+
}
94+
95+
// Only add the OpaqueCast projection if the given place is an opaque type and the
96+
// expected type from the pattern is not.
97+
let may_need_cast = match place_builder.base() {
98+
PlaceBase::Local(local) => {
99+
let ty =
100+
Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
101+
ty != pattern.ty && ty.has_opaque_types()
102+
}
103+
_ => true,
104+
};
105+
if may_need_cast {
106+
place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
107+
}
108+
109+
let place = place_builder.try_to_place(cx);
110+
let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None };
111+
let mut subpairs = Vec::new();
112+
let test_case = match pattern.kind {
113+
PatKind::Wild | PatKind::Error(_) => default_irrefutable(),
114+
115+
PatKind::Or { ref pats } => TestCase::Or {
116+
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
117+
},
118+
119+
PatKind::Range(ref range) => {
120+
if range.is_full_range(cx.tcx) == Some(true) {
121+
default_irrefutable()
122+
} else {
123+
TestCase::Range(range)
124+
}
125+
}
126+
127+
PatKind::Constant { value } => TestCase::Constant { value },
128+
129+
PatKind::AscribeUserType {
130+
ascription: thir::Ascription { ref annotation, variance },
131+
ref subpattern,
132+
..
133+
} => {
134+
// Apply the type ascription to the value at `match_pair.place`
135+
let ascription = place.map(|source| super::Ascription {
136+
annotation: annotation.clone(),
137+
source,
138+
variance,
139+
});
140+
141+
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
142+
TestCase::Irrefutable { ascription, binding: None }
143+
}
144+
145+
PatKind::Binding { mode, var, ref subpattern, .. } => {
146+
let binding = place.map(|source| super::Binding {
147+
span: pattern.span,
148+
source,
149+
var_id: var,
150+
binding_mode: mode,
151+
});
152+
153+
if let Some(subpattern) = subpattern.as_ref() {
154+
// this is the `x @ P` case; have to keep matching against `P` now
155+
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
156+
}
157+
TestCase::Irrefutable { ascription: None, binding }
158+
}
159+
160+
PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
161+
// Apply a type ascription for the inline constant to the value at `match_pair.place`
162+
let ascription = place.map(|source| {
163+
let span = pattern.span;
164+
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
165+
let args = ty::InlineConstArgs::new(
166+
cx.tcx,
167+
ty::InlineConstArgsParts {
168+
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
169+
ty: cx.infcx.next_ty_var(span),
170+
},
171+
)
172+
.args;
173+
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
174+
def.to_def_id(),
175+
ty::UserArgs { args, user_self_ty: None },
176+
));
177+
let annotation = ty::CanonicalUserTypeAnnotation {
178+
inferred_ty: pattern.ty,
179+
span,
180+
user_ty: Box::new(user_ty),
181+
};
182+
super::Ascription { annotation, source, variance: ty::Contravariant }
183+
});
184+
185+
subpairs.push(MatchPair::new(place_builder, pattern, cx));
186+
TestCase::Irrefutable { ascription, binding: None }
187+
}
188+
189+
PatKind::Array { ref prefix, ref slice, ref suffix } => {
190+
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
191+
default_irrefutable()
192+
}
193+
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
194+
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
195+
196+
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
197+
default_irrefutable()
198+
} else {
199+
TestCase::Slice {
200+
len: prefix.len() + suffix.len(),
201+
variable_length: slice.is_some(),
202+
}
203+
}
204+
}
205+
206+
PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => {
207+
let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)`
208+
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
209+
210+
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
211+
i == variant_index || {
212+
(cx.tcx.features().exhaustive_patterns
213+
|| cx.tcx.features().min_exhaustive_patterns)
214+
&& !v
215+
.inhabited_predicate(cx.tcx, adt_def)
216+
.instantiate(cx.tcx, args)
217+
.apply_ignore_module(cx.tcx, cx.param_env)
218+
}
219+
}) && (adt_def.did().is_local()
220+
|| !adt_def.is_variant_list_non_exhaustive());
221+
if irrefutable {
222+
default_irrefutable()
223+
} else {
224+
TestCase::Variant { adt_def, variant_index }
225+
}
226+
}
227+
228+
PatKind::Leaf { ref subpatterns } => {
229+
subpairs = cx.field_match_pairs(place_builder, subpatterns);
230+
default_irrefutable()
231+
}
232+
233+
PatKind::Deref { ref subpattern } => {
234+
subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx));
235+
default_irrefutable()
236+
}
237+
238+
PatKind::DerefPattern { ref subpattern, mutability } => {
239+
// Create a new temporary for each deref pattern.
240+
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
241+
let temp = cx.temp(
242+
Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
243+
pattern.span,
244+
);
245+
subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
246+
TestCase::Deref { temp, mutability }
247+
}
248+
249+
PatKind::Never => TestCase::Never,
250+
};
251+
252+
MatchPair { place, test_case, subpairs, pattern }
253+
}
254+
}

0 commit comments

Comments
 (0)