Skip to content

Commit

Permalink
Auto merge of #111919 - matthiaskrgr:rollup-8qcdp0q, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #111121 (Work around `rust-analyzer` false-positive type errors)
 - #111759 (Leverage the interval property to precompute borrow kill points.)
 - #111841 (Run AST validation on match guards correctly)
 - #111862 (Split out opaque collection from from `type_of`)
 - #111863 (Don't skip mir typeck if body has errors)
 - #111903 (Migrate GUI colors test to original CSS color format)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed May 24, 2023
2 parents c373194 + 0cc987f commit 096309e
Show file tree
Hide file tree
Showing 15 changed files with 661 additions and 428 deletions.
5 changes: 2 additions & 3 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,11 +736,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
this.visit_expr(&arm.body);
this.visit_pat(&arm.pat);
walk_list!(this, visit_attribute, &arm.attrs);
if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
if let Some(guard) = &arm.guard {
this.with_let_management(None, |this, _| {
this.visit_expr(guard_expr)
this.visit_expr(guard)
});
return;
}
}
}
Expand Down
95 changes: 46 additions & 49 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
&mut self,
borrow_index: BorrowIndex,
borrow_region: RegionVid,
location: Location,
first_location: Location,
) {
// We visit one BB at a time. The complication is that we may start in the
// middle of the first BB visited (the one containing `location`), in which
// middle of the first BB visited (the one containing `first_location`), in which
// case we may have to later on process the first part of that BB if there
// is a path back to its start.

Expand All @@ -168,61 +168,58 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
// `visited` once they are added to `stack`, before they are actually
// processed, because this avoids the need to look them up again on
// completion.
self.visited.insert(location.block);
self.visited.insert(first_location.block);

let mut first_lo = location.statement_index;
let first_hi = self.body[location.block].statements.len();
let first_block = first_location.block;
let mut first_lo = first_location.statement_index;
let first_hi = self.body[first_block].statements.len();

self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi });
self.visit_stack.push(StackEntry { bb: first_block, lo: first_lo, hi: first_hi });

while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
// If we process the first part of the first basic block (i.e. we encounter that block
// for the second time), we no longer have to visit its successors again.
let mut finished_early = bb == location.block && hi != first_hi;
for i in lo..=hi {
let location = Location { block: bb, statement_index: i };
'preorder: while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
if let Some(kill_stmt) =
self.regioncx.first_non_contained_inclusive(borrow_region, bb, lo, hi)
{
let kill_location = Location { block: bb, statement_index: kill_stmt };
// If region does not contain a point at the location, then add to list and skip
// successor locations.
if !self.regioncx.region_contains(borrow_region, location) {
debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
self.borrows_out_of_scope_at_location
.entry(location)
.or_default()
.push(borrow_index);
finished_early = true;
break;
}
debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
self.borrows_out_of_scope_at_location
.entry(kill_location)
.or_default()
.push(borrow_index);
continue 'preorder;
}

if !finished_early {
// Add successor BBs to the work list, if necessary.
let bb_data = &self.body[bb];
debug_assert!(hi == bb_data.statements.len());
for succ_bb in bb_data.terminator().successors() {
if !self.visited.insert(succ_bb) {
if succ_bb == location.block && first_lo > 0 {
// `succ_bb` has been seen before. If it wasn't
// fully processed, add its first part to `stack`
// for processing.
self.visit_stack.push(StackEntry {
bb: succ_bb,
lo: 0,
hi: first_lo - 1,
});

// And update this entry with 0, to represent the
// whole BB being processed.
first_lo = 0;
}
} else {
// succ_bb hasn't been seen before. Add it to
// `stack` for processing.
self.visit_stack.push(StackEntry {
bb: succ_bb,
lo: 0,
hi: self.body[succ_bb].statements.len(),
});
// If we process the first part of the first basic block (i.e. we encounter that block
// for the second time), we no longer have to visit its successors again.
if bb == first_block && hi != first_hi {
continue;
}

// Add successor BBs to the work list, if necessary.
let bb_data = &self.body[bb];
debug_assert!(hi == bb_data.statements.len());
for succ_bb in bb_data.terminator().successors() {
if !self.visited.insert(succ_bb) {
if succ_bb == first_block && first_lo > 0 {
// `succ_bb` has been seen before. If it wasn't
// fully processed, add its first part to `stack`
// for processing.
self.visit_stack.push(StackEntry { bb: succ_bb, lo: 0, hi: first_lo - 1 });

// And update this entry with 0, to represent the
// whole BB being processed.
first_lo = 0;
}
} else {
// succ_bb hasn't been seen before. Add it to
// `stack` for processing.
self.visit_stack.push(StackEntry {
bb: succ_bb,
lo: 0,
hi: self.body[succ_bb].statements.len(),
});
}
}
}
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
TerminatorKind,
};
Expand Down Expand Up @@ -598,6 +598,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.scc_values.contains(scc, p)
}

/// Returns the lowest statement index in `start..=end` which is not contained by `r`.
///
/// Panics if called before `solve()` executes.
pub(crate) fn first_non_contained_inclusive(
&self,
r: RegionVid,
block: BasicBlock,
start: usize,
end: usize,
) -> Option<usize> {
let scc = self.constraint_sccs.scc(r);
self.scc_values.first_non_contained_inclusive(scc, block, start, end)
}

/// Returns access to the value of `r` for debugging purposes.
pub(crate) fn region_value_str(&self, r: RegionVid) -> String {
let scc = self.constraint_sccs.scc(r);
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,22 @@ impl<N: Idx> RegionValues<N> {
elem.contained_in_row(self, r)
}

/// Returns the lowest statement index in `start..=end` which is not contained by `r`.
pub(crate) fn first_non_contained_inclusive(
&self,
r: N,
block: BasicBlock,
start: usize,
end: usize,
) -> Option<usize> {
let row = self.points.row(r)?;
let block = self.elements.entry_point(block);
let start = block.plus(start);
let end = block.plus(end);
let first_unset = row.first_unset_in(start..=end)?;
Some(first_unset.index() - block.index())
}

/// `self[to] |= values[from]`, essentially: that is, take all the
/// elements for the region `from` from `values` and add them to
/// the region `to` in `self`.
Expand Down
36 changes: 9 additions & 27 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,10 @@ pub(crate) fn type_check<'mir, 'tcx>(
&mut borrowck_context,
);

let errors_reported = {
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);
verifier.errors_reported
};

if !errors_reported {
// if verifier failed, don't do further checks to avoid ICEs
checker.typeck_mir(body);
}
let mut verifier = TypeVerifier::new(&mut checker, promoted);
verifier.visit_body(&body);

checker.typeck_mir(body);
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
checker.check_signature_annotation(&body);

Expand Down Expand Up @@ -294,7 +287,6 @@ struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
last_span: Span,
errors_reported: bool,
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
Expand Down Expand Up @@ -383,13 +375,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
};
};

if !self.errors_reported {
let promoted_body = &self.promoted[promoted];
self.sanitize_promoted(promoted_body, location);
let promoted_body = &self.promoted[promoted];
self.sanitize_promoted(promoted_body, location);

let promoted_ty = promoted_body.return_ty();
check_err(self, promoted_body, ty, promoted_ty);
}
let promoted_ty = promoted_body.return_ty();
check_err(self, promoted_body, ty, promoted_ty);
} else {
self.cx.ascribe_user_type(
constant.literal.ty(),
Expand Down Expand Up @@ -483,9 +473,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
for local_decl in &body.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
}
if self.errors_reported {
return;
}
self.super_body(body);
}
}
Expand All @@ -495,7 +482,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
) -> Self {
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
TypeVerifier { promoted, last_span: cx.body.span, cx }
}

fn body(&self) -> &Body<'tcx> {
Expand Down Expand Up @@ -529,7 +516,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
if let Err(guar) = place_ty.ty.error_reported() {
assert!(self.errors_reported);
return PlaceTy::from_ty(self.tcx().ty_error(guar));
}
}
Expand Down Expand Up @@ -593,10 +579,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {

self.visit_body(&promoted_body);

if !self.errors_reported {
// if verifier failed, don't do further checks to avoid ICEs
self.cx.typeck_mir(promoted_body);
}
self.cx.typeck_mir(promoted_body);

self.cx.body = parent_body;
// Merge the outlives constraints back in, at the given location.
Expand Down Expand Up @@ -762,7 +745,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}

fn error(&mut self) -> Ty<'tcx> {
self.errors_reported = true;
self.tcx().ty_error_misc()
}

Expand Down
Loading

0 comments on commit 096309e

Please sign in to comment.