diff options
Diffstat (limited to 'compiler/rustc_infer/src')
40 files changed, 983 insertions, 1138 deletions
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 65b3dd1a8..b1e819e83 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -71,7 +71,7 @@ pub struct AmbiguousImpl<'a> { // Copy of `AnnotationRequired` for E0284 #[derive(Diagnostic)] #[diag(infer_type_annotations_needed, code = "E0284")] -pub struct AmbigousReturn<'a> { +pub struct AmbiguousReturn<'a> { #[primary_span] pub span: Span, pub source_kind: &'static str, @@ -1085,7 +1085,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_with_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_with_sup)] + #[note(infer_prlf_must_outlive_with_sup)] sup_span: Span, sub_symbol: Symbol, sup_symbol: Symbol, @@ -1098,7 +1098,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_with_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_without_sup)] + #[note(infer_prlf_must_outlive_without_sup)] sup_span: Span, sub_symbol: Symbol, #[note(infer_prlf_known_limitation)] @@ -1110,7 +1110,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_without_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_with_sup)] + #[note(infer_prlf_must_outlive_with_sup)] sup_span: Span, sup_symbol: Symbol, #[note(infer_prlf_known_limitation)] @@ -1122,7 +1122,7 @@ pub enum PlaceholderRelationLfNotSatisfied { span: Span, #[note(infer_prlf_defined_without_sub)] sub_span: Span, - #[note(infer_prlf_must_oultive_without_sup)] + #[note(infer_prlf_must_outlive_without_sup)] sup_span: Span, #[note(infer_prlf_known_limitation)] note: (), @@ -1488,8 +1488,8 @@ pub enum ObligationCauseFailureCode { #[subdiagnostic] subdiags: Vec<TypeErrorAdditionalDiags>, }, - #[diag(infer_oc_intristic_correct_type, code = "E0308")] - IntristicCorrectType { + #[diag(infer_oc_intrinsic_correct_type, code = "E0308")] + IntrinsicCorrectType { #[primary_span] span: Span, #[subdiagnostic] diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index d240d8e49..0c8854e96 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -30,8 +30,6 @@ 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 @@ -84,7 +82,6 @@ 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()), } } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index e808911a3..427d05c8b 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, use std::sync::atomic::Ordering; use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::Idx; +use rustc_index::Idx; use smallvec::SmallVec; impl<'tcx> InferCtxt<'tcx> { @@ -205,7 +205,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { // `delay_span_bug` to allow type error over an ICE. canonicalizer.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, - &format!("unexpected region in query response: `{:?}`", r), + format!("unexpected region in query response: `{:?}`", r), ); r } @@ -561,15 +561,13 @@ 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_INFER | TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER } else { - TypeFlags::NEEDS_INFER + TypeFlags::HAS_INFER | TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER @@ -600,7 +598,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { // Once we have canonicalized `out_value`, it should not // contain anything that ties it to this inference context // anymore. - debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders()); + debug_assert!(!out_value.has_infer() && !out_value.has_placeholders()); let canonical_variables = tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables()); diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index fbb2257bf..2abdd5b0a 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -23,7 +23,7 @@ use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, List, TyCtxt}; diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index e98f68ae5..88256c819 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -15,12 +15,12 @@ use crate::infer::canonical::{ use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin}; -use crate::traits::query::{Fallible, NoSolution}; +use crate::traits::query::NoSolution; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt}; use rustc_data_structures::captures::Captures; -use rustc_index::vec::Idx; -use rustc_index::vec::IndexVec; +use rustc_index::Idx; +use rustc_index::IndexVec; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::fold::TypeFoldable; @@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> { inference_vars: CanonicalVarValues<'tcx>, answer: T, fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Fallible<CanonicalQueryResponse<'tcx, T>> + ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, @@ -153,20 +153,22 @@ impl<'tcx> InferCtxt<'tcx> { /// Used by the new solver as that one takes the opaque types at the end of a probe /// to deal with multiple candidates without having to recompute them. - pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + pub fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner .borrow() .opaque_type_storage .opaque_types .iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (*k, v.hidden_type.ty)) .collect() } - fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (k, v.hidden_type.ty)) .collect() } @@ -467,11 +469,11 @@ impl<'tcx> InferCtxt<'tcx> { } } GenericArgKind::Const(result_value) => { - if let ty::ConstKind::Bound(debrujin, b) = result_value.kind() { + if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debrujin, ty::INNERMOST); + assert_eq!(debruijn, ty::INNERMOST); opt_values[b] = Some(*original_value); } } @@ -507,8 +509,22 @@ impl<'tcx> InferCtxt<'tcx> { let a = substitute_value(self.tcx, &result_subst, a); let b = substitute_value(self.tcx, &result_subst, b); debug!(?a, ?b, "constrain opaque type"); - obligations - .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations); + // We use equate here instead of, for example, just registering the + // opaque type's hidden value directly, because we may be instantiating + // a query response that was canonicalized in an InferCtxt that had + // a different defining anchor. In that case, we may have inferred + // `NonLocalOpaque := LocalOpaque` but can only instantiate it in + // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq + // here allows us to try both directions (in `InferCtxt::handle_opaque_type`). + obligations.extend( + self.at(cause, param_env) + .eq( + DefineOpaqueTypes::Yes, + self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs), + b, + )? + .obligations, + ); } Ok(InferOk { value: result_subst, obligations }) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index fe45b5ebe..b6b935de6 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -26,24 +26,17 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::type_variable::TypeVariableValue; -use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace}; +use super::{DefineOpaqueTypes, InferCtxt, TypeTrace}; +use crate::infer::generalize::{self, CombineDelegate, Generalization}; 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::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{ - self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeVisitableExt, -}; +use rustc_middle::ty::relate::{RelateResult, TypeRelation}; +use rustc_middle::ty::{self, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -55,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> { pub define_opaque_types: DefineOpaqueTypes, } -#[derive(Copy, Clone, Debug)] -pub enum RelationDir { - SubtypeOf, - SupertypeOf, - EqTo, -} - impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys<R>( &self, @@ -73,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> { R: ObligationEmittingRelation<'tcx>, { let a_is_expected = relation.a_is_expected(); + debug_assert!(!a.has_escaping_bound_vars()); + debug_assert!(!b.has_escaping_bound_vars()); match (a.kind(), b.kind()) { // Relate integral variables to other types @@ -125,9 +113,7 @@ impl<'tcx> InferCtxt<'tcx> { bug!() } - (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _) - if self.tcx.trait_solver_next() => - { + (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => { relation.register_type_relate_obligation(a, b); Ok(a) } @@ -149,7 +135,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::super_relate_tys(relation, a, b), + _ => ty::relate::structurally_relate_tys(relation, a, b), } } @@ -163,6 +149,8 @@ impl<'tcx> InferCtxt<'tcx> { R: ObligationEmittingRelation<'tcx>, { debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); + debug_assert!(!a.has_escaping_bound_vars()); + debug_assert!(!b.has_escaping_bound_vars()); if a == b { return Ok(a); } @@ -192,7 +180,7 @@ impl<'tcx> InferCtxt<'tcx> { 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,), + format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,), ) }) }); @@ -204,13 +192,13 @@ impl<'tcx> InferCtxt<'tcx> { // 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); + let a_error = self.tcx.const_error(a.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { - return self.unify_const_variable(vid, a_error); + return self.unify_const_variable(vid, a_error, relation.param_env()); } - let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar); + let b_error = self.tcx.const_error(b.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { - return self.unify_const_variable(vid, b_error); + return self.unify_const_variable(vid, b_error, relation.param_env()); } return Ok(if relation.a_is_expected() { a_error } else { b_error }); @@ -232,32 +220,22 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b); + return self.unify_const_variable(vid, b, relation.param_env()); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a); + return self.unify_const_variable(vid, a, relation.param_env()); } - (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { - // FIXME(#59490): Need to remove the leak check to accommodate - // escaping bound variables here. - if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { - relation.register_const_equate_obligation(a, b); - } + (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) + if self.tcx.lazy_normalization() => + { + relation.register_const_equate_obligation(a, b); return Ok(b); } - (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => { - // FIXME(#59490): Need to remove the leak check to accommodate - // escaping bound variables here. - if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { - relation.register_const_equate_obligation(a, b); - } - return Ok(a); - } _ => {} } - ty::relate::super_relate_consts(relation, a, b) + ty::relate::structurally_relate_consts(relation, a, b) } /// Unifies the const variable `target_vid` with the given constant. @@ -299,24 +277,17 @@ impl<'tcx> InferCtxt<'tcx> { &self, target_vid: ty::ConstVid<'tcx>, ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let (for_universe, span) = { - let mut inner = self.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(target_vid); - match var_value.val { - ConstVariableValue::Known { value } => { - bug!("instantiating {:?} which has a known value {:?}", target_vid, value) - } - ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), - } - }; - let value = ct.try_fold_with(&mut ConstInferUnifier { - infcx: self, - span, - for_universe, + let span = + self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span; + let Generalization { value, needs_wf: _ } = generalize::generalize( + self, + &mut CombineDelegate { infcx: self, span, param_env }, + ct, target_vid, - })?; + ty::Variance::Invariant, + )?; self.inner.borrow_mut().const_unification_table().union_value( target_vid, @@ -397,12 +368,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { pub fn instantiate( &mut self, a_ty: Ty<'tcx>, - dir: RelationDir, + ambient_variance: ty::Variance, b_vid: ty::TyVid, a_is_expected: bool, ) -> RelateResult<'tcx, ()> { - use self::RelationDir::*; - // Get the actual variable that b_vid has been inferred to debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); @@ -417,7 +386,18 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // `'?2` and `?3` are fresh region/type inference // variables. (Down below, we will relate `a_ty <: b_ty`, // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; + let Generalization { value: b_ty, needs_wf } = generalize::generalize( + self.infcx, + &mut CombineDelegate { + infcx: self.infcx, + param_env: self.param_env, + span: self.trace.span(), + }, + a_ty, + b_vid, + ambient_variance, + )?; + debug!(?b_ty); self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); @@ -436,78 +416,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(a_ty, b_ty), - SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( + match ambient_variance { + ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance( ty::Contravariant, ty::VarianceDiagInfo::default(), a_ty, b_ty, ), + ty::Variance::Bivariant => { + unreachable!("no code should be generalizing bivariantly (currently)") + } }?; Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. - /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. The `dir` is the "direction" for which we - /// a performing the generalization (i.e., are we producing a type - /// that can be used as a supertype etc). - /// - /// Preconditions: - /// - /// - `for_vid` is a "root vid" - #[instrument(skip(self), level = "trace", ret)] - fn generalize( - &self, - ty: Ty<'tcx>, - for_vid: ty::TyVid, - dir: RelationDir, - ) -> RelateResult<'tcx, Generalization<'tcx>> { - // Determine the ambient variance within which `ty` appears. - // The surrounding equation is: - // - // ty [op] ty2 - // - // where `op` is either `==`, `<:`, or `:>`. This maps quite - // naturally. - let ambient_variance = match dir { - RelationDir::EqTo => ty::Invariant, - RelationDir::SubtypeOf => ty::Covariant, - RelationDir::SupertypeOf => ty::Contravariant, - }; - - trace!(?ambient_variance); - - let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { - v @ TypeVariableValue::Known { .. } => { - bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) - } - TypeVariableValue::Unknown { universe } => universe, - }; - - trace!(?for_universe); - trace!(?self.trace); - - let mut generalize = Generalizer { - infcx: self.infcx, - cause: &self.trace.cause, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - for_universe, - ambient_variance, - needs_wf: false, - root_ty: ty, - param_env: self.param_env, - cache: SsoHashMap::new(), - }; - - let ty = generalize.relate(ty, ty)?; - let needs_wf = generalize.needs_wf; - Ok(Generalization { ty, needs_wf }) - } - pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations.into_iter()); } @@ -519,320 +444,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -struct Generalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - /// The span, used when creating new type variables and things. - cause: &'cx ObligationCause<'tcx>, - - /// The vid of the type variable that is in the process of being - /// instantiated; if we find this within the type we are folding, - /// that means we would have created a cyclic type. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of - /// being instantiated. Any fresh variables that we create in this - /// process should be in that same universe. - for_universe: ty::UniverseIndex, - - /// Track the variance as we descend into the type. - ambient_variance: ty::Variance, - - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, - - /// The root type that we are generalizing. Used when reporting cycles. - root_ty: Ty<'tcx>, - - param_env: ty::ParamEnv<'tcx>, - - cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, -} - -/// Result from a generalization operation. This includes -/// not only the generalized type, but also a bool flag -/// indicating whether further WF checks are needed. -#[derive(Debug)] -struct Generalization<'tcx> { - ty: Ty<'tcx>, - - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: - /// - /// struct Foo<A, B> where A: Iterator<Item = B> { - /// data: A - /// } - /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, - /// then after generalization we will wind up with a type like - /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, - /// ?D>` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo<?C, ?D>)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - needs_wf: bool, -} - -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "Generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) - } - - fn relate_item_substs( - &mut self, - item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { - // Avoid fetching the variance if we are in an invariant - // context; no need, and it can induce dependency cycles - // (e.g., #41849). - relate::relate_substs(self, a_subst, b_subst) - } else { - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate::relate_substs_with_variances( - self, - item_def_id, - &opt_variances, - a_subst, - b_subst, - true, - ) - } - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - let result = self.relate(a, b); - self.ambient_variance = old_ambient_variance; - result - } - - fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - if let Some(&result) = self.cache.get(&t) { - return Ok(result); - } - debug!("generalize: t={:?}", t); - - // Check to see whether the type we are generalizing references - // any other type variable related to `vid` via - // subtyping. This is basically our "occurs check", preventing - // us from creating infinitely sized types. - let result = match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - Err(TypeError::CyclicTy(self.root_ty)) - } else { - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("generalize: known value {:?}", u); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe } => { - match self.ambient_variance { - // Invariant: no need to make a fresh type variable. - ty::Invariant => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - } - - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, - - // Co/contravariant: this will be - // sufficiently constrained later on. - ty::Covariant | ty::Contravariant => (), - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); - - // Record that we replaced `vid` with `new_var_id` as part of a generalization - // operation. This is needed to detect cyclic types. To see why, see the - // docs in the `type_variables` module. - self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(t) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - let s = self.relate(substs, substs)?; - Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) - } - _ => relate::super_relate_tys(self, t, t), - }?; - - self.cache.insert(t, result); - Ok(result) - } - - fn regions( - &mut self, - r: ty::Region<'tcx>, - r2: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - debug!("generalize: regions r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased => { - return Ok(r); - } - - ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - // If we are in an invariant context, we can re-use the region - // as is, unless it happens to be in some universe that we - // can't name. (In the case of a region *variable*, we could - // use it if we promoted it into our universe, but we don't - // bother.) - if let ty::Invariant = self.ambient_variance { - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } - } - - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) - } - - fn consts( - &mut self, - c: ty::Const<'tcx>, - c2: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => { - drop(inner); - self.relate(u, u) - } - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); - Ok(self.tcx().mk_const(new_var_id, c.ty())) - } - } - } - } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) - } - _ => relate::super_relate_consts(self, c, c), - } - } -} - pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register obligations that must hold in order for this relation to hold fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); /// Register predicates that must hold in order for this relation to hold. Uses /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should - /// be used if control over the obligaton causes is required. + /// be used if control over the obligation causes is required. fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>); /// Register an obligation that both constants must be equal to each other. @@ -878,135 +496,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -struct ConstInferUnifier<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - span: Span, - - for_universe: ty::UniverseIndex, - - /// The vid of the const variable that is in the process of being - /// instantiated; if we find this within the const we are folding, - /// that means we would have created a cyclic const. - target_vid: ty::ConstVid<'tcx>, -} - -impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> { - type Error = TypeError<'tcx>; - - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> { - match t.kind() { - &ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("ConstOccursChecker: known value {:?}", u); - u.try_fold_with(self) - } - TypeVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - Ok(self.interner().mk_ty_var(new_var_id)) - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), - _ => t.try_super_fold_with(self), - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_region( - &mut self, - r: ty::Region<'tcx>, - ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> { - debug!("ConstInferUnifier: r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } else { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> { - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - // Check if the current unification would end up - // unifying `target_vid` with a const which contains - // an inference variable which is unioned with `target_vid`. - // - // Not doing so can easily result in stack overflows. - if self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .unioned(self.target_vid, vid) - { - return Err(TypeError::CyclicConst(c)); - } - - let var_value = - self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => u.try_fold_with(self), - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = - self.infcx.inner.borrow_mut().const_unification_table().new_key( - ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { - universe: self.for_universe, - }, - }, - ); - Ok(self.interner().mk_const(new_var_id, c.ty())) - } - } - } - } - _ => c.try_super_fold_with(self), - } - } -} diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index fe4a2dd38..42dfe4f6b 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -1,7 +1,7 @@ use crate::infer::DefineOpaqueTypes; use crate::traits::PredicateObligations; -use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir}; +use super::combine::{CombineFields, ObligationEmittingRelation}; use super::Subtype; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -88,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?; } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; } ( @@ -104,7 +104,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 == DefineOpaqueTypes::Yes - && def_id.is_local() => + && def_id.is_local() + && !self.tcx().trait_solver_next() => { self.fields.obligations.extend( infcx @@ -178,7 +179,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { where T: Relate<'tcx>, { - // A binder is equal to itself if it's structually equal to itself + // A binder is equal to itself if it's structurally equal to itself if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9e5f6d107..35c05e80b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -74,7 +74,6 @@ 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}; @@ -138,7 +137,7 @@ impl Drop for TypeErrCtxt<'_, '_> { self.infcx .tcx .sess - .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation"); + .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint"); } } } @@ -283,9 +282,9 @@ fn emit_msg_span( let message = format!("{}{}{}", prefix, description, suffix); if let Some(span) = span { - err.span_note(span, &message); + err.span_note(span, message); } else { - err.note(&message); + err.note(message); } } @@ -299,9 +298,9 @@ fn label_msg_span( let message = format!("{}{}{}", prefix, description, suffix); if let Some(span) = span { - err.span_label(span, &message); + err.span_label(span, message); } else { - err.note(&message); + err.note(message); } } @@ -403,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( + self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map( |(predicate, _)| { predicate .kind() @@ -1826,7 +1825,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { s }; if !(values.expected.is_simple_text() && values.found.is_simple_text()) - || (exp_found.map_or(false, |ef| { + || (exp_found.is_some_and(|ef| { // This happens when the type error is a subset of the expectation, // like when you have two references but one is `usize` and the other // is `f32`. In those cases we still want to show the `note`. If the @@ -1878,7 +1877,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let exp_found = match terr { // `terr` has more accurate type information than `exp_found` in match expressions. ty::error::TypeError::Sorts(terr) - if exp_found.map_or(false, |ef| terr.found == ef.found) => + if exp_found.is_some_and(|ef| terr.found == ef.found) => { Some(terr) } @@ -1927,6 +1926,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); + self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag); } // It reads better to have the error origin as the final @@ -1961,7 +1961,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 + && code.chars().next().is_some_and(|c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII { suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) }) } @@ -2329,7 +2329,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .source_map() .span_to_prev_source(p.span.shrink_to_hi()) .ok() - .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&') + .is_some_and(|s| *s.as_bytes().last().unwrap() == b'&') { add_lt_suggs .push(Some( @@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), GenericKind::Alias(ref p) => match p.kind(self.tcx) { - ty::AliasKind::Projection => format!("the associated type `{}`", p), + ty::AliasKind::Projection | ty::AliasKind::Inherent => { + format!("the associated type `{}`", p) + } ty::AliasKind::Opaque => format!("the opaque type `{}`", p), }, }; @@ -2395,7 +2397,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } else { let consider = format!("{} `{}: {}`...", msg, bound_kind, sub); - err.help(&consider); + err.help(consider); } } @@ -2625,7 +2627,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); err.span_note( sup_trace.cause.span, - &format!("...so that the {}", sup_trace.cause.as_requirement_str()), + format!("...so that the {}", sup_trace.cause.as_requirement_str()), ); err.note_expected_found(&"", sup_expected, &"", sup_found); @@ -2721,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { | (ty::Infer(ty::InferTy::TyVar(_)), _) | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), - _ => relate::super_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, a, b), } } @@ -2885,7 +2887,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, - IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags }, + IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, // In the case where we have no more specific thing to @@ -2942,7 +2944,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { IfExpressionWithNoElse => "no_else", MainFunctionType => "fn_main_correct_type", StartFunctionType => "fn_start_correct_type", - IntrinsicType => "intristic_correct_type", + IntrinsicType => "intrinsic_correct_type", MethodReceiver => "method_correct_type", _ => "other", } 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 75cc4e257..f3b2ec4c5 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::{ - AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, + AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, SourceKindMultiSuggestion, SourceKindSubdiag, }; use crate::infer::error_reporting::TypeErrCtxt; @@ -31,7 +31,7 @@ pub enum TypeAnnotationNeeded { /// ``` E0282, /// An implementation cannot be chosen unambiguously because of lack of information. - /// ```compile_fail,E0283 + /// ```compile_fail,E0790 /// let _ = Default::default(); /// ``` E0283, @@ -368,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> { bad_label, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0284 => AmbigousReturn { + TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, source_name, @@ -573,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { bad_label: None, } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), - TypeAnnotationNeeded::E0284 => AmbigousReturn { + TypeAnnotationNeeded::E0284 => AmbiguousReturn { span, source_kind, source_name: &name, @@ -671,7 +671,7 @@ impl<'tcx> InferSource<'tcx> { receiver.span.from_expansion() } InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => { - data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion) + data.span().from_expansion() || should_wrap_expr.is_some_and(Span::from_expansion) } }; source_from_expansion || self.span.from_expansion() @@ -984,7 +984,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a { let tcx = self.infcx.tcx; let have_turbofish = path.segments.iter().any(|segment| { - segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const())) + segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const())) }); // The last segment of a path often has `Res::Err` and the // correct `Res` is the one of the whole path. diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index da0271a34..1a60bab18 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// /// Consider a case where we have /// - /// ```compile_fail,E0623 + /// ```compile_fail /// fn foo(x: &mut Vec<&u8>, y: &u8) { /// x.push(y); /// } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index fec04af23..0df417d09 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Region, TyCtxt}; /// br - the bound region corresponding to the above region which is of type `BrAnon(_)` /// /// # Example -/// ```compile_fail,E0623 +/// ```compile_fail /// fn foo(x: &mut Vec<&u8>, y: &u8) /// { x.push(y); } /// ``` diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index c1ea0a0d9..c9c1f0aea 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -261,11 +261,16 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { (false, None, None, Some(span), String::new()) }; - let expected_trait_ref = self - .cx - .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs)); - let actual_trait_ref = - self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs)); + let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new( + self.cx.tcx, + trait_def_id, + expected_substs, + )); + let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new( + self.cx.tcx, + trait_def_id, + actual_substs, + )); // Search the expected and actual trait references to see (a) // whether the sub/sup placeholders appear in them (sometimes 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 22c1e3871..aad988582 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 @@ -299,7 +299,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( span, - &format!("{consider} `{ty}`'s {explicit_static}"), + format!("{consider} `{ty}`'s {explicit_static}"), &lifetime_name, Applicability::MaybeIncorrect, ); @@ -312,13 +312,10 @@ pub fn suggest_new_region_bound( Applicability::MaybeIncorrect, ); } - } else if opaque.bounds.iter().any(|arg| match arg { - GenericBound::Outlives(Lifetime { ident, .. }) - if ident.name.to_string() == lifetime_name => - { - true - } - _ => false, + } else if opaque.bounds.iter().any(|arg| { + matches!(arg, + GenericBound::Outlives(Lifetime { ident, .. }) + if ident.name.to_string() == lifetime_name ) }) { } else { // get a lifetime name of existing named lifetimes if any @@ -370,7 +367,7 @@ pub fn suggest_new_region_bound( spans_suggs .push((fn_return.span.shrink_to_hi(), format!(" + {name} "))); err.multipart_suggestion_verbose( - &format!( + format!( "{declare} `{ty}` {captures}, {use_lt}", ), spans_suggs, @@ -379,7 +376,7 @@ pub fn suggest_new_region_bound( } else { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), - &format!("{declare} `{ty}` {captures}, {explicit}",), + format!("{declare} `{ty}` {captures}, {explicit}",), &plus_lt, Applicability::MaybeIncorrect, ); @@ -390,7 +387,7 @@ pub fn suggest_new_region_bound( if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res { err.span_suggestion_verbose( fn_return.span.shrink_to_hi(), - &format!( + format!( "{declare} the trait object {captures}, {explicit}", declare = declare, captures = captures, @@ -407,7 +404,7 @@ pub fn suggest_new_region_bound( if let Some(explicit_static) = &explicit_static { err.span_suggestion_verbose( lt.ident.span, - &format!("{} the trait object's {}", consider, explicit_static), + format!("{} the trait object's {}", consider, explicit_static), &lifetime_name, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 2875448ee..ce70bcc5c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; use rustc_span::Span; use std::ops::ControlFlow; @@ -81,7 +81,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { self.highlight.highlighting_region(r, self.counter); self.counter += 1; } - r.super_visit_with(self) + ControlFlow::Continue(()) } } 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 b38bbdfe7..421eb807a 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 @@ -2,6 +2,7 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; @@ -71,9 +72,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #traits-as-parameters", ); } - (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => { + (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => { diag.note("an associated type was expected, but a different one was found"); } + // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) if !tcx.is_impl_trait_in_trait(proj.def_id) => { @@ -209,7 +211,7 @@ impl<T> Trait<T> for X { if !sp.contains(p_span) { diag.span_label(p_span, "this type parameter"); } - diag.help(&format!( + diag.help(format!( "every closure has a distinct type and so could not always match the \ caller-chosen type of parameter `{}`", p @@ -222,7 +224,7 @@ impl<T> Trait<T> for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { + (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { self.expected_projection( diag, proj_ty, @@ -231,7 +233,7 @@ impl<T> Trait<T> for X { cause.code(), ); } - (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { + (_, ty::Alias(ty::Projection | ty::Inherent, 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, @@ -248,13 +250,22 @@ impl<T> Trait<T> for X { proj_ty, values.expected, )) { - diag.help(&msg); + diag.help(msg); diag.note( "for more information, visit \ https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } } + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { + if tcx.is_type_alias_impl_trait(alias.def_id) { + if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { + diag.span_note(tcx.def_span(body_owner_def_id), "\ + this item must have the opaque type in its signature \ + in order to be able to register hidden types"); + } + } + } (ty::FnPtr(_), ty::FnDef(def, _)) if let hir::def::DefKind::Fn = tcx.def_kind(def) => { diag.note( @@ -415,12 +426,12 @@ impl<T> Trait<T> for X { if !impl_comparison { // Generic suggestion when we can't be more specific. if callable_scope { - diag.help(&format!( + diag.help(format!( "{} or calling a method that returns `{}`", msg, values.expected )); } else { - diag.help(&msg); + diag.help(msg); } diag.note( "for more information, visit \ @@ -462,10 +473,7 @@ fn foo(&self) -> Self::T { String::new() } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { let opaque_local_def_id = def_id.as_local(); let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - match &tcx.hir().expect_item(opaque_local_def_id).kind { - hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty, - _ => bug!("The HirId comes from a `ty::Opaque`"), - } + tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty() } else { return false; }; @@ -539,7 +547,7 @@ fn foo(&self) -> Self::T { String::new() } for (sp, label) in methods.into_iter() { span.push_span_label(sp, label); } - diag.span_help(span, &msg); + diag.span_help(span, msg); return true; } false diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index b5aeca12a..d885d0407 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -1,16 +1,15 @@ use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::Diagnostic; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, StatementAsExpression, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; use rustc_span::{sym, BytePos, Span}; -use rustc_target::abi::FieldIdx; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, @@ -114,7 +113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn) }) .filter_map(|variant| { - let sole_field = &variant.fields[FieldIdx::from_u32(0)]; + let sole_field = &variant.single_field(); 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 = @@ -536,6 +535,82 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } None } + + /// For "one type is more general than the other" errors on closures, suggest changing the lifetime + /// of the parameters to accept all lifetimes. + pub(super) fn suggest_for_all_lifetime_closure( + &self, + span: Span, + hir: hir::Node<'_>, + exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>, + diag: &mut Diagnostic, + ) { + // 0. Extract fn_decl from hir + let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), .. }) = hir else { return; }; + let hir::Body { params, .. } = self.tcx.hir().body(*body); + + // 1. Get the substs of the closure. + // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. + let Some(expected) = exp_found.expected.skip_binder().substs.get(1) else { return; }; + let Some(found) = exp_found.found.skip_binder().substs.get(1) else { return; }; + let expected = expected.unpack(); + let found = found.unpack(); + // 3. Extract the tuple type from Fn trait and suggest the change. + if let GenericArgKind::Type(expected) = expected && + let GenericArgKind::Type(found) = found && + let ty::Tuple(expected) = expected.kind() && + let ty::Tuple(found)= found.kind() && + expected.len() == found.len() { + let mut suggestion = "|".to_string(); + let mut is_first = true; + let mut has_suggestion = false; + + for (((expected, found), param_hir), arg_hir) in expected.iter() + .zip(found.iter()) + .zip(params.iter()) + .zip(fn_decl.inputs.iter()) { + if is_first { + is_first = false; + } else { + suggestion += ", "; + } + + if let ty::Ref(expected_region, _, _) = expected.kind() && + let ty::Ref(found_region, _, _) = found.kind() && + expected_region.is_late_bound() && + !found_region.is_late_bound() && + let hir::TyKind::Infer = arg_hir.kind { + // If the expected region is late bound, the found region is not, and users are asking compiler + // to infer the type, we can suggest adding `: &_`. + if param_hir.pat.span == param_hir.ty_span { + // for `|x|`, `|_|`, `|x: impl Foo|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + suggestion += &format!("{}: &_", pat); + } else { + // for `|x: ty|`, `|_: ty|` + let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; }; + suggestion += &format!("{}: &{}", pat, ty); + } + has_suggestion = true; + } else { + let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; }; + // Otherwise, keep it as-is. + suggestion += &arg; + } + } + suggestion += "|"; + + if has_suggestion { + diag.span_suggestion_verbose( + span, + "consider specifying the type of the closure parameters", + suggestion, + Applicability::MaybeIncorrect, + ); + } + } + } } impl<'tcx> TypeErrCtxt<'_, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index d89f63e5c..0219167f6 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -127,7 +127,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { #[inline] fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { + if !t.has_infer() && !t.has_erasable_regions() { t } else { match *t.kind() { diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs new file mode 100644 index 000000000..d4a1dacde --- /dev/null +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -0,0 +1,479 @@ +use rustc_data_structures::sso::SsoHashMap; +use rustc_hir::def_id::DefId; +use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; + +use crate::infer::nll_relate::TypeRelatingDelegate; +use crate::infer::type_variable::TypeVariableValue; +use crate::infer::{InferCtxt, RegionVariableOrigin}; + +/// Attempts to generalize `term` for the type variable `for_vid`. +/// This checks for cycles -- that is, whether the type `term` +/// references `for_vid`. +pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( + infcx: &InferCtxt<'tcx>, + delegate: &mut D, + term: T, + for_vid: impl Into<ty::TermVid<'tcx>>, + ambient_variance: ty::Variance, +) -> RelateResult<'tcx, Generalization<T>> { + let (for_universe, root_vid) = match for_vid.into() { + ty::TermVid::Ty(ty_vid) => ( + infcx.probe_ty_var(ty_vid).unwrap_err(), + ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), + ), + ty::TermVid::Const(ct_vid) => ( + infcx.probe_const_var(ct_vid).unwrap_err(), + ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)), + ), + }; + + let mut generalizer = Generalizer { + infcx, + delegate, + ambient_variance, + root_vid, + for_universe, + root_term: term.into(), + needs_wf: false, + cache: Default::default(), + }; + + assert!(!term.has_escaping_bound_vars()); + let value = generalizer.relate(term, term)?; + let needs_wf = generalizer.needs_wf; + Ok(Generalization { value, needs_wf }) +} + +/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking +/// in the generalizer code. +pub trait GeneralizerDelegate<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx>; + + fn forbid_inference_vars() -> bool; + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; +} + +pub struct CombineDelegate<'cx, 'tcx> { + pub infcx: &'cx InferCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub span: Span, +} + +impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn forbid_inference_vars() -> bool { + false + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx + .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe) + } +} + +impl<'tcx, T> GeneralizerDelegate<'tcx> for T +where + T: TypeRelatingDelegate<'tcx>, +{ + fn param_env(&self) -> ty::ParamEnv<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::param_env(self) + } + + fn forbid_inference_vars() -> bool { + <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars() + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe) + } +} + +/// The "generalizer" is used when handling inference variables. +/// +/// The basic strategy for handling a constraint like `?A <: B` is to +/// apply a "generalization strategy" to the term `B` -- this replaces +/// all the lifetimes in the term `B` with fresh inference variables. +/// (You can read more about the strategy in this [blog post].) +/// +/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x +/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the +/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which +/// establishes `'0: 'x` as a constraint. +/// +/// [blog post]: https://is.gd/0hKvIr +struct Generalizer<'me, 'tcx, D> { + infcx: &'me InferCtxt<'tcx>, + + /// This is used to abstract the behaviors of the three previous + /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`, + /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more + /// information. + delegate: &'me mut D, + + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + + /// The vid of the type variable that is in the process of being + /// instantiated. If we find this within the value we are folding, + /// that means we would have created a cyclic value. + root_vid: ty::TermVid<'tcx>, + + /// The universe of the type variable that is in the process of being + /// instantiated. If we find anything that this universe cannot name, + /// we reject the relation. + for_universe: ty::UniverseIndex, + + /// The root term (const or type) we're generalizing. Used for cycle errors. + root_term: Term<'tcx>, + + cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, + + /// See the field `needs_wf` in `Generalization`. + needs_wf: bool, +} + +impl<'tcx, D> Generalizer<'_, 'tcx, D> { + /// Create an error that corresponds to the term kind in `root_term` + fn cyclic_term_error(&self) -> TypeError<'tcx> { + match self.root_term.unpack() { + ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty), + ty::TermKind::Const(ct) => TypeError::CyclicConst(ct), + } + } +} + +impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D> +where + D: GeneralizerDelegate<'tcx>, +{ + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.delegate.param_env() + } + + fn tag(&self) -> &'static str { + "Generalizer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_item_substs( + &mut self, + item_def_id: DefId, + a_subst: ty::SubstsRef<'tcx>, + b_subst: ty::SubstsRef<'tcx>, + ) -> RelateResult<'tcx, ty::SubstsRef<'tcx>> { + if self.ambient_variance == ty::Variance::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate::relate_substs(self, a_subst, b_subst) + } else { + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_substs_with_variances( + self, + item_def_id, + opt_variances, + a_subst, + b_subst, + true, + ) + } + } + + #[instrument(level = "debug", skip(self, variance, b), ret)] + fn relate_with_variance<T: Relate<'tcx>>( + &mut self, + variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + let r = self.relate(a, b)?; + self.ambient_variance = old_ambient_variance; + Ok(r) + } + + #[instrument(level = "debug", skip(self, t2), ret)] + fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + if let Some(&result) = self.cache.get(&t) { + return Ok(result); + } + + // Check to see whether the type we are generalizing references + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. + let g = match *t.kind() { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) + if D::forbid_inference_vars() => + { + bug!("unexpected inference variable encountered in NLL generalization: {t}"); + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected infer type: {t}") + } + + ty::Infer(ty::TyVar(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let vid = inner.type_variables().root_var(vid); + let sub_vid = inner.type_variables().sub_root_var(vid); + + if ty::TermVid::Ty(sub_vid) == self.root_vid { + // If sub-roots are equal, then `root_vid` and + // `vid` are related via subtyping. + Err(self.cyclic_term_error()) + } else { + let probe = inner.type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + TypeVariableValue::Unknown { universe } => { + match self.ambient_variance { + // Invariant: no need to make a fresh type variable + // if we can name the universe. + ty::Invariant => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + } + + // Bivariant: make a fresh var, but we + // may need a WF predicate. See + // comment on `needs_wf` field for + // more info. + ty::Bivariant => self.needs_wf = true, + + // Co/contravariant: this will be + // sufficiently constrained later on. + ty::Covariant | ty::Contravariant => (), + } + + let origin = *inner.type_variables().var_origin(vid); + let new_var_id = + inner.type_variables().new_var(self.for_universe, origin); + let u = self.tcx().mk_ty_var(new_var_id); + + // Record that we replaced `vid` with `new_var_id` as part of a generalization + // operation. This is needed to detect cyclic types. To see why, see the + // docs in the `type_variables` module. + inner.type_variables().sub(vid, new_var_id); + debug!("replacing original vid={:?} with new={:?}", vid, u); + Ok(u) + } + } + } + } + + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + // No matter what mode we are in, + // integer/floating-point types must be equal to be + // relatable. + Ok(t) + } + + ty::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + + _ => relate::structurally_relate_tys(self, t, t), + }?; + + self.cache.insert(t, g); + Ok(g) + } + + #[instrument(level = "debug", skip(self, r2), ret)] + fn regions( + &mut self, + r: ty::Region<'tcx>, + r2: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match *r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + // It doesn't really matter for correctness if we generalize ReError, + // since we're already on a doomed compilation path. + ty::ReError(_) => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + // If we are in an invariant context, we can re-use the region + // as is, unless it happens to be in some universe that we + // can't name. + if let ty::Invariant = self.ambient_variance { + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } + } + + Ok(self.delegate.generalize_region(self.for_universe)) + } + + #[instrument(level = "debug", skip(self, c2), ret)] + fn consts( + &mut self, + c: ty::Const<'tcx>, + c2: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match c.kind() { + ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + bug!("unexpected inference variable encountered in NLL generalization: {:?}", c); + } + ty::ConstKind::Infer(InferConst::Var(vid)) => { + // If root const vids are equal, then `root_vid` and + // `vid` are related and we'd be inferring an infinitely + // deep const. + if ty::TermVid::Const( + self.infcx.inner.borrow_mut().const_unification_table().find(vid), + ) == self.root_vid + { + return Err(self.cyclic_term_error()); + } + + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const(new_var_id, c.ty())) + } + } + } + } + // FIXME: remove this branch once `structurally_relate_consts` is fully + // structural. + ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { + let substs = self.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + substs, + substs, + )?; + Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) + } + ty::ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + _ => relate::structurally_relate_consts(self, c, c), + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn binders<T>( + &mut self, + a: ty::Binder<'tcx, T>, + _: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate<'tcx>, + { + let result = self.relate(a.skip_binder(), a.skip_binder())?; + Ok(a.rebind(result)) + } +} + +/// Result from a generalization operation. This includes +/// not only the generalized type, but also a bool flag +/// indicating whether further WF checks are needed. +#[derive(Debug)] +pub struct Generalization<T> { + pub value: T, + + /// If true, then the generalized type may not be well-formed, + /// even if the source type is well-formed, so we should add an + /// additional check to enforce that it is. This arises in + /// particular around 'bivariant' type parameters that are only + /// constrained by a where-clause. As an example, imagine a type: + /// + /// struct Foo<A, B> where A: Iterator<Item = B> { + /// data: A + /// } + /// + /// here, `A` will be covariant, but `B` is + /// unconstrained. However, whatever it is, for `Foo` to be WF, it + /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, + /// then after generalization we will wind up with a type like + /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, + /// ?D>` (or `>:`), we will wind up with the requirement that `?A + /// <: ?C`, but no particular relationship between `?B` and `?D` + /// (after all, we do not know the variance of the normalized form + /// of `A::Item` with respect to `A`). If we do nothing else, this + /// may mean that `?D` goes unconstrained (as in #41677). So, in + /// this scenario where we create a new type variable in a + /// bivariant context, we set the `needs_wf` flag to true. This + /// will force the calling code to check that `WF(Foo<?C, ?D>)` + /// holds, which in turn implies that `?C::Item == ?D`. So once + /// `?C` is constrained, that should suffice to restrict `?D`. + pub needs_wf: bool, +} diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index a63cfbc91..c304cd25c 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -42,7 +42,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- - // but no other pre-existing region variables -- can name + // but no other preexisting region variables -- can name // the placeholders. let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub); diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 7f4c141b9..7190d33d2 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -108,9 +108,12 @@ where &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) 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() == DefineOpaqueTypes::Yes && def_id.is_local() => + if this.define_opaque_types() == DefineOpaqueTypes::Yes + && def_id.is_local() + && !this.tcx().trait_solver_next() => { 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 f298b95ca..8482ae2aa 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::{IndexSlice, IndexVec}; +use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::PlaceholderRegion; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -102,6 +102,17 @@ pub enum RegionResolutionError<'tcx> { ), } +impl<'tcx> RegionResolutionError<'tcx> { + pub fn origin(&self) -> &SubregionOrigin<'tcx> { + match self { + RegionResolutionError::ConcreteFailure(origin, _, _) + | RegionResolutionError::GenericBoundFailure(origin, _, _) + | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _) + | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin, + } + } +} + struct RegionAndOrigin<'tcx> { region: Region<'tcx>, origin: SubregionOrigin<'tcx>, @@ -131,10 +142,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.dump_constraints(); } - let graph = self.construct_graph(); self.expansion(&mut var_data); self.collect_errors(&mut var_data, errors); - self.collect_var_errors(&var_data, &graph, errors); + self.collect_var_errors(&var_data, errors); var_data } @@ -622,7 +632,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { fn collect_var_errors( &self, var_data: &LexicalRegionResolutions<'tcx>, - graph: &RegionGraph<'tcx>, errors: &mut Vec<RegionResolutionError<'tcx>>, ) { debug!("collect_var_errors, var_data = {:#?}", var_data.values); @@ -640,6 +649,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // overlapping locations. let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars()); + // Only construct the graph when necessary, because it's moderately + // expensive. + let mut graph = None; + for (node_vid, value) in var_data.values.iter_enumerated() { match *value { VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ } @@ -672,7 +685,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); + let g = graph.get_or_insert_with(|| self.construct_graph()); + self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors); } } } @@ -821,7 +835,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // resolution errors here; delay ICE in favor of those errors. self.tcx().sess.delay_span_bug( self.var_infos[node_idx].origin.span(), - &format!( + format!( "collect_error_for_expanding_node() could not find \ error for var {:?} in universe {:?}, lower_bounds={:#?}, \ upper_bounds={:#?}", diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 66f51328b..cd99fc312 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -24,7 +24,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::select; +use rustc_middle::traits::{select, DefiningAnchor}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -39,7 +39,6 @@ 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; @@ -59,6 +58,7 @@ pub mod error_reporting; pub mod free_regions; mod freshen; mod fudge; +mod generalize; mod glb; mod higher_ranked; pub mod lattice; @@ -231,17 +231,6 @@ impl<'tcx> InferCtxtInner<'tcx> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum DefiningAnchor { - /// `DefId` of the item. - Bind(LocalDefId), - /// When opaque types are not resolved, we `Bubble` up, meaning - /// return the opaque/hidden type pair from query, for caller of query to handle it. - Bubble, - /// Used to catch type mismatch errors when handling opaque types. - Error, -} - pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, @@ -342,11 +331,6 @@ pub struct InferCtxt<'tcx> { /// 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. @@ -638,7 +622,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { skip_leak_check: Cell::new(false), universe: Cell::new(ty::UniverseIndex::ROOT), intercrate, - inside_canonicalization_ctxt: Cell::new(false), } } } @@ -1228,11 +1211,11 @@ impl<'tcx> InferCtxt<'tcx> { /// hence that `resolve_regions_and_report_errors` can never be /// called. This is used only during NLL processing to "hand off" ownership /// of the set of region variables into the NLL region context. - pub fn take_region_var_origins(&self) -> VarInfos { + pub fn get_region_var_origins(&self) -> VarInfos { let mut inner = self.inner.borrow_mut(); let (var_infos, data) = inner .region_constraint_storage - .take() + .clone() .expect("regions already resolved") .with_log(&mut inner.undo_log) .into_infos_and_data(); @@ -1327,7 +1310,7 @@ impl<'tcx> InferCtxt<'tcx> { where T: TypeFoldable<TyCtxt<'tcx>>, { - if !value.needs_infer() { + if !value.has_infer() { return value; // Avoid duplicated subst-folding. } let mut r = InferenceLiteralEraser { tcx: self.tcx }; @@ -1365,7 +1348,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> { let value = resolve::fully_resolve(self, value); assert!( - value.as_ref().map_or(true, |value| !value.needs_infer()), + value.as_ref().map_or(true, |value| !value.has_infer()), "`{value:?}` is not fully resolved" ); value @@ -1500,7 +1483,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(Some(val)) => Ok(self.tcx.mk_const(val, ty)), Ok(None) => { let tcx = self.tcx; - let def_id = unevaluated.def.did; + let def_id = unevaluated.def; span_bug!( tcx.def_span(def_id), "unable to construct a constant value for the unevaluated constant {:?}", @@ -1537,18 +1520,18 @@ impl<'tcx> InferCtxt<'tcx> { // variables let tcx = self.tcx; if substs.has_non_region_infer() { - if let Some(ct) = tcx.bound_abstract_const(unevaluated.def)? { + if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { let ct = tcx.expand_abstract_consts(ct.subst(tcx, substs)); if let Err(e) = ct.error_reported() { - return Err(ErrorHandled::Reported(e)); + return Err(ErrorHandled::Reported(e.into())); } else if ct.has_non_region_infer() || ct.has_non_region_param() { return Err(ErrorHandled::TooGeneric); } else { substs = replace_param_and_infer_substs_with_placeholder(tcx, substs); } } else { - substs = InternalSubsts::identity_for_item(tcx, unevaluated.def.did); - param_env = tcx.param_env(unevaluated.def.did); + substs = InternalSubsts::identity_for_item(tcx, unevaluated.def); + param_env = tcx.param_env(unevaluated.def); } } @@ -1577,10 +1560,10 @@ impl<'tcx> InferCtxt<'tcx> { (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, - } + matches!( + inner.try_type_variables_probe_ref(ty_var), + Some(TypeVariableValue::Unknown { .. }) + ) } _ => false, }; @@ -1636,31 +1619,6 @@ impl<'tcx> InferCtxt<'tcx> { } } } - - pub fn inside_canonicalization_ctxt(&self) -> bool { - self.inside_canonicalization_ctxt.get() - } - - 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 } - } - - fn set_canonicalization_ctxt_to(&self, ctxt: bool) { - self.inside_canonicalization_ctxt.set(ctxt); - } -} - -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> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 9f7b26b87..d3fd01b96 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -21,22 +21,20 @@ //! thing we relate in chalk are basically domain goals and their //! constituents) -use crate::infer::InferCtxt; -use crate::infer::{ConstVarValue, ConstVariableValue}; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -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::relate::{Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::{Span, Symbol}; use std::fmt::Debug; -use std::ops::ControlFlow; -use super::combine::ObligationEmittingRelation; +use crate::infer::combine::ObligationEmittingRelation; +use crate::infer::generalize::{self, Generalization}; +use crate::infer::InferCtxt; +use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::traits::{Obligation, PredicateObligations}; pub struct TypeRelating<'me, 'tcx, D> where @@ -115,11 +113,6 @@ pub trait TypeRelatingDelegate<'tcx> { fn forbid_inference_vars() -> bool; } -#[derive(Clone, Debug, Default)] -struct BoundRegionScope<'tcx> { - map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, -} - #[derive(Copy, Clone)] struct UniversallyQuantified(bool); @@ -204,7 +197,7 @@ where _ => (), } - let generalized_ty = self.generalize_value(value_ty, vid)?; + let generalized_ty = self.generalize(value_ty, vid)?; debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); if D::forbid_inference_vars() { @@ -223,23 +216,15 @@ where result } - fn generalize_value<T: Relate<'tcx>>( - &mut self, - value: T, - for_vid: ty::TyVid, - ) -> RelateResult<'tcx, T> { - let universe = self.infcx.probe_ty_var(for_vid).unwrap_err(); - - let mut generalizer = TypeGeneralizer { - infcx: self.infcx, - delegate: &mut self.delegate, - first_free_index: ty::INNERMOST, - ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - universe, - }; - - generalizer.relate(value, value) + fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { + let Generalization { value: ty, needs_wf: _ } = generalize::generalize( + self.infcx, + &mut self.delegate, + ty, + for_vid, + self.ambient_variance, + )?; + Ok(ty) } fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { @@ -488,13 +473,7 @@ where } if a == b { - // Subtle: if a or b has a bound variable that we are lazily - // substituting, then even if a == b, it could be that the values we - // will substitute for those bound variables are *not* the same, and - // hence returning `Ok(a)` is incorrect. - if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() { - return Ok(a); - } + return Ok(a); } match (a.kind(), b.kind()) { @@ -512,16 +491,22 @@ where ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| { - self.tcx().sess.delay_span_bug( - self.delegate.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - }), + ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => { + infcx.super_combine_tys(self, a, b).or_else(|err| { + // This behavior is only there for the old solver, the new solver + // shouldn't ever fail. Instead, it unconditionally emits an + // alias-relate goal. + assert!(!self.tcx().trait_solver_next()); + self.tcx().sess.delay_span_bug( + self.delegate.span(), + "failure to relate an opaque to itself should result in an error later on", + ); + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + }) + } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() => + if def_id.is_local() && !self.tcx().trait_solver_next() => { self.relate_opaques(a, b) } @@ -725,287 +710,3 @@ where })]); } } - -/// When we encounter a binder like `for<..> fn(..)`, we actually have -/// to walk the `fn` value to find all the values bound by the `for` -/// (these are not explicitly present in the ty representation right -/// now). This visitor handles that: it descends the type, tracking -/// binder depth, and finds late-bound regions targeting the -/// `for<..`>. For each of those, it creates an entry in -/// `bound_region_scope`. -struct ScopeInstantiator<'me, 'tcx> { - next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - // The debruijn index of the scope we are instantiating. - target_index: ty::DebruijnIndex, - bound_region_scope: &'me mut BoundRegionScope<'tcx>, -} - -impl<'me, 'tcx> TypeVisitor<TyCtxt<'tcx>> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( - &mut self, - t: &ty::Binder<'tcx, T>, - ) -> ControlFlow<Self::BreakTy> { - self.target_index.shift_in(1); - t.super_visit_with(self); - self.target_index.shift_out(1); - - ControlFlow::Continue(()) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - let ScopeInstantiator { bound_region_scope, next_region, .. } = self; - - match *r { - ty::ReLateBound(debruijn, br) if debruijn == self.target_index => { - bound_region_scope.map.entry(br).or_insert_with(|| next_region(br)); - } - - _ => {} - } - - ControlFlow::Continue(()) - } -} - -/// The "type generalizer" is used when handling inference variables. -/// -/// The basic strategy for handling a constraint like `?A <: B` is to -/// apply a "generalization strategy" to the type `B` -- this replaces -/// all the lifetimes in the type `B` with fresh inference -/// variables. (You can read more about the strategy in this [blog -/// post].) -/// -/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x -/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the -/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which -/// establishes `'0: 'x` as a constraint. -/// -/// As a side-effect of this generalization procedure, we also replace -/// all the bound regions that we have traversed with concrete values, -/// so that the resulting generalized type is independent from the -/// scopes. -/// -/// [blog post]: https://is.gd/0hKvIr -struct TypeGeneralizer<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'tcx>, - - delegate: &'me mut D, - - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - - first_free_index: ty::DebruijnIndex, - - /// The vid of the type variable that is in the process of being - /// instantiated. If we find this within the value we are folding, - /// that means we would have created a cyclic value. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of being - /// instantiated. If we find anything that this universe cannot name, - /// we reject the relation. - universe: ty::UniverseIndex, -} - -impl<'tcx, D> TypeRelation<'tcx> for TypeGeneralizer<'_, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.delegate.param_env() - } - - fn tag(&self) -> &'static str { - "nll::generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - debug!( - "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - use crate::infer::type_variable::TypeVariableValue; - - debug!("TypeGeneralizer::tys(a={:?})", a); - - match *a.kind() { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - - ty::Infer(ty::TyVar(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variables = &mut inner.type_variables(); - let vid = variables.root_var(vid); - let sub_vid = variables.sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - debug!("TypeGeneralizer::tys: occurs check failed"); - Err(TypeError::Mismatch) - } else { - match variables.probe(vid) { - TypeVariableValue::Known { value: u } => { - drop(variables); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe: _universe } => { - if self.ambient_variance == ty::Bivariant { - // FIXME: we may need a WF predicate (related to #54105). - } - - let origin = *variables.var_origin(vid); - - // Replacing with a new variable in the universe `self.universe`, - // it will be unified later with the original type variable in - // the universe `_universe`. - let new_var_id = variables.new_var(self.universe, origin); - - let u = self.tcx().mk_ty_var(new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(a) - } - - ty::Placeholder(placeholder) => { - if self.universe.cannot_name(placeholder.universe) { - debug!( - "TypeGeneralizer::tys: root universe {:?} cannot name\ - placeholder in universe {:?}", - self.universe, placeholder.universe - ); - Err(TypeError::Mismatch) - } else { - Ok(a) - } - } - - _ => relate::super_relate_tys(self, a, a), - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a); - - if let ty::ReLateBound(debruijn, _) = *a && debruijn < self.first_free_index { - return Ok(a); - } - - // For now, we just always create a fresh region variable to - // replace all the regions in the source type. In the main - // type checker, we special case the case where the ambient - // variance is `Invariant` and try to avoid creating a fresh - // region variable, but since this comes up so much less in - // NLL (only when users use `_` etc) it is much less - // important. - // - // As an aside, since these new variables are created in - // `self.universe` universe, this also serves to enforce the - // universe scoping rules. - // - // FIXME(#54105) -- if the ambient variance is bivariant, - // though, we may however need to check well-formedness or - // risk a problem like #41677 again. - - let replacement_region_vid = self.delegate.generalize_existential(self.universe); - - Ok(replacement_region_vid) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - _: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - match a.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val.known() { - Some(u) => self.relate(u, u), - None => { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.universe }, - }); - Ok(self.tcx().mk_const(new_var_id, a.ty())) - } - } - } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a), - _ => relate::super_relate_consts(self, a, a), - } - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - _: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - debug!("TypeGeneralizer::binders(a={:?})", a); - - self.first_free_index.shift_in(1); - let result = self.relate(a.skip_binder(), a.skip_binder())?; - self.first_free_index.shift_out(1); - Ok(a.rebind(result)) - } -} diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 3a0a0494a..9d5ec228d 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,14 +1,14 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; -use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; -use crate::traits; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::{DefiningAnchor, ObligationCause}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::GenericArgKind; @@ -48,12 +48,18 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { + // We handle opaque types differently in the new solver. + if self.tcx.trait_solver_next() { + return InferOk { value, obligations: vec![] }; + } + if !value.has_opaque_types() { return InferOk { value, obligations: vec![] }; } + let mut obligations = vec![]; let replace_opaque_type = |def_id: DefId| { - def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some()) + def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some()) }; let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, @@ -149,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = + if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) { self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { @@ -381,8 +387,12 @@ impl<'tcx> InferCtxt<'tcx> { // Anonymous `impl Trait` hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, // Named `type Foo = impl Bar;` - hir::OpaqueTyOrigin::TyAlias => { - may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + if in_assoc_ty { + self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id) + } else { + may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + } } }; in_definition_scope.then_some(origin) @@ -392,12 +402,7 @@ impl<'tcx> InferCtxt<'tcx> { /// defining scope. #[instrument(skip(self), level = "trace", ret)] fn opaque_type_origin_unchecked(&self, def_id: LocalDefId) -> OpaqueTyOrigin { - match self.tcx.hir().expect_item(def_id).kind { - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, - ref itemkind => { - bug!("weird opaque type: {:?}, {:#?}", def_id, itemkind) - } - } + self.tcx.hir().expect_item(def_id).expect_opaque_ty().origin } } @@ -522,30 +527,69 @@ impl<'tcx> InferCtxt<'tcx> { origin: hir::OpaqueTyOrigin, a_is_expected: bool, ) -> InferResult<'tcx, ()> { - let tcx = self.tcx; - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - // Ideally, we'd get the span where *this specific `ty` came // from*, but right now we just use the span from the overall // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - - let mut obligations = vec![]; let prev = self.inner.borrow_mut().opaque_types().register( - OpaqueTypeKey { def_id, substs }, + opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }, origin, ); - if let Some(prev) = prev { - obligations = self - .at(&cause, param_env) + let mut obligations = if let Some(prev) = prev { + self.at(&cause, param_env) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations; - } + .obligations + } else { + Vec::new() + }; + + self.add_item_bounds_for_hidden_type( + opaque_type_key, + cause, + param_env, + hidden_ty, + &mut obligations, + ); + + Ok(InferOk { value: (), obligations }) + } - let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); + /// Registers an opaque's hidden type -- only should be used when the opaque + /// can be defined. For something more fallible -- checks the anchors, tries + /// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`. + pub fn register_hidden_type_in_new_solver( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + ) -> InferResult<'tcx, ()> { + assert!(self.tcx.trait_solver_next()); + let origin = self + .opaque_type_origin(opaque_type_key.def_id) + .expect("should be called for defining usages only"); + self.register_hidden_type( + opaque_type_key, + ObligationCause::dummy(), + param_env, + hidden_ty, + origin, + true, + ) + } + + pub fn add_item_bounds_for_hidden_type( + &self, + OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + obligations: &mut Vec<PredicateObligation<'tcx>>, + ) { + let tcx = self.tcx; + let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { let predicate = predicate.fold_with(&mut BottomUpFolder { @@ -554,16 +598,18 @@ impl<'tcx> InferCtxt<'tcx> { // We can't normalize associated types from `rustc_infer`, // but we can eagerly register inference variables for them. // FIXME(RPITIT): Don't replace RPITITs with inference vars. + // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() - && !tcx.is_impl_trait_in_trait(projection_ty.def_id) => + && !tcx.is_impl_trait_in_trait(projection_ty.def_id) + && !tcx.trait_solver_next() => { self.infer_projection( param_env, projection_ty, cause.clone(), 0, - &mut obligations, + obligations, ) } // Replace all other mentions of the same opaque type with the hidden type, @@ -574,6 +620,7 @@ impl<'tcx> InferCtxt<'tcx> { hidden_ty } // FIXME(RPITIT): This can go away when we move to associated types + // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. ty::Alias( ty::Projection, ty::AliasTy { def_id: def_id2, substs: substs2, .. }, @@ -588,10 +635,10 @@ impl<'tcx> InferCtxt<'tcx> { predicate.kind().skip_binder() { if projection.term.references_error() { - // No point on adding these obligations since there's a type error involved. - return Ok(InferOk { value: (), obligations: vec![] }); + // No point on adding any obligations since there's a type error involved. + obligations.clear(); + return; } - trace!("{:#?}", projection.term); } // Require that the predicate holds for the concrete type. debug!(?predicate); @@ -602,7 +649,6 @@ impl<'tcx> InferCtxt<'tcx> { predicate, )); } - Ok(InferOk { value: (), obligations }) } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index ae4b85c87..a0f6d7eca 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -42,7 +42,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { fn drop(&mut self) { if !self.opaque_types.is_empty() { ty::tls::with(|tcx| { - tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types)) + tcx.sess.delay_span_bug(DUMMY_SP, format!("{:?}", self.opaque_types)) }); } } diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index ff23087fe..cb63d2f18 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -143,7 +143,7 @@ fn compute_components<'tcx>( // through and constrain Pi. let mut subcomponents = smallvec![]; let mut subvisited = SsoHashSet::new(); - compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited); + compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -193,7 +193,43 @@ fn compute_components<'tcx>( /// /// This should not be used to get the components of `parent` itself. /// Use [push_outlives_components] instead. -pub(super) fn compute_components_recursive<'tcx>( +pub(super) fn compute_alias_components_recursive<'tcx>( + tcx: TyCtxt<'tcx>, + alias_ty: Ty<'tcx>, + out: &mut SmallVec<[Component<'tcx>; 4]>, + visited: &mut SsoHashSet<GenericArg<'tcx>>, +) { + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { bug!() }; + let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; + for (index, child) in alias_ty.substs.iter().enumerate() { + if opt_variances.get(index) == Some(&ty::Bivariant) { + continue; + } + if !visited.insert(child) { + continue; + } + match child.unpack() { + GenericArgKind::Type(ty) => { + compute_components(tcx, ty, out, visited); + } + GenericArgKind::Lifetime(lt) => { + // Ignore late-bound regions. + if !lt.is_late_bound() { + out.push(Component::Region(lt)); + } + } + GenericArgKind::Const(_) => { + compute_components_recursive(tcx, child, out, visited); + } + } + } +} + +/// Collect [Component]s for *all* the substs of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +fn compute_components_recursive<'tcx>( tcx: TyCtxt<'tcx>, parent: GenericArg<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>, diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 9a9a1696b..8a44d5031 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -61,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> { }; let lexical_region_resolutions = LexicalRegionResolutions { - values: rustc_index::vec::IndexVec::from_elem_n( + values: rustc_index::IndexVec::from_elem_n( crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased), var_infos.len(), ), diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ccf11c61b..9c20c814b 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -256,7 +256,7 @@ where // this point it never will be self.tcx.sess.delay_span_bug( origin.span(), - &format!("unresolved inference variable in outlives: {:?}", v), + format!("unresolved inference variable in outlives: {:?}", v), ); } } @@ -344,12 +344,14 @@ where // the problem is to add `T: 'r`, which isn't true. So, if there are no // inference variables, we use a verify constraint instead of adding // edges, which winds up enforcing the same condition. + let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque; if approx_env_bounds.is_empty() && trait_bounds.is_empty() - && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque) + && (alias_ty.has_infer() || is_opaque) { debug!("no declared bounds"); - self.substs_must_outlive(alias_ty.substs, origin, region); + let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id)); + self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances); return; } @@ -395,22 +397,31 @@ where self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound); } + #[instrument(level = "debug", skip(self))] fn substs_must_outlive( &mut self, substs: SubstsRef<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, + opt_variances: Option<&[ty::Variance]>, ) { let constraint = origin.to_constraint_category(); - for k in substs { + for (index, k) in substs.iter().enumerate() { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint( - origin.clone(), - region, - lt, - constraint, - ); + let variance = if let Some(variances) = opt_variances { + variances[index] + } else { + ty::Invariant + }; + if variance == ty::Invariant { + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); + } } GenericArgKind::Type(ty) => { self.type_must_outlive(origin.clone(), ty, region, constraint); 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 01f900f05..cd2462d3c 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -13,9 +13,11 @@ use crate::infer::region_constraints::VerifyIfEq; /// Given a "verify-if-eq" type test like: /// -/// exists<'a...> { -/// verify_if_eq(some_type, bound_region) -/// } +/// ```rust,ignore (pseudo-Rust) +/// exists<'a...> { +/// verify_if_eq(some_type, bound_region) +/// } +/// ``` /// /// and the type `test_ty` that the type test is being tested against, /// returns: @@ -185,7 +187,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } else if pattern == value { Ok(pattern) } else { - relate::super_relate_tys(self, pattern, value) + relate::structurally_relate_tys(self, pattern, value) } } @@ -199,7 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { if pattern == value { Ok(pattern) } else { - relate::super_relate_consts(self, pattern, value) + relate::structurally_relate_consts(self, pattern, value) } } diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index bae246418..c2bf0f3db 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,4 +1,4 @@ -use crate::infer::outlives::components::{compute_components_recursive, Component}; +use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::VerifyBound; @@ -130,7 +130,12 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // see the extensive comment in projection_must_outlive let recursive_bound = { let mut components = smallvec![]; - compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited); + compute_alias_components_recursive( + self.tcx, + alias_ty_as_ty.into(), + &mut components, + visited, + ); self.bound_from_components(&components, visited) }; @@ -174,7 +179,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // this point it never will be self.tcx.sess.delay_span_bug( rustc_span::DUMMY_SP, - &format!("unresolved inference variable in outlives: {:?}", v), + format!("unresolved inference variable in outlives: {:?}", v), ); // add a bound that never holds VerifyBound::AnyBound(vec![]) @@ -272,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// /// It will not, however, work for higher-ranked bounds like: /// - /// ```compile_fail,E0311 + /// ```ignore(this does compile today, previously was marked as `compile_fail,E0311`) /// trait Foo<'a, 'b> /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x /// { 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 b8ba98fc0..89cfc9ea3 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -5,7 +5,7 @@ use rustc_data_structures::{ graph::{scc::Sccs, vec_graph::VecGraph}, undo_log::UndoLogs, }; -use rustc_index::vec::Idx; +use rustc_index::Idx; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 7b272dfd2..c7a307b89 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,7 +12,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -217,7 +217,7 @@ pub enum VerifyBound<'tcx> { /// and supplies a bound if it ended up being relevant. It's used in situations /// like this: /// -/// ```rust +/// ```rust,ignore (pseudo-Rust) /// fn foo<'a, 'b, T: SomeTrait<'a>> /// where /// <T as SomeTrait<'a>>::Item: 'b @@ -232,7 +232,7 @@ pub enum VerifyBound<'tcx> { /// In the [`VerifyBound`], this struct is enclosed in `Binder` to account /// for cases like /// -/// ```rust +/// ```rust,ignore (pseudo-Rust) /// where for<'a> <T as SomeTrait<'a>::Item: 'a /// ``` /// diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4f49f4165..3c41e8b37 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -213,7 +213,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { } fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> { - if !t.needs_infer() { + if !t.has_infer() { Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); @@ -243,7 +243,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { } fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> { - if !c.needs_infer() { + if !c.has_infer() { Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects... } else { let c = self.infcx.shallow_resolve(c); diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 0dd73a6e9..ceafafb55 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -1,4 +1,4 @@ -use super::combine::{CombineFields, RelationDir}; +use super::combine::CombineFields; use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; @@ -108,11 +108,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; + self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?; Ok(a) } @@ -131,7 +131,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 == DefineOpaqueTypes::Yes - && def_id.is_local() => + && def_id.is_local() + && !self.tcx().trait_solver_next() => { self.fields.obligations.extend( infcx @@ -210,7 +211,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { where T: Relate<'tcx>, { - // A binder is always a subtype of itself if it's structually equal to itself + // A binder is always a subtype of itself if it's structurally equal to itself if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 738a12376..e92ba05aa 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -35,7 +35,7 @@ extern crate tracing; extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_macros::fluent_messages; +use rustc_fluent_macro::fluent_messages; mod errors; pub mod infer; diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index b8940e2f0..11f434694 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -18,7 +18,7 @@ pub trait TraitEngine<'tcx>: 'tcx { def_id: DefId, cause: ObligationCause<'tcx>, ) { - let trait_ref = infcx.tcx.mk_trait_ref(def_id, [ty]); + let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); self.register_predicate_obligation( infcx, Obligation { diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 4d5351958..b5a7d0326 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -73,7 +73,7 @@ pub fn report_object_safety_error<'tcx>( format!("...because {}", violation.error_msg()) }; if spans.is_empty() { - err.note(&msg); + err.note(msg); } else { for span in spans { multi_span.push(span); diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index e01b6caf4..8ce8b4e20 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -89,10 +89,10 @@ impl<'tcx> PredicateObligation<'tcx> { impl<'tcx> TraitObligation<'tcx> { /// Returns `true` if the trait predicate is considered `const` in its ParamEnv. pub fn is_const(&self) -> bool { - match (self.predicate.skip_binder().constness, self.param_env.constness()) { - (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true, - _ => false, - } + matches!( + (self.predicate.skip_binder().constness, self.param_env.constness()), + (ty::BoundConstness::ConstIfConst, hir::Constness::Const) + ) } pub fn derived_cause( @@ -123,7 +123,7 @@ pub struct FulfillmentError<'tcx> { #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented. - CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>), + CodeCycle(Vec<PredicateObligation<'tcx>>), CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index ac455055b..e375d6119 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, } -#[derive(Clone, TypeFoldable, TypeVisitable)] +#[derive(Clone)] pub struct Normalized<'tcx, T> { pub value: T, pub obligations: Vec<PredicateObligation<'tcx>>, @@ -103,7 +103,7 @@ pub enum ProjectionCacheEntry<'tcx> { /// if this field is set. Evaluation only /// cares about the final result, so we don't /// care about any region constraint side-effects - /// produced by evaluating the sub-boligations. + /// produced by evaluating the sub-obligations. /// /// Additionally, we will clear out the sub-obligations /// entirely if we ever evaluate the cache entry (along diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index ef01d5d51..74a78f380 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -200,6 +200,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let bound_predicate = elaboratable.predicate().kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(data)) => { + // Negative trait bounds do not imply any supertrait bounds + if data.polarity == ty::ImplPolarity::Negative { + return; + } // Get predicates implied by the trait, or only super predicates if we only care about self predicates. let predicates = if self.only_self { tcx.super_predicates_of(data.def_id()) @@ -376,11 +380,11 @@ pub fn transitive_bounds<'tcx>( } /// A specialized variant of `elaborate` that only elaborates trait references that may -/// define the given associated type `assoc_name`. It uses the -/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that +/// define the given associated item with the name `assoc_name`. It uses the +/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or /// `T::Item` and helps to avoid cycle errors (see e.g. #35237). -pub fn transitive_bounds_that_define_assoc_type<'tcx>( +pub fn transitive_bounds_that_define_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, assoc_name: Ident, @@ -393,7 +397,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>( let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref); if visited.insert(anon_trait_ref) { let super_predicates = - tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name)); + tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name)); for (super_predicate, _) in super_predicates.predicates { let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref); if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() { |