Skip to content
Merged
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
100 changes: 89 additions & 11 deletions compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use tracing::{debug, instrument};

use super::reverse_sccs::ReverseSccGraph;
use crate::BorrowckInferCtxt;
use crate::consumers::RegionInferenceContext;
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
use crate::type_check::canonical::fully_perform_op_raw;
use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::type_check::{Locations, MirTypeckRegionConstraints};
use crate::universal_regions::{RegionClassification, UniversalRegions};
use crate::{BorrowckInferCtxt, CollectRegionConstraintsResult};

mod member_constraints;
mod region_ctxt;
Expand Down Expand Up @@ -126,6 +126,31 @@ fn nll_var_to_universal_region<'tcx>(
}
}

/// Record info needed to report the same name error later.
#[derive(Copy, Clone, Debug)]
pub(crate) struct UnexpectedHiddenRegion<'tcx> {
// The def_id of the body where this error occurs.
// Needed to handle region vars with their corresponding `infcx`.
def_id: LocalDefId,
opaque_type_key: OpaqueTypeKey<'tcx>,
hidden_type: ProvisionalHiddenType<'tcx>,
member_region: Region<'tcx>,
}

impl<'tcx> UnexpectedHiddenRegion<'tcx> {
pub(crate) fn to_error(self) -> (LocalDefId, DeferredOpaqueTypeError<'tcx>) {
let UnexpectedHiddenRegion { def_id, opaque_type_key, hidden_type, member_region } = self;
(
def_id,
DeferredOpaqueTypeError::UnexpectedHiddenRegion {
opaque_type_key,
hidden_type,
member_region,
},
)
}
}

/// Collect all defining uses of opaque types inside of this typeck root. This
/// expects the hidden type to be mapped to the definition parameters of the opaque
/// and errors if we end up with distinct hidden types.
Expand Down Expand Up @@ -176,11 +201,13 @@ struct DefiningUse<'tcx> {
/// It also means that this whole function is not really soundness critical as we
/// recheck all uses of the opaques regardless.
pub(crate) fn compute_definition_site_hidden_types<'tcx>(
def_id: LocalDefId,
infcx: &BorrowckInferCtxt<'tcx>,
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
constraints: &MirTypeckRegionConstraints<'tcx>,
location_map: Rc<DenseLocationMap>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
opaque_types: &[(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)],
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
let mut errors = Vec::new();
Expand All @@ -204,8 +231,10 @@ pub(crate) fn compute_definition_site_hidden_types<'tcx>(
// up equal to one of their choice regions and compute the actual hidden type of
// the opaque type definition. This is stored in the `root_cx`.
compute_definition_site_hidden_types_from_defining_uses(
def_id,
&rcx,
hidden_types,
unconstrained_hidden_type_errors,
&defining_uses,
&mut errors,
);
Expand Down Expand Up @@ -274,8 +303,10 @@ fn collect_defining_uses<'tcx>(

#[instrument(level = "debug", skip(rcx, hidden_types, defining_uses, errors))]
fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
def_id: LocalDefId,
rcx: &RegionCtxt<'_, 'tcx>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
defining_uses: &[DefiningUse<'tcx>],
errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
) {
Expand All @@ -293,16 +324,29 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
Ok(hidden_type) => hidden_type,
Err(r) => {
debug!("UnexpectedHiddenRegion: {:?}", r);
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
let guar = tcx.dcx().span_delayed_bug(
hidden_type.span,
"opaque type with non-universal region args",
);
ty::ProvisionalHiddenType::new_error(tcx, guar)
// If we're using the next solver, the unconstrained region may be resolved by a
// fully defining use from another body.
// So we don't generate error eagerly here.
if rcx.infcx.tcx.use_typing_mode_borrowck() {
unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion {
def_id,
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
continue;
} else {
errors.push(DeferredOpaqueTypeError::UnexpectedHiddenRegion {
hidden_type,
opaque_type_key,
member_region: ty::Region::new_var(tcx, r),
});
let guar = tcx.dcx().span_delayed_bug(
hidden_type.span,
"opaque type with non-universal region args",
);
ty::ProvisionalHiddenType::new_error(tcx, guar)
}
}
};

Expand Down Expand Up @@ -570,6 +614,40 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
errors
}

/// We handle `UnexpectedHiddenRegion` error lazily in the next solver as
/// there may be a fully defining use in another body.
///
/// In case such a defining use does not exist, we register an error here.
pub(crate) fn handle_unconstrained_hidden_type_errors<'tcx>(
tcx: TyCtxt<'tcx>,
hidden_types: &mut FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
unconstrained_hidden_type_errors: &mut Vec<UnexpectedHiddenRegion<'tcx>>,
collect_region_constraints_results: &mut FxIndexMap<
LocalDefId,
CollectRegionConstraintsResult<'tcx>,
>,
) {
let mut unconstrained_hidden_type_errors = std::mem::take(unconstrained_hidden_type_errors);
unconstrained_hidden_type_errors
.retain(|unconstrained| !hidden_types.contains_key(&unconstrained.opaque_type_key.def_id));

unconstrained_hidden_type_errors.iter().for_each(|t| {
tcx.dcx()
.span_delayed_bug(t.hidden_type.span, "opaque type with non-universal region args");
});

// `UnexpectedHiddenRegion` error contains region var which only makes sense in the
// corresponding `infcx`.
// So we need to insert the error to the body where it originates from.
for error in unconstrained_hidden_type_errors {
let (def_id, error) = error.to_error();
let Some(result) = collect_region_constraints_results.get_mut(&def_id) else {
unreachable!("the body should depend on opaques type if it has opaque use");
};
result.deferred_opaque_type_errors.push(error);
}
}

/// In theory `apply_definition_site_hidden_types` could introduce new uses of opaque types.
/// We do not check these new uses so this could be unsound.
///
Expand Down
20 changes: 18 additions & 2 deletions compiler/rustc_borrowck/src/root_cx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use smallvec::SmallVec;
use crate::consumers::BorrowckConsumer;
use crate::nll::compute_closure_requirements_modulo_opaques;
use crate::region_infer::opaque_types::{
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
handle_unconstrained_hidden_type_errors,
};
use crate::type_check::{Locations, constraint_conversion};
use crate::{
Expand All @@ -26,7 +27,12 @@ use crate::{
pub(super) struct BorrowCheckRootCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
root_def_id: LocalDefId,
/// This contains fully resolved hidden types or `ty::Error`.
hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
/// This contains unconstrained regions in hidden types.
/// Only used for deferred error reporting. See
/// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
/// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
/// their parents.
Expand All @@ -49,6 +55,7 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
tcx,
root_def_id,
hidden_types: Default::default(),
unconstrained_hidden_type_errors: Default::default(),
collect_region_constraints_results: Default::default(),
propagated_borrowck_results: Default::default(),
tainted_by_errors: None,
Expand Down Expand Up @@ -84,23 +91,32 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {

fn handle_opaque_type_uses(&mut self) {
let mut per_body_info = Vec::new();
for input in self.collect_region_constraints_results.values_mut() {
for (def_id, input) in &mut self.collect_region_constraints_results {
let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
&input.infcx,
&input.universal_region_relations,
&mut input.constraints,
);
input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
*def_id,
&input.infcx,
&input.universal_region_relations,
&input.constraints,
Rc::clone(&input.location_map),
&mut self.hidden_types,
&mut self.unconstrained_hidden_type_errors,
&opaque_types,
);
per_body_info.push((num_entries, opaque_types));
}

handle_unconstrained_hidden_type_errors(
self.tcx,
&mut self.hidden_types,
&mut self.unconstrained_hidden_type_errors,
&mut self.collect_region_constraints_results,
);

for (input, (opaque_types_storage_num_entries, opaque_types)) in
self.collect_region_constraints_results.values_mut().zip(per_body_info)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//@ check-pass
//@ compile-flags: -Znext-solver

// Regression test for trait-system-refactor-initiative#264.
//
// Some defining uses of opaque types can't constrain captured regions to universals.
// Previouly, we eagerly report error in this case.
// Now we report error only if there's no fully defining use from all bodies of the typeck root.
Copy link
Contributor

Choose a reason for hiding this comment

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

link the issue this is a regression test for


struct Inv<'a>(*mut &'a ());

fn mk_static() -> Inv<'static> { todo!() }

fn guide_closure_sig<'a>(f: impl FnOnce() -> Inv<'a>) {}

fn unconstrained_in_closure() -> impl Sized {
guide_closure_sig(|| unconstrained_in_closure());
mk_static()
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//@ compile-flags: -Znext-solver

// Just for diagnostics completeness.
// This is probably unimportant as we only report one error for such case in HIR typeck.

#![feature(type_alias_impl_trait)]

struct Invar<'a>(*mut &'a ());

fn mk_invar<'a>(a: &'a i32) -> Invar<'a> {
todo!()
}

type MultiUse = impl Sized;

#[define_opaque(MultiUse)]
fn capture_different_universals_not_on_bounds<'a, 'b, 'c>(a: &'a i32, b: &'b i32, c: &'c i32) {
let _ = || -> MultiUse {
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
mk_invar(a)
};
let _ = || -> MultiUse {
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
mk_invar(b)
};
let _ = || {
let _ = || -> MultiUse {
//~^ ERROR: hidden type for `MultiUse` captures lifetime that does not appear in bounds [E0700]
mk_invar(c)
};
};
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
--> $DIR/report-all-unexpected-hidden-errors.rs:18:19
|
LL | type MultiUse = impl Sized;
| ---------- opaque type defined here
...
LL | let _ = || -> MultiUse {
| ^^^^^^^^
|
= note: hidden type `Invar<'_>` captures lifetime `'_`

error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
--> $DIR/report-all-unexpected-hidden-errors.rs:22:19
|
LL | type MultiUse = impl Sized;
| ---------- opaque type defined here
...
LL | let _ = || -> MultiUse {
| ^^^^^^^^
|
= note: hidden type `Invar<'_>` captures lifetime `'_`

error[E0700]: hidden type for `MultiUse` captures lifetime that does not appear in bounds
--> $DIR/report-all-unexpected-hidden-errors.rs:27:23
|
LL | type MultiUse = impl Sized;
| ---------- opaque type defined here
...
LL | let _ = || -> MultiUse {
| ^^^^^^^^
|
= note: hidden type `Invar<'_>` captures lifetime `'_`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0700`.
Loading