Auto merge of #119989 - lcnr:sub_relations-bye-bye, r=compiler-errors

remove `sub_relations` from the `InferCtxt`

While doing so, I tried to remove the `delay_span_bug` in `rematch_impl` again, which lead me to discover another `freshen` bug, fixing that one in the second commit. See commit descriptions for the reasoning behind each change.

r? `@compiler-errors`
This commit is contained in:
bors 2024-02-22 20:45:24 +00:00
commit 397937d812
47 changed files with 408 additions and 454 deletions

View File

@ -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);

View File

@ -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| {

View File

@ -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,

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -56,49 +56,46 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
}
}
fn freshen_ty<F>(&mut self, opt_ty: Option<Ty<'tcx>>, key: ty::InferTy, mk_fresh: F) -> Ty<'tcx>
fn freshen_ty<F>(&mut self, input: Result<Ty<'tcx>, ty::InferTy>, mk_fresh: F) -> Ty<'tcx>
where
F: FnOnce(u32) -> Ty<'tcx>,
{
if let Some(ty) = opt_ty {
return ty.fold_with(self);
}
match self.ty_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.ty_freshen_count;
self.ty_freshen_count += 1;
let t = mk_fresh(index);
entry.insert(t);
t
}
match input {
Ok(ty) => ty.fold_with(self),
Err(key) => match self.ty_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.ty_freshen_count;
self.ty_freshen_count += 1;
let t = mk_fresh(index);
entry.insert(t);
t
}
},
}
}
fn freshen_const<F>(
&mut self,
opt_ct: Option<ty::Const<'tcx>>,
key: ty::InferConst,
input: Result<ty::Const<'tcx>, ty::InferConst>,
freshener: F,
ty: Ty<'tcx>,
) -> ty::Const<'tcx>
where
F: FnOnce(u32) -> ty::InferConst,
{
if let Some(ct) = opt_ct {
return ct.fold_with(self);
}
match self.const_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.const_freshen_count;
self.const_freshen_count += 1;
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
entry.insert(ct);
ct
}
match input {
Ok(ct) => ct.fold_with(self),
Err(key) => match self.const_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
let index = self.const_freshen_count;
self.const_freshen_count += 1;
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
entry.insert(ct);
ct
}
},
}
}
}
@ -146,19 +143,22 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct =
self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
let mut inner = self.infcx.inner.borrow_mut();
let input =
inner.const_unification_table().probe_value(v).known().ok_or_else(|| {
ty::InferConst::Var(inner.const_unification_table().find(v).vid)
});
drop(inner);
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
}
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
let opt_ct =
self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known();
self.freshen_const(
opt_ct,
ty::InferConst::EffectVar(v),
ty::InferConst::Fresh,
ct.ty(),
)
let mut inner = self.infcx.inner.borrow_mut();
let input =
inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
});
drop(inner);
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
@ -191,35 +191,37 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
match v {
ty::TyVar(v) => {
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n)))
let mut inner = self.infcx.inner.borrow_mut();
let input = inner
.type_variables()
.probe(v)
.known()
.ok_or_else(|| ty::TyVar(inner.type_variables().root_var(v)));
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n)))
}
ty::IntVar(v) => Some(
self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.int_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx)),
ty::IntVar(v),
|n| Ty::new_fresh_int(self.infcx.tcx, n),
),
),
ty::IntVar(v) => {
let mut inner = self.infcx.inner.borrow_mut();
let input = inner
.int_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx))
.ok_or_else(|| ty::IntVar(inner.int_unification_table().find(v)));
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
}
ty::FloatVar(v) => Some(
self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.float_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx)),
ty::FloatVar(v),
|n| Ty::new_fresh_float(self.infcx.tcx, n),
),
),
ty::FloatVar(v) => {
let mut inner = self.infcx.inner.borrow_mut();
let input = inner
.float_unification_table()
.probe_value(v)
.map(|v| v.to_type(self.infcx.tcx))
.ok_or_else(|| ty::FloatVar(inner.float_unification_table().find(v)));
drop(inner);
Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
}
ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
if ct >= self.ty_freshen_count {

View File

@ -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));
}
_ => {}

View File

@ -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)
}

View File

@ -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,

View File

@ -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>),

View File

@ -1,4 +1,4 @@
use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt};
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{BoundVarReplacer, PlaceholderReplacer};
use rustc_data_structures::stack::ensure_sufficient_stack;
@ -60,8 +60,12 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
let tcx = infcx.tcx;
let recursion_limit = tcx.recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
let ty::Alias(_, data) = *alias_ty.kind() else {
unreachable!();
};
self.at.infcx.err_ctxt().report_overflow_error(
&alias_ty,
OverflowCause::DeeplyNormalize(data),
self.at.cause.span,
true,
|_| {},
@ -109,7 +113,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
let recursion_limit = tcx.recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.at.infcx.err_ctxt().report_overflow_error(
&ty::Const::new_unevaluated(tcx, uv, ty),
OverflowCause::DeeplyNormalize(ty::AliasTy::new(tcx, uv.def, uv.args)),
self.at.cause.span,
true,
|_| {},

View File

@ -57,12 +57,21 @@ use super::{
pub use rustc_infer::traits::error_reporting::*;
pub enum OverflowCause<'tcx> {
DeeplyNormalize(ty::AliasTy<'tcx>),
TraitSolver(ty::Predicate<'tcx>),
}
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
&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>,
@ -180,49 +189,78 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// whose result could not be truly determined and thus we can't say
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
fn report_overflow_error<T>(
fn report_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
mutate: impl FnOnce(&mut DiagnosticBuilder<'_>),
) -> !
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
) -> ! {
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
mutate(&mut err);
err.emit();
FatalError.raise();
}
fn build_overflow_error<T>(
fn build_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
) -> DiagnosticBuilder<'tcx>
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let predicate = self.resolve_vars_if_possible(predicate.clone());
let mut pred_str = predicate.to_string();
if pred_str.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
let mut cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(self.tcx, Namespace::TypeNS, rustc_session::Limit(6));
predicate.print(&mut cx).unwrap();
pred_str = cx.into_buffer();
) -> DiagnosticBuilder<'tcx> {
fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
where
T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let s = value.to_string();
if s.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
let mut cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
value.print(&mut cx).unwrap();
cx.into_buffer()
} else {
s
}
}
let mut err = struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{}`",
pred_str,
);
let mut err = match cause {
OverflowCause::DeeplyNormalize(alias_ty) => {
let alias_ty = self.resolve_vars_if_possible(alias_ty);
let kind = alias_ty.opt_kind(self.tcx).map_or("alias", |k| k.descr());
let alias_str = with_short_path(self.tcx, alias_ty);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow normalizing the {kind} `{alias_str}`",
)
}
OverflowCause::TraitSolver(predicate) => {
let predicate = self.resolve_vars_if_possible(predicate);
match predicate.kind().skip_binder() {
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
| ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow assigning `{a}` to `{b}`",
)
}
_ => {
let pred_str = with_short_path(self.tcx, predicate);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{pred_str}`",
)
}
}
}
};
if suggest_increasing_limit {
self.suggest_new_overflow_limit(&mut err);
@ -248,7 +286,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let predicate = obligation.predicate.clone().to_predicate(self.tcx);
let predicate = self.resolve_vars_if_possible(predicate);
self.report_overflow_error(
&predicate,
OverflowCause::TraitSolver(predicate),
obligation.cause.span,
suggest_increasing_limit,
|err| {
@ -299,7 +337,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
let mut err = self.build_overflow_error(
OverflowCause::TraitSolver(obligation.predicate),
obligation.cause.span,
true,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()

View File

@ -450,12 +450,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
.recursion_limit()
.value_within_limit(obligation.recursion_depth) =>
{
self.selcx.infcx.err_ctxt().report_overflow_error(
&obligation.predicate,
obligation.cause.span,
false,
|_| {},
);
self.selcx.infcx.err_ctxt().report_overflow_obligation(&obligation, false);
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {

View File

@ -1,4 +1,8 @@
//! Deeply normalize types using the old trait solver.
use super::error_reporting::OverflowCause;
use super::error_reporting::TypeErrCtxtExt;
use super::SelectionContext;
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At;
use rustc_infer::infer::InferOk;
@ -8,10 +12,6 @@ use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder};
use rustc_middle::ty::{TypeFoldable, TypeSuperFoldable, TypeVisitable, TypeVisitableExt};
use super::error_reporting::TypeErrCtxtExt;
use super::SelectionContext;
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
#[extension(pub trait NormalizeExt<'tcx>)]
impl<'tcx> At<'_, 'tcx> {
/// Normalize a value using the `AssocTypeNormalizer`.
@ -173,7 +173,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
}
let (kind, data) = match *ty.kind() {
ty::Alias(kind, alias_ty) => (kind, alias_ty),
ty::Alias(kind, data) => (kind, data),
_ => return ty.super_fold_with(self),
};
@ -210,7 +210,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error(
&ty,
OverflowCause::DeeplyNormalize(data),
self.cause.span,
true,
|_| {},
@ -306,7 +306,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error(
&ty,
OverflowCause::DeeplyNormalize(data),
self.cause.span,
false,
|diag| {

View File

@ -5,6 +5,7 @@
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::error_reporting::OverflowCause;
use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::normalize::needs_normalization;
use crate::traits::{BoundVarReplacer, PlaceholderReplacer};
@ -228,7 +229,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let guar = self
.infcx
.err_ctxt()
.build_overflow_error(&ty, self.cause.span, true)
.build_overflow_error(
OverflowCause::DeeplyNormalize(data),
self.cause.span,
true,
)
.delay_as_bug();
return Ok(Ty::new_error(self.interner(), guar));
}

View File

@ -40,7 +40,6 @@ use rustc_middle::dep_graph::DepNodeIndex;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::_match::MatchAgainstFreshVars;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
@ -2435,28 +2434,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
match self.match_impl(impl_def_id, impl_trait_header, obligation) {
Ok(args) => args,
Err(()) => {
// FIXME: A rematch may fail when a candidate cache hit occurs
// on the freshened form of the trait predicate, but the match
// fails for some reason that is not captured in the freshened
// cache key. For example, equating an impl trait ref against
// the placeholder trait ref may fail due the Generalizer relation
// raising a CyclicalTy error due to a sub_root_var relation
// for a variable being generalized...
let guar = self.infcx.dcx().span_delayed_bug(
obligation.cause.span,
format!(
"Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
),
);
let value = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
let err = Ty::new_error(self.tcx(), guar);
let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx(),
ty_op: |_| err,
lt_op: |l| l,
ct_op: |c| c,
});
Normalized { value, obligations: vec![] }
let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not")
}
}
}

View File

@ -105,6 +105,17 @@ pub enum AliasKind {
Weak,
}
impl AliasKind {
pub fn descr(self) -> &'static str {
match self {
AliasKind::Projection => "associated type",
AliasKind::Inherent => "inherent associated type",
AliasKind::Opaque => "opaque type",
AliasKind::Weak => "type alias",
}
}
}
/// Defines the kinds of types used by the type system.
///
/// Types written by the user start out as `hir::TyKind` and get

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -3,6 +3,7 @@ use std::marker::PhantomData;
fn _alias_check() {
WrongImpl::foo(0i32);
//~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
WrongImpl::<()>::foo(0i32);
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
//~| ERROR trait bounds were not satisfied

View File

@ -1,3 +1,18 @@
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
|
LL | WrongImpl::foo(0i32);
| ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl::<T, A>::foo`
--> $DIR/issue-62742.rs:29:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ required by this bound in `SafeImpl::<T, A>::foo`
LL | pub fn foo(value: A::Value) {}
| --- required by a bound in this associated function
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5
|
@ -6,13 +21,13 @@ LL | WrongImpl::foo(0i32);
|
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:26:35
--> $DIR/issue-62742.rs:27:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
--> $DIR/issue-62742.rs:6:22
--> $DIR/issue-62742.rs:7:22
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
@ -24,20 +39,20 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ----------------------------------------- function or associated item `foo` not found for this struct
|
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
--> $DIR/issue-62742.rs:28:20
--> $DIR/issue-62742.rs:29:20
|
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ --------------
| |
| unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented
--> $DIR/issue-62742.rs:12:1
--> $DIR/issue-62742.rs:13:1
|
LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
--> $DIR/issue-62742.rs:6:5
--> $DIR/issue-62742.rs:7:5
|
LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
@ -45,12 +60,12 @@ LL | WrongImpl::<()>::foo(0i32);
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl`
--> $DIR/issue-62742.rs:26:35
--> $DIR/issue-62742.rs:27:35
|
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl`
error: aborting due to 3 previous errors
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.

View File

@ -29,5 +29,5 @@ where
}
fn main() {
Race::new(|race| race.when()); //~ ERROR type annotations needed
Race::new(|race| race.when()); //~ ERROR overflow assigning `_` to `Option<_>`
}

View File

@ -1,14 +1,9 @@
error[E0282]: type annotations needed for `RaceBuilder<T, Never<T>>`
--> $DIR/issue-84073.rs:32:16
error[E0275]: overflow assigning `_` to `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`.

View File

@ -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 assigning `Box<_>` to `_`
x.foo;
x.bar();
}

View File

@ -1,54 +1,9 @@
error[E0308]: mismatched types
--> $DIR/infinite-autoderef.rs:19:13
error[E0275]: overflow assigning `Box<_>` to `_`
--> $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`.

View File

@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `X2`
error[E0275]: overflow normalizing the type alias `X2`
--> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
|
LL | type X1 = X2;
@ -6,7 +6,7 @@ LL | type X1 = X2;
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `X3`
error[E0275]: overflow normalizing the type alias `X3`
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
|
LL | type X2 = X3;
@ -14,7 +14,7 @@ LL | type X2 = X3;
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `X1`
error[E0275]: overflow normalizing the type alias `X1`
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
|
LL | type X3 = X1;

View File

@ -5,10 +5,10 @@
type X1 = X2;
//[gated]~^ ERROR cycle detected when expanding type alias `X1`
//[feature]~^^ ERROR: overflow evaluating the requirement `X2`
//[feature]~^^ ERROR: overflow normalizing the type alias `X2`
type X2 = X3;
//[feature]~^ ERROR: overflow evaluating the requirement `X3`
//[feature]~^ ERROR: overflow normalizing the type alias `X3`
type X3 = X1;
//[feature]~^ ERROR: overflow evaluating the requirement `X1`
//[feature]~^ ERROR: overflow normalizing the type alias `X1`
fn main() {}

View File

@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `X`
error[E0275]: overflow normalizing the type alias `X`
--> $DIR/infinite-vec-type-recursion.rs:6:10
|
LL | type X = Vec<X>;

View File

@ -5,7 +5,7 @@
type X = Vec<X>;
//[gated]~^ ERROR cycle detected
//[feature]~^^ ERROR: overflow evaluating the requirement `X`
//[feature]~^^ ERROR: overflow normalizing the type alias `X`
#[rustfmt::skip]
fn main() { let b: X = Vec::new(); }

View File

@ -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]
}

View File

@ -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`.

View File

@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `Loop`
error[E0275]: overflow normalizing the type alias `Loop`
--> $DIR/inherent-impls-overflow.rs:7:13
|
LL | type Loop = Loop;
@ -6,7 +6,7 @@ LL | type Loop = Loop;
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `Loop`
error[E0275]: overflow normalizing the type alias `Loop`
--> $DIR/inherent-impls-overflow.rs:9:1
|
LL | impl Loop {}
@ -14,24 +14,24 @@ LL | impl Loop {}
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `Poly0<((((((...,),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:11:17
error[E0275]: overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:13:17
|
LL | type Poly0<T> = Poly1<(T,)>;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `Poly1<((((((...,),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:14:17
error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:16:17
|
LL | type Poly1<T> = Poly0<(T,)>;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead
error[E0275]: overflow evaluating the requirement `Poly1<((((((...,),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:18:1
error[E0275]: overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
--> $DIR/inherent-impls-overflow.rs:20:1
|
LL | impl Poly0<()> {}
| ^^^^^^^^^^^^^^^^^

View File

@ -7,7 +7,7 @@ LL | impl Loop {}
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
error[E0392]: type parameter `T` is never used
--> $DIR/inherent-impls-overflow.rs:11:12
--> $DIR/inherent-impls-overflow.rs:13:12
|
LL | type Poly0<T> = Poly1<(T,)>;
| ^ unused type parameter
@ -16,7 +16,7 @@ LL | type Poly0<T> = Poly1<(T,)>;
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error[E0392]: type parameter `T` is never used
--> $DIR/inherent-impls-overflow.rs:14:12
--> $DIR/inherent-impls-overflow.rs:16:12
|
LL | type Poly1<T> = Poly0<(T,)>;
| ^ unused type parameter
@ -25,7 +25,7 @@ LL | type Poly1<T> = Poly0<(T,)>;
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
error[E0275]: overflow evaluating the requirement `Poly0<()> == _`
--> $DIR/inherent-impls-overflow.rs:18:6
--> $DIR/inherent-impls-overflow.rs:20:6
|
LL | impl Poly0<()> {}
| ^^^^^^^^^

View File

@ -4,17 +4,21 @@
#![feature(lazy_type_alias)]
#![allow(incomplete_features)]
type Loop = Loop; //[classic]~ ERROR overflow evaluating the requirement
type Loop = Loop; //[classic]~ ERROR overflow normalizing the type alias `Loop`
impl Loop {} //~ ERROR overflow evaluating the requirement
impl Loop {}
//[classic]~^ ERROR overflow normalizing the type alias `Loop`
//[next]~^^ ERROR overflow evaluating the requirement `Loop == _`
type Poly0<T> = Poly1<(T,)>;
//[classic]~^ ERROR overflow evaluating the requirement
//[classic]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>`
//[next]~^^ ERROR type parameter `T` is never used
type Poly1<T> = Poly0<(T,)>;
//[classic]~^ ERROR overflow evaluating the requirement
//[classic]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
//[next]~^^ ERROR type parameter `T` is never used
impl Poly0<()> {} //~ ERROR overflow evaluating the requirement
impl Poly0<()> {}
//[classic]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>`
//[next]~^^ ERROR overflow evaluating the requirement `Poly0<()> == _`
fn main() {}

View File

@ -5,6 +5,5 @@ fn main() {
g = f;
f = Box::new(g);
//~^ ERROR mismatched types
//~| cyclic type of infinite size
//~^ ERROR overflow assigning `Box<_>` to `_`
}

View File

@ -1,14 +1,9 @@
error[E0308]: mismatched types
error[E0275]: overflow assigning `Box<_>` to `_`
--> $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`.

View File

@ -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 assigning `Clam<_>` to `_`
match c {
Clam::A::<isize>(_) => { }
}
}

View File

@ -1,9 +1,9 @@
error[E0308]: mismatched types
--> $DIR/occurs-check-3.rs:4:24
error[E0275]: overflow assigning `Clam<_>` to `_`
--> $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`.

View File

@ -1,8 +1,5 @@
fn main() {
let f;
f = Box::new(f);
//~^ ERROR mismatched types
//~| cyclic type of infinite size
//~^ ERROR overflow assigning `Box<_>` to `_`
}

View File

@ -1,14 +1,9 @@
error[E0308]: mismatched types
--> $DIR/occurs-check.rs:5:9
error[E0275]: overflow assigning `Box<_>` to `_`
--> $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`.

View File

@ -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

View File

@ -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`.

View File

@ -10,7 +10,7 @@ fn main() {
let x = return;
let y = return;
let mut w = (x, y);
//~^ ERROR overflow evaluating the requirement
//~^ ERROR overflow assigning `_` to `*const _`
// Avoid creating lifetimes, `Sized` bounds or function calls.
let a = (ptr::addr_of!(y), ptr::addr_of!(x));
w = a;

View File

@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `_ <: *const _`
error[E0275]: overflow assigning `_` to `*const _`
--> $DIR/subtype-recursion-limit.rs:12:17
|
LL | let mut w = (x, y);

View File

@ -13,8 +13,8 @@ pub fn iso_un_option<A: 'static, B: 'static>(i: ISO<Option<A>, Option<B>>) -> IS
//~^ ERROR no field `ab` on type
//~| ERROR no field `ba` on type
let left = move |o_a| match o_a {
//~^ ERROR overflow evaluating the requirement
None => panic!("absured"),
//~^ ERROR overflow assigning `_` to `Option<_>`
None => panic!("absurd"),
Some(a) => a,
};
let right = move |o_b| match o_b {

View File

@ -10,7 +10,7 @@ error[E0609]: no field `ba` on type `(Box<(dyn Fn(Option<A>) -> Option<B> + 'sta
LL | let (ab, ba) = (i.ab, i.ba);
| ^^ unknown field
error[E0275]: overflow evaluating the requirement `_ <: Option<_>`
error[E0275]: overflow assigning `_` to `Option<_>`
--> $DIR/well-formed-recursion-limit.rs:15:33
|
LL | let left = move |o_a| match o_a {