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.
This commit is contained in:
parent
1bb3a9f67a
commit
91535ad026
27 changed files with 180 additions and 280 deletions
|
@ -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);
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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<sub_relations::SubRelations>,
|
||||
|
||||
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
|
||||
pub fallback_has_occurred: bool,
|
||||
|
||||
|
|
|
@ -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<GenericArgsRef<'tcx>> {
|
||||
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<Ty<'tcx>> {
|
||||
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<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + '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<Item = InsertableGenericArgs<'tcx>> + '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<dyn Iterator<Item = InsertableGenericArgs<'tcx>> + '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 {
|
||||
|
|
|
@ -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<ty::TyVid, SubId>,
|
||||
table: ut::UnificationTableStorage<SubId>,
|
||||
}
|
||||
|
||||
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<Item = ty::Predicate<'tcx>>,
|
||||
) {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -217,10 +217,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
) -> RelateResult<'tcx, Generalization<T>> {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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<ut::Delegate<TyVidEqKey<'tcx>>>),
|
||||
SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>),
|
||||
}
|
||||
|
||||
/// Convert from a specific kind of undo to the more general UndoLog
|
||||
impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
|
||||
fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self {
|
||||
UndoLog::EqRelation(l)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from a specific kind of undo to the more general UndoLog
|
||||
impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> {
|
||||
fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self {
|
||||
UndoLog::SubRelation(l)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Rollback<UndoLog<'tcx>> 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<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
|
||||
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
|
||||
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<TyVidEqKey<'tcx>>,
|
||||
|
||||
/// 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<?3> <: ?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<?6>`. We would then relate `Box<?3> <: Box<?6>`
|
||||
/// and infer that `?3 <: ?6`. Next, since `?1` was instantiated,
|
||||
/// we would process `?1 <: ?3`, generalize `?1 = Box<?6>` to `Box<?9>`,
|
||||
/// and instantiate `?3` with `Box<?9>`. Finally, we would relate
|
||||
/// `?6 <: ?9`. But now that we instantiated `?3`, we can process
|
||||
/// `?3 <: ?6`, which gives us `Box<?9> <: ?6`... and the cycle
|
||||
/// continues. (This is `occurs-check-2.rs`.)
|
||||
///
|
||||
/// What prevents this cycle is that when we generalize
|
||||
/// `Box<?3>` to `Box<?6>`, we also sub-unify `?3` and `?6`
|
||||
/// (in the generalizer). When we then process `Box<?6> <: ?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> <: ?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<ty::TyVid>,
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> {
|
|||
#[derive(Clone)]
|
||||
pub(crate) enum UndoLog<'tcx> {
|
||||
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
|
||||
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
|
||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
|
@ -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<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
|
||||
TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
|
||||
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
|
||||
|
||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
|
||||
EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
|
||||
|
||||
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
|
||||
ProjectionCache(traits::UndoLog<'tcx>),
|
||||
|
|
|
@ -63,6 +63,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
&self,
|
||||
mut errors: Vec<FulfillmentError<'tcx>>,
|
||||
) -> 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>,
|
||||
|
|
|
@ -20,9 +20,10 @@ impl<T> Bind<T> 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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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<_>`
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>`
|
||||
--> $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<T, Never<T>>| 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`.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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<A, B, C>(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`.
|
||||
|
|
|
@ -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<_> <: _`
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
// From Issue #778
|
||||
|
||||
enum Clam<T> { A(T) }
|
||||
fn main() { let c; c = Clam::A(c); match c { Clam::A::<isize>(_) => { } } }
|
||||
//~^ ERROR mismatched types
|
||||
fn main() {
|
||||
let c;
|
||||
c = Clam::A(c);
|
||||
//~^ ERROR overflow evaluating the requirement `Clam<_> <: _`
|
||||
match c {
|
||||
Clam::A::<isize>(_) => { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<isize>(_) => { } } }
|
||||
| ^^^^^^^^^^ 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`.
|
||||
|
|
|
@ -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<_> <: _`
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`.
|
||||
|
|
Loading…
Add table
Reference in a new issue