diff options
Diffstat (limited to 'compiler/rustc_infer/src')
| -rw-r--r-- | compiler/rustc_infer/src/infer/at.rs | 155 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/canonical/query_response.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/combine.rs | 26 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/equate.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/note.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/glb.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/lattice.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/lub.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/mod.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/opaque_types.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/sub.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/type_variable.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/traits/mod.rs | 10 |
16 files changed, 219 insertions, 140 deletions
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 7d9bae735e5..0c8854e962a 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -30,16 +30,20 @@ use super::*; use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; +/// 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 +59,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 @@ -84,7 +88,6 @@ impl<'tcx> InferCtxt<'tcx> { pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { fn to_trace( - tcx: TyCtxt<'tcx>, cause: &ObligationCause<'tcx>, a_is_expected: bool, a: Self, @@ -93,33 +96,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 +120,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 +213,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 +231,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 +261,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 +270,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 +287,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 +302,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 +317,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 +334,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 +341,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 +356,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 +370,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 +381,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 +395,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 +422,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 +433,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 +447,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 +461,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/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 436d29c2449..156a7e68ed1 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}; @@ -510,7 +510,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 +603,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 +615,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()); } _ => { diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a2332797e86..4503af03ca3 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -27,7 +27,7 @@ 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; @@ -52,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)] @@ -194,10 +189,19 @@ impl<'tcx> InferCtxt<'tcx> { // 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 { - return Ok(self.tcx.const_error_with_guaranteed( - if relation.a_is_expected() { a.ty() } else { b.ty() }, - guar, - )); + // 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()) { diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 54a62326ef7..c92a74b6241 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}; @@ -110,7 +111,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 diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8a2b800af0e..fd16363a1db 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -359,10 +359,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) } @@ -613,9 +615,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 +630,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); } } }; @@ -1568,6 +1577,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 +1766,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()); @@ -2124,6 +2135,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(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 7ffe1fd20b4..e720af73c39 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -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 b33729d0be5..b38bbdfe7bb 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 55dcfd05e0a..ec122dc039f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -356,7 +356,7 @@ 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; } @@ -400,8 +400,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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; } diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index 49df393d83b..5c12351226a 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}; @@ -142,7 +142,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 } } diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index f377ac1d19e..7f4c141b97a 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/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index c871ccb21f8..dbef42db8f1 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}; @@ -142,7 +142,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 } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 4a834957959..aeb4ddb4212 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::*; @@ -187,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) } @@ -338,6 +349,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>>), @@ -729,7 +741,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, @@ -864,7 +876,7 @@ impl<'tcx> InferCtxt<'tcx> { 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 @@ -872,7 +884,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")] @@ -967,7 +979,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()) })) @@ -1643,6 +1656,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(_)`) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index d5c824d4c41..49f823a47b8 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,7 +1,8 @@ +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::sync::Lrc; @@ -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> = VecMap<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/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 3e8c2052de8..230cadb1184 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}; @@ -138,7 +138,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 diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 263c6a47dd2..f7ab05b2d49 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> { diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 77c67c14ecc..dd9b2e548c7 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -8,6 +8,8 @@ mod project; mod structural_impls; pub mod util; +use std::cmp; + use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> { Self::with_depth(tcx, cause, 0, param_env, predicate) } + /// We often create nested obligations without setting the correct depth. + /// + /// To deal with this evaluate and fulfill explicitly update the depth + /// of nested obligations using this function. + pub fn set_depth_from_parent(&mut self, parent_depth: usize) { + self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth); + } + pub fn with_depth( tcx: TyCtxt<'tcx>, cause: ObligationCause<'tcx>, |
