Auto merge of #109753 - compiler-errors:replenish-region-constraints, r=aliemjay
Clone region var origins instead of taking them in borrowck Fixes an issue with the new solver where reporting a borrow-checker error ICEs because it calls `InferCtxt::evaluate_obligation`. This also removes a handful of unnecessary `tcx.infer_ctxt().build()` calls that are only there to mitigate this same exact issue, but with the old solver. Fixes compiler-errors/next-solver-hir-issues#12. ---- This implements `@aliemjay's` solution where we just don't *take* the region constraints, but clone them. This potentially makes it easier to write a bug about taking region constraints twice or never at all, but again, not many folks are touching this code.
This commit is contained in:
commit
4396ceca05
6 changed files with 43 additions and 33 deletions
|
@ -10,7 +10,6 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
|
@ -643,11 +642,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
|
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
// Regions are already solved, so we must use a fresh InferCtxt,
|
self.infcx
|
||||||
// but the type has region variables, so erase those.
|
.type_implements_trait(default_trait, [ty], param_env)
|
||||||
tcx.infer_ctxt()
|
|
||||||
.build()
|
|
||||||
.type_implements_trait(default_trait, [tcx.erase_regions(ty)], param_env)
|
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -740,13 +736,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
|
fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||||
let infcx = tcx.infer_ctxt().build();
|
|
||||||
|
|
||||||
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
|
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
|
||||||
&& infcx
|
&& self.infcx
|
||||||
.type_implements_trait(
|
.type_implements_trait(
|
||||||
clone_trait_def,
|
clone_trait_def,
|
||||||
[tcx.erase_regions(ty)],
|
[ty],
|
||||||
self.param_env,
|
self.param_env,
|
||||||
)
|
)
|
||||||
.must_apply_modulo_regions()
|
.must_apply_modulo_regions()
|
||||||
|
@ -770,12 +764,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
.and_then(|def_id| tcx.hir().get_generics(def_id))
|
||||||
else { return; };
|
else { return; };
|
||||||
// Try to find predicates on *generic params* that would allow copying `ty`
|
// Try to find predicates on *generic params* that would allow copying `ty`
|
||||||
let infcx = tcx.infer_ctxt().build();
|
let ocx = ObligationCtxt::new(&self.infcx);
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
|
||||||
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
|
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
|
||||||
let cause = ObligationCause::misc(span, self.mir_def_id());
|
let cause = ObligationCause::misc(span, self.mir_def_id());
|
||||||
|
|
||||||
ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
|
ocx.register_bound(cause, self.param_env, ty, copy_did);
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
|
|
||||||
// Only emit suggestion if all required predicates are on generic
|
// Only emit suggestion if all required predicates are on generic
|
||||||
|
@ -2219,7 +2212,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||||
let return_ty = tcx.erase_regions(return_ty);
|
|
||||||
|
|
||||||
// to avoid panics
|
// to avoid panics
|
||||||
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
|
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::GeneratorKind;
|
use rustc_hir::GeneratorKind;
|
||||||
use rustc_index::vec::IndexSlice;
|
use rustc_index::vec::IndexSlice;
|
||||||
use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
|
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
|
||||||
|
@ -1042,15 +1042,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||||
let ty = moved_place.ty(self.body, tcx).ty;
|
let ty = moved_place.ty(self.body, tcx).ty;
|
||||||
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
|
||||||
Some(def_id) => {
|
Some(def_id) => type_known_to_meet_bound_modulo_regions(
|
||||||
let infcx = self.infcx.tcx.infer_ctxt().build();
|
&self.infcx,
|
||||||
type_known_to_meet_bound_modulo_regions(
|
self.param_env,
|
||||||
&infcx,
|
tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty),
|
||||||
self.param_env,
|
def_id,
|
||||||
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
|
),
|
||||||
def_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if suggest {
|
if suggest {
|
||||||
|
@ -1094,20 +1091,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
is_partial,
|
is_partial,
|
||||||
is_loop_message,
|
is_loop_message,
|
||||||
});
|
});
|
||||||
let infcx = tcx.infer_ctxt().build();
|
|
||||||
// Erase and shadow everything that could be passed to the new infcx.
|
// Erase and shadow everything that could be passed to the new infcx.
|
||||||
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
|
let ty = moved_place.ty(self.body, tcx).ty;
|
||||||
let method_substs = tcx.erase_regions(method_substs);
|
|
||||||
|
|
||||||
if let ty::Adt(def, substs) = ty.kind()
|
if let ty::Adt(def, substs) = ty.kind()
|
||||||
&& Some(def.did()) == tcx.lang_items().pin_type()
|
&& Some(def.did()) == tcx.lang_items().pin_type()
|
||||||
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
|
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
|
||||||
&& let self_ty = infcx.instantiate_binder_with_fresh_vars(
|
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
|
||||||
fn_call_span,
|
fn_call_span,
|
||||||
LateBoundRegionConversionTime::FnCall,
|
LateBoundRegionConversionTime::FnCall,
|
||||||
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
|
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
|
||||||
)
|
)
|
||||||
&& infcx.can_eq(self.param_env, ty, self_ty)
|
&& self.infcx.can_eq(self.param_env, ty, self_ty)
|
||||||
{
|
{
|
||||||
err.eager_subdiagnostic(
|
err.eager_subdiagnostic(
|
||||||
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
|
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
|
||||||
|
@ -1123,7 +1118,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
self.param_env,
|
self.param_env,
|
||||||
ty::Binder::dummy(trait_ref),
|
ty::Binder::dummy(trait_ref),
|
||||||
)
|
)
|
||||||
&& infcx.predicate_must_hold_modulo_regions(&o)
|
&& self.infcx.predicate_must_hold_modulo_regions(&o)
|
||||||
{
|
{
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
fn_call_span.shrink_to_lo(),
|
fn_call_span.shrink_to_lo(),
|
||||||
|
|
|
@ -235,7 +235,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
|
||||||
// Create the region inference context, taking ownership of the
|
// Create the region inference context, taking ownership of the
|
||||||
// region inference data that was contained in `infcx`, and the
|
// region inference data that was contained in `infcx`, and the
|
||||||
// base constraints generated by the type-check.
|
// base constraints generated by the type-check.
|
||||||
let var_origins = infcx.take_region_var_origins();
|
let var_origins = infcx.get_region_var_origins();
|
||||||
let MirTypeckRegionConstraints {
|
let MirTypeckRegionConstraints {
|
||||||
placeholder_indices,
|
placeholder_indices,
|
||||||
placeholder_index_to_region: _,
|
placeholder_index_to_region: _,
|
||||||
|
|
|
@ -1228,11 +1228,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
/// hence that `resolve_regions_and_report_errors` can never be
|
/// hence that `resolve_regions_and_report_errors` can never be
|
||||||
/// called. This is used only during NLL processing to "hand off" ownership
|
/// called. This is used only during NLL processing to "hand off" ownership
|
||||||
/// of the set of region variables into the NLL region context.
|
/// of the set of region variables into the NLL region context.
|
||||||
pub fn take_region_var_origins(&self) -> VarInfos {
|
pub fn get_region_var_origins(&self) -> VarInfos {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
let (var_infos, data) = inner
|
let (var_infos, data) = inner
|
||||||
.region_constraint_storage
|
.region_constraint_storage
|
||||||
.take()
|
.clone()
|
||||||
.expect("regions already resolved")
|
.expect("regions already resolved")
|
||||||
.with_log(&mut inner.undo_log)
|
.with_log(&mut inner.undo_log)
|
||||||
.into_infos_and_data();
|
.into_infos_and_data();
|
||||||
|
|
11
tests/ui/traits/new-solver/borrowck-error.rs
Normal file
11
tests/ui/traits/new-solver/borrowck-error.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// compile-flags: -Ztrait-solver=next
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
fn foo() -> &'static HashMap<i32, i32>
|
||||||
|
{
|
||||||
|
&HashMap::new()
|
||||||
|
//~^ ERROR cannot return reference to temporary value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
12
tests/ui/traits/new-solver/borrowck-error.stderr
Normal file
12
tests/ui/traits/new-solver/borrowck-error.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0515]: cannot return reference to temporary value
|
||||||
|
--> $DIR/borrowck-error.rs:7:5
|
||||||
|
|
|
||||||
|
LL | &HashMap::new()
|
||||||
|
| ^--------------
|
||||||
|
| ||
|
||||||
|
| |temporary value created here
|
||||||
|
| returns a reference to data owned by the current function
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0515`.
|
Loading…
Add table
Add a link
Reference in a new issue