summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/infer')
-rw-r--r--compiler/rustc_infer/src/infer/at.rs7
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs6
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs20
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs57
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs19
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs304
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs88
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs18
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs31
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs31
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs4
-rw-r--r--compiler/rustc_infer/src/infer/fudge.rs4
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs300
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs27
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs53
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs12
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs150
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs111
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs10
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs25
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs61
34 files changed, 815 insertions, 589 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 00e238648..5ff3779fa 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
pub struct At<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'a, 'tcx>,
+ pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
/// Whether we should define opaque types
@@ -48,9 +48,9 @@ pub struct Trace<'a, 'tcx> {
trace: TypeTrace<'tcx>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[inline]
- pub fn at(
+ pub fn at<'a>(
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -66,7 +66,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
tcx: self.tcx,
defining_use_anchor: self.defining_use_anchor,
considering_regions: self.considering_regions,
- in_progress_typeck_results: self.in_progress_typeck_results,
inner: self.inner.clone(),
skip_leak_check: self.skip_leak_check.clone(),
lexical_region_resolutions: self.lexical_region_resolutions.clone(),
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9488d0a6c..a3ff70363 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::Idx;
use smallvec::SmallVec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Canonicalizes a query value `V`. When we canonicalize a query,
/// we not only canonicalize unbound inference variables, but we
/// *also* replace all free regions whatsoever. So for example a
@@ -316,7 +316,7 @@ impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
}
struct Canonicalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
query_state: &'cx mut OriginalQueryValues<'tcx>,
@@ -521,7 +521,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
/// `canonicalize_query` and `canonicalize_response`.
fn canonicalize<V>(
value: V,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
query_state: &mut OriginalQueryValues<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index a9294a85e..06ca2534d 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -36,7 +36,7 @@ mod canonicalizer;
pub mod query_response;
mod substitute;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 56e834898..a299a3e57 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -16,8 +16,8 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{PredicateObligations, TraitEngine};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
@@ -32,7 +32,7 @@ use rustc_span::Span;
use std::fmt::Debug;
use std::iter;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This method is meant to be invoked as the final step of a canonical query
/// implementation. It is given:
///
@@ -509,7 +509,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
- obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+ obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
@@ -677,7 +677,7 @@ pub fn make_query_region_constraints<'tcx>(
}
struct QueryTypeRelatingDelegate<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
obligations: &'a mut Vec<PredicateObligation<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
cause: &'a ObligationCause<'tcx>,
@@ -741,17 +741,11 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- self.obligations.extend(
- self.infcx
- .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
- .obligations,
- );
+ self.obligations.extend(obligations);
Ok(())
}
}
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c406df9e4..b5427f639 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -43,7 +43,7 @@ use rustc_span::{Span, DUMMY_SP};
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
- pub infcx: &'infcx InferCtxt<'infcx, 'tcx>,
+ pub infcx: &'infcx InferCtxt<'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
@@ -63,7 +63,7 @@ pub enum RelationDir {
EqTo,
}
-impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
pub fn super_combine_tys<R>(
&self,
relation: &mut R,
@@ -147,11 +147,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
ty::ConstKind::Infer(InferConst::Var(a_vid)),
ty::ConstKind::Infer(InferConst::Var(b_vid)),
) => {
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_var(a_vid, b_vid)
- .map_err(|e| const_unification_error(a_is_expected, e))?;
+ self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid);
return Ok(a);
}
@@ -246,21 +242,17 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid }
.relate(ct, ct)?;
- self.inner
- .borrow_mut()
- .const_unification_table()
- .unify_var_value(
- target_vid,
- ConstVarValue {
- origin: ConstVariableOrigin {
- kind: ConstVariableOriginKind::ConstInference,
- span: DUMMY_SP,
- },
- val: ConstVariableValue::Known { value },
+ self.inner.borrow_mut().const_unification_table().union_value(
+ target_vid,
+ ConstVarValue {
+ origin: ConstVariableOrigin {
+ kind: ConstVariableOriginKind::ConstInference,
+ span: DUMMY_SP,
},
- )
- .map(|()| value)
- .map_err(|e| const_unification_error(vid_is_expected, e))
+ val: ConstVariableValue::Known { value },
+ },
+ );
+ Ok(value)
}
fn unify_integral_variable(
@@ -460,7 +452,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
}
struct Generalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
/// The span, used when creating new type variables and things.
cause: &'cx ObligationCause<'tcx>,
@@ -742,9 +734,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert_eq!(promoted, ());
-
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -753,7 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
)?;
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
@@ -768,13 +758,6 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
}
-pub fn const_unification_error<'tcx>(
- a_is_expected: bool,
- (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
-) -> TypeError<'tcx> {
- TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
-}
-
fn int_unification_error<'tcx>(
a_is_expected: bool,
v: (ty::IntVarValue, ty::IntVarValue),
@@ -792,7 +775,7 @@ fn float_unification_error<'tcx>(
}
struct ConstInferUnifier<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ infcx: &'cx InferCtxt<'tcx>,
span: Span,
@@ -964,9 +947,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert_eq!(promoted, ());
-
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -976,7 +957,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
Ok(self.tcx().mk_const(ty::ConstS {
ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
}))
}
_ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 3b1798ca7..59728148a 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -110,6 +110,25 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
.obligations,
);
}
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up equating of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ } else {
+ return Err(ty::error::TypeError::Sorts(ty::relate::expected_found(
+ self, a, b,
+ )));
+ }
+ }
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index eb5afe828..9ff703e52 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -51,6 +51,7 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
use crate::infer;
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
+use crate::infer::ExpectedFound;
use crate::traits::error_reporting::report_object_safety_error;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -69,12 +70,12 @@ use rustc_middle::dep_graph::DepContext;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
use rustc_middle::ty::{
- self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
- TypeSuperVisitable, TypeVisitable,
+ self, error::TypeError, Binder, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+ TypeVisitable,
};
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
-use std::ops::ControlFlow;
+use std::ops::{ControlFlow, Deref};
use std::{cmp, fmt, iter};
mod note;
@@ -84,6 +85,31 @@ pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
+/// A helper for building type related errors. The `typeck_results`
+/// field is only populated during an in-progress typeck.
+/// Get an instance by calling `InferCtxt::err` or `FnCtxt::infer_err`.
+pub struct TypeErrCtxt<'a, 'tcx> {
+ pub infcx: &'a InferCtxt<'tcx>,
+ pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+}
+
+impl TypeErrCtxt<'_, '_> {
+ /// This is just to avoid a potential footgun of accidentally
+ /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
+ #[deprecated(note = "you already have a `TypeErrCtxt`")]
+ #[allow(unused)]
+ pub fn err_ctxt(&self) -> ! {
+ bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call");
+ }
+}
+
+impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> {
+ type Target = InferCtxt<'tcx>;
+ fn deref(&self) -> &InferCtxt<'tcx> {
+ &self.infcx
+ }
+}
+
pub(super) fn note_and_explain_region<'tcx>(
tcx: TyCtxt<'tcx>,
err: &mut Diagnostic,
@@ -303,7 +329,38 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
err
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
+ if let ty::Opaque(def_id, substs) = ty.kind() {
+ let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+ // Future::Output
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+
+ let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
+
+ for (predicate, _) in bounds.subst_iter_copied(self.tcx, substs) {
+ let output = predicate
+ .kind()
+ .map_bound(|kind| match kind {
+ ty::PredicateKind::Projection(projection_predicate)
+ if projection_predicate.projection_ty.item_def_id == item_def_id =>
+ {
+ projection_predicate.term.ty()
+ }
+ _ => None,
+ })
+ .transpose();
+ if output.is_some() {
+ // We don't account for multiple `Future::Output = Ty` constraints.
+ return output;
+ }
+ }
+ }
+ None
+ }
+}
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn report_region_errors(
&self,
generic_param_scope: LocalDefId,
@@ -577,13 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
// don't show type `_`
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
- && let ty::Adt(def, substs) = ty.kind()
- && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
+ && let ty::Adt(def, substs) = ty.kind()
+ && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
{
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
} else {
- err.span_label(span, format!("this expression has type `{}`", ty));
- }
+ err.span_label(span, format!("this expression has type `{}`", ty));
+ }
}
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
&& ty.is_box() && ty.boxed_ty() == found
@@ -619,8 +676,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
let arg_expr = args.first().expect("try desugaring call w/out arg");
- self.in_progress_typeck_results.and_then(|typeck_results| {
- typeck_results.borrow().expr_ty_opt(arg_expr)
+ self.typeck_results.as_ref().and_then(|typeck_results| {
+ typeck_results.expr_ty_opt(arg_expr)
})
} else {
bug!("try desugaring w/out call expr as scrutinee");
@@ -726,10 +783,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => {
if let ObligationCauseCode::BindingObligation(_, span)
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
- = cause.code().peel_derives()
+ = cause.code().peel_derives()
&& let TypeError::RegionsPlaceholderMismatch = terr
{
- err.span_note(*span, "the lifetime requirement is introduced here");
+ err.span_note( * span,
+ "the lifetime requirement is introduced here");
}
}
}
@@ -1653,8 +1711,114 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
),
Mismatch::Fixed(s) => (s.into(), s.into(), None),
};
- match (&terr, expected == found) {
- (TypeError::Sorts(values), extra) => {
+
+ enum Similar<'tcx> {
+ Adts { expected: ty::AdtDef<'tcx>, found: ty::AdtDef<'tcx> },
+ PrimitiveFound { expected: ty::AdtDef<'tcx>, found: Ty<'tcx> },
+ PrimitiveExpected { expected: Ty<'tcx>, found: ty::AdtDef<'tcx> },
+ }
+
+ let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
+ if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() {
+ let path = self.tcx.def_path(expected.did()).data;
+ let name = path.last().unwrap().data.get_opt_name();
+ if name == Some(primitive) {
+ return Some(Similar::PrimitiveFound { expected: *expected, found });
+ }
+ } else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() {
+ let path = self.tcx.def_path(found.did()).data;
+ let name = path.last().unwrap().data.get_opt_name();
+ if name == Some(primitive) {
+ return Some(Similar::PrimitiveExpected { expected, found: *found });
+ }
+ } else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() {
+ if !expected.did().is_local() && expected.did().krate == found.did().krate {
+ // Most likely types from different versions of the same crate
+ // are in play, in which case this message isn't so helpful.
+ // A "perhaps two different versions..." error is already emitted for that.
+ return None;
+ }
+ let f_path = self.tcx.def_path(found.did()).data;
+ let e_path = self.tcx.def_path(expected.did()).data;
+
+ if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last {
+ return Some(Similar::Adts{expected: *expected, found: *found});
+ }
+ }
+ None
+ };
+
+ match terr {
+ // If two types mismatch but have similar names, mention that specifically.
+ TypeError::Sorts(values) if let Some(s) = similarity(values) => {
+ let diagnose_primitive =
+ |prim: Ty<'tcx>,
+ shadow: Ty<'tcx>,
+ defid: DefId,
+ diagnostic: &mut Diagnostic| {
+ let name = shadow.sort_string(self.tcx);
+ diagnostic.note(format!(
+ "{prim} and {name} have similar names, but are actually distinct types"
+ ));
+ diagnostic
+ .note(format!("{prim} is a primitive defined by the language"));
+ let def_span = self.tcx.def_span(defid);
+ let msg = if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}")
+ };
+ diagnostic.span_note(def_span, msg);
+ };
+
+ let diagnose_adts =
+ |expected_adt : ty::AdtDef<'tcx>,
+ found_adt: ty::AdtDef<'tcx>,
+ diagnostic: &mut Diagnostic| {
+ let found_name = values.found.sort_string(self.tcx);
+ let expected_name = values.expected.sort_string(self.tcx);
+
+ let found_defid = found_adt.did();
+ let expected_defid = expected_adt.did();
+
+ diagnostic.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
+ for (defid, name) in
+ [(found_defid, found_name), (expected_defid, expected_name)]
+ {
+ let def_span = self.tcx.def_span(defid);
+
+ let msg = if found_defid.is_local() && expected_defid.is_local() {
+ let module = self
+ .tcx
+ .parent_module_from_def_id(defid.expect_local())
+ .to_def_id();
+ let module_name = self.tcx.def_path(module).to_string_no_crate_verbose();
+ format!("{name} is defined in module `crate{module_name}` of the current crate")
+ } else if defid.is_local() {
+ format!("{name} is defined in the current crate")
+ } else {
+ let crate_name = self.tcx.crate_name(defid.krate);
+ format!("{name} is defined in crate `{crate_name}`")
+ };
+ diagnostic.span_note(def_span, msg);
+ }
+ };
+
+ match s {
+ Similar::Adts{expected, found} => {
+ diagnose_adts(expected, found, diag)
+ }
+ Similar::PrimitiveFound{expected, found: prim} => {
+ diagnose_primitive(prim, values.expected, expected.did(), diag)
+ }
+ Similar::PrimitiveExpected{expected: prim, found} => {
+ diagnose_primitive(prim, values.found, found.did(), diag)
+ }
+ }
+ }
+ TypeError::Sorts(values) => {
+ let extra = expected == found;
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
let sm = self.tcx.sess.source_map();
@@ -1707,10 +1871,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
}
- (TypeError::ObjectUnsafeCoercion(_), _) => {
+ TypeError::ObjectUnsafeCoercion(_) => {
diag.note_unsuccessful_coercion(found, expected);
}
- (_, _) => {
+ _ => {
debug!(
"note_type_err: exp_found={:?}, expected={:?} found={:?}",
exp_found, expected, found
@@ -1755,7 +1919,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's an actual definition. According to the comments (e.g. in
- // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+ // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -1847,36 +2011,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
- if let ty::Opaque(def_id, substs) = ty.kind() {
- let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
- // Future::Output
- let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
-
- let bounds = self.tcx.bound_explicit_item_bounds(*def_id);
-
- for predicate in bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- let predicate = predicate.subst(self.tcx, substs);
- let output = predicate
- .kind()
- .map_bound(|kind| match kind {
- ty::PredicateKind::Projection(projection_predicate)
- if projection_predicate.projection_ty.item_def_id == item_def_id =>
- {
- projection_predicate.term.ty()
- }
- _ => None,
- })
- .transpose();
- if output.is_some() {
- // We don't account for multiple `Future::Output = Ty` constraints.
- return output;
- }
- }
- }
- None
- }
-
/// A possible error is to forget to add `.await` when using futures:
///
/// ```compile_fail,E0308
@@ -2051,8 +2185,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diagnostic,
) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ && let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
+ {
+ diag.span_suggestion(
+ span,
+ msg,
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+ format!("{}.as_ref()", snippet.trim_start_matches('&')),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
- (exp_found.expected.kind(), exp_found.found.kind())
+ (expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
if exp_def == &found_def {
@@ -2090,21 +2238,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => show_suggestion = false,
}
}
- if let (Ok(snippet), true) =
- (self.tcx.sess.source_map().span_to_snippet(span), show_suggestion)
- {
- diag.span_suggestion(
- span,
- *msg,
- // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
- format!("{}.as_ref()", snippet.trim_start_matches('&')),
- Applicability::MachineApplicable,
- );
+ if show_suggestion {
+ return Some(*msg);
}
}
}
}
}
+ None
}
pub fn report_and_explain_type_error(
@@ -2130,6 +2271,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
}
FailureCode::Error0308(failure_str) => {
+ fn escape_literal(s: &str) -> String {
+ let mut escaped = String::with_capacity(s.len());
+ let mut chrs = s.chars().peekable();
+ while let Some(first) = chrs.next() {
+ match (first, chrs.peek()) {
+ ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
+ escaped.push('\\');
+ escaped.push(delim);
+ chrs.next();
+ }
+ ('"' | '\'', _) => {
+ escaped.push('\\');
+ escaped.push(first)
+ }
+ (c, _) => escaped.push(c),
+ };
+ }
+ escaped
+ }
let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
if let Some((expected, found)) = trace.values.ty() {
match (expected.kind(), found.kind()) {
@@ -2151,7 +2311,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
- format!("'{}'", code),
+ format!("'{}'", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2166,7 +2326,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.span_suggestion(
span,
"if you meant to write a `str` literal, use double quotes",
- format!("\"{}\"", code),
+ format!("\"{}\"", escape_literal(code)),
Applicability::MachineApplicable,
);
}
@@ -2317,7 +2477,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
- ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
// Attempt to obtain the span of the parameter so we can
// suggest adding an explicit lifetime bound to it.
let generics = self.tcx.generics_of(generic_param_scope);
@@ -2333,7 +2493,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
// instead we suggest `T: 'a + 'b` in that case.
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
+ let ast_generics = self.tcx.hir().get_generics(hir_id.owner.def_id);
let bounds =
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
// `sp` only covers `T`, change it so that it covers
@@ -2374,6 +2534,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
+ GenericKind::Opaque(def_id, substs) => {
+ format!("the opaque type `{}`", self.tcx.def_path_str_with_substs(def_id, substs))
+ }
};
if let Some(SubregionOrigin::CompareImplItemObligation {
@@ -2453,7 +2616,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
for h in self.tcx.hir().parent_iter(param.hir_id) {
break 'origin match h.1 {
Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::TyAlias(..),
+ kind: hir::ImplItemKind::Type(..),
generics,
..
})
@@ -2692,7 +2855,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
-struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'a, 'tcx>);
+struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -2779,7 +2942,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn report_inference_failure(
&self,
var_origin: RegionVariableOrigin,
@@ -2967,7 +3130,7 @@ impl TyCategory {
}
}
-impl<'tcx> InferCtxt<'_, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Given a [`hir::Block`], get the span of its last expression or
/// statement, peeling off any inner blocks.
pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
@@ -2994,7 +3157,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
_ => rustc_span::DUMMY_SP,
}
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// Be helpful when the user wrote `{... expr; }` and taking the `;` off
/// is enough to fix the error.
pub fn could_remove_semicolon(
@@ -3011,7 +3176,7 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let hir::StmtKind::Semi(ref last_expr) = last_stmt.kind else {
return None;
};
- let last_expr_ty = self.in_progress_typeck_results?.borrow().expr_ty_opt(*last_expr)?;
+ let last_expr_ty = self.typeck_results.as_ref()?.expr_ty_opt(*last_expr)?;
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
_ if last_expr_ty.references_error() => return None,
_ if self.same_type_modulo_infer(last_expr_ty, expected_ty) => {
@@ -3094,8 +3259,9 @@ impl<'tcx> InferCtxt<'_, 'tcx> {
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
&& let Some(pat_ty) = self
- .in_progress_typeck_results
- .and_then(|typeck_results| typeck_results.borrow().node_type_opt(*hir_id))
+ .typeck_results
+ .as_ref()
+ .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id))
{
let pat_ty = self.resolve_vars_if_possible(pat_ty);
if self.same_type_modulo_infer(pat_ty, expected_ty)
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 cb2be9358..7b3178e61 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
@@ -2,8 +2,10 @@ use crate::errors::{
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxt;
+use rustc_errors::IntoDiagnostic;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def::Res;
@@ -15,10 +17,9 @@ use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
-use rustc_session::SessionDiagnostic;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{BytePos, Span};
use std::borrow::Cow;
@@ -151,7 +152,7 @@ impl UnderspecifiedArgKind {
}
}
-fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
+fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
let mut printer = FmtPrinter::new(infcx.tcx, ns);
let ty_getter = move |ty_vid| {
if infcx.probe_ty_var(ty_vid).is_ok() {
@@ -182,7 +183,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'_, 'tcx>, ns: Namespace) -> FmtPr
printer
}
-fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn ty_to_string<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let printer = fmt_printer(infcx, Namespace::TypeNS);
let ty = infcx.resolve_vars_if_possible(ty);
match ty.kind() {
@@ -201,7 +202,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
/// We don't want to directly use `ty_to_string` for closures as their type isn't really
/// something users are familiar with. Directly printing the `fn_sig` of closures also
/// doesn't work as they actually use the "rust-call" API.
-fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String {
+fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let ty::Closure(_, substs) = ty.kind() else { unreachable!() };
let fn_sig = substs.as_closure().sig();
let args = fn_sig
@@ -225,7 +226,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String
format!("fn({}){}", args, ret)
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Extracts data used by diagnostic for either types or constants
/// which were stuck during inference.
pub fn extract_inference_diagnostics_data(
@@ -317,7 +318,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
- /// Used as a fallback in [InferCtxt::emit_inference_failure_err]
+ /// Used as a fallback in [TypeErrCtxt::emit_inference_failure_err]
/// in case we weren't able to get a better error.
fn bad_inference_failure_err(
&self,
@@ -364,7 +365,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
}
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub fn emit_inference_failure_err(
&self,
body_id: Option<hir::BodyId>,
@@ -376,14 +379,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
- let Some(typeck_results) = self.in_progress_typeck_results else {
+ let Some(typeck_results) = &self.typeck_results else {
// If we don't have any typeck results we're outside
// of a body, so we won't be able to get better info
// here.
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
};
- let typeck_results = typeck_results.borrow();
- let typeck_results = &typeck_results;
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
if let Some(body_id) = body_id {
@@ -435,6 +436,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
generics_def_id,
def_id: _,
generic_args,
+ have_turbofish,
} => {
let generics = self.tcx.generics_of(generics_def_id);
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
@@ -482,11 +484,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.unwrap()
.into_buffer();
- infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
- span: insert_span,
- arg_count: generic_args.len(),
- args,
- });
+ if !have_turbofish {
+ infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
+ span: insert_span,
+ arg_count: generic_args.len(),
+ args,
+ });
+ }
}
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
let printer = fmt_printer(self, Namespace::ValueNS);
@@ -560,7 +564,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
}
}
+}
+impl<'tcx> InferCtxt<'tcx> {
pub fn need_type_info_err_in_generator(
&self,
kind: hir::GeneratorKind,
@@ -616,6 +622,7 @@ enum InferSourceKind<'tcx> {
generics_def_id: DefId,
def_id: DefId,
generic_args: &'tcx [GenericArg<'tcx>],
+ have_turbofish: bool,
},
FullyQualifiedMethodCall {
receiver: &'tcx Expr<'tcx>,
@@ -650,7 +657,7 @@ impl<'tcx> InferSource<'tcx> {
}
impl<'tcx> InferSourceKind<'tcx> {
- fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) {
+ fn ty_localized_msg(&self, infcx: &InferCtxt<'tcx>) -> (&'static str, String) {
match *self {
InferSourceKind::LetBinding { ty, .. }
| InferSourceKind::ClosureArg { ty, .. }
@@ -676,6 +683,7 @@ struct InsertableGenericArgs<'tcx> {
substs: SubstsRef<'tcx>,
generics_def_id: DefId,
def_id: DefId,
+ have_turbofish: bool,
}
/// A visitor which searches for the "best" spot to use in the inference error.
@@ -686,7 +694,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<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
@@ -698,7 +706,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
fn new(
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
typeck_results: &'a TypeckResults<'tcx>,
target: GenericArg<'tcx>,
) -> Self {
@@ -894,11 +902,18 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
// impl is currently the `DefId` of `Output` in the trait definition
// which makes this somewhat difficult and prevents us from just
// using `self.path_inferred_subst_iter` here.
- hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _) => {
- if let Some(ty) = self.opt_node_type(expr.hir_id) {
- if let ty::Adt(_, substs) = ty.kind() {
- return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
- }
+ hir::ExprKind::Struct(&hir::QPath::Resolved(_self_ty, path), _, _)
+ // FIXME(TaKO8Ki): Ideally we should support this. For that
+ // we have to map back from the self type to the
+ // type alias though. That's difficult.
+ //
+ // See the `need_type_info/issue-103053.rs` test for
+ // a example.
+ if !matches!(path.res, Res::Def(DefKind::TyAlias, _)) => {
+ if let Some(ty) = self.opt_node_type(expr.hir_id)
+ && let ty::Adt(_, substs) = ty.kind()
+ {
+ return Box::new(self.resolved_path_inferred_subst_iter(path, substs));
}
}
hir::ExprKind::MethodCall(segment, ..) => {
@@ -916,6 +931,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id: def_id,
def_id,
+ have_turbofish: false,
}
};
return Box::new(insertable.into_iter());
@@ -933,6 +949,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
let tcx = self.infcx.tcx;
+ let have_turbofish = path.segments.iter().any(|segment| {
+ segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
+ });
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
//
@@ -942,7 +961,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
let generics_def_id = tcx.res_generics_def_id(path.res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
- None?
+ None?;
}
let insert_span =
path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
@@ -951,6 +970,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: path.res.def_id(),
+ have_turbofish,
}
};
@@ -970,6 +990,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: res.def_id(),
+ have_turbofish,
})
})
.chain(last_segment_using_path_data)
@@ -998,7 +1019,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
- InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
+ InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id: def_id,
+ def_id,
+ have_turbofish: false,
+ }
};
let parent_def_id = generics.parent.unwrap();
@@ -1021,7 +1048,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
// There cannot be inference variables in the self type,
// so there's nothing for us to do here.
- Res::SelfTy { .. } => {}
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {}
_ => warn!(
"unexpected path: def={:?} substs={:?} path={:?}",
def, substs, path,
@@ -1121,7 +1148,13 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
for args in self.expr_inferred_subst_iter(expr) {
debug!(?args);
- let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
+ let InsertableGenericArgs {
+ insert_span,
+ substs,
+ generics_def_id,
+ def_id,
+ have_turbofish,
+ } = args;
let generics = tcx.generics_of(generics_def_id);
if let Some(argument_index) = generics
.own_substs(substs)
@@ -1144,6 +1177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
generics_def_id,
def_id,
generic_args,
+ have_turbofish,
},
});
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 3a4320a9a..da0271a34 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -11,7 +11,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
use crate::infer::TyCtxt;
-use rustc_errors::AddSubdiagnostic;
+use rustc_errors::AddToDiagnostic;
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir::Ty;
use rustc_middle::ty::Region;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index 1410e2b63..c5f2a1a3f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -2,7 +2,9 @@
//! to hold.
use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
-use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
+use crate::errors::{
+ DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime,
+};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
@@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
note_and_explain::SuffixKind::Continues,
);
let mut impl_span = None;
- let mut trait_subdiags = Vec::new();
+ let mut implicit_static_lifetimes = Vec::new();
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
@@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Otherwise, point at all implicit static lifetimes
for span in &traits {
- trait_subdiags.push(TraitSubdiag::Note { span: *span });
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
// It would be nice to put this immediately under the above note, but they get
// pushed to the end.
- trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
+ implicit_static_lifetimes
+ .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
}
}
} else {
@@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
cause_span: cause.span,
unmet_lifetime_reqs: multispan_subdiag,
expl,
- impl_note: ImplNote { impl_span },
- trait_subdiags,
+ does_not_outlive_static_from_impl: impl_span
+ .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
+ .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
+ implicit_static_lifetimes,
};
let reported = self.tcx().sess.emit_err(err);
Some(reported)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 53d9acf7d..aaf5a7af0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -1,6 +1,6 @@
+use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::lexical_region_resolve::RegionResolutionError::*;
-use crate::infer::InferCtxt;
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::source_map::Span;
@@ -19,34 +19,34 @@ pub use find_anon_type::find_anon_type;
pub use static_impl_trait::{suggest_new_region_bound, HirTraitObjectVisitor, TraitObjectVisitor};
pub use util::find_param_with_region;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
- pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool {
+impl<'cx, 'tcx> TypeErrCtxt<'cx, 'tcx> {
+ pub fn try_report_nice_region_error(&'cx self, error: &RegionResolutionError<'tcx>) -> bool {
NiceRegionError::new(self, error.clone()).try_report().is_some()
}
}
pub struct NiceRegionError<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
error: Option<RegionResolutionError<'tcx>>,
regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>,
}
impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
- pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
- Self { infcx, error: Some(error), regions: None }
+ pub fn new(cx: &'cx TypeErrCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self {
+ Self { cx, error: Some(error), regions: None }
}
pub fn new_from_span(
- infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cx: &'cx TypeErrCtxt<'cx, 'tcx>,
span: Span,
sub: ty::Region<'tcx>,
sup: ty::Region<'tcx>,
) -> Self {
- Self { infcx, error: None, regions: Some((span, sub, sup)) }
+ Self { cx, error: None, regions: Some((span, sub, sup)) }
}
fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
+ self.cx.tcx
}
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index d4db07512..a58516829 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -226,12 +226,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
false
};
- let expected_trait_ref = self.infcx.resolve_vars_if_possible(ty::TraitRef {
+ let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef {
def_id: trait_def_id,
substs: expected_substs,
});
let actual_trait_ref = self
- .infcx
+ .cx
.resolve_vars_if_possible(ty::TraitRef { def_id: trait_def_id, substs: actual_substs });
// Search the expected and actual trait references to see (a)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index ae56bea6f..9bf755d7f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -185,8 +185,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
{
let parent_id = tcx.hir().get_parent_item(*hir_id);
- let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
- if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
+ if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into();
let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output {
@@ -287,8 +286,8 @@ pub fn suggest_new_region_bound(
) {
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
+ let consider = "consider changing";
+ let declare = "to declare that";
let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
let explicit_static =
arg.map(|arg| format!("explicit `'static` bound to the lifetime of {}", arg));
@@ -306,6 +305,10 @@ pub fn suggest_new_region_bound(
return;
};
+ // Get the identity type for this RPIT
+ let did = item_id.owner_id.to_def_id();
+ let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
+
if let Some(span) = opaque
.bounds
.iter()
@@ -322,7 +325,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ &format!("{consider} `{ty}`'s {explicit_static}"),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -352,12 +355,7 @@ pub fn suggest_new_region_bound(
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
+ &format!("{declare} `{ty}` {captures}, {explicit}",),
&plus_lt,
Applicability::MaybeIncorrect,
);
@@ -368,7 +366,7 @@ pub fn suggest_new_region_bound(
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
&format!(
- "{declare} trait object {captures}, {explicit}",
+ "{declare} the trait object {captures}, {explicit}",
declare = declare,
captures = captures,
explicit = explicit,
@@ -385,7 +383,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
+ &format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -415,7 +413,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let tcx = self.tcx();
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(impl_item)) => {
- match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
+ match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+ {
Some(Node::Item(Item {
kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
@@ -425,7 +424,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
Some(Node::TraitItem(trait_item)) => {
let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
- match tcx.hir().find_by_def_id(trait_did) {
+ match tcx.hir().find_by_def_id(trait_did.def_id) {
Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
// The method being called is defined in the `trait`, but the `'static`
// obligation comes from the `impl`. Find that `impl` so that we can point
@@ -486,7 +485,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
tcx,
ctxt.param_env,
ctxt.assoc_item.def_id,
- self.infcx.resolve_vars_if_possible(ctxt.substs),
+ self.cx.resolve_vars_if_possible(ctxt.substs),
) else {
return false;
};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index a6a39d062..5d536e982 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -84,12 +84,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
let expected = self
- .infcx
+ .cx
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
.name;
let found_highlight = HighlightBuilder::build(self.tcx(), found);
let found =
- self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+ self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
@@ -156,7 +156,8 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
[segment]
if matches!(
segment.res,
- Res::SelfTy { trait_: _, alias_to: _ }
+ Res::SelfTyParam { .. }
+ | Res::SelfTyAlias { .. }
| Res::Def(hir::def::DefKind::TyParam, _)
) =>
{
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 3e9d491af..f1461d701 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let ret_ty = fn_ty.fn_sig(self.tcx()).output();
let span = hir_sig.decl.output.span();
let future_output = if hir_sig.header.is_async() {
- ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+ ret_ty.map_bound(|ty| self.cx.get_impl_future_output_ty(ty)).transpose()
} else {
None
};
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index adaa47c01..41b115f33 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,8 +1,8 @@
use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::note_and_explain_region;
-use crate::infer::{self, InferCtxt, SubregionOrigin};
+use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
+use crate::infer::{self, SubregionOrigin};
use rustc_errors::{
- fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
@@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Region};
use super::ObligationCauseAsDiagArg;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
@@ -19,26 +19,27 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
expected_found: self.values_str(trace.values),
}
.add_to_diagnostic(err),
- infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
- .add_to_diagnostic(err),
+ infer::Reborrow(span) => {
+ RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
+ }
infer::ReborrowUpvar(span, ref upvar_id) => {
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
RegionOriginNote::WithName {
span,
- msg: fluent::infer::reborrow,
+ msg: fluent::infer_reborrow,
name: &var_name.to_string(),
continues: false,
}
.add_to_diagnostic(err);
}
infer::RelateObjectBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
}
infer::DataBorrowed(ty, span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::data_borrowed,
+ msg: fluent::infer_data_borrowed,
name: &self.ty_to_string(ty),
continues: false,
}
@@ -47,7 +48,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::ReferenceOutlivesReferent(ty, span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::reference_outlives_referent,
+ msg: fluent::infer_reference_outlives_referent,
name: &self.ty_to_string(ty),
continues: false,
}
@@ -56,22 +57,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::RelateParamBound(span, ty, opt_span) => {
RegionOriginNote::WithName {
span,
- msg: fluent::infer::relate_param_bound,
+ msg: fluent::infer_relate_param_bound,
name: &self.ty_to_string(ty),
continues: opt_span.is_some(),
}
.add_to_diagnostic(err);
if let Some(span) = opt_span {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
.add_to_diagnostic(err);
}
}
infer::RelateRegionParamBound(span) => {
- RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
+ RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
.add_to_diagnostic(err);
}
infer::CompareImplItemObligation { span, .. } => {
- RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
+ RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
.add_to_diagnostic(err);
}
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
@@ -80,7 +81,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
infer::AscribeUserTypeProvePredicate(span) => {
RegionOriginNote::Plain {
span,
- msg: fluent::infer::ascribe_user_type_prove_predicate,
+ msg: fluent::infer_ascribe_user_type_prove_predicate,
}
.add_to_diagnostic(err);
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index fee15afc7..ff5d1a05a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -38,7 +38,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVi
use std::collections::hash_map::Entry;
pub struct TypeFreshener<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
ty_freshen_count: u32,
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
@@ -47,7 +47,7 @@ pub struct TypeFreshener<'a, 'tcx> {
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs
index 2f0eadce6..6dd6c4e1f 100644
--- a/compiler/rustc_infer/src/infer/fudge.rs
+++ b/compiler/rustc_infer/src/infer/fudge.rs
@@ -43,7 +43,7 @@ struct VariableLengths {
region_constraints_len: usize,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
fn variable_lengths(&self) -> VariableLengths {
let mut inner = self.inner.borrow_mut();
VariableLengths {
@@ -167,7 +167,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
pub struct InferenceFudger<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>),
int_vars: Range<IntVid>,
float_vars: Range<FloatVid>,
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 1570a08f3..6ffefcb7a 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -113,7 +113,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index 0ce271c0e..28c87a115 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Replaces all bound variables (lifetimes, types, and constants) bound by
/// `binder` with placeholder variables in a new universe. This means that the
/// new placeholders can only be named by inference variables created after
@@ -114,7 +114,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn leak_check(
&self,
overly_polymorphic: bool,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
// If the user gave `-Zno-leak-check`, or we have been
// configured to skip the leak check, then skip the leak check
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 1e3293efa..eba65361a 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::{self, Ty};
/// GLB moves "down" the lattice (to smaller values); LUB moves
/// "up" the lattice (to bigger values).
pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
- fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
+ fn infcx(&self) -> &'f InferCtxt<'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>;
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index 9f96d52c8..d6e56fcb7 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -119,7 +119,7 @@ impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
}
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
- fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
+ fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
self.fields.infcx
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 3abed1221..ffb020398 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -35,10 +35,11 @@ use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
-use std::cell::{Cell, Ref, RefCell};
+use std::cell::{Cell, RefCell};
use std::fmt;
use self::combine::CombineFields;
+use self::error_reporting::TypeErrCtxt;
use self::free_regions::RegionRelations;
use self::lexical_region_resolve::LexicalRegionResolutions;
use self::outlives::env::OutlivesEnvironment;
@@ -252,7 +253,7 @@ pub enum DefiningAnchor {
Error,
}
-pub struct InferCtxt<'a, 'tcx> {
+pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The `DefId` of the item in whose context we are performing inference or typeck.
@@ -272,12 +273,6 @@ pub struct InferCtxt<'a, 'tcx> {
/// solving is left to borrowck instead.
pub considering_regions: bool,
- /// During type-checking/inference of a body, `in_progress_typeck_results`
- /// contains a reference to the typeck results being built up, which are
- /// used for reading closure kinds/signatures as they are inferred,
- /// and for error reporting logic to read arbitrary node types.
- pub in_progress_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-
pub inner: RefCell<InferCtxtInner<'tcx>>,
/// If set, this flag causes us to skip the 'leak check' during
@@ -340,7 +335,7 @@ pub struct InferCtxt<'a, 'tcx> {
universe: Cell<ty::UniverseIndex>,
normalize_fn_sig_for_diagnostic:
- Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
/// See the `error_reporting` module for more details.
@@ -551,16 +546,13 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
}
}
-/// A temporary returned by `tcx.infer_ctxt()`. This is necessary
-/// for multiple `InferCtxt` to share the same `in_progress_typeck_results`
-/// without using `Rc` or something similar.
+/// Used to configure inference contexts before their creation
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_use_anchor: DefiningAnchor,
considering_regions: bool,
- fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
normalize_fn_sig_for_diagnostic:
- Option<Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
+ Option<Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>,
}
pub trait TyCtxtInferExt<'tcx> {
@@ -573,26 +565,17 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
tcx: self,
defining_use_anchor: DefiningAnchor::Error,
considering_regions: true,
- fresh_typeck_results: None,
normalize_fn_sig_for_diagnostic: None,
}
}
}
impl<'tcx> InferCtxtBuilder<'tcx> {
- /// Used only by `rustc_typeck` during body type-checking/inference,
- /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
- /// Will also change the scope for opaque type defining use checks to the given owner.
- pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
- self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
- self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
- }
-
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
/// you need to call this function. Otherwise the opaque type will be treated opaquely.
///
/// It is only meant to be called in two places, for typeck
- /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
+ /// (via `Inherited::build`) and for the inference context used
/// in mir borrowck.
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
self.defining_use_anchor = defining_use_anchor;
@@ -606,7 +589,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
pub fn with_normalize_fn_sig_for_diagnostic(
mut self,
- fun: Lrc<dyn Fn(&InferCtxt<'_, 'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
+ fun: Lrc<dyn Fn(&InferCtxt<'tcx>, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>,
) -> Self {
self.normalize_fn_sig_for_diagnostic = Some(fun);
self
@@ -619,36 +602,30 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// `V` and a substitution `S`. This substitution `S` maps from
/// the bound values in `C` to their instantiated values in `V`
/// (in other words, `S(C) = V`).
- pub fn enter_with_canonical<T, R>(
+ pub fn build_with_canonical<T>(
&mut self,
span: Span,
canonical: &Canonical<'tcx, T>,
- f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R,
- ) -> R
+ ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
where
T: TypeFoldable<'tcx>,
{
- self.enter(|infcx| {
- let (value, subst) =
- infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
- f(infcx, value, subst)
- })
+ let infcx = self.build();
+ let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+ (infcx, value, subst)
}
- pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
+ pub fn build(&mut self) -> InferCtxt<'tcx> {
let InferCtxtBuilder {
tcx,
defining_use_anchor,
considering_regions,
- ref fresh_typeck_results,
ref normalize_fn_sig_for_diagnostic,
} = *self;
- let in_progress_typeck_results = fresh_typeck_results.as_ref();
- f(InferCtxt {
+ InferCtxt {
tcx,
defining_use_anchor,
considering_regions,
- in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
selection_cache: Default::default(),
@@ -663,7 +640,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
normalize_fn_sig_for_diagnostic: normalize_fn_sig_for_diagnostic
.as_ref()
.map(|f| f.clone()),
- })
+ }
}
}
@@ -675,7 +652,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
/// Extracts `value`, registering any obligations into `fulfill_cx`.
pub fn into_value_registering_obligations(
self,
- infcx: &InferCtxt<'_, 'tcx>,
+ infcx: &InferCtxt<'tcx>,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> T {
let InferOk { value, obligations } = self;
@@ -691,29 +668,34 @@ impl<'tcx> InferOk<'tcx, ()> {
}
#[must_use = "once you start a snapshot, you should always consume it"]
-pub struct CombinedSnapshot<'a, 'tcx> {
+pub struct CombinedSnapshot<'tcx> {
undo_snapshot: Snapshot<'tcx>,
region_constraints_snapshot: RegionSnapshot,
universe: ty::UniverseIndex,
was_in_snapshot: bool,
- _in_progress_typeck_results: Option<Ref<'a, ty::TypeckResults<'tcx>>>,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
+ /// Creates a `TypeErrCtxt` for emitting various inference errors.
+ /// During typeck, use `FnCtxt::infer_err` instead.
+ pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
+ TypeErrCtxt { infcx: self, typeck_results: None }
+ }
+
/// calls `tcx.try_unify_abstract_consts` after
/// canonicalizing the consts.
#[instrument(skip(self), level = "debug")]
pub fn try_unify_abstract_consts(
&self,
- a: ty::Unevaluated<'tcx, ()>,
- b: ty::Unevaluated<'tcx, ()>,
+ a: ty::UnevaluatedConst<'tcx>,
+ b: ty::UnevaluatedConst<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// Reject any attempt to unify two unevaluated constants that contain inference
// variables, since inference variables in queries lead to ICEs.
- if a.substs.has_infer_types_or_consts()
- || b.substs.has_infer_types_or_consts()
- || param_env.has_infer_types_or_consts()
+ if a.substs.has_non_region_infer()
+ || b.substs.has_non_region_infer()
+ || param_env.has_non_region_infer()
{
debug!("a or b or param_env contain infer vars in its substs -> cannot unify");
return false;
@@ -738,7 +720,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// if this is not a type variable.
///
/// No attempt is made to resolve `ty`.
- pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
+ pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => {
Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
@@ -779,7 +761,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
vars
}
- fn combine_fields(
+ fn combine_fields<'a>(
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -821,7 +803,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
result
}
- fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> {
+ fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");
let in_snapshot = self.in_snapshot.replace(true);
@@ -833,22 +815,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
was_in_snapshot: in_snapshot,
- // Borrow typeck results "in progress" (i.e., during typeck)
- // to ban writes from within a snapshot to them.
- _in_progress_typeck_results: self
- .in_progress_typeck_results
- .map(|typeck_results| typeck_results.borrow()),
}
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot,
universe,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -860,13 +836,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
#[instrument(skip(self, snapshot), level = "debug")]
- fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) {
+ fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot: _,
universe: _,
was_in_snapshot,
- _in_progress_typeck_results,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
@@ -878,7 +853,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> Result<T, E>,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -898,7 +873,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe<R, F>(&self, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let r = f(&snapshot);
@@ -910,7 +885,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self, f), level = "debug")]
pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R
where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
+ F: FnOnce(&CombinedSnapshot<'tcx>) -> R,
{
let snapshot = self.start_snapshot();
let was_skip_leak_check = self.skip_leak_check.get();
@@ -930,7 +905,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
pub fn region_constraints_added_in_snapshot(
&self,
- snapshot: &CombinedSnapshot<'a, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> Option<bool> {
self.inner
.borrow_mut()
@@ -938,7 +913,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
}
- pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
+ pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'tcx>) -> bool {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
@@ -1175,8 +1150,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Return the universe that the region `r` was created in. For
/// most regions (e.g., `'static`, named regions from the user,
/// etc) this is the root universe U0. For inference variables or
- /// placeholders, however, it will return the universe which which
- /// they are associated.
+ /// placeholders, however, it will return the universe which they
+ /// are associated.
pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
}
@@ -1308,7 +1283,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
assert!(old_value.is_none());
}
- /// Process the region constraints and return any any errors that
+ /// Process the region constraints and return any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
@@ -1342,32 +1317,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
errors
}
-
- /// Process the region constraints and report any errors that
- /// result. After this, no more unification operations should be
- /// done -- or the compiler will panic -- but it is legal to use
- /// `resolve_vars_if_possible` as well as `fully_resolve`.
- ///
- /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
- /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
- /// to do both of these operations together.
- pub fn resolve_regions_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) {
- let errors = self.resolve_regions(outlives_env);
-
- if !self.is_tainted_by_errors() {
- // As a heuristic, just skip reporting region errors
- // altogether if other errors have been reported while
- // this infcx was in use. This is totally hokey but
- // otherwise we have a hard time separating legit region
- // errors from silly ones.
- self.report_region_errors(generic_param_scope, &errors);
- }
- }
-
/// Obtains (and clears) the current set of region
/// constraints. The inference context is still usable: further
/// unifications will simply add new constraints.
@@ -1520,60 +1469,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
* except during the writeback phase.
*/
- resolve::fully_resolve(self, value)
- }
-
- // [Note-Type-error-reporting]
- // An invariant is that anytime the expected or actual type is Error (the special
- // error type, meaning that an error occurred when typechecking this expression),
- // this is a derived error. The error cascaded from another error (that was already
- // reported), so it's not useful to display it to the user.
- // The following methods implement this logic.
- // They check if either the actual or expected type is Error, and don't print the error
- // in this case. The typechecker should only ever report type errors involving mismatched
- // types using one of these methods, and should not call span_err directly for such
- // errors.
-
- pub fn type_error_struct_with_diag<M>(
- &self,
- sp: Span,
- mk_diag: M,
- actual_ty: Ty<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
- where
- M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- {
- let actual_ty = self.resolve_vars_if_possible(actual_ty);
- debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
-
- let mut err = mk_diag(self.ty_to_string(actual_ty));
-
- // Don't report an error if actual type is `Error`.
- if actual_ty.references_error() {
- err.downgrade_to_delayed_bug();
- }
-
- err
- }
-
- pub fn report_mismatched_types(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
- }
-
- pub fn report_mismatched_consts(
- &self,
- cause: &ObligationCause<'tcx>,
- expected: ty::Const<'tcx>,
- actual: ty::Const<'tcx>,
- err: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ let value = resolve::fully_resolve(self, value);
+ assert!(
+ value.as_ref().map_or(true, |value| !value.needs_infer()),
+ "`{value:?}` is not fully resolved"
+ );
+ value
}
pub fn replace_bound_vars_with_fresh_vars<T>(
@@ -1590,7 +1491,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
struct ToFreshVars<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
span: Span,
lbrct: LateBoundRegionConversionTime,
map: FxHashMap<ty::BoundVar, ty::GenericArg<'tcx>>,
@@ -1690,7 +1591,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx, ()>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
span: Option<Span>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
@@ -1725,7 +1626,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
mut param_env: ty::ParamEnv<'tcx>,
- unevaluated: ty::Unevaluated<'tcx, ()>,
+ unevaluated: ty::UnevaluatedConst<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
let mut substs = self.resolve_vars_if_possible(unevaluated.substs);
@@ -1733,7 +1634,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Postpone the evaluation of constants whose substs depend on inference
// variables
- if substs.has_infer_types_or_consts() {
+ if substs.has_non_region_infer() {
let ac = AbstractConst::new(self.tcx, unevaluated);
match ac {
Ok(None) => {
@@ -1756,8 +1657,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!(?param_env_erased);
debug!(?substs_erased);
- let unevaluated =
- ty::Unevaluated { def: unevaluated.def, substs: substs_erased, promoted: () };
+ let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, substs: substs_erased };
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
@@ -1816,6 +1716,86 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+ /// Process the region constraints and report any errors that
+ /// result. After this, no more unification operations should be
+ /// done -- or the compiler will panic -- but it is legal to use
+ /// `resolve_vars_if_possible` as well as `fully_resolve`.
+ ///
+ /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
+ /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+ /// to do both of these operations together.
+ pub fn resolve_regions_and_report_errors(
+ &self,
+ generic_param_scope: LocalDefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) {
+ let errors = self.resolve_regions(outlives_env);
+
+ if !self.is_tainted_by_errors() {
+ // As a heuristic, just skip reporting region errors
+ // altogether if other errors have been reported while
+ // this infcx was in use. This is totally hokey but
+ // otherwise we have a hard time separating legit region
+ // errors from silly ones.
+ self.report_region_errors(generic_param_scope, &errors);
+ }
+ }
+
+ // [Note-Type-error-reporting]
+ // An invariant is that anytime the expected or actual type is Error (the special
+ // error type, meaning that an error occurred when typechecking this expression),
+ // this is a derived error. The error cascaded from another error (that was already
+ // reported), so it's not useful to display it to the user.
+ // The following methods implement this logic.
+ // They check if either the actual or expected type is Error, and don't print the error
+ // in this case. The typechecker should only ever report type errors involving mismatched
+ // types using one of these methods, and should not call span_err directly for such
+ // errors.
+
+ pub fn type_error_struct_with_diag<M>(
+ &self,
+ sp: Span,
+ mk_diag: M,
+ actual_ty: Ty<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+ where
+ M: FnOnce(String) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ {
+ let actual_ty = self.resolve_vars_if_possible(actual_ty);
+ debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
+
+ let mut err = mk_diag(self.ty_to_string(actual_ty));
+
+ // Don't report an error if actual type is `Error`.
+ if actual_ty.references_error() {
+ err.downgrade_to_delayed_bug();
+ }
+
+ err
+ }
+
+ pub fn report_mismatched_types(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
+ }
+
+ pub fn report_mismatched_consts(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: ty::Const<'tcx>,
+ actual: ty::Const<'tcx>,
+ err: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
+ }
+}
+
/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
#[derive(Copy, Clone, Debug)]
@@ -1885,7 +1865,7 @@ impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> {
}
struct ShallowResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
@@ -2072,21 +2052,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
) -> SubstsRef<'tcx> {
tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
match arg.unpack() {
- GenericArgKind::Type(_)
- if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
- {
+ GenericArgKind::Type(_) if arg.has_non_region_param() || arg.has_non_region_infer() => {
tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundVar::from_usize(idx),
}))
.into()
}
- GenericArgKind::Const(ct)
- if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
- {
+ GenericArgKind::Const(ct) if ct.has_non_region_infer() || ct.has_non_region_param() => {
let ty = ct.ty();
// If the type references param or infer, replace that too...
- if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
+ if ty.has_non_region_param() || ty.has_non_region_infer() {
bug!("const `{ct}`'s type should not reference params or types");
}
tcx.mk_const(ty::ConstS {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 00fc442d3..600f94f09 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -25,7 +25,9 @@ use crate::infer::combine::ConstEquateRelation;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::PredicateObligation;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -44,7 +46,7 @@ pub struct TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
/// Callback to use when we deduce an outlives relationship.
delegate: D,
@@ -91,11 +93,9 @@ pub trait TypeRelatingDelegate<'tcx> {
);
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: Vec<PredicateObligation<'tcx>>,
) -> Result<(), TypeError<'tcx>>;
/// Creates a new universe index. Used when instantiating placeholders.
@@ -149,11 +149,7 @@ impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- pub fn new(
- infcx: &'me InferCtxt<'me, 'tcx>,
- delegate: D,
- ambient_variance: ty::Variance,
- ) -> Self {
+ pub fn new(infcx: &'me InferCtxt<'tcx>, delegate: D, ambient_variance: ty::Variance) -> Self {
Self {
infcx,
delegate,
@@ -357,7 +353,7 @@ where
// In NLL, we don't have type inference variables
// floating around, so we can do this rather imprecise
// variant of the occurs-check.
- assert!(!generalized_ty.has_infer_types_or_consts());
+ assert!(!generalized_ty.has_non_region_infer());
}
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
@@ -418,7 +414,12 @@ where
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
- self.delegate.register_opaque_type(a, b, true)?;
+ let cause = ObligationCause::dummy_with_span(self.delegate.span());
+ let obligations = self
+ .infcx
+ .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
+ .obligations;
+ self.delegate.register_opaque_type_obligations(obligations)?;
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
@@ -867,7 +868,7 @@ struct TypeGeneralizer<'me, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
- infcx: &'me InferCtxt<'me, 'tcx>,
+ infcx: &'me InferCtxt<'tcx>,
delegate: &'me mut D,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 8c9ddf866..a982f11f7 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,14 +1,16 @@
use crate::errors::OpaqueHiddenTypeDiag;
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
+use hir::def::DefKind;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
@@ -40,7 +42,7 @@ pub struct OpaqueTypeDecl<'tcx> {
pub origin: hir::OpaqueTyOrigin,
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// This is a backwards compatibility hack to prevent breaking changes from
/// lazy TAIT around RPIT handling.
pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
@@ -101,7 +103,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
- let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+ let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
@@ -167,25 +169,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
param_env,
b,
origin,
+ a_is_expected,
))
}
_ => None,
};
- if let Some(res) = process(a, b) {
+ if let Some(res) = process(a, b, true) {
res
- } else if let Some(res) = process(b, a) {
+ } else if let Some(res) = process(b, a, false) {
res
} else {
- // Rerun equality check, but this time error out due to
- // different types.
- match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
- Ok(_) => span_bug!(
- cause.span,
- "opaque types are never equal to anything but themselves: {:#?}",
- (a.kind(), b.kind())
- ),
- Err(e) => Err(e),
- }
+ let (a, b) = self.resolve_vars_if_possible((a, b));
+ Err(TypeError::Sorts(ExpectedFound::new(true, a, b)))
}
}
@@ -518,15 +513,16 @@ impl UseKind {
}
}
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self), level = "debug")]
- pub fn register_hidden_type(
+ fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
+ a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
@@ -545,21 +541,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin,
);
if let Some(prev) = prev {
- obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+ obligations =
+ self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
}
let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
- for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
-
+ for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| match *ty.kind() {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
- ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+ // FIXME(RPITIT): Don't replace RPITITs with inference vars.
+ ty::Projection(projection_ty)
+ if !projection_ty.has_escaping_bound_vars()
+ && tcx.def_kind(projection_ty.item_def_id)
+ != DefKind::ImplTraitPlaceholder =>
+ {
self.infer_projection(
param_env,
projection_ty,
@@ -575,6 +574,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
{
hidden_ty
}
+ // FIXME(RPITIT): This can go away when we move to associated types
+ ty::Projection(proj)
+ if def_id.to_def_id() == proj.item_def_id && substs == proj.substs =>
+ {
+ hidden_ty
+ }
_ => ty,
},
lt_op: |lt| lt,
@@ -623,7 +628,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
let scope = tcx.hir().get_defining_scope(opaque_hir_id);
// We walk up the node tree until we hit the root or the scope of the opaque type.
while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
+ hir_id = tcx.hir().get_parent_item(hir_id).into();
}
// Syntactically, we are allowed to define the concrete type if:
let res = hir_id == scope;
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index b2d7f4a66..14ee9f051 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -3,8 +3,9 @@
// RFC for reference.
use rustc_data_structures::sso::SsoHashSet;
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::{smallvec, SmallVec};
#[derive(Debug)]
@@ -45,6 +46,8 @@ pub enum Component<'tcx> {
// them. This gives us room to improve the regionck reasoning in
// the future without breaking backwards compat.
EscapingProjection(Vec<Component<'tcx>>),
+
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Push onto `out` all the things that must outlive `'a` for the condition
@@ -120,6 +123,17 @@ fn compute_components<'tcx>(
out.push(Component::Param(p));
}
+ // Ignore lifetimes found in opaque types. Opaque types can
+ // have lifetimes in their substs which their hidden type doesn't
+ // actually use. If we inferred that an opaque type is outlived by
+ // its parameter lifetimes, then we could prove that any lifetime
+ // outlives any other lifetime, which is unsound.
+ // See https://github.com/rust-lang/rust/issues/84305 for
+ // more details.
+ ty::Opaque(def_id, substs) => {
+ out.push(Component::Opaque(def_id, substs));
+ },
+
// For projections, we prefer to generate an obligation like
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
// regionck more ways to prove that it holds. However,
@@ -168,7 +182,6 @@ fn compute_components<'tcx>(
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
- ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
ty::Slice(..) | // ...
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9922b156e..33543135d 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -87,9 +87,9 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
}
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
- pub fn with_bounds<'a>(
+ pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>,
- infcx: Option<&InferCtxt<'a, 'tcx>>,
+ infcx: Option<&InferCtxt<'tcx>>,
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
) -> Self {
let mut builder = Self::builder(param_env);
@@ -108,7 +108,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
}
}
-impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
+impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
#[inline]
#[instrument(level = "debug")]
fn build(self) -> OutlivesEnvironment<'tcx> {
@@ -125,7 +125,7 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
- fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
+ fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'tcx>>, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@@ -142,6 +142,10 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Projection(projection_b), r_a));
}
+ OutlivesBound::RegionSubOpaque(r_a, def_id, substs) => {
+ self.region_bound_pairs
+ .insert(ty::OutlivesPredicate(GenericKind::Opaque(def_id, substs), r_a));
+ }
OutlivesBound::RegionSubRegion(r_a, r_b) => {
if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
infcx
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 5bd1774f6..6ca884799 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -68,13 +68,14 @@ use crate::infer::{
};
use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::undo_log::UndoLogs;
+use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
use smallvec::smallvec;
-impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Registers that the given region obligation must be resolved
/// from within the scope of `body_id`. These regions are enqueued
/// and later processed by regionck, when full type information is
@@ -182,7 +183,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
outlives_env.param_env,
);
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
}
}
@@ -283,6 +284,9 @@ where
Component::Param(param_ty) => {
self.param_ty_must_outlive(origin, region, *param_ty);
}
+ Component::Opaque(def_id, substs) => {
+ self.opaque_must_outlive(*def_id, substs, origin, region)
+ }
Component::Projection(projection_ty) => {
self.projection_must_outlive(origin, region, *projection_ty);
}
@@ -314,17 +318,69 @@ where
);
let generic = GenericKind::Param(param_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.param_bound(param_ty);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
#[instrument(level = "debug", skip(self))]
+ fn opaque_must_outlive(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Opaque(def_id, substs),
+ def_id,
+ substs,
+ true,
+ |ty| match *ty.kind() {
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self))]
fn projection_must_outlive(
&mut self,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
) {
+ self.generic_must_outlive(
+ origin,
+ region,
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ false,
+ |ty| match ty.kind() {
+ ty::Projection(projection_ty) => (projection_ty.item_def_id, projection_ty.substs),
+ _ => bug!("expected only projection types from env, not {:?}", ty),
+ },
+ );
+ }
+
+ #[instrument(level = "debug", skip(self, filter))]
+ fn generic_must_outlive(
+ &mut self,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ is_opaque: bool,
+ filter: impl Fn(Ty<'tcx>) -> (DefId, SubstsRef<'tcx>),
+ ) {
+ // An optimization for a common case with opaque types.
+ if substs.is_empty() {
+ return;
+ }
+
// This case is thorny for inference. The fundamental problem is
// that there are many cases where we have choice, and inference
// doesn't like choice (the current region inference in
@@ -343,16 +399,15 @@ where
// These are guaranteed to apply, no matter the inference
// results.
let trait_bounds: Vec<_> =
- self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
+ self.verify_bound.declared_region_bounds(def_id, substs).collect();
debug!(?trait_bounds);
// Compute the bounds we can derive from the environment. This
// is an "approximate" match -- in some cases, these bounds
// may not apply.
- let mut approx_env_bounds =
- self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty);
- debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds);
+ let mut approx_env_bounds = self.verify_bound.approx_declared_bounds_from_env(generic);
+ debug!(?approx_env_bounds);
// Remove outlives bounds that we get from the environment but
// which are also deducible from the trait. This arises (cc
@@ -366,14 +421,8 @@ where
// If the declaration is `trait Trait<'b> { type Item: 'b; }`, then `projection_declared_bounds_from_trait`
// will be invoked with `['b => ^1]` and so we will get `^1` returned.
let bound = bound_outlives.skip_binder();
- match *bound.0.kind() {
- ty::Projection(projection_ty) => self
- .verify_bound
- .projection_declared_bounds_from_trait(projection_ty)
- .all(|r| r != bound.1),
-
- _ => panic!("expected only projection types from env, not {:?}", bound.0),
- }
+ let (def_id, substs) = filter(bound.0);
+ self.verify_bound.declared_region_bounds(def_id, substs).all(|r| r != bound.1)
});
// If declared bounds list is empty, the only applicable rule is
@@ -390,29 +439,11 @@ where
// the problem is to add `T: 'r`, which isn't true. So, if there are no
// inference variables, we use a verify constraint instead of adding
// edges, which winds up enforcing the same condition.
- let needs_infer = projection_ty.needs_infer();
- if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
- debug!("projection_must_outlive: no declared bounds");
-
- let constraint = origin.to_constraint_category();
- for k in projection_ty.substs {
- match k.unpack() {
- GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(
- origin.clone(),
- region,
- lt,
- constraint,
- );
- }
- GenericArgKind::Type(ty) => {
- self.type_must_outlive(origin.clone(), ty, region, constraint);
- }
- GenericArgKind::Const(_) => {
- // Const parameters don't impose constraints.
- }
- }
- }
+ let needs_infer = substs.needs_infer();
+ if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) {
+ debug!("no declared bounds");
+
+ self.substs_must_outlive(substs, origin, region);
return;
}
@@ -442,8 +473,8 @@ where
.all(|b| b == Some(trait_bounds[0]))
{
let unique_bound = trait_bounds[0];
- debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound);
- debug!("projection_must_outlive: unique declared bound appears in trait ref");
+ debug!(?unique_bound);
+ debug!("unique declared bound appears in trait ref");
let category = origin.to_constraint_category();
self.delegate.push_sub_region_constraint(origin, region, unique_bound, category);
return;
@@ -454,14 +485,45 @@ where
// projection outlive; in some cases, this may add insufficient
// edges into the inference graph, leading to inference failures
// even though a satisfactory solution exists.
- let generic = GenericKind::Projection(projection_ty);
- let verify_bound = self.verify_bound.generic_bound(generic);
+ let verify_bound = self.verify_bound.projection_opaque_bounds(
+ generic,
+ def_id,
+ substs,
+ &mut Default::default(),
+ );
debug!("projection_must_outlive: pushing {:?}", verify_bound);
self.delegate.push_verify(origin, generic, region, verify_bound);
}
+
+ fn substs_must_outlive(
+ &mut self,
+ substs: SubstsRef<'tcx>,
+ origin: infer::SubregionOrigin<'tcx>,
+ region: ty::Region<'tcx>,
+ ) {
+ let constraint = origin.to_constraint_category();
+ for k in substs {
+ match k.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
+ }
+ GenericArgKind::Type(ty) => {
+ self.type_must_outlive(origin.clone(), ty, region, constraint);
+ }
+ GenericArgKind::Const(_) => {
+ // Const parameters don't impose constraints.
+ }
+ }
+ }
+ }
}
-impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'tcx> {
fn push_sub_region_constraint(
&mut self,
origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 752334950..f470b2eb8 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -2,11 +2,10 @@ use crate::infer::outlives::components::{compute_components_recursive, Component
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
use crate::infer::{GenericKind, VerifyBound};
-use rustc_data_structures::captures::Captures;
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir::def_id::DefId;
-use rustc_middle::ty::subst::{GenericArg, Subst};
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
+use rustc_middle::ty::GenericArg;
+use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
use smallvec::smallvec;
@@ -38,20 +37,8 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
}
- /// Returns a "verify bound" that encodes what we know about
- /// `generic` and the regions it outlives.
- pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
- let mut visited = SsoHashSet::new();
- match generic {
- GenericKind::Param(param_ty) => self.param_bound(param_ty),
- GenericKind::Projection(projection_ty) => {
- self.projection_bound(projection_ty, &mut visited)
- }
- }
- }
-
#[instrument(level = "debug", skip(self))]
- fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
+ pub fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
// Start with anything like `T: 'a` we can scrape from the
// environment. If the environment contains something like
// `for<'a> T: 'a`, then we know that `T` outlives everything.
@@ -105,41 +92,31 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// the clause from the environment only applies if `'0 = 'a`,
/// which we don't know yet. But we would still include `'b` in
/// this list.
- pub fn projection_approx_declared_bounds_from_env(
+ pub fn approx_declared_bounds_from_env(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
- let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
+ let projection_ty = generic.to_ty(self.tcx);
let erased_projection_ty = self.tcx.erase_regions(projection_ty);
self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
}
- /// Searches the where-clauses in scope for regions that
- /// `projection_ty` is known to outlive. Currently requires an
- /// exact match.
- pub fn projection_declared_bounds_from_trait(
+ #[instrument(level = "debug", skip(self, visited))]
+ pub fn projection_opaque_bounds(
&self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- self.declared_projection_bounds_from_trait(projection_ty)
- }
-
- pub fn projection_bound(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
+ generic: GenericKind<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
- debug!("projection_bound(projection_ty={:?})", projection_ty);
-
- let projection_ty_as_ty =
- self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
+ let generic_ty = generic.to_ty(self.tcx);
// Search the env for where clauses like `P: 'a`.
- let env_bounds = self
- .projection_approx_declared_bounds_from_env(projection_ty)
+ let projection_opaque_bounds = self
+ .approx_declared_bounds_from_env(generic)
.into_iter()
.map(|binder| {
- if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
+ if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == generic_ty {
// Micro-optimize if this is an exact match (this
// occurs often when there are no region variables
// involved).
@@ -149,21 +126,19 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
VerifyBound::IfEq(verify_if_eq_b)
}
});
-
// Extend with bounds that we can find from the trait.
- let trait_bounds = self
- .projection_declared_bounds_from_trait(projection_ty)
- .map(|r| VerifyBound::OutlivedBy(r));
+ let trait_bounds =
+ self.declared_region_bounds(def_id, substs).map(|r| VerifyBound::OutlivedBy(r));
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
- let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
- compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
+ compute_components_recursive(self.tcx, generic_ty.into(), &mut components, visited);
self.bound_from_components(&components, visited)
};
- VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
+ VerifyBound::AnyBound(projection_opaque_bounds.chain(trait_bounds).collect())
+ .or(recursive_bound)
}
fn bound_from_components(
@@ -195,7 +170,18 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
match *component {
Component::Region(lt) => VerifyBound::OutlivedBy(lt),
Component::Param(param_ty) => self.param_bound(param_ty),
- Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
+ Component::Opaque(did, substs) => self.projection_opaque_bounds(
+ GenericKind::Opaque(did, substs),
+ did,
+ substs,
+ visited,
+ ),
+ Component::Projection(projection_ty) => self.projection_opaque_bounds(
+ GenericKind::Projection(projection_ty),
+ projection_ty.item_def_id,
+ projection_ty.substs,
+ visited,
+ ),
Component::EscapingProjection(ref components) => {
self.bound_from_components(components, visited)
}
@@ -293,30 +279,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
/// }
/// ```
///
- /// then this function would return `'x`. This is subject to the
- /// limitations around higher-ranked bounds described in
- /// `region_bounds_declared_on_associated_item`.
- fn declared_projection_bounds_from_trait(
- &self,
- projection_ty: ty::ProjectionTy<'tcx>,
- ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
- debug!("projection_bounds(projection_ty={:?})", projection_ty);
- let tcx = self.tcx;
- self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
- .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
- }
-
- /// Given the `DefId` of an associated item, returns any region
- /// bounds attached to that associated item from the trait definition.
- ///
- /// For example:
- ///
- /// ```rust
- /// trait Foo<'a> {
- /// type Bar: 'a;
- /// }
- /// ```
- ///
/// If we were given the `DefId` of `Foo::Bar`, we would return
/// `'a`. You could then apply the substitutions from the
/// projection to convert this into your namespace. This also
@@ -336,17 +298,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
///
/// This is for simplicity, and because we are not really smart
/// enough to cope with such bounds anywhere.
- fn region_bounds_declared_on_associated_item(
+ pub fn declared_region_bounds(
&self,
- assoc_item_def_id: DefId,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = ty::Region<'tcx>> {
let tcx = self.tcx;
- let bounds = tcx.item_bounds(assoc_item_def_id);
+ let bounds = tcx.item_bounds(def_id);
+ trace!("{:#?}", bounds);
bounds
.into_iter()
.filter_map(|p| p.to_opt_type_outlives())
.filter_map(|p| p.no_bound_vars())
.map(|b| b.1)
+ .map(move |r| EarlyBinder(r).subst(tcx, substs))
}
/// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index b45a6514d..9f12bc972 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -6,7 +6,7 @@ use crate::traits::{Obligation, PredicateObligation};
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::InferCtxt;
-impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+impl<'tcx> InferCtxt<'tcx> {
/// Instead of normalizing an associated type projection,
/// this function generates an inference variable and registers
/// an obligation that this inference variable must be the result
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 397efe6ee..90858e307 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -66,7 +66,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
tcx: TyCtxt<'tcx>,
overly_polymorphic: bool,
max_universe: ty::UniverseIndex,
- snapshot: &CombinedSnapshot<'_, 'tcx>,
+ snapshot: &CombinedSnapshot<'tcx>,
) -> RelateResult<'tcx, ()> {
debug!(
"leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index e43d28ee5..67b3da687 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,8 +12,10 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
+use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReLateBound, ReVar};
@@ -168,6 +170,7 @@ pub struct Verify<'tcx> {
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
+ Opaque(DefId, SubstsRef<'tcx>),
}
/// Describes the things that some `GenericKind` value `G` is known to
@@ -747,6 +750,9 @@ impl<'tcx> fmt::Debug for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{:?}", p),
GenericKind::Projection(ref p) => write!(f, "{:?}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -756,6 +762,9 @@ impl<'tcx> fmt::Display for GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => write!(f, "{}", p),
GenericKind::Projection(ref p) => write!(f, "{}", p),
+ GenericKind::Opaque(def_id, substs) => ty::tls::with(|tcx| {
+ write!(f, "{}", tcx.def_path_str_with_substs(def_id, tcx.lift(substs).unwrap()))
+ }),
}
}
}
@@ -765,6 +774,7 @@ impl<'tcx> GenericKind<'tcx> {
match *self {
GenericKind::Param(ref p) => p.to_ty(tcx),
GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs),
+ GenericKind::Opaque(def_id, substs) => tcx.mk_opaque(def_id, substs),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 3d99f0958..4db4ff238 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,6 +1,5 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{FixupError, FixupResult, InferCtxt, Span};
-use rustc_middle::mir;
use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
@@ -16,12 +15,12 @@ use std::ops::ControlFlow;
/// useful for printing messages etc but also required at various
/// points for correctness.
pub struct OpportunisticVarResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> {
#[inline]
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticVarResolver { infcx }
}
}
@@ -32,7 +31,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.has_infer_types_or_consts() {
+ if !t.has_non_region_infer() {
t // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
@@ -41,17 +40,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
}
fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
- if !ct.has_infer_types_or_consts() {
+ if !ct.has_non_region_infer() {
ct // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
-
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
- constant.super_fold_with(self)
- }
}
/// The opportunistic region resolver opportunistically resolves regions
@@ -62,11 +57,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> {
/// If you want to resolve type and const variables as well, call
/// [InferCtxt::resolve_vars_if_possible] first.
pub struct OpportunisticRegionResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
OpportunisticRegionResolver { infcx }
}
}
@@ -116,11 +111,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> {
/// It does not construct the fully resolved type (which might
/// involve some hashing and so forth).
pub struct UnresolvedTypeFinder<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
UnresolvedTypeFinder { infcx }
}
}
@@ -167,7 +162,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
/// Full type resolution replaces all type and region variables with
/// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned.
-pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: T) -> FixupResult<'tcx, T>
+pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
@@ -177,7 +172,7 @@ where
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
+ infcx: &'a InferCtxt<'tcx>,
}
impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index b7eab5d43..97354ba5d 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -2,9 +2,7 @@ use super::combine::{CombineFields, RelationDir};
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::TyVar;
@@ -12,8 +10,8 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use std::mem;
/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
-pub struct Sub<'combine, 'infcx, 'tcx> {
- fields: &'combine mut CombineFields<'infcx, 'tcx>,
+pub struct Sub<'combine, 'a, 'tcx> {
+ fields: &'combine mut CombineFields<'a, 'tcx>,
a_is_expected: bool,
}
@@ -130,39 +128,36 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
- let mut generalize = |ty, ty_is_expected| {
- let var = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.fields.trace.cause.span,
- },
- ty::UniverseIndex::ROOT,
- );
- self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
- Ok(infcx.tcx.mk_ty_var(var))
- };
- let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
- let (ga, gb) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, true)?),
- (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
- _ => unreachable!(),
- };
self.fields.obligations.extend(
infcx
- .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
- // Don't leak any generalized type variables out of this
- // subtyping relation in the case of a type error.
- .map_err(|err| {
- let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
- if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
- TypeError::Sorts(ExpectedFound { expected: a, found: b })
- } else {
- err
- }
- })?
+ .handle_opaque_type(
+ a,
+ b,
+ self.a_is_expected,
+ &self.fields.trace.cause,
+ self.param_env(),
+ )?
.obligations,
);
- Ok(ga)
+ Ok(a)
+ }
+ // Optimization of GeneratorWitness relation since we know that all
+ // free regions are replaced with bound regions during construction.
+ // This greatly speeds up subtyping of GeneratorWitness.
+ (&ty::GeneratorWitness(a_types), &ty::GeneratorWitness(b_types)) => {
+ let a_types = infcx.tcx.anonymize_bound_vars(a_types);
+ let b_types = infcx.tcx.anonymize_bound_vars(b_types);
+ if a_types.bound_vars() == b_types.bound_vars() {
+ let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
+ );
+ for (a, b) in std::iter::zip(a_types, b_types) {
+ self.relate(a, b)?;
+ }
+ Ok(a)
+ } else {
+ Err(ty::error::TypeError::Sorts(ty::relate::expected_found(self, a, b)))
+ }
}
_ => {