Rollup merge of #152218 - adwinwhite:fix-mir-borrowck-opaque-handling-keep-all-errors, r=lcnr
Report unconstrained region in hidden types lazily Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/264 I didn't copy the mechanism of HIR typeck as I found that we just need to be lax in the unconstrained region case. It already ignores non-defining uses and invalid params. About tests, I'm having trouble coming up with more complex ones. 🙁 This fixes `ukanren` and `codecrafters-redis-rust` but not rust-lang/rust#151322 and rust-lang/rust#151323. I believe they are a [different problem](https://github.com/rust-lang/rust/issues/151322#issuecomment-3864656974). r? @lcnr
This commit is contained in:
commit
98e8f99bc0
5 changed files with 198 additions and 13 deletions
|
|
@ -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;
|
||||
|
|
@ -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.
|
||||
|
|
@ -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();
|
||||
|
|
@ -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,
|
||||
);
|
||||
|
|
@ -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>>,
|
||||
) {
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
@ -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.
|
||||
|
|
@ -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,
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
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() {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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…
Add table
Add a link
Reference in a new issue