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.rs158
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs77
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs28
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs104
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs620
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs23
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs20
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-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.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs217
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs17
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs18
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs14
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs6
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs53
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs18
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs333
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs326
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs22
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs48
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs107
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs47
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs8
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs7
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs89
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs15
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs17
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs5
33 files changed, 1183 insertions, 1265 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 7d9bae735..d240d8e49 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,16 +30,22 @@ use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
+use std::cell::Cell;
+
+/// Whether we should define opaque types or just treat them opaquely.
+///
+/// Currently only used to prevent predicate matching from matching anything
+/// against opaque types.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum DefineOpaqueTypes {
+ Yes,
+ No,
+}
+
pub struct At<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
- /// Whether we should define opaque types
- /// or just treat them opaquely.
- /// Currently only used to prevent predicate
- /// matching from matching anything against opaque
- /// types.
- pub define_opaque_types: bool,
}
pub struct Trace<'a, 'tcx> {
@@ -55,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> {
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> At<'a, 'tcx> {
- At { infcx: self, cause, param_env, define_opaque_types: false }
+ At { infcx: self, cause, param_env }
}
/// Forks the inference context, creating a new inference context with the same inference
@@ -78,13 +84,13 @@ impl<'tcx> InferCtxt<'tcx> {
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
intercrate: self.intercrate,
+ inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
}
}
}
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -93,33 +99,21 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
}
impl<'a, 'tcx> At<'a, 'tcx> {
- pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
- Self { define_opaque_types, ..self }
- }
-
- /// Hacky routine for equating two impl headers in coherence.
- pub fn eq_impl_headers(
- self,
- expected: &ty::ImplHeader<'tcx>,
- actual: &ty::ImplHeader<'tcx>,
- ) -> InferResult<'tcx, ()> {
- debug!("eq_impl_header({:?} = {:?})", expected, actual);
- match (expected.trait_ref, actual.trait_ref) {
- (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref),
- (None, None) => self.eq(expected.self_ty, actual.self_ty),
- _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
- }
- }
-
/// Makes `a <: b`, where `a` may or may not be expected.
///
/// See [`At::trace_exp`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn sub_exp<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ a_is_expected: bool,
+ a: T,
+ b: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace_exp(a_is_expected, a, b).sub(a, b)
+ self.trace_exp(a_is_expected, a, b).sub(define_opaque_types, a, b)
}
/// Makes `actual <: expected`. For example, if type-checking a
@@ -129,54 +123,81 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn sup<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.sub_exp(false, actual, expected)
+ self.sub_exp(define_opaque_types, false, actual, expected)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace`] and [`Trace::sub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn sub<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.sub_exp(true, expected, actual)
+ self.sub_exp(define_opaque_types, true, expected, actual)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace_exp`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn eq_exp<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ a_is_expected: bool,
+ a: T,
+ b: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace_exp(a_is_expected, a, b).eq(a, b)
+ self.trace_exp(a_is_expected, a, b).eq(define_opaque_types, a, b)
}
/// Makes `expected <: actual`.
///
/// See [`At::trace`] and [`Trace::eq`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()>
+ pub fn eq<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).eq(expected, actual)
+ self.trace(expected, actual).eq(define_opaque_types, expected, actual)
}
- pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()>
+ pub fn relate<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ variance: ty::Variance,
+ actual: T,
+ ) -> InferResult<'tcx, ()>
where
T: ToTrace<'tcx>,
{
match variance {
- ty::Variance::Covariant => self.sub(expected, actual),
- ty::Variance::Invariant => self.eq(expected, actual),
- ty::Variance::Contravariant => self.sup(expected, actual),
+ ty::Variance::Covariant => self.sub(define_opaque_types, expected, actual),
+ ty::Variance::Invariant => self.eq(define_opaque_types, expected, actual),
+ ty::Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
// We could make this make sense but it's not readily
// exposed and I don't feel like dealing with it. Note
@@ -195,11 +216,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::lub`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+ pub fn lub<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, T>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).lub(expected, actual)
+ self.trace(expected, actual).lub(define_opaque_types, expected, actual)
}
/// Computes the greatest-lower-bound, or mutual subtype, of two
@@ -208,11 +234,16 @@ impl<'a, 'tcx> At<'a, 'tcx> {
///
/// See [`At::trace`] and [`Trace::glb`] for a version of
/// this method that only requires `T: Relate<'tcx>`
- pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
+ pub fn glb<T>(
+ self,
+ define_opaque_types: DefineOpaqueTypes,
+ expected: T,
+ actual: T,
+ ) -> InferResult<'tcx, T>
where
T: ToTrace<'tcx>,
{
- self.trace(expected, actual).glb(expected, actual)
+ self.trace(expected, actual).glb(define_opaque_types, expected, actual)
}
/// Sets the "trace" values that will be used for
@@ -233,7 +264,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
where
T: ToTrace<'tcx>,
{
- let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
+ let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace, a_is_expected }
}
}
@@ -242,13 +273,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected).
#[instrument(skip(self), level = "debug")]
- pub fn sub<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn sub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.sub(a_is_expected)
.relate(a, b)
@@ -259,13 +290,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
/// Makes `a == b`; the expectation is set by the call to
/// `trace()`.
#[instrument(skip(self), level = "debug")]
- pub fn eq<T>(self, a: T, b: T) -> InferResult<'tcx, ()>
+ pub fn eq<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, ()>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.equate(a_is_expected)
.relate(a, b)
@@ -274,13 +305,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- pub fn lub<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+ pub fn lub<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.lub(a_is_expected)
.relate(a, b)
@@ -289,13 +320,13 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
- pub fn glb<T>(self, a: T, b: T) -> InferResult<'tcx, T>
+ pub fn glb<T>(self, define_opaque_types: DefineOpaqueTypes, a: T, b: T) -> InferResult<'tcx, T>
where
T: Relate<'tcx>,
{
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
- let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
+ let mut fields = at.infcx.combine_fields(trace, at.param_env, define_opaque_types);
fields
.glb(a_is_expected)
.relate(a, b)
@@ -306,7 +337,6 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -314,10 +344,10 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
) -> TypeTrace<'tcx> {
match (a, b) {
(ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, trait_ref_a, trait_ref_b)
+ ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b)
}
(ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
- ToTrace::to_trace(tcx, cause, a_is_expected, ty_a, ty_b)
+ ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b)
}
(ImplSubject::Trait(_), ImplSubject::Inherent(_))
| (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
@@ -329,7 +359,6 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -344,7 +373,6 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -356,7 +384,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -371,7 +398,6 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -399,7 +425,6 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -411,7 +436,6 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -426,7 +450,6 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
@@ -441,24 +464,17 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
fn to_trace(
- tcx: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self,
) -> TypeTrace<'tcx> {
- let a_ty = tcx.mk_projection(a.def_id, a.substs);
- let b_ty = tcx.mk_projection(b.def_id, b.substs);
- TypeTrace {
- cause: cause.clone(),
- values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
- }
+ TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
}
}
impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
fn to_trace(
- _: TyCtxt<'tcx>,
cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 678c4a0be..e808911a3 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -230,9 +230,9 @@ impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
match *r {
- ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReError(_) => r,
ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
- _ => {
+ ty::RePlaceholder(..) | ty::ReLateBound(..) => {
// We only expect region names that the user can type.
bug!("unexpected region in query response: `{:?}`", r)
}
@@ -352,19 +352,17 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
ty::ReVar(vid) => {
- let resolved_vid = self
+ let resolved = self
.infcx
.inner
.borrow_mut()
.unwrap_region_constraints()
- .opportunistic_resolve_var(vid);
+ .opportunistic_resolve_var(self.tcx, vid);
debug!(
- "canonical: region var found with vid {:?}, \
- opportunistically resolved to {:?}",
- vid, resolved_vid
+ "canonical: region var found with vid {vid:?}, \
+ opportunistically resolved to {resolved:?}",
);
- let r = self.tcx.mk_re_var(resolved_vid);
- self.canonicalize_mode.canonicalize_free_region(self, r)
+ self.canonicalize_mode.canonicalize_free_region(self, resolved)
}
ty::ReStatic
@@ -376,9 +374,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
+ ty::Infer(ty::TyVar(mut vid)) => {
+ // We need to canonicalize the *root* of our ty var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.root_var(vid);
+ if root_vid != vid {
+ t = self.infcx.tcx.mk_ty_var(root_vid);
+ vid = root_vid;
+ }
+
debug!("canonical: type var found with vid {:?}", vid);
match self.infcx.probe_ty_var(vid) {
// `t` could be a float / int variable; canonicalize that instead.
@@ -404,15 +411,28 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
- t,
- ),
-
- ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
- CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
- t,
- ),
+ ty::Infer(ty::IntVar(vid)) => {
+ let nt = self.infcx.opportunistic_resolve_int_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
+ t,
+ )
+ }
+ }
+ ty::Infer(ty::FloatVar(vid)) => {
+ let nt = self.infcx.opportunistic_resolve_float_var(vid);
+ if nt != t {
+ return self.fold_ty(nt);
+ } else {
+ self.canonicalize_ty_var(
+ CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
+ t,
+ )
+ }
+ }
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
@@ -469,9 +489,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
}
}
- fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
+ ty::ConstKind::Infer(InferConst::Var(mut vid)) => {
+ // We need to canonicalize the *root* of our const var.
+ // This is so that our canonical response correctly reflects
+ // any equated inference vars correctly!
+ let root_vid = self.infcx.root_const_var(vid);
+ if root_vid != vid {
+ ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty());
+ vid = root_vid;
+ }
+
debug!("canonical: const var found with vid {:?}", vid);
match self.infcx.probe_const_var(vid) {
Ok(c) => {
@@ -532,6 +561,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
+ let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
+
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
@@ -741,7 +772,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into());
- let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
+ let br = ty::BoundRegion { var, kind: ty::BrAnon(None) };
self.interner().mk_re_late_bound(self.binder_index, br)
}
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index ce230afda..fbb2257bf 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -125,9 +125,9 @@ impl<'tcx> InferCtxt<'tcx> {
ty.into()
}
- CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => {
+ CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound };
self.tcx.mk_placeholder(placeholder_mapped).into()
}
@@ -138,9 +138,9 @@ impl<'tcx> InferCtxt<'tcx> {
)
.into(),
- CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => {
+ CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, bound }) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, bound };
self.tcx.mk_re_placeholder(placeholder_mapped).into()
}
@@ -152,9 +152,9 @@ impl<'tcx> InferCtxt<'tcx> {
)
.into(),
- CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
+ CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
let universe_mapped = universe_map(universe);
- let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
+ let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
self.tcx.mk_const(placeholder_mapped, ty).into()
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 436d29c24..e98f68ae5 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -14,7 +14,7 @@ use crate::infer::canonical::{
};
use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
+use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
@@ -159,9 +159,7 @@ impl<'tcx> InferCtxt<'tcx> {
.opaque_type_storage
.opaque_types
.iter()
- .map(|&(k, ref v)| {
- (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)
- })
+ .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
.collect()
}
@@ -510,7 +508,7 @@ impl<'tcx> InferCtxt<'tcx> {
let b = substitute_value(self.tcx, &result_subst, b);
debug!(?a, ?b, "constrain opaque type");
obligations
- .extend(self.at(cause, param_env).define_opaque_types(true).eq(a, b)?.obligations);
+ .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
@@ -603,8 +601,11 @@ impl<'tcx> InferCtxt<'tcx> {
match (value1.unpack(), value2.unpack()) {
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
- obligations
- .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+ obligations.extend(
+ self.at(cause, param_env)
+ .eq(DefineOpaqueTypes::Yes, v1, v2)?
+ .into_obligations(),
+ );
}
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() =>
@@ -612,11 +613,14 @@ impl<'tcx> InferCtxt<'tcx> {
// no action needed
}
(GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
- obligations
- .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
+ obligations.extend(
+ self.at(cause, param_env)
+ .eq(DefineOpaqueTypes::Yes, v1, v2)?
+ .into_obligations(),
+ );
}
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
- let ok = self.at(cause, param_env).eq(v1, v2)?;
+ let ok = self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, v1, v2)?;
obligations.extend(ok.into_obligations());
}
_ => {
@@ -636,11 +640,9 @@ pub fn make_query_region_constraints<'tcx>(
outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> QueryRegionConstraints<'tcx> {
- let RegionConstraintData { constraints, verifys, givens, member_constraints } =
- region_constraints;
+ let RegionConstraintData { constraints, verifys, member_constraints } = region_constraints;
assert!(verifys.is_empty());
- assert!(givens.is_empty());
debug!(?constraints);
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 33292e871..fe45b5ebe 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -27,14 +27,13 @@ use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
use super::type_variable::TypeVariableValue;
-use super::{InferCtxt, MiscVariable, TypeTrace};
+use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::infer::canonical::OriginalQueryValues;
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -53,12 +52,7 @@ pub struct CombineFields<'infcx, 'tcx> {
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>,
- /// Whether we should define opaque types
- /// or just treat them opaquely.
- /// Currently only used to prevent predicate
- /// matching from matching anything against opaque
- /// types.
- pub define_opaque_types: bool,
+ pub define_opaque_types: DefineOpaqueTypes,
}
#[derive(Copy, Clone, Debug)]
@@ -119,17 +113,39 @@ impl<'tcx> InferCtxt<'tcx> {
self.unify_float_variable(!a_is_expected, v_id, v)
}
+ // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm.
+ (
+ ty::Alias(AliasKind::Projection, _),
+ ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
+ )
+ | (
+ ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)),
+ ty::Alias(AliasKind::Projection, _),
+ ) if self.tcx.trait_solver_next() => {
+ bug!()
+ }
+
+ (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
+ if self.tcx.trait_solver_next() =>
+ {
+ relation.register_type_relate_obligation(a, b);
+ Ok(a)
+ }
+
// All other cases of inference are errors
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
}
- (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
- relation.register_type_equate_obligation(a, b);
- Ok(b)
- }
- (_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
- relation.register_type_equate_obligation(b, a);
+ // During coherence, opaque types should be treated as *possibly*
+ // equal to each other, even if their generic params differ, as
+ // they could resolve to the same hidden type, even for different
+ // generic params.
+ (
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
+ &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
+ ) if self.intercrate && a_def_id == b_def_id => {
+ relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
Ok(a)
}
@@ -161,9 +177,9 @@ impl<'tcx> InferCtxt<'tcx> {
//
// This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
// ourselves with a check to find bugs being required for code to compile because it made inference progress.
- self.probe(|_| {
+ let compatible_types = self.probe(|_| {
if a.ty() == b.ty() {
- return;
+ return Ok(());
}
// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
@@ -173,15 +189,33 @@ impl<'tcx> InferCtxt<'tcx> {
(relation.param_env(), a.ty(), b.ty()),
&mut OriginalQueryValues::default(),
);
-
- if let Err(NoSolution) = self.tcx.check_tys_might_be_eq(canonical) {
+ self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
self.tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
- );
- }
+ )
+ })
});
+ // If the consts have differing types, just bail with a const error with
+ // the expected const's type. Specifically, we don't want const infer vars
+ // to do any type shapeshifting before and after resolution.
+ if let Err(guar) = compatible_types {
+ // HACK: equating both sides with `[const error]` eagerly prevents us
+ // from leaving unconstrained inference vars during things like impl
+ // matching in the solver.
+ let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
+ return self.unify_const_variable(vid, a_error);
+ }
+ let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
+ if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
+ return self.unify_const_variable(vid, b_error);
+ }
+
+ return Ok(if relation.a_is_expected() { a_error } else { b_error });
+ }
+
match (a.kind(), b.kind()) {
(
ty::ConstKind::Infer(InferConst::Var(a_vid)),
@@ -483,10 +517,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
}))
}
-
- pub fn mark_ambiguous(&mut self) {
- self.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
- }
}
struct Generalizer<'cx, 'tcx> {
@@ -559,10 +589,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- self.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
@@ -575,10 +601,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
true
}
- fn mark_ambiguous(&mut self) {
- span_bug!(self.cause.span, "opaque types are handled in `tys`");
- }
-
fn binders<T>(
&mut self,
a: ty::Binder<'tcx, T>,
@@ -820,23 +842,25 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
- ty::PredicateKind::AliasEq(a.into(), b.into())
+ ty::PredicateKind::AliasRelate(a.into(), b.into(), ty::AliasRelationDirection::Equate)
} else {
ty::PredicateKind::ConstEquate(a, b)
})]);
}
- /// Register an obligation that both types must be equal to each other.
- ///
- /// If they aren't equal then the relation doesn't hold.
- fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
- let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
-
- self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
+ /// Register an obligation that both types must be related to each other according to
+ /// the [`ty::AliasRelationDirection`] given by [`ObligationEmittingRelation::alias_relate_direction`]
+ fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
a.into(),
b.into(),
+ self.alias_relate_direction(),
))]);
}
+
+ /// Relation direction emitted for `AliasRelate` predicates, corresponding to the direction
+ /// of the relation.
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection;
}
fn int_unification_error<'tcx>(
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 54a62326e..fe4a2dd38 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -1,3 +1,4 @@
+use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations;
use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
@@ -34,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.fields.tcx()
}
- fn intercrate(&self) -> bool {
- self.fields.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.fields.param_env
}
@@ -46,10 +43,6 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- self.fields.mark_ambiguous();
- }
-
fn relate_item_substs(
&mut self,
_item_def_id: DefId,
@@ -110,7 +103,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if self.fields.define_opaque_types && def_id.is_local() =>
+ if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+ && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -208,4 +202,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 8a2b800af..9e5f6d107 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -49,11 +49,10 @@ use super::lexical_region_resolve::RegionResolutionError;
use super::region_constraints::GenericKind;
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
-use crate::errors;
+use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags};
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,
PredicateObligation,
@@ -75,6 +74,7 @@ use rustc_middle::ty::{
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt,
};
+use rustc_span::DUMMY_SP;
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::{ControlFlow, Deref};
@@ -90,9 +90,35 @@ pub use need_type_info::TypeAnnotationNeeded;
pub mod nice_region_error;
+/// Makes a valid string literal from a string by escaping special characters (" and \),
+/// unless they are already escaped.
+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
+}
+
/// 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`.
+/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`.
+///
+/// You must only create this if you intend to actually emit an error.
+/// This provides a lot of utility methods which should not be used
+/// during the happy path.
pub struct TypeErrCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
@@ -104,6 +130,19 @@ pub struct TypeErrCtxt<'a, 'tcx> {
Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
}
+impl Drop for TypeErrCtxt<'_, '_> {
+ fn drop(&mut self) {
+ if let Some(_) = self.infcx.tcx.sess.has_errors_or_delayed_span_bugs() {
+ // ok, emitted an error.
+ } else {
+ self.infcx
+ .tcx
+ .sess
+ .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
+ }
+ }
+}
+
impl TypeErrCtxt<'_, '_> {
/// This is just to avoid a potential footgun of accidentally
/// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
@@ -164,83 +203,73 @@ fn msg_span_from_named_region<'tcx>(
alt_span: Option<Span>,
) -> (String, Option<Span>) {
match *region {
- ty::ReEarlyBound(_) | ty::ReFree(_) => {
- let (msg, span) = msg_span_from_early_bound_and_free_regions(tcx, region);
- (msg, Some(span))
- }
- ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrNamed(def_id, name),
- ..
- }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrAnon(_, Some(span)),
- ..
- }) => (format!("the anonymous lifetime defined here"), Some(span)),
- ty::RePlaceholder(ty::PlaceholderRegion {
- name: ty::BoundRegionKind::BrAnon(_, None),
- ..
- }) => (format!("an anonymous lifetime"), None),
- _ => bug!("{:?}", region),
- }
-}
-
-fn msg_span_from_early_bound_and_free_regions<'tcx>(
- tcx: TyCtxt<'tcx>,
- region: ty::Region<'tcx>,
-) -> (String, Span) {
- let scope = region.free_region_binding_scope(tcx).expect_local();
- match *region {
ty::ReEarlyBound(ref br) => {
- let mut sp = tcx.def_span(scope);
- if let Some(param) =
+ let scope = region.free_region_binding_scope(tcx).expect_local();
+ let span = if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
{
- sp = param.span;
- }
+ param.span
+ } else {
+ tcx.def_span(scope)
+ };
let text = if br.has_name() {
format!("the lifetime `{}` as defined here", br.name)
} else {
"the anonymous lifetime as defined here".to_string()
};
- (text, sp)
+ (text, Some(span))
}
ty::ReFree(ref fr) => {
if !fr.bound_region.is_named()
&& let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
{
- ("the anonymous lifetime defined here".to_string(), ty.span)
+ ("the anonymous lifetime defined here".to_string(), Some(ty.span))
} else {
+ let scope = region.free_region_binding_scope(tcx).expect_local();
match fr.bound_region {
ty::BoundRegionKind::BrNamed(_, name) => {
- let mut sp = tcx.def_span(scope);
- if let Some(param) =
+ let span = if let Some(param) =
tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
{
- sp = param.span;
- }
+ param.span
+ } else {
+ tcx.def_span(scope)
+ };
let text = if name == kw::UnderscoreLifetime {
"the anonymous lifetime as defined here".to_string()
} else {
format!("the lifetime `{}` as defined here", name)
};
- (text, sp)
+ (text, Some(span))
}
- ty::BrAnon(idx, span) => (
- format!("the anonymous lifetime #{} defined here", idx + 1),
- match span {
+ ty::BrAnon(span) => (
+ "the anonymous lifetime as defined here".to_string(),
+ Some(match span {
Some(span) => span,
None => tcx.def_span(scope)
- }
+ })
),
_ => (
format!("the lifetime `{}` as defined here", region),
- tcx.def_span(scope),
+ Some(tcx.def_span(scope)),
),
}
}
}
- _ => bug!(),
+ ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, name), .. },
+ ..
+ }) => (format!("the lifetime `{name}` as defined here"), Some(tcx.def_span(def_id))),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(Some(span)), .. },
+ ..
+ }) => (format!("the anonymous lifetime defined here"), Some(span)),
+ ty::RePlaceholder(ty::PlaceholderRegion {
+ bound: ty::BoundRegion { kind: ty::BoundRegionKind::BrAnon(None), .. },
+ ..
+ }) => (format!("an anonymous lifetime"), None),
+ _ => bug!("{:?}", region),
}
}
@@ -359,10 +388,12 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
let (def_id, substs) = match *ty.kind() {
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
- if matches!(
- self.tcx.def_kind(def_id),
- DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder
- ) =>
+ if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) =>
+ {
+ (def_id, substs)
+ }
+ ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ if self.tcx.is_impl_trait_in_trait(def_id) =>
{
(def_id, substs)
}
@@ -396,7 +427,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&self,
generic_param_scope: LocalDefId,
errors: &[RegionResolutionError<'tcx>],
- ) {
+ ) -> ErrorGuaranteed {
+ if let Some(guaranteed) = self.infcx.tainted_by_errors() {
+ return guaranteed;
+ }
+
debug!("report_region_errors(): {} errors to start", errors.len());
// try to pre-process the errors, which will group some of them
@@ -476,6 +511,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
}
+
+ self.tcx
+ .sess
+ .delay_span_bug(self.tcx.def_span(generic_param_scope), "expected region errors")
}
// This method goes through all the errors and try to group certain types
@@ -613,9 +652,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| {
- // Only external crates, if either is from a local
- // module we could have false positives
- if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
+ // Only report definitions from different crates. If both definitions
+ // are from a local module we could have false positives, e.g.
+ // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
+ if did1.krate != did2.krate {
let abs_path =
|def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]);
@@ -627,10 +667,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
if same_path().unwrap_or(false) {
let crate_name = self.tcx.crate_name(did1.krate);
- err.note(&format!(
- "perhaps two different versions of crate `{}` are being used?",
- crate_name
- ));
+ let msg = if did1.is_local() || did2.is_local() {
+ format!(
+ "the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
+ )
+ } else {
+ format!(
+ "perhaps two different versions of crate `{crate_name}` are being used?"
+ )
+ };
+ err.note(msg);
}
}
};
@@ -969,7 +1015,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let (_, sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
.name_all_regions(sig)
.unwrap();
- let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect();
+ let lts: Vec<String> = reg.into_values().map(|kind| kind.to_string()).collect();
(if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig)
};
@@ -1568,6 +1614,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
(false, Mismatch::Fixed("trait"))
}
+ ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => {
+ (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
+ }
ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
};
let Some(vals) = self.values_str(values) else {
@@ -1754,8 +1803,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
)
}
(true, ty::Alias(ty::Projection, proj))
- if self.tcx.def_kind(proj.def_id)
- == DefKind::ImplTraitPlaceholder =>
+ if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let sm = self.tcx.sess.source_map();
let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
@@ -1797,7 +1845,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// will try to hide in some case such as `async fn`, so
// to make an error more use friendly we will
// avoid to suggest a mismatch type with a
- // type that the user usually are not usign
+ // type that the user usually are not using
// directly such as `impl Future<Output = u8>`.
if !self.tcx.ty_is_opaque_future(found_ty) {
diag.note_expected_found_extra(
@@ -1888,232 +1936,182 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
debug!(?diag);
}
- pub fn report_and_explain_type_error(
+ pub fn type_error_additional_suggestions(
&self,
- trace: TypeTrace<'tcx>,
+ trace: &TypeTrace<'tcx>,
terr: TypeError<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ ) -> Vec<TypeErrorAdditionalDiags> {
use crate::traits::ObligationCauseCode::MatchExpressionArm;
-
- debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
-
+ let mut suggestions = Vec::new();
let span = trace.cause.span();
- let failure_code = trace.cause.as_failure_code(terr);
- let mut diag = match failure_code {
- FailureCode::Error0038(did) => {
- let violations = self.tcx.object_safety_violations(did);
- report_object_safety_error(self.tcx, span, did, violations)
- }
- FailureCode::Error0317(failure_str) => {
- struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
- }
- FailureCode::Error0580(failure_str) => {
- 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),
- };
+ let values = self.resolve_vars_if_possible(trace.values);
+ if let Some((expected, found)) = values.ty() {
+ match (expected.kind(), found.kind()) {
+ (ty::Tuple(_), ty::Tuple(_)) => {}
+ // If a tuple of length one was expected and the found expression has
+ // parentheses around it, perhaps the user meant to write `(expr,)` to
+ // build a tuple (issue #86100)
+ (ty::Tuple(fields), _) => {
+ suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields))
+ }
+ // If a byte was expected and the found expression is a char literal
+ // containing a single ASCII character, perhaps the user meant to write `b'c'` to
+ // specify a byte literal
+ (ty::Uint(ty::UintTy::U8), ty::Char) => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ && !code.starts_with("\\u") // forbid all Unicode escapes
+ && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) })
}
- 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()) {
- (ty::Tuple(_), ty::Tuple(_)) => {}
- // If a tuple of length one was expected and the found expression has
- // parentheses around it, perhaps the user meant to write `(expr,)` to
- // build a tuple (issue #86100)
- (ty::Tuple(fields), _) => {
- self.emit_tuple_wrap_err(&mut err, span, found, fields)
- }
- // If a byte was expected and the found expression is a char literal
- // containing a single ASCII character, perhaps the user meant to write `b'c'` to
- // specify a byte literal
- (ty::Uint(ty::UintTy::U8), ty::Char) => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
- && !code.starts_with("\\u") // forbid all Unicode escapes
- && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
- {
- err.span_suggestion(
- span,
- "if you meant to write a byte literal, prefix with `b`",
- format!("b'{}'", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- // If a character was expected and the found expression is a string literal
- // containing a single character, perhaps the user meant to write `'c'` to
- // specify a character literal (issue #92479)
- (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
- && code.chars().count() == 1
- {
- err.span_suggestion(
- span,
- "if you meant to write a `char` literal, use single quotes",
- format!("'{}'", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- // If a string was expected and the found expression is a character literal,
- // perhaps the user meant to write `"s"` to specify a string literal.
- (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
- if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
- if let Some(code) =
- code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
- {
- err.span_suggestion(
- span,
- "if you meant to write a `str` literal, use double quotes",
- format!("\"{}\"", escape_literal(code)),
- Applicability::MachineApplicable,
- );
- }
- }
- }
- // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
- // we try to suggest to add the missing `let` for `if let Some(..) = expr`
- (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
- self.suggest_let_for_letchains(&mut err, &trace.cause, span);
- }
- (ty::Array(_, _), ty::Array(_, _)) => 'block: {
- let hir = self.tcx.hir();
- let TypeError::FixedArraySize(sz) = terr else {
- break 'block;
- };
- let tykind = match hir.find_by_def_id(trace.cause.body_id) {
- Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, _, body_id),
- ..
- })) => {
- let body = hir.body(*body_id);
- struct LetVisitor<'v> {
- span: Span,
- result: Option<&'v hir::Ty<'v>>,
- }
- impl<'v> Visitor<'v> for LetVisitor<'v> {
- fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
- if self.result.is_some() {
- return;
- }
- // Find a local statement where the initializer has
- // the same span as the error and the type is specified.
- if let hir::Stmt {
- kind: hir::StmtKind::Local(hir::Local {
- init: Some(hir::Expr {
- span: init_span,
- ..
- }),
- ty: Some(array_ty),
- ..
- }),
- ..
- } = s
- && init_span == &self.span {
- self.result = Some(*array_ty);
- }
- }
- }
- let mut visitor = LetVisitor {span, result: None};
- visitor.visit_body(body);
- visitor.result.map(|r| &r.peel_refs().kind)
- }
- Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Const(ty, _),
- ..
- })) => {
- Some(&ty.peel_refs().kind)
- }
- _ => None
- };
-
- if let Some(tykind) = tykind
- && let hir::TyKind::Array(_, length) = tykind
- && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
- && let Some(span) = self.tcx.hir().opt_span(*hir_id)
- {
- err.span_suggestion(
- span,
- "consider specifying the actual array length",
- sz.found,
- Applicability::MaybeIncorrect,
- );
- }
+ // If a character was expected and the found expression is a string literal
+ // containing a single character, perhaps the user meant to write `'c'` to
+ // specify a character literal (issue #92479)
+ (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+ && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
+ && code.chars().count() == 1
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { span, code: escape_literal(code) })
+ }
+ }
+ // If a string was expected and the found expression is a character literal,
+ // perhaps the user meant to write `"s"` to specify a string literal.
+ (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+ if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+ if let Some(code) =
+ code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
+ {
+ suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { span, code: escape_literal(code) })
}
- _ => {}
}
}
- let code = trace.cause.code();
- if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
+ // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
+ // we try to suggest to add the missing `let` for `if let Some(..) = expr`
+ (ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
+ suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
+ }
+ (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)),
+ _ => {}
+ }
+ }
+ let code = trace.cause.code();
+ if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code
&& let hir::MatchSource::TryDesugar = source
&& let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values)
{
- err.note(&format!(
- "`?` operator cannot convert from `{}` to `{}`",
- found_ty.content(),
- expected_ty.content(),
- ));
+ suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() });
}
- err
+ suggestions
+ }
+
+ fn suggest_specify_actual_length(
+ &self,
+ terr: TypeError<'_>,
+ trace: &TypeTrace<'_>,
+ span: Span,
+ ) -> Option<TypeErrorAdditionalDiags> {
+ let hir = self.tcx.hir();
+ let TypeError::FixedArraySize(sz) = terr else {
+ return None;
+ };
+ let tykind = match hir.find_by_def_id(trace.cause.body_id) {
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
+ let body = hir.body(*body_id);
+ struct LetVisitor<'v> {
+ span: Span,
+ result: Option<&'v hir::Ty<'v>>,
+ }
+ impl<'v> Visitor<'v> for LetVisitor<'v> {
+ fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
+ if self.result.is_some() {
+ return;
+ }
+ // Find a local statement where the initializer has
+ // the same span as the error and the type is specified.
+ if let hir::Stmt {
+ kind: hir::StmtKind::Local(hir::Local {
+ init: Some(hir::Expr {
+ span: init_span,
+ ..
+ }),
+ ty: Some(array_ty),
+ ..
+ }),
+ ..
+ } = s
+ && init_span == &self.span {
+ self.result = Some(*array_ty);
+ }
+ }
+ }
+ let mut visitor = LetVisitor { span, result: None };
+ visitor.visit_body(body);
+ visitor.result.map(|r| &r.peel_refs().kind)
}
- FailureCode::Error0644(failure_str) => {
- struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
+ Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => {
+ Some(&ty.peel_refs().kind)
}
+ _ => None,
};
+ if let Some(tykind) = tykind
+ && let hir::TyKind::Array(_, length) = tykind
+ && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+ && let Some(span) = self.tcx.hir().opt_span(*hir_id)
+ {
+ Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found })
+ } else {
+ None
+ }
+ }
+
+ pub fn report_and_explain_type_error(
+ &self,
+ trace: TypeTrace<'tcx>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
+
+ let span = trace.cause.span();
+ let failure_code = trace.cause.as_failure_code_diag(
+ terr,
+ span,
+ self.type_error_additional_suggestions(&trace, terr),
+ );
+ let mut diag = self.tcx.sess.create_err(failure_code);
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
diag
}
- fn emit_tuple_wrap_err(
+ fn suggest_wrap_to_build_a_tuple(
&self,
- err: &mut Diagnostic,
span: Span,
found: Ty<'tcx>,
expected_fields: &List<Ty<'tcx>>,
- ) {
- let [expected_tup_elem] = expected_fields[..] else { return };
+ ) -> Option<TypeErrorAdditionalDiags> {
+ let [expected_tup_elem] = expected_fields[..] else { return None};
if !self.same_type_modulo_infer(expected_tup_elem, found) {
- return;
+ return None;
}
let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
- else { return };
+ else { return None };
- let msg = "use a trailing comma to create a tuple with one element";
- if code.starts_with('(') && code.ends_with(')') {
+ let sugg = if code.starts_with('(') && code.ends_with(')') {
let before_close = span.hi() - BytePos::from_u32(1);
- err.span_suggestion(
- span.with_hi(before_close).shrink_to_hi(),
- msg,
- ",",
- Applicability::MachineApplicable,
- );
+ TypeErrorAdditionalDiags::TupleOnlyComma {
+ span: span.with_hi(before_close).shrink_to_hi(),
+ }
} else {
- err.multipart_suggestion(
- msg,
- vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
- Applicability::MachineApplicable,
- );
- }
+ TypeErrorAdditionalDiags::TupleAlsoParentheses {
+ span_low: span.shrink_to_lo(),
+ span_high: span.shrink_to_hi(),
+ }
+ };
+ Some(sugg)
}
fn values_str(
@@ -2124,6 +2122,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match values {
infer::Regions(exp_found) => self.expected_found_str(exp_found),
infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
+ infer::Aliases(exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(exp_found) => {
let pretty_exp_found = ty::error::ExpectedFound {
expected: exp_found.expected.print_only_trait_path(),
@@ -2386,10 +2385,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let suggestion =
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
let mut suggestions = vec![(sp, suggestion)];
- for add_lt_sugg in add_lt_suggs {
- if let Some(add_lt_sugg) = add_lt_sugg {
- suggestions.push(add_lt_sugg);
- }
+ for add_lt_sugg in add_lt_suggs.into_iter().flatten() {
+ suggestions.push(add_lt_sugg);
}
err.multipart_suggestion_verbose(
format!("{msg}..."),
@@ -2413,11 +2410,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let mut sugg =
vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
- for add_lt_sugg in add_lt_suggs.clone() {
- if let Some(lt) = add_lt_sugg {
- sugg.push(lt);
- sugg.rotate_right(1);
- }
+ for lt in add_lt_suggs.clone().into_iter().flatten() {
+ sugg.push(lt);
+ sugg.rotate_right(1);
}
// `MaybeIncorrect` due to issue #41966.
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
@@ -2688,11 +2683,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
self.0.tcx
}
- fn intercrate(&self) -> bool {
- assert!(!self.0.intercrate);
- false
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
// Unused, only for consts which we treat as always equal
ty::ParamEnv::empty()
@@ -2706,10 +2696,6 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
true
}
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
fn relate_with_variance<T: relate::Relate<'tcx>>(
&mut self,
_variance: ty::Variance,
@@ -2828,15 +2814,21 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub enum FailureCode {
- Error0038(DefId),
- Error0317(&'static str),
- Error0580(&'static str),
- Error0308(&'static str),
- Error0644(&'static str),
+ Error0317,
+ Error0580,
+ Error0308,
+ Error0644,
}
pub trait ObligationCauseExt<'tcx> {
fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode;
+
+ fn as_failure_code_diag(
+ &self,
+ terr: TypeError<'tcx>,
+ span: Span,
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ ) -> ObligationCauseFailureCode;
fn as_requirement_str(&self) -> &'static str;
}
@@ -2845,40 +2837,68 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
use self::FailureCode::*;
use crate::traits::ObligationCauseCode::*;
match self.code() {
+ IfExpressionWithNoElse => Error0317,
+ MainFunctionType => Error0580,
+ CompareImplItemObligation { .. }
+ | MatchExpressionArm(_)
+ | IfExpression { .. }
+ | LetElse
+ | StartFunctionType
+ | IntrinsicType
+ | MethodReceiver => Error0308,
+
+ // In the case where we have no more specific thing to
+ // say, also take a look at the error code, maybe we can
+ // tailor to that.
+ _ => match terr {
+ TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => Error0644,
+ TypeError::IntrinsicCast => Error0308,
+ _ => Error0308,
+ },
+ }
+ }
+ fn as_failure_code_diag(
+ &self,
+ terr: TypeError<'tcx>,
+ span: Span,
+ subdiags: Vec<TypeErrorAdditionalDiags>,
+ ) -> ObligationCauseFailureCode {
+ use crate::traits::ObligationCauseCode::*;
+ match self.code() {
CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
- Error0308("method not compatible with trait")
+ ObligationCauseFailureCode::MethodCompat { span, subdiags }
}
CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
- Error0308("type not compatible with trait")
+ ObligationCauseFailureCode::TypeCompat { span, subdiags }
}
CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
- Error0308("const not compatible with trait")
- }
- MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
- Error0308(match source {
- hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
- _ => "`match` arms have incompatible types",
- })
- }
- IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
- IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
- LetElse => Error0308("`else` clause of `let...else` does not diverge"),
- MainFunctionType => Error0580("`main` function has wrong type"),
- StartFunctionType => Error0308("`#[start]` function has wrong type"),
- IntrinsicType => Error0308("intrinsic has wrong type"),
- MethodReceiver => Error0308("mismatched `self` parameter type"),
+ ObligationCauseFailureCode::ConstCompat { span, subdiags }
+ }
+ MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
+ hir::MatchSource::TryDesugar => {
+ ObligationCauseFailureCode::TryCompat { span, subdiags }
+ }
+ _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
+ },
+ IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags },
+ IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span },
+ LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
+ MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
+ StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
+ IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags },
+ MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
// In the case where we have no more specific thing to
// say, also take a look at the error code, maybe we can
// tailor to that.
_ => match terr {
TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
- Error0644("closure/generator type that references itself")
+ ObligationCauseFailureCode::ClosureSelfref { span }
}
TypeError::IntrinsicCast => {
- Error0308("cannot coerce intrinsics to function pointers")
+ ObligationCauseFailureCode::CantCoerce { span, subdiags }
}
- _ => Error0308("mismatched types"),
+ _ => ObligationCauseFailureCode::Generic { span, subdiags },
},
}
}
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 e242900fd..75cc4e257 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
@@ -1,5 +1,5 @@
use crate::errors::{
- AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
+ AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
use crate::infer::error_reporting::TypeErrCtxt;
@@ -10,14 +10,14 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
use rustc_middle::hir::nested_filter;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{self, InferConst};
use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
use rustc_span::symbol::{kw, sym, Ident};
@@ -358,7 +358,7 @@ impl<'tcx> InferCtxt<'tcx> {
bad_label,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ TypeAnnotationNeeded::E0283 => AmbiguousImpl {
span,
source_kind,
source_name,
@@ -386,7 +386,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self, error_code))]
pub fn emit_inference_failure_err(
&self,
- body_id: Option<hir::BodyId>,
+ body_def_id: LocalDefId,
failure_span: Span,
arg: GenericArg<'tcx>,
error_code: TypeAnnotationNeeded,
@@ -403,8 +403,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
let mut local_visitor = FindInferSourceVisitor::new(&self, typeck_results, arg);
- if let Some(body_id) = body_id {
- let expr = self.tcx.hir().expect_expr(body_id.hir_id);
+ if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(
+ self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
+ ) {
+ let expr = self.tcx.hir().body(body_id).value;
local_visitor.visit_expr(expr);
}
@@ -561,7 +563,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
bad_label: None,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0283 => AmbigousImpl {
+ TypeAnnotationNeeded::E0283 => AmbiguousImpl {
span,
source_kind,
source_name: &name,
@@ -1189,11 +1191,14 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
have_turbofish,
} = args;
let generics = tcx.generics_of(generics_def_id);
- if let Some(argument_index) = generics
+ if let Some(mut argument_index) = generics
.own_substs(substs)
.iter()
.position(|&arg| self.generic_arg_contains_target(arg))
{
+ if generics.parent.is_none() && generics.has_self {
+ argument_index += 1;
+ }
let substs = self.infcx.resolve_vars_if_possible(substs);
let generic_args = &generics.own_substs_no_defaults(tcx, substs)
[generics.own_counts().lifetimes..];
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index e8d94f0c0..8a78a1956 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -16,22 +16,34 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
match &self.error {
Some(RegionResolutionError::ConcreteFailure(
SubregionOrigin::RelateRegionParamBound(span),
- Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
- Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
+ Region(Interned(
+ RePlaceholder(ty::Placeholder {
+ bound: ty::BoundRegion { kind: sub_name, .. },
+ ..
+ }),
+ _,
+ )),
+ Region(Interned(
+ RePlaceholder(ty::Placeholder {
+ bound: ty::BoundRegion { kind: sup_name, .. },
+ ..
+ }),
+ _,
+ )),
)) => {
let span = *span;
let (sub_span, sub_symbol) = match sub_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
- ty::BrAnon(_, span) => (*span, None),
+ ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
};
let (sup_span, sup_symbol) = match sup_name {
ty::BrNamed(def_id, symbol) => {
(Some(self.tcx().def_span(def_id)), Some(symbol))
}
- ty::BrAnon(_, span) => (*span, None),
+ ty::BrAnon(span) => (*span, None),
ty::BrEnv => (None, None),
};
let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) {
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 b06ff10d8..22c1e3871 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
@@ -104,7 +104,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) {
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
- // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
+ // The desugaring of `async fn`s causes `sup_origin` and `param` to point at the same
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
//
// This avoids the following:
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 db4b8af46..c5ef48fe3 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
@@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::TyCtxt;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable};
use rustc_span::Span;
/// Information about the anonymous region we are searching for.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 7ffe1fd20..07a9eff2d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
+ note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent,
RefLongerThanData, RegionOriginNote, WhereClauseSuggestions,
};
use crate::fluent_generated as fluent;
@@ -176,7 +176,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let note = note_and_explain::RegionExplanation::new(
self.tcx, sub, opt_span, prefix, suffix,
);
- FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
+ FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
}
infer::RelateRegionParamBound(span) => {
@@ -306,9 +306,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// Replace the explicit self type with `Self` for better suggestion rendering
.with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
.substs;
- let trait_item_substs =
- ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
- .rebase_onto(self.tcx, impl_def_id, trait_substs);
+ let trait_item_substs = ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id)
+ .rebase_onto(self.tcx, impl_def_id, trait_substs);
let Ok(trait_predicates) = self
.tcx
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index b33729d0b..b38bbdfe7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -1,7 +1,7 @@
use super::TypeErrCtxt;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
-use rustc_hir::{self as hir, def::DefKind};
+use rustc_hir as hir;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::Printer;
@@ -75,7 +75,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diag.note("an associated type was expected, but a different one was found");
}
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
- if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
+ if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{
let p_def_id = tcx
.generics_of(body_owner_def_id)
@@ -222,7 +222,7 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter");
}
}
- (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+ (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
self.expected_projection(
diag,
proj_ty,
@@ -231,7 +231,7 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
- (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+ (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 55dcfd05e..b5aeca12a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -1,7 +1,7 @@
use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::Diagnostic;
use rustc_hir as hir;
use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
@@ -10,13 +10,23 @@ use rustc_middle::traits::{
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt};
use rustc_span::{sym, BytePos, Span};
+use rustc_target::abi::FieldIdx;
use crate::errors::{
- ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding,
+ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
+ FunctionPointerSuggestion, SuggestAccessingField, SuggestAsRefWhereAppropriate,
+ SuggestBoxingForReturnImplTrait, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany,
+ SuggestTuplePatternOne, TypeErrorAdditionalDiags,
};
use super::TypeErrCtxt;
+#[derive(Clone, Copy)]
+pub enum SuggestAsRefKind {
+ Option,
+ Result,
+}
+
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
pub(super) fn suggest_remove_semi_or_return_binding(
&self,
@@ -71,25 +81,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return_sp: Span,
arm_spans: impl Iterator<Item = Span>,
) {
- err.multipart_suggestion(
- "you could change the return type to be a boxed trait object",
- vec![
- (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
- (return_sp.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- let sugg = arm_spans
- .flat_map(|sp| {
- [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
- .into_iter()
- })
- .collect::<Vec<_>>();
- err.multipart_suggestion(
- "if you change the return type to expect trait objects, box the returned expressions",
- sugg,
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestBoxingForReturnImplTrait::ChangeReturnType {
+ start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)),
+ end_sp: return_sp.shrink_to_hi(),
+ };
+ err.subdiagnostic(sugg);
+
+ let mut starts = Vec::new();
+ let mut ends = Vec::new();
+ for span in arm_spans {
+ starts.push(span.shrink_to_lo());
+ ends.push(span.shrink_to_hi());
+ }
+ let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends };
+ err.subdiagnostic(sugg);
}
pub(super) fn suggest_tuple_pattern(
@@ -109,7 +114,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
})
.filter_map(|variant| {
- let sole_field = &variant.fields[0];
+ let sole_field = &variant.fields[FieldIdx::from_u32(0)];
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
let variant_path =
@@ -129,30 +134,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
match &compatible_variants[..] {
[] => {}
[variant] => {
- diag.multipart_suggestion_verbose(
- &format!("try wrapping the pattern in `{}`", variant),
- vec![
- (cause.span.shrink_to_lo(), format!("{}(", variant)),
- (cause.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestTuplePatternOne {
+ variant: variant.to_owned(),
+ span_low: cause.span.shrink_to_lo(),
+ span_high: cause.span.shrink_to_hi(),
+ };
+ diag.subdiagnostic(sugg);
}
_ => {
// More than one matching variant.
- diag.multipart_suggestions(
- &format!(
- "try wrapping the pattern in a variant of `{}`",
- self.tcx.def_path_str(expected_adt.did())
- ),
- compatible_variants.into_iter().map(|variant| {
- vec![
- (cause.span.shrink_to_lo(), format!("{}(", variant)),
- (cause.span.shrink_to_hi(), ")".to_string()),
- ]
- }),
- Applicability::MaybeIncorrect,
- );
+ let sugg = SuggestTuplePatternMany {
+ path: self.tcx.def_path_str(expected_adt.did()),
+ cause_span: cause.span,
+ compatible_variants,
+ };
+ diag.subdiagnostic(sugg);
}
}
}
@@ -255,15 +251,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
- pub fn suggest_await_on_future(&self, diag: &mut Diagnostic, sp: Span) {
- diag.span_suggestion_verbose(
- sp.shrink_to_hi(),
- "consider `await`ing on the `Future`",
- ".await",
- Applicability::MaybeIncorrect,
- );
- }
-
pub(super) fn suggest_accessing_field_where_appropriate(
&self,
cause: &ObligationCause<'tcx>,
@@ -290,21 +277,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let suggestion = if expected_def.is_struct() {
- format!("{}.{}", snippet, name)
+ SuggestAccessingField::Safe { span, snippet, name, ty }
} else if expected_def.is_union() {
- format!("unsafe {{ {}.{} }}", snippet, name)
+ SuggestAccessingField::Unsafe { span, snippet, name, ty }
} else {
return;
};
- diag.span_suggestion(
- span,
- &format!(
- "you might have meant to use field `{}` whose type is `{}`",
- name, ty
- ),
- suggestion,
- Applicability::MaybeIncorrect,
- );
+ diag.subdiagnostic(suggestion);
}
}
}
@@ -320,15 +299,15 @@ impl<'tcx> TypeErrCtxt<'_, '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)
+ && let Some(msg) = self.should_suggest_as_ref_kind(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,
- );
+ // HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
+ let snippet = snippet.trim_start_matches('&');
+ let subdiag = match msg {
+ SuggestAsRefKind::Option => SuggestAsRefWhereAppropriate::Option { span, snippet },
+ SuggestAsRefKind::Result => SuggestAsRefWhereAppropriate::Result { span, snippet },
+ };
+ diag.subdiagnostic(subdiag);
}
}
@@ -356,36 +335,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|| !sig.is_suggestable(self.tcx, true)
- || ty::util::is_intrinsic(self.tcx, *did)
+ || self.tcx.is_intrinsic(*did)
{
return;
}
- let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
- (true, false) => {
- let msg = "consider using a reference";
- let sug = format!("&{fn_name}");
- (msg, sug)
- }
- (false, true) => {
- let msg = "consider removing the reference";
- let sug = format!("{fn_name}");
- (msg, sug)
- }
+ let sugg = match (expected.is_ref(), found.is_ref()) {
+ (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
+ (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
(true, true) => {
- diag.note("fn items are distinct from fn pointers");
- let msg = "consider casting to a fn pointer";
- let sug = format!("&({fn_name} as {sig})");
- (msg, sug)
+ diag.subdiagnostic(FnItemsAreDistinct);
+ FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig }
}
(false, false) => {
- diag.note("fn items are distinct from fn pointers");
- let msg = "consider casting to a fn pointer";
- let sug = format!("{fn_name} as {sig}");
- (msg, sug)
+ diag.subdiagnostic(FnItemsAreDistinct);
+ FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig }
}
};
- diag.span_suggestion_verbose(span, msg, sug, Applicability::MaybeIncorrect);
+ diag.subdiagnostic(sugg);
}
(ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
let expected_sig =
@@ -394,30 +361,36 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did2).subst(self.tcx, substs2));
if self.same_type_modulo_infer(*expected_sig, *found_sig) {
- diag.note("different fn items have unique types, even if their signatures are the same");
+ diag.subdiagnostic(FnUniqTypes);
}
if !self.same_type_modulo_infer(*found_sig, *expected_sig)
|| !found_sig.is_suggestable(self.tcx, true)
|| !expected_sig.is_suggestable(self.tcx, true)
- || ty::util::is_intrinsic(self.tcx, *did1)
- || ty::util::is_intrinsic(self.tcx, *did2)
+ || self.tcx.is_intrinsic(*did1)
+ || self.tcx.is_intrinsic(*did2)
{
return;
}
let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
let sug = if found.is_ref() {
- format!("&({fn_name} as {found_sig})")
+ FunctionPointerSuggestion::CastBothRef {
+ span,
+ fn_name,
+ found_sig: *found_sig,
+ expected_sig: *expected_sig,
+ }
} else {
- format!("{fn_name} as {found_sig}")
+ FunctionPointerSuggestion::CastBoth {
+ span,
+ fn_name,
+ found_sig: *found_sig,
+ expected_sig: *expected_sig,
+ }
};
- let msg = format!(
- "consider casting both fn items to fn pointers using `as {expected_sig}`"
- );
-
- diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
+ diag.subdiagnostic(sug);
}
(ty::FnDef(did, substs), ty::FnPtr(sig)) => {
let expected_sig =
@@ -436,7 +409,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
format!("{fn_name} as {found_sig}")
};
- diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
+ diag.subdiagnostic(FnConsiderCasting { casting });
}
_ => {
return;
@@ -444,23 +417,19 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
};
}
- pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
+ pub fn should_suggest_as_ref_kind(
+ &self,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ ) -> Option<SuggestAsRefKind> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
(expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
if exp_def == &found_def {
let have_as_ref = &[
- (
- sym::Option,
- "you can convert from `&Option<T>` to `Option<&T>` using \
- `.as_ref()`",
- ),
- (
- sym::Result,
- "you can convert from `&Result<T, E>` to \
- `Result<&T, &E>` using `.as_ref()`",
- ),
+ (sym::Option, SuggestAsRefKind::Option),
+ (sym::Result, SuggestAsRefKind::Result),
];
if let Some(msg) = have_as_ref.iter().find_map(|(name, msg)| {
self.tcx.is_diagnostic_item(*name, exp_def.did()).then_some(msg)
@@ -494,15 +463,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
None
}
+ // FIXME: Remove once `rustc_hir_typeck` is migrated to diagnostic structs
+ pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
+ match self.should_suggest_as_ref_kind(expected, found) {
+ Some(SuggestAsRefKind::Option) => Some(
+ "you can convert from `&Option<T>` to `Option<&T>` using \
+ `.as_ref()`",
+ ),
+ Some(SuggestAsRefKind::Result) => Some(
+ "you can convert from `&Result<T, E>` to \
+ `Result<&T, &E>` using `.as_ref()`",
+ ),
+ None => None,
+ }
+ }
/// Try to find code with pattern `if Some(..) = expr`
/// use a `visitor` to mark the `if` which its span contains given error span,
/// and then try to find a assignment in the `cond` part, which span is equal with error span
pub(super) fn suggest_let_for_letchains(
&self,
- err: &mut Diagnostic,
cause: &ObligationCause<'_>,
span: Span,
- ) {
+ ) -> Option<TypeErrorAdditionalDiags> {
let hir = self.tcx.hir();
if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
let hir::Node::Item(hir::Item {
@@ -549,9 +531,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
visitor.visit_body(&body);
if visitor.result {
- err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()});
+ return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()});
}
}
+ None
}
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index f09f93abf..d89f63e5c 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -43,18 +43,16 @@ pub struct TypeFreshener<'a, 'tcx> {
const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
- keep_static: bool,
}
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
- pub fn new(infcx: &'a InferCtxt<'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'tcx>) -> TypeFreshener<'a, 'tcx> {
TypeFreshener {
infcx,
ty_freshen_count: 0,
const_freshen_count: 0,
ty_freshen_map: Default::default(),
const_freshen_map: Default::default(),
- keep_static,
}
}
@@ -121,18 +119,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
| ty::ReFree(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
+ | ty::ReStatic
| ty::ReError(_)
- | ty::ReErased => {
- // replace all free regions with 'erased
- self.interner().lifetimes.re_erased
- }
- ty::ReStatic => {
- if self.keep_static {
- r
- } else {
- self.interner().lifetimes.re_erased
- }
- }
+ | ty::ReErased => self.interner().lifetimes.re_erased,
}
}
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 49df393d8..2f659d9a6 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
"Glb"
}
- fn intercrate(&self) -> bool {
- assert!(!self.fields.infcx.intercrate);
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.tcx()
}
@@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- bug!("mark_ambiguous used outside of coherence");
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@@ -142,7 +133,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
Ok(())
}
- fn define_opaque_types(&self) -> bool {
+ fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types
}
}
@@ -155,4 +146,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ // FIXME(deferred_projection_equality): This isn't right, I think?
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index d1897cf24..a63cfbc91 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -82,20 +82,20 @@ impl<'tcx> InferCtxt<'tcx> {
let delegate = FnMutDelegate {
regions: &mut |br: ty::BoundRegion| {
- self.tcx.mk_re_placeholder(ty::PlaceholderRegion {
- universe: next_universe,
- name: br.kind,
- })
+ self.tcx
+ .mk_re_placeholder(ty::PlaceholderRegion { universe: next_universe, bound: br })
},
types: &mut |bound_ty: ty::BoundTy| {
self.tcx.mk_placeholder(ty::PlaceholderType {
universe: next_universe,
- name: bound_ty.kind,
+ bound: bound_ty,
})
},
consts: &mut |bound_var: ty::BoundVar, ty| {
- self.tcx
- .mk_const(ty::PlaceholderConst { universe: next_universe, name: bound_var }, ty)
+ self.tcx.mk_const(
+ ty::PlaceholderConst { universe: next_universe, bound: bound_var },
+ ty,
+ )
},
};
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index f377ac1d1..7f4c141b9 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -19,7 +19,7 @@
use super::combine::ObligationEmittingRelation;
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferCtxt;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::ObligationCause;
use rustc_middle::ty::relate::RelateResult;
@@ -36,7 +36,7 @@ pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
fn cause(&self) -> &ObligationCause<'tcx>;
- fn define_opaque_types(&self) -> bool;
+ fn define_opaque_types(&self) -> DefineOpaqueTypes;
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
@@ -110,7 +110,7 @@ where
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if this.define_opaque_types() && def_id.is_local() =>
+ if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
{
this.register_obligations(
infcx
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 2c4803550..f298b95ca 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::{IndexSlice, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -132,7 +132,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
let graph = self.construct_graph();
- self.expand_givens(&graph);
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
@@ -164,38 +163,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
- fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
- // Givens are a kind of horrible hack to account for
- // constraints like 'c <= '0 that are known to hold due to
- // closure signatures (see the comment above on the `givens`
- // field). They should go away. But until they do, the role
- // of this fn is to account for the transitive nature:
- //
- // Given 'c <= '0
- // and '0 <= '1
- // then 'c <= '1
-
- let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
- for (r, vid) in seeds {
- // While all things transitively reachable in the graph
- // from the variable (`'0` in the example above).
- let seed_index = NodeIndex(vid.index() as usize);
- for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
- let succ_index = succ_index.0;
-
- // The first N nodes correspond to the region
- // variables. Other nodes correspond to constant
- // regions.
- if succ_index < self.num_vars() {
- let succ_vid = RegionVid::new(succ_index);
-
- // Add `'c <= '1`.
- self.data.givens.insert((r, succ_vid));
- }
- }
- }
- }
-
/// Gets the LUb of a given region and the empty region
fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
match *a_region {
@@ -236,7 +203,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// Tracks the `VarSubVar` constraints generated for each region vid. We
// later use this to expand across vids.
- let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
+ let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values);
// Tracks the changed region vids.
let mut changes = Vec::new();
for constraint in self.data.constraints.keys() {
@@ -362,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
) -> bool {
debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);
- match *a_region {
- // Check if this relationship is implied by a given.
- ty::ReEarlyBound(_) | ty::ReFree(_) => {
- if self.data.givens.contains(&(a_region, b_vid)) {
- debug!("given");
- return false;
- }
- }
-
- _ => {}
- }
-
match *b_data {
VarValue::Empty(empty_ui) => {
let lub = match self.lub_empty(a_region) {
@@ -768,7 +723,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
fn collect_error_for_expanding_node(
&self,
graph: &RegionGraph<'tcx>,
- dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>,
+ dup_vec: &mut IndexSlice<RegionVid, Option<RegionVid>>,
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
@@ -891,7 +846,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
graph: &RegionGraph<'tcx>,
orig_node_idx: RegionVid,
dir: Direction,
- mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>,
+ mut dup_vec: Option<&mut IndexSlice<RegionVid, Option<RegionVid>>>,
) -> (Vec<RegionAndOrigin<'tcx>>, FxHashSet<RegionVid>, bool) {
struct WalkState<'tcx> {
set: FxHashSet<RegionVid>,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index c871ccb21..e41ec7e6c 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -2,8 +2,8 @@
use super::combine::{CombineFields, ObligationEmittingRelation};
use super::lattice::{self, LatticeDir};
-use super::InferCtxt;
use super::Subtype;
+use super::{DefineOpaqueTypes, InferCtxt};
use crate::traits::{ObligationCause, PredicateObligations};
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
@@ -29,11 +29,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
"Lub"
}
- fn intercrate(&self) -> bool {
- assert!(!self.fields.infcx.intercrate);
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.tcx()
}
@@ -46,10 +41,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- bug!("mark_ambiguous used outside of coherence");
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
@@ -142,7 +133,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
Ok(())
}
- fn define_opaque_types(&self) -> bool {
+ fn define_opaque_types(&self) -> DefineOpaqueTypes {
self.fields.define_opaque_types
}
}
@@ -155,4 +146,9 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations)
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ // FIXME(deferred_projection_equality): This isn't right, I think?
+ ty::AliasRelationDirection::Equate
+ }
}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bd1f96635..66f51328b 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,3 +1,4 @@
+pub use self::at::DefineOpaqueTypes;
pub use self::freshen::TypeFreshener;
pub use self::lexical_region_resolve::RegionResolutionError;
pub use self::LateBoundRegionConversionTime::*;
@@ -38,13 +39,13 @@ use rustc_span::Span;
use std::cell::{Cell, RefCell};
use std::fmt;
+use std::ops::Drop;
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;
-use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound};
+use self::region_constraints::{GenericKind, VarInfos, VerifyBound};
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
@@ -94,10 +95,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
/// call to `start_snapshot` and `rollback_to`.
#[derive(Clone)]
pub struct InferCtxtInner<'tcx> {
- /// Cache for projections. This cache is snapshotted along with the infcx.
+ /// Cache for projections.
///
- /// Public so that `traits::project` can use it.
- pub projection_cache: traits::ProjectionCacheStorage<'tcx>,
+ /// This cache is snapshotted along with the infcx.
+ projection_cache: traits::ProjectionCacheStorage<'tcx>,
/// We instantiate `UnificationTable` with `bounds<Ty>` because the types
/// that might instantiate a general type variable have an order,
@@ -114,24 +115,26 @@ pub struct InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Tracks the set of region variables and the constraints between them.
+ ///
/// This is initially `Some(_)` but when
/// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
/// -- further attempts to perform unification, etc., may fail if new
/// region constraints would've been added.
region_constraint_storage: Option<RegionConstraintStorage<'tcx>>,
- /// A set of constraints that regionck must validate. Each
- /// constraint has the form `T:'a`, meaning "some type `T` must
+ /// A set of constraints that regionck must validate.
+ ///
+ /// Each constraint has the form `T:'a`, meaning "some type `T` must
/// outlive the lifetime 'a". These constraints derive from
/// instantiated type parameters. So if you had a struct defined
- /// like
+ /// like the following:
/// ```ignore (illustrative)
- /// struct Foo<T:'static> { ... }
+ /// struct Foo<T: 'static> { ... }
/// ```
- /// then in some expression `let x = Foo { ... }` it will
+ /// In some expression `let x = Foo { ... }`, it will
/// instantiate the type parameter `T` with a fresh type `$0`. At
/// the same time, it will record a region obligation of
- /// `$0:'static`. This will get checked later by regionck. (We
+ /// `$0: 'static`. This will get checked later by regionck. (We
/// can't generally check these things right away because we have
/// to wait until types are resolved.)
///
@@ -185,6 +188,16 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
#[inline]
+ fn try_type_variables_probe_ref(
+ &self,
+ vid: ty::TyVid,
+ ) -> Option<&type_variable::TypeVariableValue<'tcx>> {
+ // Uses a read-only view of the unification table, this way we don't
+ // need an undo log.
+ self.type_variable_storage.eq_relations_ref().try_probe_value(vid)
+ }
+
+ #[inline]
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
self.type_variable_storage.with_log(&mut self.undo_log)
}
@@ -268,7 +281,7 @@ pub struct InferCtxt<'tcx> {
/// Caches the results of trait evaluation.
pub evaluation_cache: select::EvaluationCache<'tcx>,
- /// the set of predicates on which errors have been reported, to
+ /// The set of predicates on which errors have been reported, to
/// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
@@ -291,7 +304,7 @@ pub struct InferCtxt<'tcx> {
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
/// Track how many errors were reported when this infcx is created.
- /// If the number of errors increases, that's also a sign (line
+ /// If the number of errors increases, that's also a sign (like
/// `tainted_by_errors`) to avoid reporting certain kinds of errors.
// FIXME(matthewjasper) Merge into `tainted_by_errors`
err_count_on_creation: usize,
@@ -313,7 +326,7 @@ pub struct InferCtxt<'tcx> {
/// During coherence we have to assume that other crates may add
/// additional impls which we currently don't know about.
///
- /// To deal with this evaluation should be conservative
+ /// To deal with this evaluation, we should be conservative
/// and consider the possibility of impls from outside this crate.
/// This comes up primarily when resolving ambiguity. Imagine
/// there is some trait reference `$0: Bar` where `$0` is an
@@ -323,12 +336,17 @@ pub struct InferCtxt<'tcx> {
/// bound to some type that in a downstream crate that implements
/// `Bar`.
///
- /// Outside of coherence we set this to false because we are only
+ /// Outside of coherence, we set this to false because we are only
/// interested in types that the user could actually have written.
/// In other words, we consider `$0: Bar` to be unimplemented if
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
pub intercrate: bool,
+
+ /// Flag that is set when we enter canonicalization. Used for debugging to ensure
+ /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
+ /// inside non-canonicalization contexts.
+ inside_canonicalization_ctxt: Cell<bool>,
}
/// See the `error_reporting` module for more details.
@@ -336,6 +354,7 @@ pub struct InferCtxt<'tcx> {
pub enum ValuePairs<'tcx> {
Regions(ExpectedFound<ty::Region<'tcx>>),
Terms(ExpectedFound<ty::Term<'tcx>>),
+ Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
Sigs(ExpectedFound<ty::FnSig<'tcx>>),
@@ -373,7 +392,7 @@ pub enum SubregionOrigin<'tcx> {
Subtype(Box<TypeTrace<'tcx>>),
/// When casting `&'a T` to an `&'b Trait` object,
- /// relating `'a` to `'b`
+ /// relating `'a` to `'b`.
RelateObjectBound(Span),
/// Some type parameter was instantiated with the given type,
@@ -384,7 +403,7 @@ pub enum SubregionOrigin<'tcx> {
/// that must outlive some other region.
RelateRegionParamBound(Span),
- /// Creating a pointer `b` to contents of another reference
+ /// Creating a pointer `b` to contents of another reference.
Reborrow(Span),
/// (&'a &'b T) where a >= b
@@ -398,7 +417,7 @@ pub enum SubregionOrigin<'tcx> {
trait_item_def_id: DefId,
},
- /// Checking that the bounds of a trait's associated type hold for a given impl
+ /// Checking that the bounds of a trait's associated type hold for a given impl.
CheckAssociatedTypeBounds {
parent: Box<SubregionOrigin<'tcx>>,
impl_item_def_id: LocalDefId,
@@ -435,32 +454,33 @@ pub enum LateBoundRegionConversionTime {
AssocTypeProjection(DefId),
}
-/// Reasons to create a region inference variable
+/// Reasons to create a region inference variable.
///
-/// See `error_reporting` module for more details
+/// See `error_reporting` module for more details.
#[derive(Copy, Clone, Debug)]
pub enum RegionVariableOrigin {
- /// Region variables created for ill-categorized reasons,
- /// mostly indicates places in need of refactoring
+ /// Region variables created for ill-categorized reasons.
+ ///
+ /// They mostly indicate places in need of refactoring.
MiscVariable(Span),
- /// Regions created by a `&P` or `[...]` pattern
+ /// Regions created by a `&P` or `[...]` pattern.
PatternRegion(Span),
- /// Regions created by `&` operator
+ /// Regions created by `&` operator.
+ ///
AddrOfRegion(Span),
-
- /// Regions created as part of an autoref of a method receiver
+ /// Regions created as part of an autoref of a method receiver.
Autoref(Span),
- /// Regions created as part of an automatic coercion
+ /// Regions created as part of an automatic coercion.
Coercion(Span),
- /// Region variables created as the values for early-bound regions
+ /// Region variables created as the values for early-bound regions.
EarlyBoundRegion(Span, Symbol),
/// Region variables created for bound regions
- /// in a function or method that is called
+ /// in a function or method that is called.
LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime),
UpvarRegion(ty::UpvarId, Span),
@@ -534,7 +554,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
}
}
-/// Used to configure inference contexts before their creation
+/// Used to configure inference contexts before their creation.
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
defining_use_anchor: DefiningAnchor,
@@ -570,8 +590,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}
- pub fn intercrate(mut self) -> Self {
- self.intercrate = true;
+ pub fn intercrate(mut self, intercrate: bool) -> Self {
+ self.intercrate = intercrate;
self
}
@@ -618,6 +638,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
skip_leak_check: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
intercrate,
+ inside_canonicalization_ctxt: Cell::new(false),
}
}
}
@@ -691,12 +712,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
- freshen::TypeFreshener::new(self, false)
- }
-
- /// Like `freshener`, but does not replace `'static` regions.
- pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
- freshen::TypeFreshener::new(self, true)
+ freshen::TypeFreshener::new(self)
}
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
@@ -726,7 +742,7 @@ impl<'tcx> InferCtxt<'tcx> {
&'a self,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- define_opaque_types: bool,
+ define_opaque_types: DefineOpaqueTypes,
) -> CombineFields<'a, 'tcx> {
CombineFields {
infcx: self,
@@ -835,9 +851,9 @@ impl<'tcx> InferCtxt<'tcx> {
/// Scan the constraints produced since `snapshot` began and returns:
///
- /// - `None` -- if none of them involve "region outlives" constraints
- /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder
- /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
+ /// - `None` -- if none of them involves "region outlives" constraints.
+ /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder.
+ /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders.
pub fn region_constraints_added_in_snapshot(
&self,
snapshot: &CombinedSnapshot<'tcx>,
@@ -852,16 +868,12 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
}
- pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
- self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
- }
-
pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
where
T: at::ToTrace<'tcx>,
{
let origin = &ObligationCause::dummy();
- self.probe(|_| self.at(origin, param_env).sub(a, b).is_ok())
+ self.probe(|_| self.at(origin, param_env).sub(DefineOpaqueTypes::No, a, b).is_ok())
}
pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool
@@ -869,7 +881,7 @@ impl<'tcx> InferCtxt<'tcx> {
T: at::ToTrace<'tcx>,
{
let origin = &ObligationCause::dummy();
- self.probe(|_| self.at(origin, param_env).eq(a, b).is_ok())
+ self.probe(|_| self.at(origin, param_env).eq(DefineOpaqueTypes::No, a, b).is_ok())
}
#[instrument(skip(self), level = "debug")]
@@ -964,7 +976,8 @@ impl<'tcx> InferCtxt<'tcx> {
let ty::SubtypePredicate { a_is_expected, a, b } =
self.instantiate_binder_with_placeholders(predicate);
- let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
+ let ok =
+ self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
Ok(ok.unit())
}))
@@ -1199,95 +1212,6 @@ impl<'tcx> InferCtxt<'tcx> {
self.tainted_by_errors.set(Some(e));
}
- pub fn skip_region_resolution(&self) {
- let (var_infos, _) = {
- let mut inner = self.inner.borrow_mut();
- let inner = &mut *inner;
- // Note: `inner.region_obligations` may not be empty, because we
- // didn't necessarily call `process_registered_region_obligations`.
- // This is okay, because that doesn't introduce new vars.
- inner
- .region_constraint_storage
- .take()
- .expect("regions already resolved")
- .with_log(&mut inner.undo_log)
- .into_infos_and_data()
- };
-
- let lexical_region_resolutions = LexicalRegionResolutions {
- values: rustc_index::vec::IndexVec::from_elem_n(
- crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
- var_infos.len(),
- ),
- };
-
- let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
- assert!(old_value.is_none());
- }
-
- /// 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`.
- pub fn resolve_regions(
- &self,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Vec<RegionResolutionError<'tcx>> {
- let (var_infos, data) = {
- let mut inner = self.inner.borrow_mut();
- let inner = &mut *inner;
- assert!(
- self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
- "region_obligations not empty: {:#?}",
- inner.region_obligations
- );
- inner
- .region_constraint_storage
- .take()
- .expect("regions already resolved")
- .with_log(&mut inner.undo_log)
- .into_infos_and_data()
- };
-
- let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
-
- let (lexical_region_resolutions, errors) =
- lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
-
- let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
- assert!(old_value.is_none());
-
- errors
- }
- /// Obtains (and clears) the current set of region
- /// constraints. The inference context is still usable: further
- /// unifications will simply add new constraints.
- ///
- /// This method is not meant to be used with normal lexical region
- /// resolution. Rather, it is used in the NLL mode as a kind of
- /// interim hack: basically we run normal type-check and generate
- /// region constraints as normal, but then we take them and
- /// translate them into the form that the NLL solver
- /// understands. See the NLL module for mode details.
- pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
- assert!(
- self.inner.borrow().region_obligations.is_empty(),
- "region_obligations not empty: {:#?}",
- self.inner.borrow().region_obligations
- );
-
- self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
- }
-
- /// Gives temporary access to the region constraint data.
- pub fn with_region_constraints<R>(
- &self,
- op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
- ) -> R {
- let mut inner = self.inner.borrow_mut();
- op(inner.unwrap_region_constraints().data())
- }
-
pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
let mut inner = self.inner.borrow_mut();
let inner = &mut *inner;
@@ -1356,6 +1280,32 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var)
}
+ pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
+ self.inner.borrow_mut().const_unification_table().find(var)
+ }
+
+ /// Resolves an int var to a rigid int type, if it was constrained to one,
+ /// or else the root int var in the unification table.
+ pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
+ let mut inner = self.inner.borrow_mut();
+ if let Some(value) = inner.int_unification_table().probe_value(vid) {
+ value.to_type(self.tcx)
+ } else {
+ self.tcx.mk_int_var(inner.int_unification_table().find(vid))
+ }
+ }
+
+ /// Resolves a float var to a rigid int type, if it was constrained to one,
+ /// or else the root float var in the unification table.
+ pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
+ let mut inner = self.inner.borrow_mut();
+ if let Some(value) = inner.float_unification_table().probe_value(vid) {
+ value.to_type(self.tcx)
+ } else {
+ self.tcx.mk_float_var(inner.float_unification_table().find(vid))
+ }
+ }
+
/// Where possible, replaces type/const variables in
/// `value` with their final value. Note that region variables
/// are unaffected. If a type/const variable has not been unified, it
@@ -1614,6 +1564,28 @@ impl<'tcx> InferCtxt<'tcx> {
tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}
+ /// The returned function is used in a fast path. If it returns `true` the variable is
+ /// unchanged, `false` indicates that the status is unknown.
+ #[inline]
+ pub fn is_ty_infer_var_definitely_unchanged<'a>(
+ &'a self,
+ ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) {
+ // This hoists the borrow/release out of the loop body.
+ let inner = self.inner.try_borrow();
+
+ return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) {
+ (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
+ use self::type_variable::TypeVariableValue;
+
+ match inner.try_type_variables_probe_ref(ty_var) {
+ Some(TypeVariableValue::Unknown { .. }) => true,
+ _ => false,
+ }
+ }
+ _ => false,
+ };
+ }
+
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:
/// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`)
/// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`)
@@ -1664,59 +1636,34 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
}
-}
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
- /// Processes registered region obliations and resolves regions, reporting
- /// any errors if any were raised. Prefer using this function over manually
- /// calling `resolve_regions_and_report_errors`.
- pub fn check_region_obligations_and_report_errors(
- &self,
- generic_param_scope: LocalDefId,
- outlives_env: &OutlivesEnvironment<'tcx>,
- ) -> Result<(), ErrorGuaranteed> {
- self.process_registered_region_obligations(
- outlives_env.region_bound_pairs(),
- outlives_env.param_env,
- );
+ pub fn inside_canonicalization_ctxt(&self) -> bool {
+ self.inside_canonicalization_ctxt.get()
+ }
- self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+ pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
+ let prev_ctxt = self.inside_canonicalization_ctxt();
+ self.inside_canonicalization_ctxt.set(true);
+ CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
}
- /// 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 [`TypeErrCtxt::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>,
- ) -> Result<(), ErrorGuaranteed> {
- let errors = self.resolve_regions(outlives_env);
-
- if let None = self.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);
- }
+ fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
+ self.inside_canonicalization_ctxt.set(ctxt);
+ }
+}
- if errors.is_empty() {
- Ok(())
- } else {
- Err(self
- .tcx
- .sess
- .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
- }
+pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
+ prev_ctxt: bool,
+ infcx: &'cx InferCtxt<'tcx>,
+}
+
+impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
+ fn drop(&mut self) {
+ self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
}
+}
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// [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),
@@ -1770,7 +1717,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
-/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
+/// Helper for [InferCtxt::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)]
pub enum TyOrConstInferVar<'tcx> {
@@ -2043,13 +1990,17 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(_) = t.kind() {
+ let idx = {
+ let idx = self.idx;
+ self.idx += 1;
+ idx
+ };
self.tcx.mk_placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundTyKind::Anon({
- let idx = self.idx;
- self.idx += 1;
- idx
- }),
+ bound: ty::BoundTy {
+ var: ty::BoundVar::from_u32(idx),
+ kind: ty::BoundTyKind::Anon,
+ },
})
} else {
t.super_fold_with(self)
@@ -2066,7 +2017,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
self.tcx.mk_const(
ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundVar::from_u32({
+ bound: ty::BoundVar::from_u32({
let idx = self.idx;
self.idx += 1;
idx
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 573cd91a2..9f7b26b87 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
@@ -55,21 +56,6 @@ where
ambient_variance: ty::Variance,
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
-
- /// When we pass through a set of binders (e.g., when looking into
- /// a `fn` type), we push a new bound region scope onto here. This
- /// will contain the instantiated region for each region in those
- /// binders. When we then encounter a `ReLateBound(d, br)`, we can
- /// use the De Bruijn index `d` to find the right scope, and then
- /// bound region name `br` to find the specific instantiation from
- /// within that scope. See `replace_bound_region`.
- ///
- /// This field stores the instantiations for late-bound regions in
- /// the `a` type.
- a_scopes: Vec<BoundRegionScope<'tcx>>,
-
- /// Same as `a_scopes`, but for the `b` type.
- b_scopes: Vec<BoundRegionScope<'tcx>>,
}
pub trait TypeRelatingDelegate<'tcx> {
@@ -147,8 +133,6 @@ where
delegate,
ambient_variance,
ambient_variance_info: ty::VarianceDiagInfo::default(),
- a_scopes: vec![],
- b_scopes: vec![],
}
}
@@ -166,88 +150,6 @@ where
}
}
- fn create_scope(
- &mut self,
- value: ty::Binder<'tcx, impl Relate<'tcx>>,
- universally_quantified: UniversallyQuantified,
- ) -> BoundRegionScope<'tcx> {
- let mut scope = BoundRegionScope::default();
-
- // Create a callback that creates (via the delegate) either an
- // existential or placeholder region as needed.
- let mut next_region = {
- let delegate = &mut self.delegate;
- let mut lazy_universe = None;
- move |br: ty::BoundRegion| {
- if universally_quantified.0 {
- // The first time this closure is called, create a
- // new universe for the placeholders we will make
- // from here out.
- let universe = lazy_universe.unwrap_or_else(|| {
- let universe = delegate.create_next_universe();
- lazy_universe = Some(universe);
- universe
- });
-
- let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
- delegate.next_placeholder_region(placeholder)
- } else {
- delegate.next_existential_region_var(true, br.kind.get_name())
- }
- }
- };
-
- value.skip_binder().visit_with(&mut ScopeInstantiator {
- next_region: &mut next_region,
- target_index: ty::INNERMOST,
- bound_region_scope: &mut scope,
- });
-
- scope
- }
-
- /// When we encounter binders during the type traversal, we record
- /// the value to substitute for each of the things contained in
- /// that binder. (This will be either a universal placeholder or
- /// an existential inference variable.) Given the De Bruijn index
- /// `debruijn` (and name `br`) of some binder we have now
- /// encountered, this routine finds the value that we instantiated
- /// the region with; to do so, it indexes backwards into the list
- /// of ambient scopes `scopes`.
- fn lookup_bound_region(
- debruijn: ty::DebruijnIndex,
- br: &ty::BoundRegion,
- first_free_index: ty::DebruijnIndex,
- scopes: &[BoundRegionScope<'tcx>],
- ) -> ty::Region<'tcx> {
- // The debruijn index is a "reverse index" into the
- // scopes listing. So when we have INNERMOST (0), we
- // want the *last* scope pushed, and so forth.
- let debruijn_index = debruijn.index() - first_free_index.index();
- let scope = &scopes[scopes.len() - debruijn_index - 1];
-
- // Find this bound region in that scope to map to a
- // particular region.
- scope.map[br]
- }
-
- /// If `r` is a bound region, find the scope in which it is bound
- /// (from `scopes`) and return the value that we instantiated it
- /// with. Otherwise just return `r`.
- fn replace_bound_region(
- &self,
- r: ty::Region<'tcx>,
- first_free_index: ty::DebruijnIndex,
- scopes: &[BoundRegionScope<'tcx>],
- ) -> ty::Region<'tcx> {
- debug!("replace_bound_regions(scopes={:?})", scopes);
- if let ty::ReLateBound(debruijn, br) = *r {
- Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
- } else {
- r
- }
- }
-
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(
@@ -314,18 +216,9 @@ where
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
- // The generalized values we extract from `canonical_var_values` have
- // been fully instantiated and hence the set of scopes we have
- // doesn't matter -- just to be sure, put an empty vector
- // in there.
- let old_a_scopes = std::mem::take(pair.vid_scopes(self));
-
// Relate the generalized kind to the original one.
let result = pair.relate_generalized_ty(self, generalized_ty);
- // Restore the old scopes now.
- *pair.vid_scopes(self) = old_a_scopes;
-
debug!("relate_ty_var: complete, result = {:?}", result);
result
}
@@ -379,6 +272,97 @@ where
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
+
+ #[instrument(skip(self), level = "debug")]
+ fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+ where
+ T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+ {
+ if let Some(inner) = binder.no_bound_vars() {
+ return inner;
+ }
+
+ let mut next_region = {
+ let nll_delegate = &mut self.delegate;
+ let mut lazy_universe = None;
+
+ move |br: ty::BoundRegion| {
+ // The first time this closure is called, create a
+ // new universe for the placeholders we will make
+ // from here out.
+ let universe = lazy_universe.unwrap_or_else(|| {
+ let universe = nll_delegate.create_next_universe();
+ lazy_universe = Some(universe);
+ universe
+ });
+
+ let placeholder = ty::PlaceholderRegion { universe, bound: br };
+ debug!(?placeholder);
+ let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
+ debug!(?placeholder_reg);
+
+ placeholder_reg
+ }
+ };
+
+ let delegate = FnMutDelegate {
+ regions: &mut next_region,
+ types: &mut |_bound_ty: ty::BoundTy| {
+ unreachable!("we only replace regions in nll_relate, not types")
+ },
+ consts: &mut |_bound_var: ty::BoundVar, _ty| {
+ unreachable!("we only replace regions in nll_relate, not consts")
+ },
+ };
+
+ let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+ debug!(?replaced);
+
+ replaced
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
+ where
+ T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
+ {
+ if let Some(inner) = binder.no_bound_vars() {
+ return inner;
+ }
+
+ let mut next_region = {
+ let nll_delegate = &mut self.delegate;
+ let mut reg_map = FxHashMap::default();
+
+ move |br: ty::BoundRegion| {
+ if let Some(ex_reg_var) = reg_map.get(&br) {
+ return *ex_reg_var;
+ } else {
+ let ex_reg_var =
+ nll_delegate.next_existential_region_var(true, br.kind.get_name());
+ debug!(?ex_reg_var);
+ reg_map.insert(br, ex_reg_var);
+
+ ex_reg_var
+ }
+ }
+ };
+
+ let delegate = FnMutDelegate {
+ regions: &mut next_region,
+ types: &mut |_bound_ty: ty::BoundTy| {
+ unreachable!("we only replace regions in nll_relate, not types")
+ },
+ consts: &mut |_bound_var: ty::BoundVar, _ty| {
+ unreachable!("we only replace regions in nll_relate, not consts")
+ },
+ };
+
+ let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
+ debug!(?replaced);
+
+ replaced
+ }
}
/// When we instantiate an inference variable with a value in
@@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug {
/// opposite part of the tuple from the vid).
fn value_ty(&self) -> Ty<'tcx>;
- /// Extract the scopes that apply to whichever side of the tuple
- /// the vid was found on. See the comment where this is called
- /// for more details on why we want them.
- fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>;
-
/// Given a generalized type G that should replace the vid, relate
/// G to the value, putting G on whichever side the vid would have
/// appeared.
@@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
self.1
}
- fn vid_scopes<'r, D>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>
- where
- D: TypeRelatingDelegate<'tcx>,
- {
- &mut relate.a_scopes
- }
-
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
self.0
}
- fn vid_scopes<'r, D>(
- &self,
- relate: &'r mut TypeRelating<'_, 'tcx, D>,
- ) -> &'r mut Vec<BoundRegionScope<'tcx>>
- where
- D: TypeRelatingDelegate<'tcx>,
- {
- &mut relate.b_scopes
- }
-
fn relate_generalized_ty<D>(
&self,
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -487,10 +443,6 @@ where
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- self.infcx.intercrate
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.delegate.param_env()
}
@@ -503,17 +455,6 @@ where
true
}
- fn mark_ambiguous(&mut self) {
- let cause = ObligationCause::dummy_with_span(self.delegate.span());
- let param_env = self.delegate.param_env();
- self.delegate.register_obligations(vec![Obligation::new(
- self.tcx(),
- cause,
- param_env,
- ty::Binder::dummy(ty::PredicateKind::Ambiguous),
- )]);
- }
-
#[instrument(skip(self, info), level = "trace", ret)]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
@@ -602,20 +543,14 @@ where
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!(?self.ambient_variance);
- let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
- let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
-
- debug!(?v_a);
- debug!(?v_b);
-
if self.ambient_covariance() {
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
- self.push_outlives(v_a, v_b, self.ambient_variance_info);
+ self.push_outlives(a, b, self.ambient_variance_info);
}
if self.ambient_contravariance() {
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
- self.push_outlives(v_b, v_a, self.ambient_variance_info);
+ self.push_outlives(b, a, self.ambient_variance_info);
}
Ok(a)
@@ -689,15 +624,6 @@ where
// instantiation of B (i.e., B instantiated with
// universals).
- let b_scope = self.create_scope(b, UniversallyQuantified(true));
- let a_scope = self.create_scope(a, UniversallyQuantified(false));
-
- debug!(?a_scope, "(existential)");
- debug!(?b_scope, "(universal)");
-
- self.b_scopes.push(b_scope);
- self.a_scopes.push(a_scope);
-
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
@@ -718,12 +644,14 @@ where
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
- self.relate(a.skip_binder(), b.skip_binder())?;
+ // Note: the order here is important. Create the placeholders first, otherwise
+ // we assign the wrong universe to the existential!
+ let b_replaced = self.instantiate_binder_with_placeholders(b);
+ let a_replaced = self.instantiate_binder_with_existentials(a);
- self.ambient_variance = variance;
+ self.relate(a_replaced, b_replaced)?;
- self.b_scopes.pop().unwrap();
- self.a_scopes.pop().unwrap();
+ self.ambient_variance = variance;
}
if self.ambient_contravariance() {
@@ -733,26 +661,17 @@ where
// instantiation of B (i.e., B instantiated with
// existentials). Opposite of above.
- let a_scope = self.create_scope(a, UniversallyQuantified(true));
- let b_scope = self.create_scope(b, UniversallyQuantified(false));
-
- debug!(?a_scope, "(universal)");
- debug!(?b_scope, "(existential)");
-
- self.a_scopes.push(a_scope);
- self.b_scopes.push(b_scope);
-
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance =
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
- self.relate(a.skip_binder(), b.skip_binder())?;
+ let a_replaced = self.instantiate_binder_with_placeholders(a);
+ let b_replaced = self.instantiate_binder_with_existentials(b);
- self.ambient_variance = variance;
+ self.relate(a_replaced, b_replaced)?;
- self.b_scopes.pop().unwrap();
- self.a_scopes.pop().unwrap();
+ self.ambient_variance = variance;
}
Ok(a)
@@ -777,6 +696,34 @@ where
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.delegate.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
+ }
+
+ fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+ self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
+ ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
+ a.into(),
+ b.into(),
+ ty::AliasRelationDirection::Subtype,
+ ),
+ // a :> b is b <: a
+ ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
+ b.into(),
+ a.into(),
+ ty::AliasRelationDirection::Subtype,
+ ),
+ ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
+ a.into(),
+ b.into(),
+ ty::AliasRelationDirection::Equate,
+ ),
+ // FIXME(deferred_projection_equality): Implement this when we trigger it.
+ // Probably just need to do nothing here.
+ ty::Variance::Bivariant => unreachable!(),
+ })]);
+ }
}
/// When we encounter a binder like `for<..> fn(..)`, we actually have
@@ -872,11 +819,6 @@ where
self.infcx.tcx
}
- fn intercrate(&self) -> bool {
- assert!(!self.infcx.intercrate);
- false
- }
-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.delegate.param_env()
}
@@ -889,10 +831,6 @@ where
true
}
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index d5c824d4c..3a0a0494a 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,11 +1,12 @@
+use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use super::{DefineOpaqueTypes, InferResult};
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::OpaqueTyOrigin;
+use rustc_data_structures::fx::FxIndexMap;
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};
@@ -16,18 +17,13 @@ use rustc_middle::ty::{
TypeVisitable, TypeVisitableExt, TypeVisitor,
};
use rustc_span::Span;
-
use std::ops::ControlFlow;
-pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-
mod table;
+pub type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
-use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use super::InferResult;
-
/// Information about the opaque types whose values we
/// are inferring in this function (these are the `impl Trait` that
/// appear in the return type).
@@ -481,9 +477,7 @@ where
}
}
- ty::Alias(ty::Projection, proj)
- if self.tcx.def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder =>
- {
+ ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => {
// Skip lifetime parameters that are not captures.
let variances = self.tcx.variances_of(proj.def_id);
@@ -547,8 +541,7 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(prev) = prev {
obligations = self
.at(&cause, param_env)
- .define_opaque_types(true)
- .eq_exp(a_is_expected, prev, hidden_ty)?
+ .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
.obligations;
}
@@ -563,8 +556,7 @@ impl<'tcx> InferCtxt<'tcx> {
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
- && tcx.def_kind(projection_ty.def_id)
- != DefKind::ImplTraitPlaceholder =>
+ && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
{
self.infer_projection(
param_env,
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 24e3c34dd..47e3dd762 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,9 +1,9 @@
use crate::infer::free_regions::FreeRegionMap;
-use crate::infer::{GenericKind, InferCtxt};
+use crate::infer::GenericKind;
use crate::traits::query::OutlivesBound;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
-use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
+use rustc_middle::ty::{self, Region};
use super::explicit_outlives_bounds;
@@ -75,7 +75,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
region_bound_pairs: Default::default(),
};
- builder.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
+ builder.add_outlives_bounds(explicit_outlives_bounds(param_env));
builder
}
@@ -89,11 +89,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
/// Create a new `OutlivesEnvironment` with extra outlives bounds.
pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>,
- infcx: Option<&InferCtxt<'tcx>>,
extra_bounds: impl IntoIterator<Item = OutlivesBound<'tcx>>,
) -> Self {
let mut builder = Self::builder(param_env);
- builder.add_outlives_bounds(infcx, extra_bounds);
+ builder.add_outlives_bounds(extra_bounds);
builder.build()
}
@@ -120,12 +119,7 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
}
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
- ///
- /// The `infcx` parameter is optional; if the implied bounds may
- /// 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<'tcx>>, outlives_bounds: I)
+ fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
@@ -142,27 +136,17 @@ impl<'tcx> OutlivesEnvironmentBuilder<'tcx> {
self.region_bound_pairs
.insert(ty::OutlivesPredicate(GenericKind::Alias(alias_b), r_a));
}
- OutlivesBound::RegionSubRegion(r_a, r_b) => {
- if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
- infcx
- .expect("no infcx provided but region vars found")
- .add_given(r_a, vid_b);
- } else {
- // In principle, we could record (and take
- // advantage of) every relationship here, but
- // we are also free not to -- it simply means
- // strictly less that we can successfully type
- // check. Right now we only look for things
- // relationships between free regions. (It may
- // also be that we should revise our inference
- // system to be more general and to make use
- // of *every* relationship that arises here,
- // but presently we do not.)
- if r_a.is_free_or_static() && r_b.is_free() {
- self.region_relation.add(r_a, r_b)
- }
- }
- }
+ OutlivesBound::RegionSubRegion(r_a, r_b) => match (*r_a, *r_b) {
+ (
+ ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+ ty::ReStatic | ty::ReEarlyBound(_) | ty::ReFree(_),
+ ) => self.region_relation.add(r_a, r_b),
+ (ty::ReError(_), _) | (_, ty::ReError(_)) => {}
+ // FIXME(#109628): We shouldn't have existential variables in implied bounds.
+ // Panic here once the linked issue is resolved!
+ (ty::ReVar(_), _) | (_, ty::ReVar(_)) => {}
+ _ => bug!("add_outlives_bounds: unexpected regions: ({r_a:?}, {r_b:?})"),
+ },
}
}
}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 83f3d5a74..9a9a1696b 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -1,4 +1,11 @@
//! Various code related to computing outlives relations.
+use self::env::OutlivesEnvironment;
+use super::region_constraints::RegionConstraintData;
+use super::{InferCtxt, RegionResolutionError};
+use crate::infer::free_regions::RegionRelations;
+use crate::infer::lexical_region_resolve::{self, LexicalRegionResolutions};
+use rustc_middle::traits::query::OutlivesBound;
+use rustc_middle::ty;
pub mod components;
pub mod env;
@@ -6,9 +13,6 @@ pub mod obligations;
pub mod test_type_match;
pub mod verify;
-use rustc_middle::traits::query::OutlivesBound;
-use rustc_middle::ty;
-
#[instrument(level = "debug", skip(param_env), ret)]
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
@@ -22,7 +26,7 @@ pub fn explicit_outlives_bounds<'tcx>(
ty::PredicateKind::Clause(ty::Clause::Projection(..))
| ty::PredicateKind::Clause(ty::Clause::Trait(..))
| ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::AliasEq(..)
+ | ty::PredicateKind::AliasRelate(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
@@ -39,3 +43,98 @@ pub fn explicit_outlives_bounds<'tcx>(
))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)),
})
}
+
+impl<'tcx> InferCtxt<'tcx> {
+ pub fn skip_region_resolution(&self) {
+ let (var_infos, _) = {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ // Note: `inner.region_obligations` may not be empty, because we
+ // didn't necessarily call `process_registered_region_obligations`.
+ // This is okay, because that doesn't introduce new vars.
+ inner
+ .region_constraint_storage
+ .take()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .into_infos_and_data()
+ };
+
+ let lexical_region_resolutions = LexicalRegionResolutions {
+ values: rustc_index::vec::IndexVec::from_elem_n(
+ crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
+ var_infos.len(),
+ ),
+ };
+
+ let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+ assert!(old_value.is_none());
+ }
+
+ /// 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`.
+ #[must_use]
+ pub fn resolve_regions(
+ &self,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ ) -> Vec<RegionResolutionError<'tcx>> {
+ self.process_registered_region_obligations(outlives_env);
+
+ let (var_infos, data) = {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ assert!(
+ self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(),
+ "region_obligations not empty: {:#?}",
+ inner.region_obligations
+ );
+ inner
+ .region_constraint_storage
+ .take()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .into_infos_and_data()
+ };
+
+ let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
+
+ let (lexical_region_resolutions, errors) =
+ lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
+
+ let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
+ assert!(old_value.is_none());
+
+ errors
+ }
+
+ /// Obtains (and clears) the current set of region
+ /// constraints. The inference context is still usable: further
+ /// unifications will simply add new constraints.
+ ///
+ /// This method is not meant to be used with normal lexical region
+ /// resolution. Rather, it is used in the NLL mode as a kind of
+ /// interim hack: basically we run normal type-check and generate
+ /// region constraints as normal, but then we take them and
+ /// translate them into the form that the NLL solver
+ /// understands. See the NLL module for mode details.
+ pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
+ assert!(
+ self.inner.borrow().region_obligations.is_empty(),
+ "region_obligations not empty: {:#?}",
+ self.inner.borrow().region_obligations
+ );
+
+ self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data()
+ }
+
+ /// Gives temporary access to the region constraint data.
+ pub fn with_region_constraints<R>(
+ &self,
+ op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
+ ) -> R {
+ let mut inner = self.inner.borrow_mut();
+ op(inner.unwrap_region_constraints().data())
+ }
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index bbe7d4c63..ccf11c61b 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -72,6 +72,8 @@ use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitableExt};
use smallvec::smallvec;
+use super::env::OutlivesEnvironment;
+
impl<'tcx> InferCtxt<'tcx> {
/// Registers that the given region obligation must be resolved
/// from within the scope of `body_id`. These regions are enqueued
@@ -112,39 +114,17 @@ impl<'tcx> InferCtxt<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().region_obligations)
}
- /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
- /// instead of calling this directly.
- ///
/// Process the region obligations that must be proven (during
/// `regionck`) for the given `body_id`, given information about
- /// the region bounds in scope and so forth. This function must be
- /// invoked for all relevant body-ids before region inference is
- /// done (or else an assert will fire).
+ /// the region bounds in scope and so forth.
///
/// See the `region_obligations` field of `InferCtxt` for some
/// comments about how this function fits into the overall expected
/// flow of the inferencer. The key point is that it is
/// invoked after all type-inference variables have been bound --
- /// towards the end of regionck. This also ensures that the
- /// region-bound-pairs are available (see comments above regarding
- /// closures).
- ///
- /// # Parameters
- ///
- /// - `region_bound_pairs_map`: the set of region bounds implied by
- /// the parameters and where-clauses. In particular, each pair
- /// `('a, K)` in this list tells us that the bounds in scope
- /// indicate that `K: 'a`, where `K` is either a generic
- /// parameter like `T` or a projection like `T::Item`.
- /// - `param_env` is the parameter environment for the enclosing function.
- /// - `body_id` is the body-id whose region obligations are being
- /// processed.
- #[instrument(level = "debug", skip(self, region_bound_pairs))]
- pub fn process_registered_region_obligations(
- &self,
- region_bound_pairs: &RegionBoundPairs<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) {
+ /// right before lexical region resolution.
+ #[instrument(level = "debug", skip(self, outlives_env))]
+ pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
assert!(
!self.in_snapshot.get(),
"cannot process registered region obligations in a snapshot"
@@ -153,15 +133,16 @@ impl<'tcx> InferCtxt<'tcx> {
let my_region_obligations = self.take_registered_region_obligations();
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
- debug!(
- "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
- sup_type, sub_region, origin
- );
-
+ debug!(?sup_type, ?sub_region, ?origin);
let sup_type = self.resolve_vars_if_possible(sup_type);
- let outlives =
- &mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
+ let outlives = &mut TypeOutlives::new(
+ self,
+ self.tcx,
+ &outlives_env.region_bound_pairs(),
+ None,
+ outlives_env.param_env,
+ );
let category = origin.to_constraint_category();
outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 3c6cc2b90..01f900f05 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -137,10 +137,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
"Match"
}
- fn intercrate(&self) -> bool {
- false
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
@@ -151,10 +147,6 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
true
} // irrelevant
- fn mark_ambiguous(&mut self) {
- bug!()
- }
-
#[instrument(level = "trace", skip(self))]
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index f79504770..fa6529dfa 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -26,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> {
// completely change the normalization routine with the new solver.
//
// The new solver correctly handles projection equality so this hack
- // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
+ // is not necessary. if re-enabled it should emit `PredicateKind::AliasRelate`
// not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
// `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
return projection_ty.to_ty(self.tcx);
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 e413b2bb5..b8ba98fc0 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -290,9 +290,9 @@ impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
) -> TypeError<'tcx> {
debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
if self.overly_polymorphic {
- TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region)
+ TypeError::RegionsOverlyPolymorphic(placeholder.bound.kind, other_region)
} else {
- TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region)
+ TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region)
}
}
}
@@ -424,9 +424,6 @@ impl<'tcx> MiniGraph<'tcx> {
&AddConstraint(Constraint::RegSubReg(a, b)) => {
each_edge(a, b);
}
- &AddGiven(a, b) => {
- each_edge(a, tcx.mk_re_var(b));
- }
&AddVerify(i) => span_bug!(
verifys[i].origin.span(),
"we never add verifications while doing higher-ranked things",
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 872f61747..7b272dfd2 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -7,7 +7,7 @@ use super::{
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
@@ -104,26 +104,6 @@ pub struct RegionConstraintData<'tcx> {
/// An example is a `A <= B` where neither `A` nor `B` are
/// inference variables.
pub verifys: Vec<Verify<'tcx>>,
-
- /// A "given" is a relationship that is known to hold. In
- /// particular, we often know from closure fn signatures that a
- /// particular free region must be a subregion of a region
- /// variable:
- ///
- /// foo.iter().filter(<'a> |x: &'a &'b T| ...)
- ///
- /// In situations like this, `'b` is in fact a region variable
- /// introduced by the call to `iter()`, and `'a` is a bound region
- /// on the closure (as indicated by the `<'a>` prefix). If we are
- /// naive, we wind up inferring that `'b` must be `'static`,
- /// because we require that it be greater than `'a` and we do not
- /// know what `'a` is precisely.
- ///
- /// This hashmap is used to avoid that naive scenario. Basically
- /// we record the fact that `'a <= 'b` is implied by the fn
- /// signature, and then ignore the constraint when solving
- /// equations. This is a bit of a hack but seems to work.
- pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
}
/// Represents a constraint that influences the inference process.
@@ -297,9 +277,6 @@ pub(crate) enum UndoLog<'tcx> {
/// We added the given `verify`.
AddVerify(usize),
- /// We added the given `given`.
- AddGiven(Region<'tcx>, ty::RegionVid),
-
/// We added a GLB/LUB "combination variable".
AddCombination(CombineMapType, TwoRegions<'tcx>),
}
@@ -348,9 +325,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> {
self.data.verifys.pop();
assert_eq!(self.data.verifys.len(), index);
}
- AddGiven(sub, sup) => {
- self.data.givens.remove(&(sub, sup));
- }
AddCombination(Glb, ref regions) => {
self.glbs.remove(regions);
}
@@ -420,7 +394,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
// `RegionConstraintData` contains the relationship here.
if *any_unifications {
*any_unifications = false;
- self.unification_table().reset_unifications(|_| UnifiedRegion(None));
+ self.unification_table_mut().reset_unifications(|_| UnifiedRegion::new(None));
}
data
@@ -447,7 +421,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
) -> RegionVid {
let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
- let u_vid = self.unification_table().new_key(UnifiedRegion(None));
+ let u_vid = self.unification_table_mut().new_key(UnifiedRegion::new(None));
assert_eq!(vid, u_vid.vid);
self.undo_log.push(AddVar(vid));
debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
@@ -492,15 +466,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
self.undo_log.push(AddVerify(index));
}
- pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
- // cannot add givens once regions are resolved
- if self.data.givens.insert((sub, sup)) {
- debug!("add_given({:?} <= {:?})", sub, sup);
-
- self.undo_log.push(AddGiven(sub, sup));
- }
- }
-
pub(super) fn make_eqregion(
&mut self,
origin: SubregionOrigin<'tcx>,
@@ -516,13 +481,13 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
match (sub, sup) {
(Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
- self.unification_table().union(*sub, *sup);
+ self.unification_table_mut().union(*sub, *sup);
self.any_unifications = true;
}
(Region(Interned(ReVar(vid), _)), value)
| (value, Region(Interned(ReVar(vid), _))) => {
debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
- self.unification_table().union_value(*vid, UnifiedRegion(Some(value)));
+ self.unification_table_mut().union_value(*vid, UnifiedRegion::new(Some(value)));
self.any_unifications = true;
}
(_, _) => {}
@@ -633,28 +598,25 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
}
- /// Resolves the passed RegionVid to the root RegionVid in the unification table
- pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
- self.unification_table().find(rid).vid
- }
-
- /// If the Region is a `ReVar`, then resolves it either to the root value in
- /// the unification table, if it exists, or to the root `ReVar` in the table.
- /// If the Region is not a `ReVar`, just returns the Region itself.
- pub fn opportunistic_resolve_region(
+ /// Resolves a region var to its value in the unification table, if it exists.
+ /// Otherwise, it is resolved to the root `ReVar` in the table.
+ pub fn opportunistic_resolve_var(
&mut self,
tcx: TyCtxt<'tcx>,
- region: ty::Region<'tcx>,
+ vid: ty::RegionVid,
) -> ty::Region<'tcx> {
- match *region {
- ty::ReVar(rid) => {
- let unified_region = self.unification_table().probe_value(rid);
- unified_region.0.unwrap_or_else(|| {
- let root = self.unification_table().find(rid).vid;
- tcx.mk_re_var(root)
- })
- }
- _ => region,
+ let mut ut = self.unification_table_mut(); // FIXME(rust-lang/ena#42): unnecessary mut
+ let root_vid = ut.find(vid).vid;
+ let resolved = ut
+ .probe_value(root_vid)
+ .get_value_ignoring_universes()
+ .unwrap_or_else(|| tcx.mk_re_var(root_vid));
+
+ // Don't resolve a variable to a region that it cannot name.
+ if self.var_universe(vid).can_name(self.universe(resolved)) {
+ resolved
+ } else {
+ tcx.mk_re_var(vid)
}
}
@@ -733,7 +695,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
}
#[inline]
- fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
+ fn unification_table_mut(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
}
}
@@ -807,11 +769,8 @@ impl<'tcx> RegionConstraintData<'tcx> {
/// Returns `true` if this region constraint data contains no constraints, and `false`
/// otherwise.
pub fn is_empty(&self) -> bool {
- let RegionConstraintData { constraints, member_constraints, verifys, givens } = self;
- constraints.is_empty()
- && member_constraints.is_empty()
- && verifys.is_empty()
- && givens.is_empty()
+ let RegionConstraintData { constraints, member_constraints, verifys } = self;
+ constraints.is_empty() && member_constraints.is_empty() && verifys.is_empty()
}
}
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 5bb358329..4f49f4165 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -85,15 +85,12 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for OpportunisticRegionResolver<'a, 'tcx
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
- ty::ReVar(rid) => {
- let resolved = self
- .infcx
- .inner
- .borrow_mut()
- .unwrap_region_constraints()
- .opportunistic_resolve_var(rid);
- TypeFolder::interner(self).mk_re_var(resolved)
- }
+ ty::ReVar(vid) => self
+ .infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_var(TypeFolder::interner(self), vid),
_ => r,
}
}
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 3e8c2052d..0dd73a6e9 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -1,5 +1,5 @@
use super::combine::{CombineFields, RelationDir};
-use super::{ObligationEmittingRelation, SubregionOrigin};
+use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
@@ -35,10 +35,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
"Sub"
}
- fn intercrate(&self) -> bool {
- self.fields.infcx.intercrate
- }
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.fields.infcx.tcx
}
@@ -51,10 +47,6 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
self.a_is_expected
}
- fn mark_ambiguous(&mut self) {
- self.fields.mark_ambiguous()
- }
-
fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
@@ -138,7 +130,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
}
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if self.fields.define_opaque_types && def_id.is_local() =>
+ if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
+ && def_id.is_local() =>
{
self.fields.obligations.extend(
infcx
@@ -235,4 +228,8 @@ impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.fields.register_obligations(obligations);
}
+
+ fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
+ ty::AliasRelationDirection::Subtype
+ }
}
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 263c6a47d..f7ab05b2d 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -190,6 +190,11 @@ impl<'tcx> TypeVariableStorage<'tcx> {
) -> TypeVariableTable<'a, 'tcx> {
TypeVariableTable { storage: self, undo_log }
}
+
+ #[inline]
+ pub(crate) fn eq_relations_ref(&self) -> &ut::UnificationTableStorage<TyVidEqKey<'tcx>> {
+ &self.eq_relations
+ }
}
impl<'tcx> TypeVariableTable<'_, 'tcx> {