diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 63cde3c6809c6..9a602a5a29d9d 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -3,7 +3,7 @@ //! # Note //! //! This API is completely unstable and subject to change. - +#![recursion_limit = "256"] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index eace5ce820892..c156f8817712a 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 9ae5c9b3cec6c..67c1d6a1ec1ca 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_ast = { path = "../rustc_ast" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index bafc62c7318b4..70643aba7561f 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start either = "1.5.0" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } polonius-engine = "0.13.0" rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index bb5045ec87241..a246baabf59f5 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -9,7 +9,7 @@ test = false [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } libc = "0.2" measureme = "11" object = { version = "0.32.0", default-features = false, features = ["std", "read"] } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3771fc6b0a271..3f5a93270fcaf 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -10,7 +10,7 @@ arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90" either = "1.5.0" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } jobserver = "0.1.28" pathdiff = "0.2.0" regex = "1.4" diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index d477b86da74e8..c9e9e7e52aaec 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -146,7 +146,25 @@ pub enum ProcessResult { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] struct ObligationTreeId(usize); -type ObligationTreeIdGenerator = impl Iterator; +use uwu::*; + +mod uwu { + use super::*; + pub type ObligationTreeIdGenerator = impl Iterator; + + impl ObligationForest { + pub fn new() -> ObligationForest { + ObligationForest { + nodes: vec![], + done_cache: Default::default(), + active_cache: Default::default(), + reused_node_vec: vec![], + obligation_tree_id_generator: (0..).map(ObligationTreeId), + error_cache: Default::default(), + } + } + } +} pub struct ObligationForest { /// The list of obligations. In between calls to [Self::process_obligations], @@ -311,17 +329,6 @@ pub struct Error { } impl ObligationForest { - pub fn new() -> ObligationForest { - ObligationForest { - nodes: vec![], - done_cache: Default::default(), - active_cache: Default::default(), - reused_node_vec: vec![], - obligation_tree_id_generator: (0..).map(ObligationTreeId), - error_cache: Default::default(), - } - } - /// Returns the total number of nodes in the forest that have not /// yet been fully resolved. pub fn len(&self) -> usize { diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 04ca7f123d3e0..cb56ef7fffba0 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } 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_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 73a775690d66b..6e47fa45ab0b0 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr = { path = "../rustc_attr" } 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/lib.rs b/compiler/rustc_middle/src/lib.rs index d47e393c912ad..ddffd0fc2641e 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -21,7 +21,7 @@ //! # Note //! //! This API is completely unstable and subject to change. - +#![recursion_limit = "256"] // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] 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_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 7508f0080ccfe..1e30b0146b1e0 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -149,9 +149,9 @@ impl SimplifiedType { } } -/// Given generic arguments from an obligation and an impl, -/// could these two be unified after replacing parameters in the -/// the impl with inference variables. +/// Given generic arguments from an obligation and a candidate, +/// could these two be unified after replacing parameters and bound +/// variables in the candidate with inference variables. /// /// For obligations, parameters won't be replaced by inference /// variables and only unify with themselves. We treat them @@ -170,28 +170,30 @@ impl DeepRejectCtxt { pub fn args_may_unify<'tcx>( self, obligation_args: GenericArgsRef<'tcx>, - impl_args: GenericArgsRef<'tcx>, + candidate_args: GenericArgsRef<'tcx>, ) -> bool { - iter::zip(obligation_args, impl_args).all(|(obl, imp)| { + iter::zip(obligation_args, candidate_args).all(|(obl, imp)| { match (obl.unpack(), imp.unpack()) { // We don't fast reject based on regions. (GenericArgKind::Lifetime(_), GenericArgKind::Lifetime(_)) => true, - (GenericArgKind::Type(obl), GenericArgKind::Type(imp)) => { - self.types_may_unify(obl, imp) + (GenericArgKind::Type(obl), GenericArgKind::Type(candidate)) => { + self.types_may_unify(obl, candidate) } - (GenericArgKind::Const(obl), GenericArgKind::Const(imp)) => { - self.consts_may_unify(obl, imp) + (GenericArgKind::Const(obl), GenericArgKind::Const(candidate)) => { + self.consts_may_unify(obl, candidate) } _ => bug!("kind mismatch: {obl} {imp}"), } }) } - pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -> bool { - match impl_ty.kind() { - // Start by checking whether the type in the impl may unify with + pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, candidate_ty: Ty<'tcx>) -> bool { + match candidate_ty.kind() { + // Start by checking whether the type in the candidate may unify with // pretty much everything. Just return `true` in that case. - ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true, + ty::Param(_) | ty::Error(_) | ty::Alias(..) | ty::Infer(_) | ty::Placeholder(..) => { + return true; + } // These types only unify with inference variables or their own // variant. ty::Bool @@ -210,18 +212,15 @@ impl DeepRejectCtxt { | ty::Never | ty::Tuple(..) | ty::FnPtr(..) - | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), + | ty::Foreign(..) => debug_assert!(candidate_ty.is_known_rigid()), ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(_) => bug!("unexpected impl_ty: {impl_ty}"), + | ty::Bound(..) => bug!("unexpected candidate_ty: {candidate_ty}"), } - let k = impl_ty.kind(); match *obligation_ty.kind() { // Purely rigid types, use structural equivalence. ty::Bool @@ -231,65 +230,68 @@ impl DeepRejectCtxt { | ty::Float(_) | ty::Str | ty::Never - | ty::Foreign(_) => obligation_ty == impl_ty, - ty::Ref(_, obl_ty, obl_mutbl) => match k { - &ty::Ref(_, impl_ty, impl_mutbl) => { - obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty) + | ty::Foreign(_) => obligation_ty == candidate_ty, + ty::Ref(_, obl_ty, obl_mutbl) => match candidate_ty.kind() { + &ty::Ref(_, cand_ty, cand_mutbl) => { + obl_mutbl == cand_mutbl && self.types_may_unify(obl_ty, cand_ty) } _ => false, }, - ty::Adt(obl_def, obl_args) => match k { - &ty::Adt(impl_def, impl_args) => { - obl_def == impl_def && self.args_may_unify(obl_args, impl_args) + ty::Adt(obl_def, obl_args) => match candidate_ty.kind() { + &ty::Adt(cand_def, cand_args) => { + obl_def == cand_def && self.args_may_unify(obl_args, cand_args) } _ => false, }, - ty::Pat(obl_ty, _) => { + ty::Pat(obl_ty, _) => match candidate_ty.kind() { // FIXME(pattern_types): take pattern into account - matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) - } - ty::Slice(obl_ty) => { - matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) - } - ty::Array(obl_ty, obl_len) => match k { - &ty::Array(impl_ty, impl_len) => { - self.types_may_unify(obl_ty, impl_ty) - && self.consts_may_unify(obl_len, impl_len) + &ty::Pat(cand_ty, _) => self.types_may_unify(obl_ty, cand_ty), + _ => false, + }, + ty::Slice(obl_ty) => match candidate_ty.kind() { + &ty::Slice(cand_ty) => self.types_may_unify(obl_ty, cand_ty), + _ => false, + }, + ty::Array(obl_ty, obl_len) => match candidate_ty.kind() { + &ty::Array(cand_ty, cand_len) => { + self.types_may_unify(obl_ty, cand_ty) + && self.consts_may_unify(obl_len, cand_len) } _ => false, }, - ty::Tuple(obl) => match k { - &ty::Tuple(imp) => { - obl.len() == imp.len() - && iter::zip(obl, imp).all(|(obl, imp)| self.types_may_unify(obl, imp)) + ty::Tuple(obl) => match candidate_ty.kind() { + &ty::Tuple(cand) => { + obl.len() == cand.len() + && iter::zip(obl, cand).all(|(obl, cand)| self.types_may_unify(obl, cand)) } _ => false, }, - ty::RawPtr(obl_ty, obl_mutbl) => match *k { - ty::RawPtr(imp_ty, imp_mutbl) => { - obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty) + ty::RawPtr(obl_ty, obl_mutbl) => match *candidate_ty.kind() { + ty::RawPtr(cand_ty, cand_mutbl) => { + obl_mutbl == cand_mutbl && self.types_may_unify(obl_ty, cand_ty) } _ => false, }, - ty::Dynamic(obl_preds, ..) => { + ty::Dynamic(obl_preds, ..) => match candidate_ty.kind() { // Ideally we would walk the existential predicates here or at least // compare their length. But considering that the relevant `Relate` impl // actually sorts and deduplicates these, that doesn't work. - matches!(k, ty::Dynamic(impl_preds, ..) if - obl_preds.principal_def_id() == impl_preds.principal_def_id() - ) - } - ty::FnPtr(obl_sig) => match k { - ty::FnPtr(impl_sig) => { + ty::Dynamic(cand_preds, ..) => { + obl_preds.principal_def_id() == cand_preds.principal_def_id() + } + _ => false, + }, + ty::FnPtr(obl_sig) => match candidate_ty.kind() { + ty::FnPtr(cand_sig) => { let ty::FnSig { inputs_and_output, c_variadic, safety, abi } = obl_sig.skip_binder(); - let impl_sig = impl_sig.skip_binder(); + let cand_sig = cand_sig.skip_binder(); - abi == impl_sig.abi - && c_variadic == impl_sig.c_variadic - && safety == impl_sig.safety - && inputs_and_output.len() == impl_sig.inputs_and_output.len() - && iter::zip(inputs_and_output, impl_sig.inputs_and_output) + abi == cand_sig.abi + && c_variadic == cand_sig.c_variadic + && safety == cand_sig.safety + && inputs_and_output.len() == cand_sig.inputs_and_output.len() + && iter::zip(inputs_and_output, cand_sig.inputs_and_output) .all(|(obl, imp)| self.types_may_unify(obl, imp)) } _ => false, @@ -308,9 +310,9 @@ impl DeepRejectCtxt { TreatParams::AsCandidateKey => true, }, - ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(), + ty::Infer(ty::IntVar(_)) => candidate_ty.is_integral(), - ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(), + ty::Infer(ty::FloatVar(_)) => candidate_ty.is_floating_point(), ty::Infer(_) => true, @@ -329,17 +331,22 @@ impl DeepRejectCtxt { } } - pub fn consts_may_unify(self, obligation_ct: ty::Const<'_>, impl_ct: ty::Const<'_>) -> bool { - let impl_val = match impl_ct.kind() { + pub fn consts_may_unify( + self, + obligation_ct: ty::Const<'_>, + candidate_ct: ty::Const<'_>, + ) -> bool { + let candidate_val = match candidate_ct.kind() { ty::ConstKind::Expr(_) | ty::ConstKind::Param(_) | ty::ConstKind::Unevaluated(_) + | ty::ConstKind::Placeholder(_) | ty::ConstKind::Error(_) => { return true; } - ty::ConstKind::Value(impl_val) => impl_val, - ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - bug!("unexpected impl arg: {:?}", impl_ct) + ty::ConstKind::Value(candidate_val) => candidate_val, + ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => { + bug!("unexpected candidate arg: {:?}", candidate_ct) } }; @@ -357,7 +364,7 @@ impl DeepRejectCtxt { ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { true } - ty::ConstKind::Value(obl_val) => obl_val == impl_val, + ty::ConstKind::Value(obl_val) => obl_val == candidate_val, ty::ConstKind::Infer(_) => true, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index efb6cf2554625..c730f5117c561 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -121,17 +121,14 @@ impl<'tcx> Predicate<'tcx> { #[inline] pub fn allow_normalization(self) -> bool { match self.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::WellFormed(_)) => false, - // `NormalizesTo` is only used in the new solver, so this shouldn't - // matter. Normalizing `term` would be 'wrong' however, as it changes whether - // `normalizes-to(::Assoc, ::Assoc)` holds. - PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::WellFormed(_)) + | PredicateKind::AliasRelate(..) + | PredicateKind::NormalizesTo(..) => false, PredicateKind::Clause(ClauseKind::Trait(_)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::AliasRelate(..) | PredicateKind::ObjectSafe(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 40f3db89df56e..4fb865e621a17 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1713,6 +1713,11 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_))) } + #[inline] + pub fn is_placeholder(self) -> bool { + matches!(self.kind(), Placeholder(_)) + } + #[inline] pub fn is_char(self) -> bool { matches!(self.kind(), Char) diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 77f27236437dd..038d965359358 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start either = "1" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index bd0a54ef3638a..db23e98745a78 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start either = "1" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr = { path = "../rustc_attr" } 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_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 322739be3fb3c..691276d1cc4d6 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -1,5 +1,5 @@ //! The main parser interface. - +#![recursion_limit = "256"] #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 65660286dd73a..fa750612c1d19 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1815,7 +1815,8 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), - next_solver: Option = (None, parse_next_solver_config, [TRACKED], + next_solver: Option = (Some(NextSolverConfig { coherence: true, globally: true, dump_tree: Default::default() }) + , parse_next_solver_config, [TRACKED], "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files (default: no)"), diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1f4fb57d996cc..68aa2de86ec45 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # tidy-alphabetical-start bitflags = "2.4.1" derivative = "2.2.0" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr = { path = "../rustc_attr" } diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 43e61de955af7..93f0ab3b1b679 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -16,9 +16,12 @@ //! relate them structurally. use super::EvalCtxt; +use rustc_data_structures::fx::FxHashSet; use rustc_infer::infer::InferCtxt; +use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; -use rustc_middle::ty; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] @@ -28,6 +31,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ) -> QueryResult<'tcx> { let tcx = self.tcx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; + debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); + + if self.fast_reject_unnameable_rigid_term(param_env, lhs, rhs) + || self.fast_reject_unnameable_rigid_term(param_env, rhs, lhs) + { + return Err(NoSolution); + } + + if self.fast_reject_unnameable_rigid_term(param_env, lhs, rhs) + || self.fast_reject_unnameable_rigid_term(param_env, rhs, lhs) + { + return Err(NoSolution); + } // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { @@ -84,3 +100,105 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } } + +enum IgnoreAliases { + Yes, + No, +} + +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { + /// In case a rigid term refers to a placeholder which is not referenced by the + /// alias, the alias cannot be normalized to that rigid term unless it contains + /// either inference variables or these placeholders are referenced in a term + /// of a `Projection`-clause in the environment. + fn fast_reject_unnameable_rigid_term( + &mut self, + param_env: ty::ParamEnv<'tcx>, + rigid_term: ty::Term<'tcx>, + alias: ty::Term<'tcx>, + ) -> bool { + // Check that the rigid term is actually rigid. + if rigid_term.to_alias_term().is_some() || alias.to_alias_term().is_none() { + return false; + } + + // If the alias has any type or const inference variables, + // do not try to apply the fast path as these inference variables + // may resolve to something containing placeholders. + if alias.has_non_region_infer() { + return false; + } + + let mut referenced_placeholders = + self.collect_placeholders_in_term(rigid_term, IgnoreAliases::Yes); + for clause in param_env.caller_bounds() { + match clause.kind().skip_binder() { + ty::ClauseKind::Projection(ty::ProjectionPredicate { term, .. }) => { + if term.has_non_region_infer() { + return false; + } + + let env_term_placeholders = + self.collect_placeholders_in_term(term, IgnoreAliases::No); + #[allow(rustc::potential_query_instability)] + referenced_placeholders.retain(|p| !env_term_placeholders.contains(p)); + } + ty::ClauseKind::Trait(_) + | ty::ClauseKind::TypeOutlives(_) + | ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => continue, + } + } + + if referenced_placeholders.is_empty() { + return false; + } + + let alias_placeholders = self.collect_placeholders_in_term(alias, IgnoreAliases::No); + // If the rigid term references a placeholder not mentioned by the alias, + // they can never unify. + !referenced_placeholders.is_subset(&alias_placeholders) + } + + fn collect_placeholders_in_term( + &mut self, + term: ty::Term<'tcx>, + ignore_aliases: IgnoreAliases, + ) -> FxHashSet> { + // Fast path to avoid walking the term. + if !term.has_placeholders() { + return Default::default(); + } + + struct PlaceholderCollector<'tcx> { + ignore_aliases: IgnoreAliases, + placeholders: FxHashSet>, + } + impl<'tcx> TypeVisitor> for PlaceholderCollector<'tcx> { + type Result = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) { + match t.kind() { + ty::Placeholder(_) => drop(self.placeholders.insert(t.into())), + ty::Alias(..) if matches!(self.ignore_aliases, IgnoreAliases::Yes) => {} + _ => t.super_visit_with(self), + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + match ct.kind() { + ty::ConstKind::Placeholder(_) => drop(self.placeholders.insert(ct.into())), + ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) + if matches!(self.ignore_aliases, IgnoreAliases::Yes) => {} + _ => ct.super_visit_with(self), + } + } + } + + let mut visitor = PlaceholderCollector { ignore_aliases, placeholders: Default::default() }; + term.visit_with(&mut visitor); + visitor.placeholders + } +} diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 1152441069280..5726b600d91a9 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -846,7 +846,16 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let Some(result) = self.try_merge_responses(&responses) { return Ok(result); } else { - self.flounder(&responses) + let param_env_candidates = candidates + .iter() + .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .map(|c| c.result) + .collect::>(); + if let Some(result) = self.try_merge_responses(¶m_env_candidates) { + return Ok(result); + } else { + self.flounder(&responses) + } } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 9590a82c0677f..06d98308426a2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { previous call to `try_evaluate_added_goals!`" ); + // We only check for leaks from universes which were entered inside + // of the query. + self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { + trace!(?e, "failed the leak check"); + NoSolution + })?; + // When normalizing, we've replaced the expected term with an unconstrained // inference variable. This means that we dropped information which could // have been important. We handle this by instead returning the nested goals @@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }; let external_constraints = - self.compute_external_query_constraints(normalization_nested_goals)?; + self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = (self.var_values, external_constraints).fold_with(&mut EagerResolver::new(self.infcx)); // Remove any trivial region constraints once we've resolved regions @@ -170,30 +177,37 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] fn compute_external_query_constraints( &self, + certainty: Certainty, normalization_nested_goals: NestedNormalizationGoals<'tcx>, - ) -> Result, NoSolution> { - // We only check for leaks from universes which were entered inside - // of the query. - self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { - trace!(?e, "failed the leak check"); - NoSolution - })?; - - // Cannot use `take_registered_region_obligations` as we may compute the response - // inside of a `probe` whenever we have multiple choices inside of the solver. - let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.tcx(), - region_obligations - .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), - region_constraints, - ) - }); - - let mut seen = FxHashSet::default(); - region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); + ) -> ExternalConstraintsData<'tcx> { + // We only return region constraints once the certainty is `Yes`. + // This is necessary as we may drop nested goals on ambiguity, which + // may result in unconstrained inference variables in the region + // constraints. It also prevents us from emitting duplicate region + // constraints, avoiding some unnecessary work. + // + // This slightly weakens the leak check in case it uses region constraints + // from an ambiguous nested goal. TODO link test + let region_constraints = if certainty == Certainty::Yes { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations.iter().map(|r_o| { + (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) + }), + region_constraints, + ) + }); + + let mut seen = FxHashSet::default(); + region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); + region_constraints + } else { + Default::default() + }; let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); // Only return opaque type keys for newly-defined opaques @@ -201,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) }); - Ok(ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }) + ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } /// After calling a canonical query, we apply the constraints returned 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 7e1d7d73e0b3f..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,23 +5,27 @@ 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::{ inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult, }; use rustc_middle::traits::specialization_graph; +use rustc_middle::ty::AliasRelationDirection; +use rustc_middle::ty::TypeFolder; use rustc_middle::ty::{ self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::config::DumpSolverProofTree; use rustc_span::DUMMY_SP; +use rustc_type_ir::fold::TypeSuperFoldable; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -468,13 +472,23 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -612,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); @@ -968,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( @@ -1101,3 +1121,63 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }); } } + +/// Eagerly replace aliases with inference variables, emitting `AliasRelate` +/// goals, used when adding goals to the `EvalCtxt`. We compute the +/// `AliasRelate` goals before evaluating the actual goal to get all the +/// constraints we can. +/// +/// This is a performance optimization to more eagerly detect cycles during trait +/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. +struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { + ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.ecx.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Alias(..) if !ty.has_escaping_bound_vars() => { + let infer_ty = self.ecx.next_ty_infer(); + let normalizes_to = ty::PredicateKind::AliasRelate( + ty.into(), + infer_ty.into(), + AliasRelationDirection::Equate, + ); + self.ecx.add_goal( + GoalSource::Misc, + Goal::new(self.interner(), self.param_env, normalizes_to), + ); + infer_ty + } + _ => ty.super_fold_with(self), + } + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + match ct.kind() { + ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + let infer_ct = self.ecx.next_const_infer(ct.ty()); + let normalizes_to = ty::PredicateKind::AliasRelate( + ct.into(), + infer_ct.into(), + AliasRelationDirection::Equate, + ); + self.ecx.add_goal( + GoalSource::Misc, + Goal::new(self.interner(), self.param_env, normalizes_to), + ); + infer_ct + } + _ => ct.super_fold_with(self), + } + } + + fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 737d03f73f00b..7ac3b62cd0d7e 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -89,10 +89,8 @@ impl<'tcx> NormalizesToTermHack<'tcx> { pub struct InspectCandidate<'a, 'tcx> { goal: &'a InspectGoal<'a, 'tcx>, kind: inspect::ProbeKind>, - nested_goals: - Vec<(GoalSource, inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>)>, + steps: Vec<&'a inspect::ProbeStep>>, final_state: inspect::CanonicalState, ()>, - impl_args: Option, ty::GenericArgsRef<'tcx>>>, result: QueryResult<'tcx>, shallow_certainty: Certainty, } @@ -148,7 +146,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { #[instrument( level = "debug", skip_all, - fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals) + fields(goal = ?self.goal.goal, steps = ?self.steps) )] pub fn instantiate_nested_goals_and_opt_impl_args( &self, @@ -157,22 +155,35 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); - let instantiated_goals: Vec<_> = self - .nested_goals - .iter() - .map(|(source, goal)| { - ( - *source, + + let mut instantiated_goals = vec![]; + let mut opt_impl_args = None; + for step in &self.steps { + match **step { + inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push(( + source, canonical::instantiate_canonical_state( infcx, span, param_env, &mut orig_values, - *goal, + goal, ), - ) - }) - .collect(); + )), + inspect::ProbeStep::RecordImplArgs { impl_args } => { + opt_impl_args = Some(canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + )); + } + inspect::ProbeStep::MakeCanonicalResponse { .. } + | inspect::ProbeStep::EvaluateGoals(_) + | inspect::ProbeStep::NestedProbe(_) => unreachable!(), + } + } let () = canonical::instantiate_canonical_state( infcx, @@ -182,17 +193,6 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); - let impl_args = self.impl_args.map(|impl_args| { - canonical::instantiate_canonical_state( - infcx, - span, - param_env, - &mut orig_values, - impl_args, - ) - .fold_with(&mut EagerResolver::new(infcx)) - }); - if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is @@ -200,6 +200,9 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } + let opt_impl_args = + opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx))); + let goals = instantiated_goals .into_iter() .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() { @@ -249,7 +252,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { }) .collect(); - (goals, impl_args) + (goals, opt_impl_args) } /// Visit all nested goals of this candidate, rolling back @@ -279,17 +282,20 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { fn candidates_recur( &'a self, candidates: &mut Vec>, - nested_goals: &mut Vec<( - GoalSource, - inspect::CanonicalState, Goal<'tcx, ty::Predicate<'tcx>>>, - )>, - probe: &inspect::Probe>, + steps: &mut Vec<&'a inspect::ProbeStep>>, + probe: &'a inspect::Probe>, ) { let mut shallow_certainty = None; - let mut impl_args = None; for step in &probe.steps { match *step { - inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), + inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => { + steps.push(step) + } + inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { + assert_eq!(shallow_certainty.replace(c), None); + } + // We ignore evaluate goals steps for no. + inspect::ProbeStep::EvaluateGoals(_) => {} inspect::ProbeStep::NestedProbe(ref probe) => { match probe.kind { // These never assemble candidates for the goal we're trying to solve. @@ -305,19 +311,12 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { // Nested probes have to prove goals added in their parent // but do not leak them, so we truncate the added goals // afterwards. - let num_goals = nested_goals.len(); - self.candidates_recur(candidates, nested_goals, probe); - nested_goals.truncate(num_goals); + let num_steps = steps.len(); + self.candidates_recur(candidates, steps, probe); + steps.truncate(num_steps); } } } - inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(c), None); - } - inspect::ProbeStep::RecordImplArgs { impl_args: i } => { - assert_eq!(impl_args.replace(i), None); - } - inspect::ProbeStep::EvaluateGoals(_) => (), } } @@ -339,11 +338,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { candidates.push(InspectCandidate { goal: self, kind: probe.kind, - nested_goals: nested_goals.clone(), + steps: steps.clone(), final_state: probe.final_state, - result, shallow_certainty, - impl_args, + result, }); } } 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/fast_reject.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/fast_reject.rs new file mode 100644 index 0000000000000..f3efc6eba1b4e --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/fast_reject.rs @@ -0,0 +1,69 @@ +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; +/// We early return `NoSolution` when trying to normalize associated types if +/// we know them to be rigid. This is necessary if there are a huge amount of +/// rigid associated types in the `ParamEnv` as we would otherwise get hangs +/// when trying to normalize each associated type with all other associated types. +/// +/// See trait-system-refactor-initiative#109 for an example. +/// +/// ```plain +/// is_rigid_alias(alias) :- +/// is_placeholder(alias.self_ty), +/// no_applicable_blanket_impls(alias.trait_def_id), +/// not(may_normalize_via_env(alias)), +/// +/// may_normalize_via_env(alias) :- exists { +/// projection_clause.def_id == alias.def_id, +/// projection_clause.args may_unify alias.args, +/// } +/// ``` +#[instrument(level = "debug", skip(tcx), ret)] +pub(super) fn is_rigid_alias<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + alias: ty::AliasTerm<'tcx>, +) -> bool { + // FIXME: This could consider associated types as rigid as long + // as it considers the *recursive* item bounds of the alias, + // which is non-trivial. We may be forced to handle this case + // in the future. + alias.self_ty().is_placeholder() + && no_applicable_blanket_impls(tcx, alias.trait_def_id(tcx)) + && !may_normalize_via_env(param_env, alias) +} + +// FIXME: This could check whether the blanket impl has any where-bounds +// which definitely don't hold. Doing so is quite annoying, both just in +// general, but we also have to be careful about builtin blanket impls, +// e.g. `DiscriminantKind`. +#[instrument(level = "trace", skip(tcx), ret)] +fn no_applicable_blanket_impls<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> bool { + // FIXME(ptr_metadata): There's currently a builtin impl for `Pointee` which + // applies for all `T` as long as `T: Sized` holds. THis impl should + // get removed in favor of `Pointee` being a super trait of `Sized`. + tcx.trait_impls_of(trait_def_id).blanket_impls().is_empty() + && !tcx.lang_items().pointee_trait().is_some_and(|def_id| trait_def_id == def_id) +} + +#[instrument(level = "trace", ret)] +fn may_normalize_via_env<'tcx>(param_env: ty::ParamEnv<'tcx>, alias: ty::AliasTerm<'tcx>) -> bool { + for clause in param_env.caller_bounds() { + let Some(projection_pred) = clause.as_projection_clause() else { + continue; + }; + + if projection_pred.projection_def_id() != alias.def_id { + continue; + }; + + let drcx = ty::fast_reject::DeepRejectCtxt { + treat_obligation_params: ty::fast_reject::TreatParams::ForLookup, + }; + if drcx.args_may_unify(alias.args, projection_pred.skip_binder().projection_term.args) { + return true; + } + } + + false +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 7ef8373663ba5..f03b342916fa3 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -21,6 +21,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; mod anon_const; +mod fast_reject; mod inherent; mod opaque_types; mod weak_types; @@ -54,10 +55,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - match goal.predicate.alias.kind(self.tcx()) { + let tcx = self.tcx(); + match goal.predicate.alias.kind(tcx) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { - let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) + if fast_reject::is_rigid_alias(tcx, goal.param_env, goal.predicate.alias) { + return Err(NoSolution); + } else { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) + } } ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), 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/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 204bb487c8608..de09a3b4c55a5 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -390,6 +390,31 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); + if tcx.next_trait_solver_globally() { + predicates.retain(|&p| { + if p.is_global() { + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let param_env = ty::ParamEnv::empty(); + ocx.register_obligation(Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + p, + )); + if !ocx.select_all_or_error().is_empty() { + true + } else if ocx.resolve_regions(&OutlivesEnvironment::new(param_env)).is_empty() { + // A trivially true global bound, ignore it. + false + } else { + true + } + } else { + true + } + }) + } ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal()) } 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_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 79939d62a51a6..d0170ccc65286 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -29,5 +29,5 @@ rustc = [ [dev-dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } # tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 01d5251bfa0cc..4306a95a9e35a 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } 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/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index d3a4d6aff2d8b..bf53b2245ac59 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -80,6 +80,47 @@ macro_rules! forward_ref_op_assign { } } +/// Create a zero-size type similar to a closure type, but named. +macro_rules! impl_fn_for_zst { + ($( + $( #[$attr: meta] )* + struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn = + |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty + $body: block; + )+) => { + $( + $( #[$attr] )* + struct $Name; + + impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + $body + } + } + + impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call_mut( + &mut self, + ($( $arg, )*): ($( $ArgTy, )*) + ) -> $ReturnTy { + Fn::call(&*self, ($( $arg, )*)) + } + } + + impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name { + type Output = $ReturnTy; + + #[inline] + extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + Fn::call(&self, ($( $arg, )*)) + } + } + )+ + } +} + /// A macro for defining `#[cfg]` if-else statements. /// /// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 206d1ab885291..dcf68b36c7a2e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -255,7 +255,6 @@ #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] -#![feature(type_alias_impl_trait)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(with_negative_coherence)] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 19c91ba2eb988..8ad045275adec 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -108,7 +108,7 @@ impl [u8] { without modifying the original"] #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub fn escape_ascii(&self) -> EscapeAscii<'_> { - EscapeAscii { inner: self.iter().flat_map(|byte| byte.escape_ascii()) } + EscapeAscii { inner: self.iter().flat_map(EscapeByte) } } /// Returns a byte slice with leading ASCII whitespace bytes removed. @@ -190,7 +190,12 @@ impl [u8] { } } -type EscapeByte = impl (Fn(&u8) -> ascii::EscapeDefault) + Copy; +impl_fn_for_zst! { + #[derive(Clone)] + struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault { + ascii::escape_default(*byte) + }; +} /// An iterator over the escaped version of a byte slice. /// diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index d61f04102e5e5..19627f28e64f8 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1274,10 +1274,8 @@ pub struct SplitWhitespace<'a> { #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[derive(Clone, Debug)] pub struct SplitAsciiWhitespace<'a> { - pub(super) inner: Map< - Filter, BytesIsNotEmpty<'a>>, - UnsafeBytesToStr<'a>, - >, + pub(super) inner: + Map, BytesIsNotEmpty>, UnsafeBytesToStr>, } /// An iterator over the substrings of a string, diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index edda4d1b68703..669cdc92e3586 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -983,7 +983,7 @@ impl str { #[cfg_attr(not(test), rustc_diagnostic_item = "str_split_whitespace")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace<'_> { - SplitWhitespace { inner: self.split(char::is_whitespace).filter(|s| !s.is_empty()) } + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } /// Splits a string slice by ASCII whitespace. @@ -1032,13 +1032,8 @@ impl str { #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[inline] pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> { - let inner = self - .as_bytes() - .split(u8::is_ascii_whitespace) - .filter(|s| !s.is_empty()) - // SAFETY: the byte slice came from a string and was only split - // along character boundaries, so the resulting slices are strings. - .map(|bytes| unsafe { from_utf8_unchecked(bytes) }); + let inner = + self.as_bytes().split(IsAsciiWhitespace).filter(BytesIsNotEmpty).map(UnsafeBytesToStr); SplitAsciiWhitespace { inner } } @@ -1090,11 +1085,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines<'_> { - Lines(self.split_inclusive('\n').map(|line| { - let Some(line) = line.strip_suffix('\n') else { return line }; - let Some(line) = line.strip_suffix('\r') else { return line }; - line - })) + Lines(self.split_inclusive('\n').map(LinesMap)) } /// An iterator over the lines of a string. @@ -2645,19 +2636,14 @@ impl str { #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_debug(&self) -> EscapeDebug<'_> { let mut chars = self.chars(); - let first = chars - .next() - .map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)) - .into_iter() - .flatten(); - let inner = first.chain(chars.flat_map(|c| { - c.escape_debug_ext(EscapeDebugExtArgs { - escape_grapheme_extended: false, - escape_single_quote: true, - escape_double_quote: true, - }) - })); - EscapeDebug { inner } + EscapeDebug { + inner: chars + .next() + .map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)) + .into_iter() + .flatten() + .chain(chars.flat_map(CharEscapeDebugContinue)), + } } /// Return an iterator that escapes each char in `self` with [`char::escape_default`]. @@ -2695,7 +2681,7 @@ impl str { without modifying the original"] #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_default(&self) -> EscapeDefault<'_> { - EscapeDefault { inner: self.chars().flat_map(char::escape_default) } + EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) } } /// Return an iterator that escapes each char in `self` with [`char::escape_unicode`]. @@ -2733,7 +2719,7 @@ impl str { without modifying the original"] #[stable(feature = "str_escape", since = "1.34.0")] pub fn escape_unicode(&self) -> EscapeUnicode<'_> { - EscapeUnicode { inner: self.chars().flat_map(char::escape_unicode) } + EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) } } } @@ -2764,15 +2750,59 @@ impl Default for &mut str { } } -type LinesMap = impl (Fn(&str) -> &str) + Copy; -type CharEscapeDebugContinue = impl (FnMut(char) -> char::EscapeDebug) + Copy; -type CharEscapeUnicode = impl (Fn(char) -> char::EscapeUnicode) + Copy; -type CharEscapeDefault = impl (Fn(char) -> char::EscapeDefault) + Copy; -type IsWhitespace = impl (Fn(char) -> bool) + Copy; -type IsAsciiWhitespace = impl (Fn(&u8) -> bool) + Copy; -type IsNotEmpty = impl (Fn(&&str) -> bool) + Copy; -type BytesIsNotEmpty<'a> = impl (FnMut(&&'a [u8]) -> bool) + Copy; -type UnsafeBytesToStr<'a> = impl (FnMut(&'a [u8]) -> &'a str) + Copy; +impl_fn_for_zst! { + /// A nameable, cloneable fn type + #[derive(Clone)] + struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str { + let Some(line) = line.strip_suffix('\n') else { return line }; + let Some(line) = line.strip_suffix('\r') else { return line }; + line + }; + + #[derive(Clone)] + struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { + c.escape_debug_ext(EscapeDebugExtArgs { + escape_grapheme_extended: false, + escape_single_quote: true, + escape_double_quote: true + }) + }; + + #[derive(Clone)] + struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { + c.escape_unicode() + }; + #[derive(Clone)] + struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { + c.escape_default() + }; + + #[derive(Clone)] + struct IsWhitespace impl Fn = |c: char| -> bool { + c.is_whitespace() + }; + + #[derive(Clone)] + struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool { + byte.is_ascii_whitespace() + }; + + #[derive(Clone)] + struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool { + !s.is_empty() + }; + + #[derive(Clone)] + struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool { + !s.is_empty() + }; + + #[derive(Clone)] + struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str { + // SAFETY: not safe + unsafe { from_utf8_unchecked(bytes) } + }; +} // This is required to make `impl From<&str> for Box` and `impl From for Box` not overlap. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 475b3e7eb9312..42196deb428e8 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -428,37 +428,41 @@ impl fmt::Display for Backtrace { } } -type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; - -fn lazy_resolve(mut capture: Capture) -> LazyResolve { - move || { - // Use the global backtrace lock to synchronize this as it's a - // requirement of the `backtrace` crate, and then actually resolve - // everything. - let _lock = lock(); - for frame in capture.frames.iter_mut() { - let symbols = &mut frame.symbols; - let frame = match &frame.frame { - RawFrame::Actual(frame) => frame, - #[cfg(test)] - RawFrame::Fake => unimplemented!(), - }; - unsafe { - backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { - symbols.push(BacktraceSymbol { - name: symbol.name().map(|m| m.as_bytes().to_vec()), - filename: symbol.filename_raw().map(|b| match b { - BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), - BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), - }), - lineno: symbol.lineno(), - colno: symbol.colno(), +use define::*; +mod define { + use super::*; + pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; + + pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { + move || { + // Use the global backtrace lock to synchronize this as it's a + // requirement of the `backtrace` crate, and then actually resolve + // everything. + let _lock = lock(); + for frame in capture.frames.iter_mut() { + let symbols = &mut frame.symbols; + let frame = match &frame.frame { + RawFrame::Actual(frame) => frame, + #[cfg(test)] + RawFrame::Fake => unimplemented!(), + }; + unsafe { + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + symbols.push(BacktraceSymbol { + name: symbol.name().map(|m| m.as_bytes().to_vec()), + filename: symbol.filename_raw().map(|b| match b { + BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()), + BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()), + }), + lineno: symbol.lineno(), + colno: symbol.colno(), + }); }); - }); + } } - } - capture + capture + } } } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 31222f213d800..b3c2d5aecf3c3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.12", default-features = false, features = ["config"] } base64 = "0.21.7" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } indexmap = "2" minifier = "0.3.0" regex = "1" diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index b48f3ab3919cc..6e4810e7009dd 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -36,7 +36,7 @@ toml = "0.7.3" walkdir = "2.3" # This is used by the `collect-metadata` alias. filetime = "0.2.9" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } # UI test dependencies clippy_utils = { path = "clippy_utils" } diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index 4104e7d94f146..e06c232e3c16e 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" aho-corasick = "1.0" clap = { version = "4.4", features = ["derive"] } indoc = "1.0" -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } opener = "0.6" shell-escape = "0.1" walkdir = "2.3" diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 5e3a119337ccd..168281ac1d16d 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -14,7 +14,7 @@ cargo_metadata = "0.18" clippy_config = { path = "../clippy_config" } clippy_utils = { path = "../clippy_utils" } declare_clippy_lint = { path = "../declare_clippy_lint" } -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } quine-mc_cluskey = "0.2" regex-syntax = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index ab883c25338ba..9db64452fc02e 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] clippy_config = { path = "../clippy_config" } arrayvec = { version = "0.7", default-features = false } -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } rustc-semver = "1.1" [features] diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index c8c734c3a7c9f..ef8ce7b3e0698 100644 --- a/src/tools/clippy/declare_clippy_lint/Cargo.toml +++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml @@ -8,7 +8,7 @@ publish = false proc-macro = true [dependencies] -itertools = "0.12" +itertools = { git = "https://github.com/rust-itertools/itertools" } quote = "1.0.21" syn = "2.0" 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/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr index 49b236f9d2aa2..781ab0fcbf766 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr @@ -12,7 +12,7 @@ LL | impl Trait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` | = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` - = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box< as WithAssoc<'a>>::Assoc>` + = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/occurs-check/opaques.next.stderr b/tests/ui/coherence/occurs-check/opaques.next.stderr index f6c5255a18693..11d1edcca2f91 100644 --- a/tests/ui/coherence/occurs-check/opaques.next.stderr +++ b/tests/ui/coherence/occurs-check/opaques.next.stderr @@ -11,7 +11,7 @@ error[E0282]: type annotations needed --> $DIR/opaques.rs:13:20 | LL | pub fn cast(x: Container, T>) -> Container { - | ^ cannot infer type for associated type `>::Assoc` + | ^ cannot infer type error: aborting due to 2 previous errors diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 47acf5b968b79..568cb8931a198 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -16,6 +16,22 @@ LL | where LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error: aborting due to 1 previous error +error[E0277]: the trait bound `&str: AsExpression` is not satisfied + --> $DIR/as_expression.rs:57:15 + | +LL | SelectInt.check("bar"); + | ^^^^^ the trait `AsExpression` is not implemented for `&str` + | + = help: the trait `AsExpression` is implemented for `&str` + = help: for that trait implementation, expected `Text`, found `Integer` + +error[E0271]: type mismatch resolving `<&str as AsExpression<::SqlType>>::Expression == _` + --> $DIR/as_expression.rs:57:5 + | +LL | SelectInt.check("bar"); + | ^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 5fd5cc544009f..37b4429f694cf 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -55,6 +55,7 @@ impl Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); - //[next]~^ ERROR the trait bound `&str: AsExpression<::SqlType>` is not satisfied - //[current]~^^ ERROR the trait bound `&str: AsExpression` is not satisfied + //~^ ERROR the trait bound `&str: AsExpression` is not satisfied + //[next]~| the trait bound `&str: AsExpression<::SqlType>` is not satisfied + //[next]~| type mismatch } 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`. diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 170f2c7d34c45..9dde1963bd49d 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated` +error[E0284]: type annotations needed: cannot satisfy `{ || {} } == _` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `{ || {} } == _` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs new file mode 100644 index 0000000000000..5c13a871a7b8d --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs @@ -0,0 +1,89 @@ +//@ compile-flags: -Znext-solver + +// A regression test for #125269. We previously ended up +// recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed` +// for all aliases which ended up causing exponential blowup. +// +// This has been fixed by eagerly normalizing the associated +// type before computing the nested goals, resulting in an +// immediate inductive cycle. + +pub trait Typed {} + +pub struct SpeciesCases(E); + +pub trait SpeciesPackedElim { + type Ogre; + type Cyclops; + type Wendigo; + type Cavetroll; + type Mountaintroll; + type Swamptroll; + type Dullahan; + type Werewolf; + type Occultsaurok; + type Mightysaurok; + type Slysaurok; + type Mindflayer; + type Minotaur; + type Tidalwarrior; + type Yeti; + type Harvester; + type Blueoni; + type Redoni; + type Cultistwarlord; + type Cultistwarlock; + type Huskbrute; + type Tursus; + type Gigasfrost; + type AdletElder; + type SeaBishop; + type HaniwaGeneral; + type TerracottaBesieger; + type TerracottaDemolisher; + type TerracottaPunisher; + type TerracottaPursuer; + type Cursekeeper; +} + +impl<'b, E: SpeciesPackedElim> Typed for &'b SpeciesCases +where + &'b E::Ogre: Typed, + &'b E::Cyclops: Typed, + &'b E::Wendigo: Typed, + &'b E::Cavetroll: Typed, + &'b E::Mountaintroll: Typed, + &'b E::Swamptroll: Typed, + &'b E::Dullahan: Typed, + &'b E::Werewolf: Typed, + &'b E::Occultsaurok: Typed, + &'b E::Mightysaurok: Typed, + &'b E::Slysaurok: Typed, + &'b E::Mindflayer: Typed, + &'b E::Minotaur: Typed, + &'b E::Tidalwarrior: Typed, + &'b E::Yeti: Typed, + &'b E::Harvester: Typed, + &'b E::Blueoni: Typed, + &'b E::Redoni: Typed, + &'b E::Cultistwarlord: Typed, + &'b E::Cultistwarlock: Typed, + &'b E::Huskbrute: Typed, + &'b E::Tursus: Typed, + &'b E::Gigasfrost: Typed, + &'b E::AdletElder: Typed, + &'b E::SeaBishop: Typed, + &'b E::HaniwaGeneral: Typed, + &'b E::TerracottaBesieger: Typed, + &'b E::TerracottaDemolisher: Typed, + &'b E::TerracottaPunisher: Typed, + &'b E::TerracottaPursuer: Typed, + &'b E::Cursekeeper: Typed, +{} + +fn foo() {} + +fn main() { + foo::<&_>(); + //~^ ERROR overflow evaluating the requirement `&_: Typed` +} diff --git a/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr new file mode 100644 index 0000000000000..d350eb0f7795c --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `&_: Typed` + --> $DIR/cycle-modulo-ambig-aliases.rs:87:11 + | +LL | foo::<&_>(); + | ^^ + | +note: required by a bound in `foo` + --> $DIR/cycle-modulo-ambig-aliases.rs:84:11 + | +LL | fn foo() {} + | ^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs index a63fe729fd687..1554d74f21453 100644 --- a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs +++ b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ check-pass +//@ run-pass // Test that selection prefers the builtin trait object impl for `Any` // instead of the user defined impl. Both impls apply to the trait diff --git a/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs new file mode 100644 index 0000000000000..18dc34f7cc437 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/ambig-goal-infer-in-type-oulives.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicitly enabled) + +// Regression test for an ICE when trying to bootstrap rustc +// with #125343. An ambiguous goal returned a `TypeOutlives` +// constraint referencing an inference variable. This inference +// variable was created inside of the goal, causing it to be +// unconstrained in the caller. This then caused an ICE in MIR +// borrowck. + +struct Foo(T); +trait Extend { + fn extend>(iter: I); +} + +impl Extend for Foo { + fn extend>(_: I) { + todo!() + } +} + +impl<'a, T: 'a + Copy> Extend<&'a T> for Foo { + fn extend>(iter: I) { + >::extend(iter.into_iter().copied()) + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/try-unify-rigid-aliases-hang.rs b/tests/ui/traits/next-solver/normalize/try-unify-rigid-aliases-hang.rs new file mode 100644 index 0000000000000..3e8f616c79f41 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/try-unify-rigid-aliases-hang.rs @@ -0,0 +1,27 @@ +//@ check-pass +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// Minimization of a hang in rayon, cc trait-solver-refactor-initiative#109 + +pub trait ParallelIterator { + type Item; +} + +macro_rules! multizip_impl { + ($($T:ident),+) => { + impl<$( $T, )+> ParallelIterator for ($( $T, )+) + where + $( + $T: ParallelIterator, + $T::Item: ParallelIterator, + )+ + { + type Item = (); + } + } +} + +multizip_impl! { A, B, C, D, E, F, G, H, I, J, K, L } + +fn main() {}