Skip to content

Commit b3cda16

Browse files
committed
Auto merge of #151701 - JonathanBrouwer:rollup-PvhvBqX, r=JonathanBrouwer
Rollup of 7 pull requests Successful merges: - #151290 (Recover from struct literals with placeholder or empty path) - #148187 (Remove uses of `&mut CmResolver`) - #151368 (Rustdoc performance improvements) - #151374 (some more rustc_borrowck cleanups) - #151536 (Fix sanitizer target builds on CI) - #151626 (Remove `Deref<Target = TyCtxt>` from `QueryCtxt`) - #151661 (Suggest changing `iter`/`into_iter` when the other was meant)
2 parents 4742769 + 9ad4ae8 commit b3cda16

File tree

30 files changed

+467
-109
lines changed

30 files changed

+467
-109
lines changed

compiler/rustc_borrowck/src/type_check/canonical.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
343343
return;
344344
}
345345

346-
// FIXME: Ideally MIR types are normalized, but this is not always true.
347-
let mir_ty = self.normalize(mir_ty, Locations::All(span));
346+
// This is a hack. `body.local_decls` are not necessarily normalized in the old
347+
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
348+
//
349+
// I am not sure of a test case where this actually matters. There is a similar
350+
// hack in `equate_inputs_and_outputs` which does have associated test cases.
351+
let mir_ty = match self.infcx.next_trait_solver() {
352+
true => mir_ty,
353+
false => self.normalize(mir_ty, Locations::All(span)),
354+
};
348355

349356
let cause = ObligationCause::dummy_with_span(span);
350357
let param_env = self.infcx.param_env;
@@ -353,6 +360,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
353360
ConstraintCategory::Boring,
354361
type_op::custom::CustomTypeOp::new(
355362
|ocx| {
363+
// The `AscribeUserType` query would normally emit a wf
364+
// obligation for the unnormalized user_ty here. This is
365+
// where the "incorrectly skips the WF checks we normally do"
366+
// happens
356367
let user_ty = ocx.normalize(&cause, param_env, user_ty);
357368
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
358369
Ok(())

compiler/rustc_borrowck/src/type_check/input_output.rs

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
126126
);
127127
}
128128

129+
// FIXME(BoxyUwU): This should probably be part of a larger borrowck dev-guide chapter
130+
//
131+
/// Enforce that the types of the locals corresponding to the inputs and output of
132+
/// the body are equal to those of the (normalized) signature.
133+
///
134+
/// This is necessary for two reasons:
135+
/// - Locals in the MIR all start out with `'erased` regions and then are replaced
136+
/// with unconstrained nll vars. If we have a function returning `&'a u32` then
137+
/// the local `_0: &'?10 u32` needs to have its region var equated with the nll
138+
/// var representing `'a`. i.e. borrow check must uphold that `'?10 = 'a`.
139+
/// - When computing the normalized signature we may introduce new unconstrained nll
140+
/// vars due to higher ranked where clauses ([#136547]). We then wind up with implied
141+
/// bounds involving these vars.
142+
///
143+
/// For this reason it is important that we equate with the *normalized* signature
144+
/// which was produced when computing implied bounds. If we do not do so then we will
145+
/// wind up with implied bounds on nll vars which cannot actually be used as the nll
146+
/// var never gets related to anything.
147+
///
148+
/// For 'closure-like' bodies this function effectively relates the *inferred* signature
149+
/// of the closure against the locals corresponding to the closure's inputs/output. It *does
150+
/// not* relate the user provided types for the signature to the locals, this is handled
151+
/// separately by: [`TypeChecker::check_signature_annotation`].
152+
///
153+
/// [#136547]: <https://www.github.com/rust-lang/rust/issues/136547>
129154
#[instrument(skip(self), level = "debug")]
130155
pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) {
131156
let (&normalized_output_ty, normalized_input_tys) =
@@ -173,38 +198,44 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
173198
);
174199
}
175200

176-
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
177-
let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty;
201+
// Equate expected output ty with the type of the RETURN_PLACE in MIR
202+
let mir_output_ty = self.body.return_ty();
178203
let output_span = self.body.local_decls[RETURN_PLACE].source_info.span;
179204
self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
180205
}
181206

182207
#[instrument(skip(self), level = "debug")]
183208
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
209+
if self.infcx.next_trait_solver() {
210+
return self
211+
.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
212+
.unwrap_or_else(|terr| {
213+
span_mirbug!(
214+
self,
215+
Location::START,
216+
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
217+
);
218+
});
219+
}
220+
221+
// This is a hack. `body.local_decls` are not necessarily normalized in the old
222+
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
223+
//
224+
// However, in most cases normalizing is unnecessary so we only do so if it may be
225+
// necessary for type equality to hold. This leads to some (very minor) performance
226+
// wins.
184227
if let Err(_) =
185228
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
186229
{
187-
// FIXME(jackh726): This is a hack. It's somewhat like
188-
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
189-
// like to normalize *before* inserting into `local_decls`, but
190-
// doing so ends up causing some other trouble.
191230
let b = self.normalize(b, Locations::All(span));
192-
193-
// Note: if we have to introduce new placeholders during normalization above, then we
194-
// won't have added those universes to the universe info, which we would want in
195-
// `relate_tys`.
196-
if let Err(terr) =
197-
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
198-
{
199-
span_mirbug!(
200-
self,
201-
Location::START,
202-
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
203-
a,
204-
b,
205-
terr
206-
);
207-
}
208-
}
231+
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
232+
.unwrap_or_else(|terr| {
233+
span_mirbug!(
234+
self,
235+
Location::START,
236+
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
237+
);
238+
});
239+
};
209240
}
210241
}

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,19 @@ pub(crate) fn type_check<'tcx>(
123123
known_type_outlives_obligations,
124124
} = free_region_relations::create(infcx, universal_regions, &mut constraints);
125125

126-
let pre_obligations = infcx.take_registered_region_obligations();
127-
assert!(
128-
pre_obligations.is_empty(),
129-
"there should be no incoming region obligations = {pre_obligations:#?}",
130-
);
131-
let pre_assumptions = infcx.take_registered_region_assumptions();
132-
assert!(
133-
pre_assumptions.is_empty(),
134-
"there should be no incoming region assumptions = {pre_assumptions:#?}",
135-
);
126+
{
127+
// Scope these variables so it's clear they're not used later
128+
let pre_obligations = infcx.take_registered_region_obligations();
129+
assert!(
130+
pre_obligations.is_empty(),
131+
"there should be no incoming region obligations = {pre_obligations:#?}",
132+
);
133+
let pre_assumptions = infcx.take_registered_region_assumptions();
134+
assert!(
135+
pre_assumptions.is_empty(),
136+
"there should be no incoming region assumptions = {pre_assumptions:#?}",
137+
);
138+
}
136139

137140
debug!(?normalized_inputs_and_output);
138141

compiler/rustc_middle/src/ty/util.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,8 @@ impl<'tcx> TyCtxt<'tcx> {
609609
/// have the same `DefKind`.
610610
///
611611
/// Note that closures have a `DefId`, but the closure *expression* also has a
612-
/// `HirId` that is located within the context where the closure appears (and, sadly,
613-
/// a corresponding `NodeId`, since those are not yet phased out). The parent of
614-
/// the closure's `DefId` will also be the context where it appears.
612+
/// `HirId` that is located within the context where the closure appears. The
613+
/// parent of the closure's `DefId` will also be the context where it appears.
615614
pub fn is_closure_like(self, def_id: DefId) -> bool {
616615
matches!(self.def_kind(def_id), DefKind::Closure)
617616
}

compiler/rustc_parse/messages.ftl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,9 +822,19 @@ parse_struct_literal_body_without_path =
822822
struct literal body without path
823823
.suggestion = you might have forgotten to add the struct literal inside the block
824824
825+
parse_struct_literal_body_without_path_late =
826+
struct literal body without path
827+
.label = struct name missing for struct literal
828+
.suggestion = add the correct type
829+
825830
parse_struct_literal_not_allowed_here = struct literals are not allowed here
826831
.suggestion = surround the struct literal with parentheses
827832
833+
parse_struct_literal_placeholder_path =
834+
placeholder `_` is not allowed for the path in struct literals
835+
.label = not allowed in struct literals
836+
.suggestion = replace it with the correct type
837+
828838
parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
829839
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
830840

compiler/rustc_parse/src/errors.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3684,3 +3684,22 @@ pub(crate) struct ImplReuseInherentImpl {
36843684
#[primary_span]
36853685
pub span: Span,
36863686
}
3687+
3688+
#[derive(Diagnostic)]
3689+
#[diag(parse_struct_literal_placeholder_path)]
3690+
pub(crate) struct StructLiteralPlaceholderPath {
3691+
#[primary_span]
3692+
#[label]
3693+
#[suggestion(applicability = "has-placeholders", code = "/* Type */", style = "verbose")]
3694+
pub span: Span,
3695+
}
3696+
3697+
#[derive(Diagnostic)]
3698+
#[diag(parse_struct_literal_body_without_path_late)]
3699+
pub(crate) struct StructLiteralWithoutPathLate {
3700+
#[primary_span]
3701+
#[label]
3702+
pub span: Span,
3703+
#[suggestion(applicability = "has-placeholders", code = "/* Type */ ", style = "verbose")]
3704+
pub suggestion_span: Span,
3705+
}

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,9 @@ impl<'a> Parser<'a> {
14681468
} else if this.check(exp!(OpenParen)) {
14691469
this.parse_expr_tuple_parens(restrictions)
14701470
} else if this.check(exp!(OpenBrace)) {
1471+
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1472+
return Ok(expr);
1473+
}
14711474
this.parse_expr_block(None, lo, BlockCheckMode::Default)
14721475
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
14731476
this.parse_expr_closure().map_err(|mut err| {
@@ -1542,6 +1545,9 @@ impl<'a> Parser<'a> {
15421545
} else if this.check_keyword(exp!(Let)) {
15431546
this.parse_expr_let(restrictions)
15441547
} else if this.eat_keyword(exp!(Underscore)) {
1548+
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1549+
return Ok(expr);
1550+
}
15451551
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
15461552
} else if this.token_uninterpolated_span().at_least_rust_2018() {
15471553
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
@@ -3698,6 +3704,45 @@ impl<'a> Parser<'a> {
36983704
}
36993705
}
37003706

3707+
fn maybe_recover_bad_struct_literal_path(
3708+
&mut self,
3709+
is_underscore_entry_point: bool,
3710+
) -> PResult<'a, Option<Box<Expr>>> {
3711+
if self.may_recover()
3712+
&& self.check_noexpect(&token::OpenBrace)
3713+
&& (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3714+
&& self.is_likely_struct_lit())
3715+
{
3716+
let span = if is_underscore_entry_point {
3717+
self.prev_token.span
3718+
} else {
3719+
self.token.span.shrink_to_lo()
3720+
};
3721+
3722+
self.bump(); // {
3723+
let expr = self.parse_expr_struct(
3724+
None,
3725+
Path::from_ident(Ident::new(kw::Underscore, span)),
3726+
false,
3727+
)?;
3728+
3729+
let guar = if is_underscore_entry_point {
3730+
self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
3731+
} else {
3732+
self.dcx()
3733+
.create_err(errors::StructLiteralWithoutPathLate {
3734+
span: expr.span,
3735+
suggestion_span: expr.span.shrink_to_lo(),
3736+
})
3737+
.emit()
3738+
};
3739+
3740+
Ok(Some(self.mk_expr_err(expr.span, guar)))
3741+
} else {
3742+
Ok(None)
3743+
}
3744+
}
3745+
37013746
pub(super) fn parse_struct_fields(
37023747
&mut self,
37033748
pth: ast::Path,

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ use rustc_span::def_id::LOCAL_CRATE;
3535

3636
use crate::QueryConfigRestored;
3737

38+
/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
39+
/// crate does not have direct access to [`TyCtxt`].
3840
#[derive(Copy, Clone)]
3941
pub struct QueryCtxt<'tcx> {
4042
pub tcx: TyCtxt<'tcx>,
@@ -47,15 +49,6 @@ impl<'tcx> QueryCtxt<'tcx> {
4749
}
4850
}
4951

50-
impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
51-
type Target = TyCtxt<'tcx>;
52-
53-
#[inline]
54-
fn deref(&self) -> &Self::Target {
55-
&self.tcx
56-
}
57-
}
58-
5952
impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
6053
type Deps = rustc_middle::dep_graph::DepsType;
6154
type DepContext = TyCtxt<'tcx>;
@@ -69,14 +62,16 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
6962
impl QueryContext for QueryCtxt<'_> {
7063
#[inline]
7164
fn jobserver_proxy(&self) -> &Proxy {
72-
&*self.jobserver_proxy
65+
&self.tcx.jobserver_proxy
7366
}
7467

7568
#[inline]
7669
fn next_job_id(self) -> QueryJobId {
7770
QueryJobId(
78-
NonZero::new(self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
79-
.unwrap(),
71+
NonZero::new(
72+
self.tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
73+
)
74+
.unwrap(),
8075
)
8176
}
8277

@@ -113,7 +108,8 @@ impl QueryContext for QueryCtxt<'_> {
113108
self,
114109
prev_dep_node_index: SerializedDepNodeIndex,
115110
) -> Option<QuerySideEffect> {
116-
self.query_system
111+
self.tcx
112+
.query_system
117113
.on_disk_cache
118114
.as_ref()
119115
.and_then(|c| c.load_side_effect(self.tcx, prev_dep_node_index))
@@ -122,7 +118,7 @@ impl QueryContext for QueryCtxt<'_> {
122118
#[inline(never)]
123119
#[cold]
124120
fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) {
125-
if let Some(c) = self.query_system.on_disk_cache.as_ref() {
121+
if let Some(c) = self.tcx.query_system.on_disk_cache.as_ref() {
126122
c.store_side_effect(dep_node_index, side_effect)
127123
}
128124
}
@@ -140,7 +136,9 @@ impl QueryContext for QueryCtxt<'_> {
140136
// as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
141137
// when accessing the `ImplicitCtxt`.
142138
tls::with_related_context(self.tcx, move |current_icx| {
143-
if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
139+
if depth_limit
140+
&& !self.tcx.recursion_limit().value_within_limit(current_icx.query_depth)
141+
{
144142
self.depth_limit_error(token);
145143
}
146144

@@ -161,16 +159,16 @@ impl QueryContext for QueryCtxt<'_> {
161159
let query_map = self.collect_active_jobs(true).expect("failed to collect active queries");
162160
let (info, depth) = job.find_dep_kind_root(query_map);
163161

164-
let suggested_limit = match self.recursion_limit() {
162+
let suggested_limit = match self.tcx.recursion_limit() {
165163
Limit(0) => Limit(2),
166164
limit => limit * 2,
167165
};
168166

169-
self.sess.dcx().emit_fatal(QueryOverflow {
167+
self.tcx.sess.dcx().emit_fatal(QueryOverflow {
170168
span: info.job.span,
171169
note: QueryOverflowNote { desc: info.query.description, depth },
172170
suggested_limit,
173-
crate_name: self.crate_name(LOCAL_CRATE),
171+
crate_name: self.tcx.crate_name(LOCAL_CRATE),
174172
});
175173
}
176174
}
@@ -367,7 +365,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
367365
Q: super::QueryConfigRestored<'tcx>,
368366
Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
369367
{
370-
let _timer = qcx.profiler().generic_activity_with_arg("encode_query_results_for", query.name());
368+
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());
371369

372370
assert!(query.query_state(qcx).all_inactive());
373371
let cache = query.query_cache(qcx);
@@ -389,8 +387,7 @@ pub(crate) fn query_key_hash_verify<'tcx>(
389387
query: impl QueryConfig<QueryCtxt<'tcx>>,
390388
qcx: QueryCtxt<'tcx>,
391389
) {
392-
let _timer =
393-
qcx.profiler().generic_activity_with_arg("query_key_hash_verify_for", query.name());
390+
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());
394391

395392
let mut map = UnordMap::default();
396393

0 commit comments

Comments
 (0)