Skip to content

support non-defining uses of opaques in borrowck #145244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 2 additions & 42 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt;

use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::graph;
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
use rustc_middle::mir::{
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
Expand Down Expand Up @@ -317,9 +316,8 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
loans_out_of_scope_at_location: FxIndexMap::default(),
};
for (loan_idx, loan_data) in borrow_set.iter_enumerated() {
let issuing_region = loan_data.region;
let loan_issued_at = loan_data.reserve_location;
prec.precompute_loans_out_of_scope(loan_idx, issuing_region, loan_issued_at);
prec.precompute_loans_out_of_scope(loan_idx, loan_issued_at);
}

prec.loans_out_of_scope_at_location
Expand All @@ -328,45 +326,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
/// Loans are in scope while they are live: whether they are contained within any live region.
/// In the location-insensitive analysis, a loan will be contained in a region if the issuing
/// region can reach it in the subset graph. So this is a reachability problem.
fn precompute_loans_out_of_scope(
&mut self,
loan_idx: BorrowIndex,
issuing_region: RegionVid,
loan_issued_at: Location,
) {
let sccs = self.regioncx.constraint_sccs();
let universal_regions = self.regioncx.universal_regions();

// The loop below was useful for the location-insensitive analysis but shouldn't be
// impactful in the location-sensitive case. It seems that it does, however, as without it a
// handful of tests fail. That likely means some liveness or outlives data related to choice
// regions is missing
// FIXME: investigate the impact of loans traversing applied member constraints and why some
// tests fail otherwise.
//
// We first handle the cases where the loan doesn't go out of scope, depending on the
// issuing region's successors.
for successor in graph::depth_first_search(&self.regioncx.region_graph(), issuing_region) {
// Via applied member constraints
//
// The issuing region can flow into the choice regions, and they are either:
// - placeholders or free regions themselves,
// - or also transitively outlive a free region.
//
// That is to say, if there are applied member constraints here, the loan escapes the
// function and cannot go out of scope. We could early return here.
//
// For additional insurance via fuzzing and crater, we verify that the constraint's min
// choice indeed escapes the function. In the future, we could e.g. turn this check into
// a debug assert and early return as an optimization.
let scc = sccs.scc(successor);
for constraint in self.regioncx.applied_member_constraints(scc) {
if universal_regions.is_universal_region(constraint.min_choice) {
return;
}
}
}

fn precompute_loans_out_of_scope(&mut self, loan_idx: BorrowIndex, loan_issued_at: Location) {
let first_block = loan_issued_at.block;
let first_bb_data = &self.body.basic_blocks[first_block];

Expand Down
54 changes: 52 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use rustc_middle::mir::{self, ConstraintCategory, Location};
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_span::Span;
use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;

use crate::MirBorrowckCtxt;
Expand All @@ -26,13 +28,61 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if errors.is_empty() {
return;
}

let infcx = self.infcx;
let mut guar = None;
let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
None;
for error in errors {
guar = Some(match error {
DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx),
DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(infcx),
DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => {
self.infcx.dcx().emit_err(err)
infcx.dcx().emit_err(err)
}
DeferredOpaqueTypeError::UnexpectedHiddenRegion {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just moved from RegionErrorKind::UnexpectedHiddenRegion

opaque_type_key,
hidden_type,
member_region,
} => {
let named_ty =
self.regioncx.name_regions_for_member_constraint(infcx.tcx, hidden_type.ty);
let named_key = self
.regioncx
.name_regions_for_member_constraint(infcx.tcx, opaque_type_key);
let named_region =
self.regioncx.name_regions_for_member_constraint(infcx.tcx, member_region);
let diag = unexpected_hidden_region_diagnostic(
infcx,
self.mir_def_id(),
hidden_type.span,
named_ty,
named_region,
named_key,
);
if last_unexpected_hidden_region
!= Some((hidden_type.span, named_ty, named_key))
{
last_unexpected_hidden_region =
Some((hidden_type.span, named_ty, named_key));
diag.emit()
} else {
diag.delay_as_bug()
}
}
DeferredOpaqueTypeError::NonDefiningUseInDefiningScope {
span,
opaque_type_key,
} => infcx.dcx().span_err(
span,
format!(
"non-defining use of `{}` in the defining scope",
Ty::new_opaque(
infcx.tcx,
opaque_type_key.def_id.to_def_id(),
opaque_type_key.args
)
),
),
});
}
let guar = guar.unwrap();
Expand Down
41 changes: 0 additions & 41 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use rustc_trait_selection::error_reporting::infer::nice_region_error::{
self, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, find_anon_type,
find_param_with_region, suggest_adding_lifetime_params,
};
use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
use tracing::{debug, instrument, trace};
Expand Down Expand Up @@ -105,18 +104,6 @@ pub(crate) enum RegionErrorKind<'tcx> {
/// A generic bound failure for a type test (`T: 'a`).
TypeTestError { type_test: TypeTest<'tcx> },

/// An unexpected hidden region for an opaque type.
UnexpectedHiddenRegion {
/// The span for the member constraint.
span: Span,
/// The hidden type.
hidden_ty: Ty<'tcx>,
/// The opaque type.
key: ty::OpaqueTypeKey<'tcx>,
/// The unexpected region.
member_region: ty::Region<'tcx>,
},

/// Higher-ranked subtyping error.
BoundUniversalRegionError {
/// The placeholder free region.
Expand Down Expand Up @@ -307,11 +294,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
// Iterate through all the errors, producing a diagnostic for each one. The diagnostics are
// buffered in the `MirBorrowckCtxt`.

let mut outlives_suggestion = OutlivesSuggestionBuilder::default();
let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> =
None;

for (nll_error, _) in nll_errors.into_iter() {
match nll_error {
RegionErrorKind::TypeTestError { type_test } => {
Expand Down Expand Up @@ -362,30 +345,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}

RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
let named_ty =
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, hidden_ty);
let named_key =
self.regioncx.name_regions_for_member_constraint(self.infcx.tcx, key);
let named_region = self
.regioncx
.name_regions_for_member_constraint(self.infcx.tcx, member_region);
let diag = unexpected_hidden_region_diagnostic(
self.infcx,
self.mir_def_id(),
span,
named_ty,
named_region,
named_key,
);
if last_unexpected_hidden_region != Some((span, named_ty, named_key)) {
self.buffer_error(diag);
last_unexpected_hidden_region = Some((span, named_ty, named_key));
} else {
diag.delay_as_bug();
}
}

RegionErrorKind::BoundUniversalRegionError {
longer_fr,
placeholder,
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_borrowck/src/handle_placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use tracing::debug;
use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
use crate::consumers::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
use crate::member_constraints::MemberConstraintSet;
use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
use crate::ty::VarianceDiagInfo;
Expand All @@ -30,7 +29,6 @@ pub(crate) struct LoweredConstraints<'tcx> {
pub(crate) constraint_sccs: Sccs<RegionVid, ConstraintSccIndex>,
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
pub(crate) scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
pub(crate) outlives_constraints: Frozen<OutlivesConstraintSet<'tcx>>,
pub(crate) type_tests: Vec<TypeTest<'tcx>>,
pub(crate) liveness_constraints: LivenessValues,
Expand Down Expand Up @@ -143,9 +141,10 @@ impl scc::Annotation for RegionTracker {

/// Determines if the region variable definitions contain
/// placeholders, and compute them for later use.
fn region_definitions<'tcx>(
universal_regions: &UniversalRegions<'tcx>,
// FIXME: This is also used by opaque type handling. Move it to a separate file.
pub(super) fn region_definitions<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
) -> (Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>, bool) {
let var_infos = infcx.get_region_var_infos();
// Create a RegionDefinition for each inference variable. This happens here because
Expand Down Expand Up @@ -209,14 +208,13 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
) -> LoweredConstraints<'tcx> {
let universal_regions = &universal_region_relations.universal_regions;
let (definitions, has_placeholders) = region_definitions(universal_regions, infcx);
let (definitions, has_placeholders) = region_definitions(infcx, universal_regions);

let MirTypeckRegionConstraints {
placeholder_indices,
placeholder_index_to_region: _,
liveness_constraints,
mut outlives_constraints,
member_constraints,
universe_causes,
type_tests,
} = constraints;
Expand All @@ -242,7 +240,6 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(

return LoweredConstraints {
type_tests,
member_constraints,
constraint_sccs,
scc_annotations: scc_annotations.scc_to_annotation,
definitions,
Expand Down Expand Up @@ -279,7 +276,6 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
constraint_sccs,
definitions,
scc_annotations,
member_constraints,
outlives_constraints: Frozen::freeze(outlives_constraints),
type_tests,
liveness_constraints,
Expand Down
19 changes: 14 additions & 5 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ mod dataflow;
mod def_use;
mod diagnostics;
mod handle_placeholders;
mod member_constraints;
mod nll;
mod path_utils;
mod place_ext;
Expand Down Expand Up @@ -335,9 +334,10 @@ fn do_mir_borrowck<'tcx>(

// Run the MIR type-checker.
let MirTypeckResults {
constraints,
mut constraints,
universal_region_relations,
opaque_type_values,
region_bound_pairs,
known_type_outlives_obligations,
polonius_context,
} = type_check::type_check(
root_cx,
Expand All @@ -352,6 +352,17 @@ fn do_mir_borrowck<'tcx>(
Rc::clone(&location_map),
);

let opaque_type_errors = region_infer::opaque_types::handle_opaque_type_uses(
root_cx,
&infcx,
&body,
&universal_region_relations,
&region_bound_pairs,
&known_type_outlives_obligations,
&location_map,
&mut constraints,
);

// Compute non-lexical lifetimes using the constraints computed
// by typechecking the MIR body.
let nll::NllOutput {
Expand All @@ -375,8 +386,6 @@ fn do_mir_borrowck<'tcx>(
polonius_context,
);

let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);

// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
Expand Down
Loading
Loading