From 91535ad0265abbe40733fdd451216efdf28ffd02 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 15 Jan 2024 11:44:56 +0100 Subject: [PATCH] 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. --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 7 ++ .../src/infer/error_reporting/mod.rs | 3 + .../infer/error_reporting/need_type_info.rs | 43 ++++--- .../infer/error_reporting/sub_relations.rs | 81 +++++++++++++ compiler/rustc_infer/src/infer/mod.rs | 2 +- .../src/infer/relate/generalize.rs | 16 +-- .../rustc_infer/src/infer/type_variable.rs | 106 +----------------- compiler/rustc_infer/src/infer/undo_log.rs | 8 +- .../error_reporting/type_err_ctxt_ext.rs | 4 + .../occurs-check/unused-substs-2.rs | 5 +- .../occurs-check/unused-substs-2.stderr | 6 +- .../occurs-check/unused-substs-5.stderr | 6 +- tests/ui/impl-trait/issues/issue-84073.rs | 2 +- tests/ui/impl-trait/issues/issue-84073.stderr | 13 +-- tests/ui/infinite/infinite-autoderef.rs | 4 +- tests/ui/infinite/infinite-autoderef.stderr | 55 +-------- tests/ui/issues/issue-59494.rs | 2 +- tests/ui/issues/issue-59494.stderr | 19 +--- tests/ui/occurs-check-2.rs | 3 +- tests/ui/occurs-check-2.stderr | 11 +- tests/ui/occurs-check-3.rs | 10 +- tests/ui/occurs-check-3.stderr | 10 +- tests/ui/occurs-check.rs | 5 +- tests/ui/occurs-check.stderr | 13 +-- tests/ui/span/coerce-suggestions.rs | 4 - tests/ui/span/coerce-suggestions.stderr | 13 +-- 27 files changed, 180 insertions(+), 280 deletions(-) create mode 100644 compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 986af2f5c9e6..9303e437a968 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1522,10 +1522,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.next_trait_solver() && let ty::Alias(..) = ty.kind() { - match self + // We need to use a separate variable here as otherwise the temporary for + // `self.fulfillment_cx.borrow_mut()` is alive in the `Err` branch, resulting + // in a reentrant borrow, causing an ICE. + let result = self .at(&self.misc(sp), self.param_env) - .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) - { + .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()); + match result { Ok(normalized_ty) => normalized_ty, Err(errors) => { let guar = self.err_ctxt().report_fulfillment_errors(errors); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index ad4546c09b54..685b1af931e3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::infer; +use rustc_infer::infer::error_reporting::sub_relations::SubRelations; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; @@ -155,8 +156,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { + let mut sub_relations = SubRelations::default(); + sub_relations.add_constraints( + self, + self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate), + ); TypeErrCtxt { infcx: &self.infcx, + sub_relations: RefCell::new(sub_relations), typeck_results: Some(self.typeck_results.borrow()), fallback_has_occurred: self.fallback_has_occurred.get(), normalize_fn_sig: Box::new(|fn_sig| { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 505d56cf4917..d40f3f501f58 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -88,6 +88,7 @@ mod note_and_explain; mod suggest; pub(crate) mod need_type_info; +pub mod sub_relations; pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; @@ -123,6 +124,8 @@ fn escape_literal(s: &str) -> String { /// methods which should not be used during the happy path. pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, + pub sub_relations: std::cell::RefCell, + pub typeck_results: Option>>, pub fallback_has_occurred: bool, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index af722b206262..896d17478504 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -502,7 +502,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { parent_name, }); - let args = if self.infcx.tcx.get_diagnostic_item(sym::iterator_collect_fn) + let args = if self.tcx.get_diagnostic_item(sym::iterator_collect_fn) == Some(generics_def_id) { "Vec<_>".to_string() @@ -710,7 +710,7 @@ struct InsertableGenericArgs<'tcx> { /// While doing so, the currently best spot is stored in `infer_source`. /// For details on how we rank spots, see [Self::source_cost] struct FindInferSourceVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'tcx>, + tecx: &'a TypeErrCtxt<'a, 'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: GenericArg<'tcx>, @@ -722,12 +722,12 @@ struct FindInferSourceVisitor<'a, 'tcx> { impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { fn new( - infcx: &'a InferCtxt<'tcx>, + tecx: &'a TypeErrCtxt<'a, 'tcx>, typeck_results: &'a TypeckResults<'tcx>, target: GenericArg<'tcx>, ) -> Self { FindInferSourceVisitor { - infcx, + tecx, typeck_results, target, @@ -778,7 +778,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } // The sources are listed in order of preference here. - let tcx = self.infcx.tcx; + let tcx = self.tecx.tcx; let ctx = CostCtxt { tcx }; match source.kind { InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty), @@ -829,12 +829,12 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { fn node_args_opt(&self, hir_id: HirId) -> Option> { let args = self.typeck_results.node_args_opt(hir_id); - self.infcx.resolve_vars_if_possible(args) + self.tecx.resolve_vars_if_possible(args) } fn opt_node_type(&self, hir_id: HirId) -> Option> { let ty = self.typeck_results.node_type_opt(hir_id); - self.infcx.resolve_vars_if_possible(ty) + self.tecx.resolve_vars_if_possible(ty) } // Check whether this generic argument is the inference variable we @@ -849,7 +849,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { use ty::{Infer, TyVar}; match (inner_ty.kind(), target_ty.kind()) { (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { - self.infcx.inner.borrow_mut().type_variables().sub_unified(a_vid, b_vid) + self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid) } _ => false, } @@ -857,12 +857,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => { use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { - (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .unioned(a_vid, b_vid), + (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { + self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid) + } _ => false, } } @@ -917,7 +914,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, ) -> Box> + 'a> { - let tcx = self.infcx.tcx; + let tcx = self.tecx.tcx; match expr.kind { hir::ExprKind::Path(ref path) => { if let Some(args) = self.node_args_opt(expr.hir_id) { @@ -980,7 +977,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { path: &'tcx hir::Path<'tcx>, args: GenericArgsRef<'tcx>, ) -> impl Iterator> + 'a { - let tcx = self.infcx.tcx; + let tcx = self.tecx.tcx; let have_turbofish = path.segments.iter().any(|segment| { segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const())) }); @@ -1034,7 +1031,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { args: GenericArgsRef<'tcx>, qpath: &'tcx hir::QPath<'tcx>, ) -> Box> + 'a> { - let tcx = self.infcx.tcx; + let tcx = self.tecx.tcx; match qpath { hir::QPath::Resolved(_self_ty, path) => { Box::new(self.resolved_path_inferred_arg_iter(path, args)) @@ -1107,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { - self.infcx.tcx.hir() + self.tecx.tcx.hir() } fn visit_local(&mut self, local: &'tcx Local<'tcx>) { @@ -1163,7 +1160,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - let tcx = self.infcx.tcx; + let tcx = self.tecx.tcx; match expr.kind { // When encountering `func(arg)` first look into `arg` and then `func`, // as `arg` is "more specific". @@ -1194,7 +1191,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { if generics.parent.is_none() && generics.has_self { argument_index += 1; } - let args = self.infcx.resolve_vars_if_possible(args); + let args = self.tecx.resolve_vars_if_possible(args); let generic_args = &generics.own_args_no_defaults(tcx, args)[generics.own_counts().lifetimes..]; let span = match expr.kind { @@ -1224,7 +1221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { { let output = args.as_closure().sig().output().skip_binder(); if self.generic_arg_contains_target(output.into()) { - let body = self.infcx.tcx.hir().body(body); + let body = self.tecx.tcx.hir().body(body); let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) { None } else { @@ -1252,12 +1249,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { && let Some(args) = self.node_args_opt(expr.hir_id) && args.iter().any(|arg| self.generic_arg_contains_target(arg)) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) - && self.infcx.tcx.trait_of_item(def_id).is_some() + && self.tecx.tcx.trait_of_item(def_id).is_some() && !has_impl_trait(def_id) { let successor = method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); - let args = self.infcx.resolve_vars_if_possible(args); + let args = self.tecx.resolve_vars_if_possible(args); self.update_infer_source(InferSource { span: path.ident.span, kind: InferSourceKind::FullyQualifiedMethodCall { diff --git a/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs b/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs new file mode 100644 index 000000000000..ef26a8ff7b86 --- /dev/null +++ b/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs @@ -0,0 +1,81 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::undo_log::NoUndo; +use rustc_data_structures::unify as ut; +use rustc_middle::ty; + +use crate::infer::InferCtxt; + +#[derive(Debug, Copy, Clone, PartialEq)] +struct SubId(u32); +impl ut::UnifyKey for SubId { + type Value = (); + #[inline] + fn index(&self) -> u32 { + self.0 + } + #[inline] + fn from_index(i: u32) -> SubId { + SubId(i) + } + fn tag() -> &'static str { + "SubId" + } +} + +/// When reporting ambiguity errors, we sometimes want to +/// treat all inference vars which are subtypes of each +/// others as if they are equal. For this case we compute +/// the transitive closure of our subtype obligations here. +/// +/// E.g. when encountering ambiguity errors, we want to suggest +/// specifying some method argument or to add a type annotation +/// to a local variable. Because subtyping cannot change the +/// shape of a type, it's fine if the cause of the ambiguity error +/// is only related to the suggested variable via subtyping. +/// +/// Even for something like `let x = returns_arg(); x.method();` the +/// type of `x` is only a supertype of the argument of `returns_arg`. We +/// still want to suggest specifying the type of the argument. +#[derive(Default)] +pub struct SubRelations { + map: FxHashMap, + table: ut::UnificationTableStorage, +} + +impl SubRelations { + fn get_id<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, vid: ty::TyVid) -> SubId { + let root_vid = infcx.root_var(vid); + *self.map.entry(root_vid).or_insert_with(|| self.table.with_log(&mut NoUndo).new_key(())) + } + + pub fn add_constraints<'tcx>( + &mut self, + infcx: &InferCtxt<'tcx>, + obls: impl IntoIterator>, + ) { + for p in obls { + let (a, b) = match p.kind().skip_binder() { + ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { + (a, b) + } + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b), + _ => continue, + }; + + match (a.kind(), b.kind()) { + (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { + let a = self.get_id(infcx, a_vid); + let b = self.get_id(infcx, b_vid); + self.table.with_log(&mut NoUndo).unify_var_var(a, b).unwrap(); + } + _ => continue, + } + } + } + + pub fn unified<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, a: ty::TyVid, b: ty::TyVid) -> bool { + let a = self.get_id(infcx, a); + let b = self.get_id(infcx, b); + self.table.with_log(&mut NoUndo).unioned(a, b) + } +} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8fc71671b271..8b5710ee9edc 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -762,6 +762,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { TypeErrCtxt { infcx: self, + sub_relations: Default::default(), typeck_results: None, fallback_has_occurred: false, normalize_fn_sig: Box::new(|fn_sig| fn_sig), @@ -1029,7 +1030,6 @@ impl<'tcx> InferCtxt<'tcx> { let r_b = self.shallow_resolve(predicate.skip_binder().b); match (r_a.kind(), r_b.kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { - self.inner.borrow_mut().type_variables().sub(a_vid, b_vid); return Err((a_vid, b_vid)); } _ => {} diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 90f10a0eba9e..c4c9ddb1ad8e 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -217,10 +217,9 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, Generalization> { assert!(!source_term.has_escaping_bound_vars()); let (for_universe, root_vid) = match target_vid.into() { - ty::TermVid::Ty(ty_vid) => ( - self.probe_ty_var(ty_vid).unwrap_err(), - ty::TermVid::Ty(self.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), - ), + ty::TermVid::Ty(ty_vid) => { + (self.probe_ty_var(ty_vid).unwrap_err(), ty::TermVid::Ty(self.root_var(ty_vid))) + } ty::TermVid::Const(ct_vid) => ( self.probe_const_var(ct_vid).unwrap_err(), ty::TermVid::Const( @@ -424,9 +423,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { ty::Infer(ty::TyVar(vid)) => { let mut inner = self.infcx.inner.borrow_mut(); let vid = inner.type_variables().root_var(vid); - let sub_vid = inner.type_variables().sub_root_var(vid); - - if ty::TermVid::Ty(sub_vid) == self.root_vid { + if ty::TermVid::Ty(vid) == self.root_vid { // If sub-roots are equal, then `root_vid` and // `vid` are related via subtyping. Err(self.cyclic_term_error()) @@ -461,11 +458,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let new_var_id = inner.type_variables().new_var(self.for_universe, origin); let u = Ty::new_var(self.tcx(), new_var_id); - - // Record that we replaced `vid` with `new_var_id` as part of a generalization - // operation. This is needed to detect cyclic types. To see why, see the - // docs in the `type_variables` module. - inner.type_variables().sub(vid, new_var_id); debug!("replacing original vid={:?} with new={:?}", vid, u); Ok(u) } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 8b81eac87390..3630b0f439ff 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::undo_log::Rollback; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::ty::{self, Ty, TyVid}; @@ -12,35 +13,9 @@ use std::cmp; use std::marker::PhantomData; use std::ops::Range; -use rustc_data_structures::undo_log::Rollback; - -/// Represents a single undo-able action that affects a type inference variable. -#[derive(Clone)] -pub(crate) enum UndoLog<'tcx> { - EqRelation(sv::UndoLog>>), - SubRelation(sv::UndoLog>), -} - -/// Convert from a specific kind of undo to the more general UndoLog -impl<'tcx> From>>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>>) -> Self { - UndoLog::EqRelation(l) - } -} - -/// Convert from a specific kind of undo to the more general UndoLog -impl<'tcx> From>> for UndoLog<'tcx> { - fn from(l: sv::UndoLog>) -> Self { - UndoLog::SubRelation(l) - } -} - -impl<'tcx> Rollback> for TypeVariableStorage<'tcx> { - fn reverse(&mut self, undo: UndoLog<'tcx>) { - match undo { - UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), - UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo), - } +impl<'tcx> Rollback>>> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: sv::UndoLog>>) { + self.eq_relations.reverse(undo) } } @@ -52,41 +27,6 @@ pub struct TypeVariableStorage<'tcx> { /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. eq_relations: ut::UnificationTableStorage>, - - /// Two variables are unified in `sub_relations` when we have a - /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second - /// table exists only to help with the occurs check. In particular, - /// we want to report constraints like these as an occurs check - /// violation: - /// ``` text - /// ?1 <: ?3 - /// Box <: ?1 - /// ``` - /// Without this second table, what would happen in a case like - /// this is that we would instantiate `?1` with a generalized - /// type like `Box`. We would then relate `Box <: Box` - /// and infer that `?3 <: ?6`. Next, since `?1` was instantiated, - /// we would process `?1 <: ?3`, generalize `?1 = Box` to `Box`, - /// and instantiate `?3` with `Box`. Finally, we would relate - /// `?6 <: ?9`. But now that we instantiated `?3`, we can process - /// `?3 <: ?6`, which gives us `Box <: ?6`... and the cycle - /// continues. (This is `occurs-check-2.rs`.) - /// - /// What prevents this cycle is that when we generalize - /// `Box` to `Box`, we also sub-unify `?3` and `?6` - /// (in the generalizer). When we then process `Box <: ?3`, - /// the occurs check then fails because `?6` and `?3` are sub-unified, - /// and hence generalization fails. - /// - /// This is reasonable because, in Rust, subtypes have the same - /// "skeleton" and hence there is no possible type such that - /// (e.g.) `Box <: ?3` for any `?3`. - /// - /// In practice, we sometimes sub-unify variables in other spots, such - /// as when processing subtype predicates. This is not necessary but is - /// done to aid diagnostics, as it allows us to be more effective when - /// we guide the user towards where they should insert type hints. - sub_relations: ut::UnificationTableStorage, } pub struct TypeVariableTable<'a, 'tcx> { @@ -158,7 +98,6 @@ impl<'tcx> TypeVariableStorage<'tcx> { TypeVariableStorage { values: Default::default(), eq_relations: ut::UnificationTableStorage::new(), - sub_relations: ut::UnificationTableStorage::new(), } } @@ -197,16 +136,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); self.eq_relations().union(a, b); - self.sub_relations().union(a, b); - } - - /// Records that `a <: b`, depending on `dir`. - /// - /// Precondition: neither `a` nor `b` are known. - pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { - debug_assert!(self.probe(a).is_unknown()); - debug_assert!(self.probe(b).is_unknown()); - self.sub_relations().union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -240,10 +169,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); - - let sub_key = self.sub_relations().new_key(()); - debug_assert_eq!(eq_key.vid, sub_key); - let index = self.storage.values.push(TypeVariableData { origin }); debug_assert_eq!(eq_key.vid, index); @@ -266,24 +191,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.eq_relations().find(vid).vid } - /// Returns the "root" variable of `vid` in the `sub_relations` - /// equivalence table. All type variables that have been are - /// related via equality or subtyping will yield the same root - /// variable (per the union-find algorithm), so `sub_root_var(a) - /// == sub_root_var(b)` implies that: - /// ```text - /// exists X. (a <: X || X <: a) && (b <: X || X <: b) - /// ``` - pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.sub_relations().find(vid) - } - - /// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some - /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. - pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { - self.sub_root_var(a) == self.sub_root_var(b) - } - /// Retrieves the type to which `vid` has been instantiated, if /// any. pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { @@ -314,11 +221,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.storage.eq_relations.with_log(self.undo_log) } - #[inline] - fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { - self.storage.sub_relations.with_log(self.undo_log) - } - /// Returns a range of the type variables created during the snapshot. pub fn vars_since_snapshot( &mut self, diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index be02452d89fb..829b0a73a0df 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> { #[derive(Clone)] pub(crate) enum UndoLog<'tcx> { OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), - TypeVariables(type_variable::UndoLog<'tcx>), + TypeVariables(sv::UndoLog>>), ConstUnificationTable(sv::UndoLog>>), IntUnificationTable(sv::UndoLog>), FloatUnificationTable(sv::UndoLog>), @@ -46,17 +46,13 @@ macro_rules! impl_from { // Upcast from a single kind of "undoable action" to the general enum impl_from! { RegionConstraintCollector(region_constraints::UndoLog<'tcx>), - TypeVariables(type_variable::UndoLog<'tcx>), TypeVariables(sv::UndoLog>>), - TypeVariables(sv::UndoLog>), - IntUnificationTable(sv::UndoLog>), - FloatUnificationTable(sv::UndoLog>), - EffectUnificationTable(sv::UndoLog>>), ConstUnificationTable(sv::UndoLog>>), + EffectUnificationTable(sv::UndoLog>>), RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 7186b96b40d0..be4c6b4d9d12 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -63,6 +63,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, mut errors: Vec>, ) -> ErrorGuaranteed { + self.sub_relations + .borrow_mut() + .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); + #[derive(Debug)] struct ErrorDescriptor<'tcx> { predicate: ty::Predicate<'tcx>, diff --git a/tests/ui/const-generics/occurs-check/unused-substs-2.rs b/tests/ui/const-generics/occurs-check/unused-substs-2.rs index 84e24d1a3f5f..5bdd3e39806e 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-2.rs +++ b/tests/ui/const-generics/occurs-check/unused-substs-2.rs @@ -20,9 +20,10 @@ impl Bind for Foo<{ 6 + 1 }> { fn main() { let (mut t, foo) = Foo::bind(); + //~^ ERROR mismatched types + //~| NOTE cyclic type + // `t` is `ty::Infer(TyVar(?1t))` // `foo` contains `ty::Infer(TyVar(?1t))` in its substs t = foo; - //~^ ERROR mismatched types - //~| NOTE cyclic type } diff --git a/tests/ui/const-generics/occurs-check/unused-substs-2.stderr b/tests/ui/const-generics/occurs-check/unused-substs-2.stderr index 4b1b9f20559e..a2c4dec47243 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-2.stderr +++ b/tests/ui/const-generics/occurs-check/unused-substs-2.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/unused-substs-2.rs:25:9 + --> $DIR/unused-substs-2.rs:22:24 | -LL | t = foo; - | ^^^ cyclic type of infinite size +LL | let (mut t, foo) = Foo::bind(); + | ^^^^^^^^^^^ cyclic type of infinite size error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/occurs-check/unused-substs-5.stderr b/tests/ui/const-generics/occurs-check/unused-substs-5.stderr index 1b3a54923284..46230d455b27 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-5.stderr +++ b/tests/ui/const-generics/occurs-check/unused-substs-5.stderr @@ -1,10 +1,8 @@ error[E0308]: mismatched types - --> $DIR/unused-substs-5.rs:15:9 + --> $DIR/unused-substs-5.rs:15:19 | LL | x = q::<_, N>(x); - | ^^^^^^^^^^^^- help: try using a conversion method: `.to_vec()` - | | - | cyclic type of infinite size + | ^ cyclic type of infinite size error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-84073.rs b/tests/ui/impl-trait/issues/issue-84073.rs index 49a34ccfa3b4..60f98a7c7b53 100644 --- a/tests/ui/impl-trait/issues/issue-84073.rs +++ b/tests/ui/impl-trait/issues/issue-84073.rs @@ -29,5 +29,5 @@ where } fn main() { - Race::new(|race| race.when()); //~ ERROR type annotations needed + Race::new(|race| race.when()); //~ ERROR overflow evaluating the requirement `_ <: Option<_>` } diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr index d03e458aeb82..b9039211db63 100644 --- a/tests/ui/impl-trait/issues/issue-84073.stderr +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -1,14 +1,9 @@ -error[E0282]: type annotations needed for `RaceBuilder>` - --> $DIR/issue-84073.rs:32:16 +error[E0275]: overflow evaluating the requirement `_ <: Option<_>` + --> $DIR/issue-84073.rs:32:22 | LL | Race::new(|race| race.when()); - | ^^^^ ---- type must be known at this point - | -help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified - | -LL | Race::new(|race: RaceBuilder>| race.when()); - | ++++++++++++++++++++++++++ + | ^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/infinite/infinite-autoderef.rs b/tests/ui/infinite/infinite-autoderef.rs index d6956e694570..cf5c9fe5678c 100644 --- a/tests/ui/infinite/infinite-autoderef.rs +++ b/tests/ui/infinite/infinite-autoderef.rs @@ -1,6 +1,3 @@ -//@ error-pattern: reached the recursion limit while auto-dereferencing -//@ compile-flags: -Zdeduplicate-diagnostics=yes - use std::ops::Deref; struct Foo; @@ -17,6 +14,7 @@ pub fn main() { let mut x; loop { x = Box::new(x); + //~^ ERROR overflow evaluating the requirement `Box<_> <: _` x.foo; x.bar(); } diff --git a/tests/ui/infinite/infinite-autoderef.stderr b/tests/ui/infinite/infinite-autoderef.stderr index 51b61e3a66bb..24be1a11373c 100644 --- a/tests/ui/infinite/infinite-autoderef.stderr +++ b/tests/ui/infinite/infinite-autoderef.stderr @@ -1,54 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/infinite-autoderef.rs:19:13 +error[E0275]: overflow evaluating the requirement `Box<_> <: _` + --> $DIR/infinite-autoderef.rs:16:13 | LL | x = Box::new(x); - | ^^^^^^^^^^^ cyclic type of infinite size - | -help: consider unboxing the value - | -LL | x = *Box::new(x); - | + + | ^^^^^^^^^^^ -error[E0055]: reached the recursion limit while auto-dereferencing `Foo` - --> $DIR/infinite-autoderef.rs:24:5 - | -LL | Foo.foo; - | ^^^^^^^ deref recursion limit reached - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) +error: aborting due to 1 previous error -error[E0055]: reached the recursion limit while auto-dereferencing `Foo` - --> $DIR/infinite-autoderef.rs:24:9 - | -LL | Foo.foo; - | ^^^ deref recursion limit reached - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) - -error[E0609]: no field `foo` on type `Foo` - --> $DIR/infinite-autoderef.rs:24:9 - | -LL | Foo.foo; - | ^^^ unknown field - -error[E0055]: reached the recursion limit while auto-dereferencing `Foo` - --> $DIR/infinite-autoderef.rs:25:9 - | -LL | Foo.bar(); - | ^^^ deref recursion limit reached - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) - -error[E0599]: no method named `bar` found for struct `Foo` in the current scope - --> $DIR/infinite-autoderef.rs:25:9 - | -LL | struct Foo; - | ---------- method `bar` not found for this struct -... -LL | Foo.bar(); - | ^^^ method not found in `Foo` - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0055, E0308, E0599, E0609. -For more information about an error, try `rustc --explain E0055`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/issues/issue-59494.rs b/tests/ui/issues/issue-59494.rs index 8dcdd88c618c..b4d50bd4ce79 100644 --- a/tests/ui/issues/issue-59494.rs +++ b/tests/ui/issues/issue-59494.rs @@ -18,6 +18,6 @@ fn main() { let f = |(_, _)| {}; let g = |(a, _)| a; let t7 = |env| |a| |b| t7p(f, g)(((env, a), b)); + //~^ ERROR mismatched types let t8 = t8n(t7, t7p(f, g)); - //~^ ERROR: expected a `Fn(_)` closure, found `impl Fn(((_, _), _))` [E0277] } diff --git a/tests/ui/issues/issue-59494.stderr b/tests/ui/issues/issue-59494.stderr index 960de1be299e..33d3e48c1aac 100644 --- a/tests/ui/issues/issue-59494.stderr +++ b/tests/ui/issues/issue-59494.stderr @@ -1,18 +1,9 @@ -error[E0277]: expected a `Fn(_)` closure, found `impl Fn(((_, _), _))` - --> $DIR/issue-59494.rs:21:22 +error[E0308]: mismatched types + --> $DIR/issue-59494.rs:20:40 | -LL | let t8 = t8n(t7, t7p(f, g)); - | --- ^^^^^^^^^ expected an `Fn(_)` closure, found `impl Fn(((_, _), _))` - | | - | required by a bound introduced by this call - | - = help: the trait `Fn<(_,)>` is not implemented for `impl Fn(((_, _), _))` -note: required by a bound in `t8n` - --> $DIR/issue-59494.rs:5:45 - | -LL | fn t8n(f: impl Fn(A) -> B, g: impl Fn(A) -> C) -> impl Fn(A) -> (B, C) - | ^^^^^^^^^^ required by this bound in `t8n` +LL | let t7 = |env| |a| |b| t7p(f, g)(((env, a), b)); + | ^^^ cyclic type of infinite size error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/occurs-check-2.rs b/tests/ui/occurs-check-2.rs index f36682a3dd82..6cdb757d65bc 100644 --- a/tests/ui/occurs-check-2.rs +++ b/tests/ui/occurs-check-2.rs @@ -5,6 +5,5 @@ fn main() { g = f; f = Box::new(g); - //~^ ERROR mismatched types - //~| cyclic type of infinite size + //~^ ERROR overflow evaluating the requirement `Box<_> <: _` } diff --git a/tests/ui/occurs-check-2.stderr b/tests/ui/occurs-check-2.stderr index 7b6fb9fafa20..acc474319b05 100644 --- a/tests/ui/occurs-check-2.stderr +++ b/tests/ui/occurs-check-2.stderr @@ -1,14 +1,9 @@ -error[E0308]: mismatched types +error[E0275]: overflow evaluating the requirement `Box<_> <: _` --> $DIR/occurs-check-2.rs:7:9 | LL | f = Box::new(g); - | ^^^^^^^^^^^ cyclic type of infinite size - | -help: consider unboxing the value - | -LL | f = *Box::new(g); - | + + | ^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/occurs-check-3.rs b/tests/ui/occurs-check-3.rs index 9c04204010b7..cdf8dc3bd160 100644 --- a/tests/ui/occurs-check-3.rs +++ b/tests/ui/occurs-check-3.rs @@ -1,5 +1,11 @@ // From Issue #778 enum Clam { A(T) } -fn main() { let c; c = Clam::A(c); match c { Clam::A::(_) => { } } } -//~^ ERROR mismatched types +fn main() { + let c; + c = Clam::A(c); + //~^ ERROR overflow evaluating the requirement `Clam<_> <: _` + match c { + Clam::A::(_) => { } + } +} diff --git a/tests/ui/occurs-check-3.stderr b/tests/ui/occurs-check-3.stderr index 675133b6d50b..7bc28e61d9f9 100644 --- a/tests/ui/occurs-check-3.stderr +++ b/tests/ui/occurs-check-3.stderr @@ -1,9 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/occurs-check-3.rs:4:24 +error[E0275]: overflow evaluating the requirement `Clam<_> <: _` + --> $DIR/occurs-check-3.rs:6:9 | -LL | fn main() { let c; c = Clam::A(c); match c { Clam::A::(_) => { } } } - | ^^^^^^^^^^ cyclic type of infinite size +LL | c = Clam::A(c); + | ^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/occurs-check.rs b/tests/ui/occurs-check.rs index aec52d839766..3fae3ff1238e 100644 --- a/tests/ui/occurs-check.rs +++ b/tests/ui/occurs-check.rs @@ -1,8 +1,5 @@ fn main() { - let f; - f = Box::new(f); - //~^ ERROR mismatched types - //~| cyclic type of infinite size + //~^ ERROR overflow evaluating the requirement `Box<_> <: _` } diff --git a/tests/ui/occurs-check.stderr b/tests/ui/occurs-check.stderr index 1cb6b32cb233..3f61d8fd08d1 100644 --- a/tests/ui/occurs-check.stderr +++ b/tests/ui/occurs-check.stderr @@ -1,14 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/occurs-check.rs:5:9 +error[E0275]: overflow evaluating the requirement `Box<_> <: _` + --> $DIR/occurs-check.rs:3:9 | LL | f = Box::new(f); - | ^^^^^^^^^^^ cyclic type of infinite size - | -help: consider unboxing the value - | -LL | f = *Box::new(f); - | + + | ^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/span/coerce-suggestions.rs b/tests/ui/span/coerce-suggestions.rs index 7920ae0b26cc..13331a016fcf 100644 --- a/tests/ui/span/coerce-suggestions.rs +++ b/tests/ui/span/coerce-suggestions.rs @@ -13,10 +13,6 @@ fn main() { //~^ ERROR E0308 test2(&y); //~^ ERROR E0308 - let f; - f = Box::new(f); - //~^ ERROR E0308 - let s = &mut String::new(); s = format!("foo"); //~^ ERROR E0308 diff --git a/tests/ui/span/coerce-suggestions.stderr b/tests/ui/span/coerce-suggestions.stderr index ff840b781f07..77b01ee08b79 100644 --- a/tests/ui/span/coerce-suggestions.stderr +++ b/tests/ui/span/coerce-suggestions.stderr @@ -54,22 +54,11 @@ LL | fn test2(_x: &mut i32) {} error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:17:9 | -LL | f = Box::new(f); - | ^^^^^^^^^^^ cyclic type of infinite size - | -help: consider unboxing the value - | -LL | f = *Box::new(f); - | + - -error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:21:9 - | LL | s = format!("foo"); | ^^^^^^^^^^^^^^ expected `&mut String`, found `String` | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`.