diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b5c067514059a..7937c67e86a1e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -345,7 +345,12 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); + let infcx = tcx + .infer_ctxt() + .with_opaque_type_mode(ty::OpaqueTypeMode::Reveal( + tcx.opaque_types_defined_by(defining_use_anchor), + )) + .build(); let ocx = ObligationCtxt::new(&infcx); let args = match *origin { @@ -359,42 +364,23 @@ fn check_opaque_meets_bounds<'tcx>( }), }; - let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - - // `ReErased` regions appear in the "parent_args" of closures/coroutines. - // We're ignoring them here and replacing them with fresh region variables. - // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs. - // - // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it - // here rather than using ReErased. - let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args); - let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() { - ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)), - _ => re, - }); - let misc_cause = traits::ObligationCause::misc(span, def_id); - - match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { - Ok(()) => {} - Err(ty_err) => { - // Some types may be left "stranded" if they can't be reached - // from a lowered rustc_middle bound but they're mentioned in the HIR. - // This will happen, e.g., when a nested opaque is inside of a non- - // existent associated type, like `impl Trait`. - // See . - let ty_err = ty_err.to_string(tcx); - let guar = tcx.dcx().span_delayed_bug( - span, - format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), - ); - return Err(guar); - } - } + let predicates: Vec<_> = tcx.item_bounds(def_id).iter_instantiated(tcx, args).collect(); + let predicates = ocx.normalize(&misc_cause, param_env, predicates); + ocx.register_obligations( + predicates + .into_iter() + .map(|clause| Obligation::new(tcx, misc_cause.clone(), param_env, clause)), + ); // Additionally require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the // hidden type is well formed even without those bounds. + let hidden_ty = + tcx.fold_regions(tcx.type_of(def_id).instantiate(tcx, args), |re, _| match *re { + ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)), + _ => re, + }); let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into()))); ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate)); @@ -412,23 +398,7 @@ fn check_opaque_meets_bounds<'tcx>( let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?; - if let hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) = origin { - // HACK: this should also fall through to the hidden type check below, but the original - // implementation had a bug where equivalent lifetimes are not identical. This caused us - // to reject existing stable code that is otherwise completely fine. The real fix is to - // compare the hidden types via our type equivalence/relation infra instead of doing an - // identity check. - let _ = infcx.take_opaque_types(); - Ok(()) - } else { - // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. - for (mut key, mut ty) in infcx.take_opaque_types() { - ty.hidden_type.ty = infcx.resolve_vars_if_possible(ty.hidden_type.ty); - key = infcx.resolve_vars_if_possible(key); - sanity_check_found_hidden_type(tcx, key, ty.hidden_type)?; - } - Ok(()) - } + Ok(()) } fn sanity_check_found_hidden_type<'tcx>( diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 16057b6ad9dc1..c4f042380c944 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -76,7 +76,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { Self { tcx: self.tcx, - defining_opaque_types: self.defining_opaque_types, + opaque_type_mode: self.opaque_type_mode, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 27b06c4b73e9d..5c5c618b2c9a9 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -60,7 +60,7 @@ impl<'tcx> InferCtxt<'tcx> { }, ); - param_env.defining_opaque_types = self.defining_opaque_types; + param_env.opaque_type_mode = self.opaque_type_mode; Canonicalizer::canonicalize_with_base( param_env, @@ -544,7 +544,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: (), - defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(), + opaque_type_mode: infcx.map(|i| i.opaque_type_mode).unwrap_or_default(), }; Canonicalizer::canonicalize_with_base( base, @@ -614,14 +614,12 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .max() .unwrap_or(ty::UniverseIndex::ROOT); - assert!( - !infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types) - ); + assert!(!infcx.is_some_and(|infcx| infcx.opaque_type_mode != base.opaque_type_mode)); Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value), - defining_opaque_types: base.defining_opaque_types, + opaque_type_mode: base.opaque_type_mode, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8d4011421bd33..ae38544d08059 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -5,6 +5,8 @@ pub use relate::combine::CombineFields; pub use relate::combine::ObligationEmittingRelation; pub use relate::StructurallyRelateAliases; pub use rustc_macros::{TypeFoldable, TypeVisitable}; +use rustc_middle::traits::Reveal; +use rustc_middle::traits::TreatOpaque; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; @@ -246,7 +248,7 @@ pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, /// The `DefIds` of the opaque types that may have their hidden types constrained. - defining_opaque_types: &'tcx ty::List, + opaque_type_mode: ty::OpaqueTypeMode>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -373,8 +375,8 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types + fn opaque_type_mode(&self) -> ty::OpaqueTypeMode> { + self.opaque_type_mode } fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { @@ -621,7 +623,7 @@ impl fmt::Display for FixupError { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_opaque_types: &'tcx ty::List, + opaque_type_mode: ty::OpaqueTypeMode>, considering_regions: bool, skip_leak_check: bool, /// Whether we are in coherence mode. @@ -636,7 +638,7 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_opaque_types: ty::List::empty(), + opaque_type_mode: Default::default(), considering_regions: true, skip_leak_check: false, intercrate: false, @@ -646,6 +648,14 @@ impl<'tcx> TyCtxt<'tcx> { } impl<'tcx> InferCtxtBuilder<'tcx> { + pub fn with_opaque_type_mode( + mut self, + opaque_type_mode: ty::OpaqueTypeMode>, + ) -> Self { + self.opaque_type_mode = opaque_type_mode; + self + } + /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, /// you need to call this function. Otherwise the opaque type will be treated opaquely. /// @@ -653,15 +663,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// (via `Inherited::build`) and for the inference context used /// in mir borrowck. pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { - self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); - self - } - - pub fn with_defining_opaque_types( - mut self, - defining_opaque_types: &'tcx ty::List, - ) -> Self { - self.defining_opaque_types = defining_opaque_types; + let types = self.tcx.opaque_types_defined_by(defining_anchor); + self.opaque_type_mode = ty::OpaqueTypeMode::Define(types); self } @@ -700,7 +703,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { where T: TypeFoldable>, { - let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build(); + let infcx = self.with_opaque_type_mode(canonical.opaque_type_mode).build(); let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } @@ -708,7 +711,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { pub fn build(&mut self) -> InferCtxt<'tcx> { let InferCtxtBuilder { tcx, - defining_opaque_types, + opaque_type_mode: defining_opaque_types, considering_regions, skip_leak_check, intercrate, @@ -716,7 +719,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } = *self; InferCtxt { tcx, - defining_opaque_types, + opaque_type_mode: defining_opaque_types, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -1240,10 +1243,30 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow().opaque_type_storage.opaque_types.clone() } - #[inline(always)] - pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { - let Some(id) = id.into().as_local() else { return false }; - self.defining_opaque_types.contains(&id) + pub fn treat_opaque_ty(&self, reveal: Reveal, def_id: DefId) -> TreatOpaque { + if self.intercrate { + return TreatOpaque::Ambiguous; + } + + match reveal { + Reveal::All => return TreatOpaque::Reveal, + Reveal::UserFacing => {} + } + + match self.opaque_type_mode { + ty::OpaqueTypeMode::Define(list) => { + if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) { + return TreatOpaque::Define; + } + } + ty::OpaqueTypeMode::Reveal(list) => { + if def_id.as_local().is_some_and(|def_id| list.contains(&def_id)) { + return TreatOpaque::Reveal; + } + } + } + + TreatOpaque::Rigid } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 8eb3185673b4a..439e606258e07 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -6,7 +6,7 @@ use hir::def_id::{DefId, LocalDefId}; 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::{ObligationCause, TreatOpaque}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::GenericArgKind; @@ -58,7 +58,10 @@ impl<'tcx> InferCtxt<'tcx> { ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) - if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() => + if matches!( + self.treat_opaque_ty(param_env.reveal(), def_id), + TreatOpaque::Define + ) && !ty.has_escaping_bound_vars() => { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; @@ -85,16 +88,6 @@ impl<'tcx> InferCtxt<'tcx> { ) -> InferResult<'tcx, ()> { let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => { - let def_id = def_id.expect_local(); - if self.intercrate { - // See comment on `insert_hidden_type` for why this is sufficient in coherence - return Some(self.register_hidden_type( - OpaqueTypeKey { def_id, args }, - cause.clone(), - param_env, - b, - )); - } // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -129,8 +122,18 @@ impl<'tcx> InferCtxt<'tcx> { // let x = || foo(); // returns the Opaque assoc with `foo` // } // ``` - if !self.can_define_opaque_ty(def_id) { - return None; + match self.treat_opaque_ty(param_env.reveal(), def_id) { + TreatOpaque::Define => {} + TreatOpaque::Reveal | TreatOpaque::Rigid => return None, + TreatOpaque::Ambiguous => { + // See comment on `insert_hidden_type` for why this is sufficient in coherence + return Some(self.register_hidden_type( + OpaqueTypeKey { def_id: def_id.expect_local(), args }, + cause.clone(), + param_env, + b, + )); + } } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { @@ -139,8 +142,10 @@ impl<'tcx> InferCtxt<'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if self.can_define_opaque_ty(b_def_id) - && self.tcx.is_type_alias_impl_trait(b_def_id) + if matches!( + self.treat_opaque_ty(param_env.reveal(), b_def_id), + TreatOpaque::Define + ) && self.tcx.is_type_alias_impl_trait(b_def_id) { self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag { span: cause.span, @@ -150,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> { } } Some(self.register_hidden_type( - OpaqueTypeKey { def_id, args }, + OpaqueTypeKey { def_id: def_id.expect_local(), args }, cause.clone(), param_env, b, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index dba71d88f404b..bc36d49991817 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -182,7 +182,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: key, - defining_opaque_types: ty::List::empty(), + opaque_type_mode: Default::default(), }; } diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8a4e3ab0e619a..6c4fcc33cbf92 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -325,7 +325,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::>() > 72 { + if mem::size_of::>() > 84 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 62e71c4db11fb..7a5071b77dae2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -81,6 +81,13 @@ pub enum Reveal { All, } +pub enum TreatOpaque { + Reveal, + Define, + Rigid, + Ambiguous, +} + /// The reason why we incurred this obligation; used for error reporting. /// /// Non-misc `ObligationCauseCode`s are stored on the heap. This gives the diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index bade0d564156f..a62d8e68f8ee8 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -194,7 +194,7 @@ impl<'tcx> CapturedPlace<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct ClosureTypeInfo<'tcx> { - user_provided_sig: ty::CanonicalPolyFnSig<'tcx>, + user_provided_sig: &'tcx ty::CanonicalPolyFnSig<'tcx>, captures: &'tcx ty::List<&'tcx ty::CapturedPlace<'tcx>>, kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>, } @@ -202,7 +202,7 @@ pub struct ClosureTypeInfo<'tcx> { fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> { debug_assert!(tcx.is_closure_like(def.to_def_id())); let typeck_results = tcx.typeck(def); - let user_provided_sig = typeck_results.user_provided_sigs[&def]; + let user_provided_sig = &typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); let captures = tcx.mk_captures_from_iter(captures); let hir_id = tcx.local_def_id_to_hir_id(def); @@ -216,7 +216,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn closure_user_provided_sig(self, def_id: LocalDefId) -> ty::CanonicalPolyFnSig<'tcx> { - self.closure_typeinfo(def_id).user_provided_sig + *self.closure_typeinfo(def_id).user_provided_sig } pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 127ebde5fec3f..caa583a72b470 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -69,8 +69,8 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc let (max_universe, variables) = canonicalizer.finalize(); - let defining_opaque_types = infcx.defining_opaque_types(); - Canonical { defining_opaque_types, max_universe, variables, value } + let opaque_type_mode = infcx.opaque_type_mode(); + Canonical { opaque_type_mode, max_universe, variables, value } } fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index a1da8aa7365ab..394188c18c37e 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -5,11 +5,12 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, + BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, RegionVariableOrigin, + TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::{ObligationCause, Reveal, TreatOpaque}; use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_middle::bug; use rustc_middle::traits::solve::{ @@ -625,6 +626,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty } + pub(super) fn next_region_infer(&mut self) -> ty::Region<'tcx> { + let ty = self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)); + self.inspect.add_var_value(ty); + ty + } + pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> { let ct = self.infcx.next_const_var(ty, DUMMY_SP); self.inspect.add_var_value(ct); @@ -981,8 +988,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .map(|is_knowable| is_knowable.is_ok()) } - pub(super) fn can_define_opaque_ty(&self, def_id: impl Into) -> bool { - self.infcx.can_define_opaque_ty(def_id) + pub(super) fn treat_opaque_ty(&self, reveal: Reveal, def_id: DefId) -> TreatOpaque { + self.infcx.treat_opaque_ty(reveal, def_id) } pub(super) fn insert_hidden_type( diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 60722d3618f9a..99bc61d91900d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -307,6 +307,6 @@ fn response_no_constraints_raw<'tcx>( external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), certainty, }, - defining_opaque_types: Default::default(), + opaque_type_mode: Default::default(), } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs index 3b83d347276f7..92fddeb9f0be3 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -4,11 +4,11 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::traits::Reveal; +use rustc_middle::traits::TreatOpaque; use rustc_middle::ty; use rustc_middle::ty::util::NotUniqueParam; -use crate::solve::{EvalCtxt, SolverMode}; +use crate::solve::EvalCtxt; impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn normalize_opaque_type( @@ -19,17 +19,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); - match (goal.param_env.reveal(), self.solver_mode()) { - (Reveal::UserFacing, SolverMode::Normal) => { - let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { - return Err(NoSolution); - }; + match self.treat_opaque_ty(goal.param_env.reveal(), opaque_ty.def_id) { + TreatOpaque::Rigid => Err(NoSolution), + TreatOpaque::Ambiguous => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + TreatOpaque::Reveal => { + // FIXME: Add an assertion that opaque type storage is empty. + let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); + let actual = tcx.fold_regions(actual, |re, _| match *re { + ty::ReErased => self.next_region_infer(), + _ => re, + }); + self.eq(goal.param_env, expected, actual)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + TreatOpaque::Define => { // FIXME: at some point we should call queries without defining // new opaque types but having the existing opaque type definitions. // This will require moving this below "Prefer opaques registered already". - if !self.can_define_opaque_ty(opaque_ty_def_id) { + let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); - } + }; // FIXME: This may have issues when the args contain aliases... match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { @@ -69,23 +88,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (Reveal::UserFacing, SolverMode::Coherence) => { - // An impossible opaque type bound is the only way this goal will fail - // e.g. assigning `impl Copy := NotCopy` - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - (Reveal::All, _) => { - // FIXME: Add an assertion that opaque type storage is empty. - let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); - self.eq(goal.param_env, expected, actual)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } } } } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e59eef22f4111..ab0f8cd14a6b6 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -14,7 +14,7 @@ use rustc_infer::traits::solve::MaybeCause; use rustc_middle::bug; use rustc_middle::traits::solve::inspect::ProbeKind; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; -use rustc_middle::traits::{BuiltinImplSource, Reveal}; +use rustc_middle::traits::{BuiltinImplSource, TreatOpaque}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; @@ -148,7 +148,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // ideally we want to avoid, since we can make progress on this goal // via an alias bound or a locally-inferred hidden type instead. // - // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since + // Also, don't call `type_of` on a TAIT when it can be revealed, since // we already normalize the self type in // `assemble_candidates_after_normalizing_self_ty`, and we'd // just be registering an identical candidate here. @@ -158,10 +158,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `assemble_candidates_after_normalizing_self_ty` due to normalizing // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { - if matches!(goal.param_env.reveal(), Reveal::All) - || matches!(ecx.solver_mode(), SolverMode::Coherence) - || ecx.can_define_opaque_ty(opaque_ty.def_id) - { + if matches!( + ecx.treat_opaque_ty(goal.param_env.reveal(), opaque_ty.def_id), + TreatOpaque::Reveal | TreatOpaque::Define | TreatOpaque::Ambiguous + ) { return Err(NoSolution); } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d10aee2d4e29e..4344c7e805da1 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -6,7 +6,9 @@ use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferOk; +use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::traits::PredicateObligation; +use rustc_infer::traits::TreatOpaque; use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; use rustc_macros::extension; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; @@ -100,21 +102,17 @@ where pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, - reveal: Reveal, + _reveal: Reveal, ) -> bool { + //TODO: // This mirrors `ty::TypeFlags::HAS_ALIASES` except that we take `Reveal` into account. - - let mut flags = ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_WEAK - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_CT_PROJECTION; - - match reveal { - Reveal::UserFacing => {} - Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE, - } - - value.has_type_flags(flags) + value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_WEAK + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_CT_PROJECTION + | ty::TypeFlags::HAS_TY_OPAQUE, + ) } struct AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -205,11 +203,8 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx match kind { ty::Opaque => { - // Only normalize `impl Trait` outside of type inference, usually in codegen. - match self.param_env.reveal() { - Reveal::UserFacing => ty.super_fold_with(self), - - Reveal::All => { + match self.selcx.infcx.treat_opaque_ty(self.param_env.reveal(), data.def_id) { + TreatOpaque::Reveal => { let recursion_limit = self.interner().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { self.selcx.infcx.err_ctxt().report_overflow_error( @@ -223,11 +218,21 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx let args = data.args.fold_with(self); let generic_ty = self.interner().type_of(data.def_id); let concrete_ty = generic_ty.instantiate(self.interner(), args); + let concrete_ty = + self.interner().fold_regions(concrete_ty, |re, _| match *re { + ty::ReErased => self.selcx.infcx.next_region_var( + RegionVariableOrigin::MiscVariable(self.cause.span), + ), + _ => re, + }); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); self.depth -= 1; folded_ty } + TreatOpaque::Define | TreatOpaque::Rigid | TreatOpaque::Ambiguous => { + ty.super_fold_with(self) + } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1b5ffeebc01f8..c9836dd35d560 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -9,10 +9,11 @@ use crate::traits::error_reporting::OverflowCause; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::needs_normalization; use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; -use crate::traits::{ObligationCause, PredicateObligation, Reveal}; +use crate::traits::{ObligationCause, PredicateObligation}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_infer::traits::Normalized; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_infer::traits::{Normalized, TreatOpaque}; use rustc_macros::extension; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; @@ -208,44 +209,49 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> // Wrap this in a closure so we don't accidentally return from the outer function let res = match kind { - ty::Opaque => { - // Only normalize `impl Trait` outside of type inference, usually in codegen. - match self.param_env.reveal() { - Reveal::UserFacing => ty.try_super_fold_with(self)?, - - Reveal::All => { - let args = data.args.try_fold_with(self)?; - let recursion_limit = self.interner().recursion_limit(); - - if !recursion_limit.value_within_limit(self.anon_depth) { - let guar = self - .infcx - .err_ctxt() - .build_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), - self.cause.span, - true, - ) - .delay_as_bug(); - return Ok(Ty::new_error(self.interner(), guar)); - } - - let generic_ty = self.interner().type_of(data.def_id); - let mut concrete_ty = generic_ty.instantiate(self.interner(), args); - self.anon_depth += 1; - if concrete_ty == ty { - concrete_ty = Ty::new_error_with_message( - self.interner(), - DUMMY_SP, - "recursive opaque type", - ); - } - let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); - self.anon_depth -= 1; - folded_ty? + ty::Opaque => match self.infcx.treat_opaque_ty(self.param_env.reveal(), data.def_id) { + TreatOpaque::Reveal => { + let args = data.args.try_fold_with(self)?; + let recursion_limit = self.interner().recursion_limit(); + + if !recursion_limit.value_within_limit(self.anon_depth) { + let guar = self + .infcx + .err_ctxt() + .build_overflow_error( + OverflowCause::DeeplyNormalize(data.into()), + self.cause.span, + true, + ) + .delay_as_bug(); + return Ok(Ty::new_error(self.interner(), guar)); } + + let generic_ty = self.interner().type_of(data.def_id); + let concrete_ty = generic_ty.instantiate(self.interner(), args); + let mut concrete_ty = + self.interner().fold_regions(concrete_ty, |re, _| match *re { + ty::ReErased => self.infcx.next_region_var( + RegionVariableOrigin::MiscVariable(self.cause.span), + ), + _ => re, + }); + self.anon_depth += 1; + if concrete_ty == ty { + concrete_ty = Ty::new_error_with_message( + self.interner(), + DUMMY_SP, + "recursive opaque type", + ); + } + let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty)); + self.anon_depth -= 1; + folded_ty? } - } + TreatOpaque::Define | TreatOpaque::Rigid | TreatOpaque::Ambiguous => { + ty.try_super_fold_with(self)? + } + }, ty::Projection | ty::Inherent | ty::Weak => { // See note in `rustc_trait_selection::traits::project` diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 1c30f03c6939a..25a80d6d31bcb 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -26,10 +26,32 @@ pub struct Canonical { pub value: V, pub max_universe: UniverseIndex, // FIXME(lcnr, oli-obk): try moving this into the query inputs instead - pub defining_opaque_types: I::DefiningOpaqueTypes, + pub opaque_type_mode: OpaqueTypeMode, pub variables: I::CanonicalVars, } +#[derive(derivative::Derivative)] +#[derivative( + Copy(bound = ""), + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum OpaqueTypeMode { + Define(I::DefiningOpaqueTypes), + Reveal(I::DefiningOpaqueTypes), +} + +impl Default for OpaqueTypeMode { + fn default() -> Self { + OpaqueTypeMode::Define(Default::default()) + } +} + impl Canonical { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. @@ -55,8 +77,8 @@ impl Canonical { /// let b: Canonical)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical { - let Canonical { defining_opaque_types, max_universe, variables, value } = self; - Canonical { defining_opaque_types, max_universe, variables, value: map_op(value) } + let Canonical { opaque_type_mode, max_universe, variables, value } = self; + Canonical { opaque_type_mode, max_universe, variables, value: map_op(value) } } /// Allows you to map the `value` of a canonical while keeping the same set of @@ -65,17 +87,17 @@ impl Canonical { /// **WARNING:** This function is very easy to mis-use, hence the name! See /// the comment of [Canonical::unchecked_map] for more details. pub fn unchecked_rebind(self, value: W) -> Canonical { - let Canonical { defining_opaque_types, max_universe, variables, value: _ } = self; - Canonical { defining_opaque_types, max_universe, variables, value } + let Canonical { opaque_type_mode, max_universe, variables, value: _ } = self; + Canonical { opaque_type_mode, max_universe, variables, value } } } impl fmt::Display for Canonical { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { value, max_universe, variables, defining_opaque_types } = self; + let Self { value, max_universe, variables, opaque_type_mode } = self; write!( f, - "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, defining_opaque_types: {defining_opaque_types:?} }}", + "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, opaque_type_mode: {opaque_type_mode:?} }}", ) } } diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 4e8be1ee4c285..41415858fc48e 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -1,10 +1,11 @@ +use std::fmt; +use std::marker::PhantomData; + use crate::{ - ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, RegionVid, TyVid, UniverseIndex, + ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, OpaqueTypeMode, RegionVid, + TyVid, UniverseIndex, }; -use core::fmt; -use std::marker::PhantomData; - pub struct NoInfcx(PhantomData); impl InferCtxtLike for NoInfcx { @@ -50,7 +51,7 @@ impl InferCtxtLike for NoInfcx { panic!("cannot resolve {vid:?}") } - fn defining_opaque_types(&self) -> I::DefiningOpaqueTypes { + fn opaque_type_mode(&self) -> OpaqueTypeMode { Default::default() } } diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index bb5081fb33576..032b0d7b72adb 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,4 +1,7 @@ -use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex}; +use crate::{ + ConstVid, EffectVid, FloatVid, IntVid, Interner, OpaqueTypeMode, RegionVid, TyVid, + UniverseIndex, +}; pub trait InferCtxtLike { type Interner: Interner; @@ -24,5 +27,5 @@ pub trait InferCtxtLike { ) -> ::Const; fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> ::Region; - fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + fn opaque_type_mode(&self) -> OpaqueTypeMode; } diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs index 682508f928082..6b5abe49a1569 100644 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,5 +1,5 @@ //@ build-pass -//@ ignore-compare-mode-next-solver (hangs) +//@ ignore-test (hangs) // Closures include captured types twice in a type tree. // diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index 9b18aceb4a731..e4e152a6a7767 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -35,6 +35,7 @@ fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` +//~| ERROR mismatched types // This should resolve. fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 2fa036f35fab3..85222bb04f350 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:57:77 + --> $DIR/nested-rpit-hrtb.rs:58:77 | LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Siz | ++++ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:65:82 + --> $DIR/nested-rpit-hrtb.rs:66:82 | LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -86,8 +86,17 @@ note: lifetime declared here LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ +error[E0308]: mismatched types + --> $DIR/nested-rpit-hrtb.rs:36:35 + | +LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected reference `&'a ()` + found reference `&()` + error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied - --> $DIR/nested-rpit-hrtb.rs:46:79 + --> $DIR/nested-rpit-hrtb.rs:47:79 | LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} | ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()` @@ -96,7 +105,7 @@ LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = help: for that trait implementation, expected `()`, found `&'a ()` error: implementation of `Bar` is not general enough - --> $DIR/nested-rpit-hrtb.rs:50:93 + --> $DIR/nested-rpit-hrtb.rs:51:93 | LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} | ^^ implementation of `Bar` is not general enough @@ -105,7 +114,7 @@ LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied - --> $DIR/nested-rpit-hrtb.rs:61:64 + --> $DIR/nested-rpit-hrtb.rs:62:64 | LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()` @@ -114,7 +123,7 @@ LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> = help: for that trait implementation, expected `()`, found `&'a ()` error: implementation of `Bar` is not general enough - --> $DIR/nested-rpit-hrtb.rs:65:86 + --> $DIR/nested-rpit-hrtb.rs:66:86 | LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ implementation of `Bar` is not general enough @@ -122,7 +131,7 @@ LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Si = note: `()` must implement `Bar<'a>` = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0261, E0277, E0657. +Some errors have detailed explanations: E0261, E0277, E0308, E0657. For more information about an error, try `rustc --explain E0261`.