Skip to content

Commit efbc121

Browse files
committed
remove sub_relations from infcx, recompute in diagnostics
we don't track them when canonicalizing or when freshening, resulting in instable caching in the old solver, and issues when instantiating query responses in the new one.
1 parent d3c9082 commit efbc121

28 files changed

+173
-281
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1493,10 +1493,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14931493
if self.next_trait_solver()
14941494
&& let ty::Alias(..) = ty.kind()
14951495
{
1496-
match self
1496+
// We need to use a separate variable here as otherwise the temporary for
1497+
// `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting
1498+
// in a reentrant borrow, causing an ICE.
1499+
let result = self
14971500
.at(&self.misc(sp), self.param_env)
1498-
.structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut())
1499-
{
1501+
.structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut());
1502+
match result {
15001503
Ok(normalized_ty) => normalized_ty,
15011504
Err(errors) => {
15021505
let guar = self.err_ctxt().report_fulfillment_errors(errors);

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_hir as hir;
1111
use rustc_hir::def_id::{DefId, LocalDefId};
1212
use rustc_hir_analysis::astconv::AstConv;
1313
use rustc_infer::infer;
14+
use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
1415
use rustc_infer::infer::error_reporting::TypeErrCtxt;
1516
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1617
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
@@ -155,8 +156,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
155156
///
156157
/// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
157158
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
159+
let mut sub_relations = SubRelations::default();
160+
sub_relations.add_constraints(
161+
self,
162+
self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
163+
);
158164
TypeErrCtxt {
159165
infcx: &self.infcx,
166+
sub_relations: RefCell::new(sub_relations),
160167
typeck_results: Some(self.typeck_results.borrow()),
161168
fallback_has_occurred: self.fallback_has_occurred.get(),
162169
normalize_fn_sig: Box::new(|fn_sig| {

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ mod note_and_explain;
8787
mod suggest;
8888

8989
pub(crate) mod need_type_info;
90+
pub mod sub_relations;
9091
pub use need_type_info::TypeAnnotationNeeded;
9192

9293
pub mod nice_region_error;
@@ -122,6 +123,8 @@ fn escape_literal(s: &str) -> String {
122123
/// during the happy path.
123124
pub struct TypeErrCtxt<'a, 'tcx> {
124125
pub infcx: &'a InferCtxt<'tcx>,
126+
pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>,
127+
125128
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
126129
pub fallback_has_occurred: bool,
127130

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
502502
parent_name,
503503
});
504504

505-
let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn)
505+
let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn)
506506
== Some(generics_def_id)
507507
{
508508
"Vec<_>".to_string()
@@ -710,7 +710,7 @@ struct InsertableGenericArgs<'tcx> {
710710
/// While doing so, the currently best spot is stored in `infer_source`.
711711
/// For details on how we rank spots, see [Self::source_cost]
712712
struct FindInferSourceVisitor<'a, 'tcx> {
713-
infcx: &'a InferCtxt<'tcx>,
713+
tecx: &'a TypeErrCtxt<'a, 'tcx>,
714714
typeck_results: &'a TypeckResults<'tcx>,
715715

716716
target: GenericArg<'tcx>,
@@ -722,12 +722,12 @@ struct FindInferSourceVisitor<'a, 'tcx> {
722722

723723
impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
724724
fn new(
725-
infcx: &'a InferCtxt<'tcx>,
725+
tecx: &'a TypeErrCtxt<'a, 'tcx>,
726726
typeck_results: &'a TypeckResults<'tcx>,
727727
target: GenericArg<'tcx>,
728728
) -> Self {
729729
FindInferSourceVisitor {
730-
infcx,
730+
tecx,
731731
typeck_results,
732732

733733
target,
@@ -778,7 +778,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
778778
}
779779

780780
// The sources are listed in order of preference here.
781-
let tcx = self.infcx.tcx;
781+
let tcx = self.tecx.tcx;
782782
let ctx = CostCtxt { tcx };
783783
match source.kind {
784784
InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
@@ -829,12 +829,12 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
829829

830830
fn node_args_opt(&self, hir_id: HirId) -> Option<GenericArgsRef<'tcx>> {
831831
let args = self.typeck_results.node_args_opt(hir_id);
832-
self.infcx.resolve_vars_if_possible(args)
832+
self.tecx.resolve_vars_if_possible(args)
833833
}
834834

835835
fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
836836
let ty = self.typeck_results.node_type_opt(hir_id);
837-
self.infcx.resolve_vars_if_possible(ty)
837+
self.tecx.resolve_vars_if_possible(ty)
838838
}
839839

840840
// Check whether this generic argument is the inference variable we
@@ -849,20 +849,17 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
849849
use ty::{Infer, TyVar};
850850
match (inner_ty.kind(), target_ty.kind()) {
851851
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
852-
self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid)
852+
self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid)
853853
}
854854
_ => false,
855855
}
856856
}
857857
(GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
858858
use ty::InferConst::*;
859859
match (inner_ct.kind(), target_ct.kind()) {
860-
(ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self
861-
.infcx
862-
.inner
863-
.borrow_mut()
864-
.const_unification_table()
865-
.unioned(a_vid, b_vid),
860+
(ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => {
861+
self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid)
862+
}
866863
_ => false,
867864
}
868865
}
@@ -914,7 +911,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
914911
&self,
915912
expr: &'tcx hir::Expr<'tcx>,
916913
) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
917-
let tcx = self.infcx.tcx;
914+
let tcx = self.tecx.tcx;
918915
match expr.kind {
919916
hir::ExprKind::Path(ref path) => {
920917
if let Some(args) = self.node_args_opt(expr.hir_id) {
@@ -977,7 +974,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
977974
path: &'tcx hir::Path<'tcx>,
978975
args: GenericArgsRef<'tcx>,
979976
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
980-
let tcx = self.infcx.tcx;
977+
let tcx = self.tecx.tcx;
981978
let have_turbofish = path.segments.iter().any(|segment| {
982979
segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const()))
983980
});
@@ -1031,7 +1028,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
10311028
args: GenericArgsRef<'tcx>,
10321029
qpath: &'tcx hir::QPath<'tcx>,
10331030
) -> Box<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + 'a> {
1034-
let tcx = self.infcx.tcx;
1031+
let tcx = self.tecx.tcx;
10351032
match qpath {
10361033
hir::QPath::Resolved(_self_ty, path) => {
10371034
Box::new(self.resolved_path_inferred_arg_iter(path, args))
@@ -1104,7 +1101,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
11041101
type NestedFilter = nested_filter::OnlyBodies;
11051102

11061103
fn nested_visit_map(&mut self) -> Self::Map {
1107-
self.infcx.tcx.hir()
1104+
self.tecx.tcx.hir()
11081105
}
11091106

11101107
fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
@@ -1160,7 +1157,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
11601157

11611158
#[instrument(level = "debug", skip(self))]
11621159
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
1163-
let tcx = self.infcx.tcx;
1160+
let tcx = self.tecx.tcx;
11641161
match expr.kind {
11651162
// When encountering `func(arg)` first look into `arg` and then `func`,
11661163
// as `arg` is "more specific".
@@ -1191,7 +1188,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
11911188
if generics.parent.is_none() && generics.has_self {
11921189
argument_index += 1;
11931190
}
1194-
let args = self.infcx.resolve_vars_if_possible(args);
1191+
let args = self.tecx.resolve_vars_if_possible(args);
11951192
let generic_args =
11961193
&generics.own_args_no_defaults(tcx, args)[generics.own_counts().lifetimes..];
11971194
let span = match expr.kind {
@@ -1221,7 +1218,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
12211218
{
12221219
let output = args.as_closure().sig().output().skip_binder();
12231220
if self.generic_arg_contains_target(output.into()) {
1224-
let body = self.infcx.tcx.hir().body(body);
1221+
let body = self.tecx.tcx.hir().body(body);
12251222
let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
12261223
None
12271224
} else {
@@ -1249,12 +1246,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
12491246
&& let Some(args) = self.node_args_opt(expr.hir_id)
12501247
&& args.iter().any(|arg| self.generic_arg_contains_target(arg))
12511248
&& let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
1252-
&& self.infcx.tcx.trait_of_item(def_id).is_some()
1249+
&& self.tecx.tcx.trait_of_item(def_id).is_some()
12531250
&& !has_impl_trait(def_id)
12541251
{
12551252
let successor =
12561253
method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
1257-
let args = self.infcx.resolve_vars_if_possible(args);
1254+
let args = self.tecx.resolve_vars_if_possible(args);
12581255
self.update_infer_source(InferSource {
12591256
span: path.ident.span,
12601257
kind: InferSourceKind::FullyQualifiedMethodCall {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use rustc_data_structures::fx::FxHashMap;
2+
use rustc_data_structures::undo_log::NoUndo;
3+
use rustc_data_structures::unify as ut;
4+
use rustc_middle::ty;
5+
6+
use crate::infer::InferCtxt;
7+
8+
#[derive(Debug, Copy, Clone, PartialEq)]
9+
struct SubId(u32);
10+
impl ut::UnifyKey for SubId {
11+
type Value = ();
12+
#[inline]
13+
fn index(&self) -> u32 {
14+
self.0
15+
}
16+
#[inline]
17+
fn from_index(i: u32) -> SubId {
18+
SubId(i)
19+
}
20+
fn tag() -> &'static str {
21+
"SubId"
22+
}
23+
}
24+
25+
/// When reporting ambiguity errors, we sometimes want to
26+
/// treat all inference vars which are subtypes of each
27+
/// others as if they are equal. For this case we compute
28+
/// the transitive closure of our subtype obligations here.
29+
#[derive(Default)]
30+
pub struct SubRelations {
31+
map: FxHashMap<ty::TyVid, SubId>,
32+
table: ut::UnificationTableStorage<SubId>,
33+
}
34+
35+
impl SubRelations {
36+
fn get_id<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, vid: ty::TyVid) -> SubId {
37+
let root_vid = infcx.root_var(vid);
38+
*self.map.entry(root_vid).or_insert_with(|| self.table.with_log(&mut NoUndo).new_key(()))
39+
}
40+
41+
pub fn add_constraints<'tcx>(
42+
&mut self,
43+
infcx: &InferCtxt<'tcx>,
44+
obls: impl IntoIterator<Item = ty::Predicate<'tcx>>,
45+
) {
46+
for p in obls {
47+
let (a, b) = match p.kind().skip_binder() {
48+
ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
49+
(a, b)
50+
}
51+
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b),
52+
_ => continue,
53+
};
54+
55+
match (a.kind(), b.kind()) {
56+
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
57+
let a = self.get_id(infcx, a_vid);
58+
let b = self.get_id(infcx, b_vid);
59+
self.table.with_log(&mut NoUndo).unify_var_var(a, b).unwrap();
60+
}
61+
_ => continue,
62+
}
63+
}
64+
}
65+
66+
pub fn unified<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, a: ty::TyVid, b: ty::TyVid) -> bool {
67+
let a = self.get_id(infcx, a);
68+
let b = self.get_id(infcx, b);
69+
self.table.with_log(&mut NoUndo).unioned(a, b)
70+
}
71+
}

compiler/rustc_infer/src/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ impl<'tcx> InferCtxt<'tcx> {
752752
pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
753753
TypeErrCtxt {
754754
infcx: self,
755+
sub_relations: Default::default(),
755756
typeck_results: None,
756757
fallback_has_occurred: false,
757758
normalize_fn_sig: Box::new(|fn_sig| fn_sig),
@@ -1019,7 +1020,6 @@ impl<'tcx> InferCtxt<'tcx> {
10191020
let r_b = self.shallow_resolve(predicate.skip_binder().b);
10201021
match (r_a.kind(), r_b.kind()) {
10211022
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
1022-
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
10231023
return Err((a_vid, b_vid));
10241024
}
10251025
_ => {}

compiler/rustc_infer/src/infer/relate/generalize.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Rela
2727
let (for_universe, root_vid) = match for_vid.into() {
2828
ty::TermVid::Ty(ty_vid) => (
2929
infcx.probe_ty_var(ty_vid).unwrap_err(),
30-
ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)),
30+
ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().root_var(ty_vid)),
3131
),
3232
ty::TermVid::Const(ct_vid) => (
3333
infcx.probe_const_var(ct_vid).unwrap_err(),
@@ -249,9 +249,8 @@ where
249249
ty::Infer(ty::TyVar(vid)) => {
250250
let mut inner = self.infcx.inner.borrow_mut();
251251
let vid = inner.type_variables().root_var(vid);
252-
let sub_vid = inner.type_variables().sub_root_var(vid);
253252

254-
if ty::TermVid::Ty(sub_vid) == self.root_vid {
253+
if ty::TermVid::Ty(vid) == self.root_vid {
255254
// If sub-roots are equal, then `root_vid` and
256255
// `vid` are related via subtyping.
257256
Err(self.cyclic_term_error())
@@ -287,11 +286,6 @@ where
287286
let new_var_id =
288287
inner.type_variables().new_var(self.for_universe, origin);
289288
let u = Ty::new_var(self.tcx(), new_var_id);
290-
291-
// Record that we replaced `vid` with `new_var_id` as part of a generalization
292-
// operation. This is needed to detect cyclic types. To see why, see the
293-
// docs in the `type_variables` module.
294-
inner.type_variables().sub(vid, new_var_id);
295289
debug!("replacing original vid={:?} with new={:?}", vid, u);
296290
Ok(u)
297291
}

0 commit comments

Comments
 (0)