From 9e42ad19649b7161bfd37aaf65a4c8203ffa97ad Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 26 Nov 2024 16:01:08 +0100 Subject: [PATCH] support revealing defined opaque post borrowck --- .../rustc_hir_analysis/src/check/check.rs | 14 +++- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +- compiler/rustc_infer/src/infer/context.rs | 6 +- compiler/rustc_infer/src/infer/mod.rs | 13 +++- .../rustc_infer/src/infer/opaque_types/mod.rs | 5 +- compiler/rustc_middle/src/ty/context.rs | 8 +++ compiler/rustc_middle/src/ty/fold.rs | 7 +- .../src/solve/assembly/mod.rs | 4 +- .../src/solve/eval_ctxt/mod.rs | 6 ++ .../rustc_next_trait_solver/src/solve/mod.rs | 15 ++++- .../src/solve/normalizes_to/mod.rs | 21 ++---- .../src/solve/normalizes_to/opaque_types.rs | 20 ++++++ .../src/solve/trait_goals.rs | 19 ++---- .../src/solve/delegate.rs | 4 +- .../src/traits/normalize.rs | 14 ++-- .../src/traits/project.rs | 4 +- .../src/traits/query/normalize.rs | 6 +- .../src/traits/select/mod.rs | 8 ++- compiler/rustc_ty_utils/src/instance.rs | 3 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 13 ++++ compiler/rustc_type_ir/src/interner.rs | 6 ++ compiler/rustc_type_ir/src/relate/combine.rs | 6 +- .../no-define-in-wf-check.current.stderr | 34 ++++++++++ .../opaques/no-define-in-wf-check.rs | 66 +++++++++++++++++++ 24 files changed, 242 insertions(+), 63 deletions(-) create mode 100644 tests/ui/traits/next-solver/opaques/no-define-in-wf-check.current.stderr create mode 100644 tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index c66572a937726..97fcc3078a4bf 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -322,8 +322,12 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - // FIXME(#132279): This should eventually use the already defined hidden types. - let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor)); + // FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed. + let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() { + TypingMode::post_borrowck_analysis(tcx, defining_use_anchor) + } else { + TypingMode::analysis_in_body(tcx, defining_use_anchor) + }); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match origin { @@ -417,7 +421,11 @@ 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 { + if infcx.next_trait_solver() { + Ok(()) + } else 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 diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 640729576fcc6..7e67741cdc6c6 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1574,7 +1574,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Thus we need to prevent them from trying to match the `&_` autoref // candidates that get created for `&self` trait methods. ty::Alias(ty::Opaque, alias_ty) - if self.infcx.can_define_opaque_ty(alias_ty.def_id) + if !self.next_trait_solver() + && self.infcx.can_define_opaque_ty(alias_ty.def_id) && !xform_self_ty.is_ty_var() => { return ProbeResult::NoMatch; diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 1968ed347529f..5fc9b679c8acf 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::relate::combine::PredicateEmittingRelation; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{DUMMY_SP, ErrorGuaranteed}; -use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin}; +use super::{BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin}; impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { type Interner = TyCtxt<'tcx>; @@ -87,6 +87,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } + fn next_region_infer(&self) -> ty::Region<'tcx> { + self.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) + } + fn next_ty_infer(&self) -> Ty<'tcx> { self.next_ty_var(DUMMY_SP) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 555c1022a8a1c..3bcf7e4d3e4e7 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -990,11 +990,17 @@ impl<'tcx> InferCtxt<'tcx> { #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { + debug_assert!(!self.next_trait_solver()); match self.typing_mode() { TypingMode::Analysis { defining_opaque_types } => { id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) } - TypingMode::Coherence | TypingMode::PostAnalysis => false, + // FIXME(#132279): This function is quite weird in post-analysis + // and post-borrowck analysis mode. We may need to modify its uses + // to support PostBorrowckAnalysis in the old solver as well. + TypingMode::Coherence + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => false, } } @@ -1276,7 +1282,6 @@ impl<'tcx> InferCtxt<'tcx> { /// using canonicalization or carrying this inference context around. pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> { let typing_mode = match self.typing_mode() { - ty::TypingMode::Coherence => ty::TypingMode::Coherence, // FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible // to handle them without proper canonicalization. This means we may cause cycle // errors and fail to reveal opaques while inside of bodies. We should rename this @@ -1284,7 +1289,9 @@ impl<'tcx> InferCtxt<'tcx> { ty::TypingMode::Analysis { defining_opaque_types: _ } => { TypingMode::non_body_analysis() } - ty::TypingMode::PostAnalysis => ty::TypingMode::PostAnalysis, + mode @ (ty::TypingMode::Coherence + | ty::TypingMode::PostBorrowckAnalysis { .. } + | ty::TypingMode::PostAnalysis) => mode, }; ty::TypingEnv { typing_mode, param_env } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index a608ea1ad579f..b64686afd2340 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -98,6 +98,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, ) -> Result>>, TypeError<'tcx>> { + debug_assert!(!self.next_trait_solver()); 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(); @@ -546,7 +547,9 @@ impl<'tcx> InferCtxt<'tcx> { ); } } - ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"), + mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => { + bug!("insert hidden type in {mode:?}") + } } Ok(()) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d982122e2aa4b..d3c32a43a5e48 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -632,6 +632,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes { self.opaque_types_defined_by(defining_anchor) } + + fn fold_regions>>( + self, + value: T, + f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> T { + self.fold_regions(value, f) + } } macro_rules! bidirectional_lang_item_map { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 7adbd556141fe..1e9e3354e9d19 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -55,14 +55,11 @@ where impl<'tcx> TyCtxt<'tcx> { /// Folds the escaping and free regions in `value` using `f`. - pub fn fold_regions( + pub fn fold_regions>>( self, value: T, mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, - ) -> T - where - T: TypeFoldable>, - { + ) -> T { value.fold_with(&mut RegionFolder::new(self, &mut f)) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index adac35b57cd70..198ccb000f345 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -339,7 +339,9 @@ where match self.typing_mode() { TypingMode::Coherence => {} - TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => { self.discard_impls_shadowed_by_env(goal, &mut candidates); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 40d1576256eb9..70ceb22bfea58 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -644,6 +644,12 @@ where } } + pub(super) fn next_region_var(&mut self) -> I::Region { + let region = self.delegate.next_region_infer(); + self.inspect.add_var_value(region); + region + } + pub(super) fn next_ty_infer(&mut self) -> I::Ty { let ty = self.delegate.next_ty_infer(); self.inspect.add_var_value(ty); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 5c54656cc59f5..ebf1013db1ecb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -23,7 +23,7 @@ mod trait_goals; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, TypingMode}; use tracing::instrument; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; @@ -321,6 +321,19 @@ where Ok(ct) } } + + fn opaque_type_is_rigid(&self, def_id: I::DefId) -> bool { + match self.typing_mode() { + // Opaques are never rigid outside of analysis mode. + TypingMode::Coherence | TypingMode::PostAnalysis => false, + // During analysis, opaques are rigid unless they may be defined by + // the current body. + TypingMode::Analysis { defining_opaque_types: non_rigid_opaques } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => { + !def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id)) + } + } + } } fn response_no_constraints_raw( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 33bd1cf2f56ee..f5b1b23b8e973 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -6,7 +6,7 @@ mod weak_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -71,21 +71,10 @@ where Ok(()) } ty::AliasTermKind::OpaqueTy => { - match self.typing_mode() { - // Opaques are never rigid outside of analysis mode. - TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution), - // During analysis, opaques are only rigid if we may not define it. - TypingMode::Analysis { defining_opaque_types } => { - if rigid_alias - .def_id - .as_local() - .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) - { - Err(NoSolution) - } else { - Ok(()) - } - } + if self.opaque_type_is_rigid(rigid_alias.def_id) { + Ok(()) + } else { + Err(NoSolution) } } // FIXME(generic_const_exprs): we would need to support generic consts here diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 336bcb9df33a6..be739b264129a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -95,6 +95,26 @@ where ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + TypingMode::PostBorrowckAnalysis { defined_opaque_types } => { + let Some(def_id) = opaque_ty.def_id.as_local() else { + return Err(NoSolution); + }; + + if !defined_opaque_types.contains(&def_id) { + return Err(NoSolution); + } + + let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); + // FIXME: Actually use a proper binder here instead of relying on `ReErased`. + // + // This is also probably unsound or sth :shrug: + let actual = cx.fold_regions(actual, |re, _dbi| match re.kind() { + ty::ReErased => self.next_region_var(), + _ => re, + }); + self.eq(goal.param_env, expected, actual)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } TypingMode::PostAnalysis => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 096dc32ccc926..6641d2bf92492 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -69,7 +69,9 @@ where // it's not a real impl. (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode() { TypingMode::Coherence => Certainty::AMBIGUOUS, - TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution), + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => return Err(NoSolution), }, // Impl matches polarity @@ -174,20 +176,7 @@ where // ideally we want to avoid, since we can make progress on this goal // via an alias bound or a locally-inferred hidden type instead. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { - match ecx.typing_mode() { - TypingMode::Coherence | TypingMode::PostAnalysis => { - unreachable!("rigid opaque outside of analysis: {goal:?}"); - } - TypingMode::Analysis { defining_opaque_types } => { - if opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) - { - return Err(NoSolution); - } - } - } + debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id)); } ecx.probe_and_evaluate_goal_for_constituent_tys( diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 09bba24ba6130..97cde67799c2c 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -205,7 +205,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. match self.typing_mode() { - TypingMode::Coherence | TypingMode::Analysis { .. } => false, + TypingMode::Coherence + | TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } => false, TypingMode::PostAnalysis => { let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); !poly_trait_ref.still_further_specializable() diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 4d3d8c66e62b0..eb428070de71d 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -118,9 +118,10 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`, // so we can ignore those. match infcx.typing_mode() { - TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { - flags.remove(ty::TypeFlags::HAS_TY_OPAQUE) - } + // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis + TypingMode::Coherence + | TypingMode::Analysis { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), TypingMode::PostAnalysis => {} } @@ -213,9 +214,10 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.selcx.infcx.typing_mode() { - TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { - ty.super_fold_with(self) - } + // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis + TypingMode::Coherence + | TypingMode::Analysis { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self), TypingMode::PostAnalysis => { let recursion_limit = self.cx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 2864f277df578..01f6cccb375ad 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -975,7 +975,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. match selcx.infcx.typing_mode() { - TypingMode::Coherence | TypingMode::Analysis { .. } => { + TypingMode::Coherence + | TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } => { debug!( assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), ?obligation.predicate, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 22cfbb2c84032..525f4e618a070 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -216,9 +216,9 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.infcx.typing_mode() { - TypingMode::Coherence | TypingMode::Analysis { defining_opaque_types: _ } => { - ty.try_super_fold_with(self)? - } + TypingMode::Coherence + | TypingMode::Analysis { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { .. } => ty.try_super_fold_with(self)?, TypingMode::PostAnalysis => { let args = data.args.try_fold_with(self)?; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 3b64a47181a6c..d4dab2605246b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1470,7 +1470,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let obligation = &stack.obligation; match self.infcx.typing_mode() { TypingMode::Coherence => {} - TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()), + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => return Ok(()), } debug!("is_knowable()"); @@ -1517,6 +1519,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TypingMode::Analysis { defining_opaque_types } => { defining_opaque_types.is_empty() || !pred.has_opaque_types() } + // The hidden type of the `defined_opaque_types` is not local to the + // current inference context, so we can freely move this to the global + // cache. + TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => true, // The global cache is only used if there are no opaque types in // the defining scope or we're outside of analysis. // diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 8798772e398d7..1a98c85bee9fb 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -149,7 +149,8 @@ fn resolve_associated_item<'tcx>( // get a result which isn't correct for all monomorphizations. match typing_env.typing_mode { ty::TypingMode::Coherence - | ty::TypingMode::Analysis { defining_opaque_types: _ } => false, + | ty::TypingMode::Analysis { .. } + | ty::TypingMode::PostBorrowckAnalysis { .. } => false, ty::TypingMode::PostAnalysis => !trait_ref.still_further_specializable(), } }; diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 13ad505bc0483..a892b88c2c636 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -63,6 +63,12 @@ pub enum TypingMode { /// } /// ``` Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, + /// Any analysis after borrowck for a given body should be able to use all the + /// hidden types defined by borrowck, without being able to define any new ones. + /// + /// This is currently only used by the new solver, but should be implemented in + /// the old solver as well. + PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes }, /// After analysis, mostly during codegen and MIR optimizations, we're able to /// reveal all opaque types. As the concrete type should *never* be observable /// directly by the user, this should not be used by checks which may expose @@ -85,6 +91,12 @@ impl TypingMode { pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } } + + pub fn post_borrowck_analysis(cx: I, body_def_id: I::LocalDefId) -> TypingMode { + TypingMode::PostBorrowckAnalysis { + defined_opaque_types: cx.opaque_types_defined_by(body_def_id), + } + } } pub trait InferCtxtLike: Sized { @@ -126,6 +138,7 @@ pub trait InferCtxtLike: Sized { vid: ty::RegionVid, ) -> ::Region; + fn next_region_infer(&self) -> ::Region; fn next_ty_infer(&self) -> ::Ty; fn next_const_infer(&self) -> ::Const; fn fresh_args_for_item( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0ae688848ebfc..1be93115d70e1 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -297,6 +297,12 @@ pub trait Interner: self, defining_anchor: Self::LocalDefId, ) -> Self::DefiningOpaqueTypes; + + fn fold_regions>( + self, + value: T, + f: impl FnMut(Self::Region, ty::DebruijnIndex) -> Self::Region, + ) -> T; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index c8abfee314e23..d49f8d3093db7 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -136,9 +136,9 @@ where relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } - TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { - structurally_relate_tys(relation, a, b) - } + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => structurally_relate_tys(relation, a, b), } } diff --git a/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.current.stderr b/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.current.stderr new file mode 100644 index 0000000000000..9a28dc093c1be --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.current.stderr @@ -0,0 +1,34 @@ +error: unconstrained opaque type + --> $DIR/no-define-in-wf-check.rs:19:18 + | +LL | type Tait1 = impl Sized; + | ^^^^^^^^^^ + | + = note: `Tait1` must be used in combination with a concrete type within the same module + +error: unconstrained opaque type + --> $DIR/no-define-in-wf-check.rs:27:18 + | +LL | type Tait1 = impl Sized; + | ^^^^^^^^^^ + | + = note: `Tait1` must be used in combination with a concrete type within the same module + +error: unconstrained opaque type + --> $DIR/no-define-in-wf-check.rs:36:18 + | +LL | type Tait1 = impl Sized; + | ^^^^^^^^^^ + | + = note: `Tait1` must be used in combination with a concrete type within the same module + +error: unconstrained opaque type + --> $DIR/no-define-in-wf-check.rs:47:18 + | +LL | type Tait1 = impl Sized; + | ^^^^^^^^^^ + | + = note: `Tait1` must be used in combination with a concrete type within the same module + +error: aborting due to 4 previous errors + diff --git a/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs b/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs new file mode 100644 index 0000000000000..dd6df097da1bb --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/no-define-in-wf-check.rs @@ -0,0 +1,66 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +// Regression test for trait-system-refactor-initiative#106. We previously +// tried to define other opaques while checking that opaques are well-formed. +// +// This resulted in undesirable ambiguity + +#![feature(type_alias_impl_trait)] + +mod ex0 { + fn foo() -> (impl Sized, impl Sized) { + ((), ()) + } +} +mod ex1 { + type Tait1 = impl Sized; + //[current]~^ ERROR unconstrained opaque type + fn foo(x: Tait1) -> impl Sized { + let () = x; + } +} + +mod ex2 { + type Tait1 = impl Sized; + //[current]~^ ERROR unconstrained opaque type + type Tait2 = impl Sized; + fn foo(x: Tait1) -> Tait2 { + let () = x; + } +} + +mod ex3 { + type Tait1 = impl Sized; + //[current]~^ ERROR unconstrained opaque type + trait Something {} + impl Something for T {} + type Tait2 = impl Something; + fn foo(x: Tait1) -> Tait2 { + let () = x; + } +} + +mod ex4 { + type Tait1 = impl Sized; + //[current]~^ ERROR unconstrained opaque type + trait Trait { + type Assoc; + } + + impl Trait for T { + type Assoc = T; + } + + // ambiguity when checking that `Tait2` is wf + // + // ambiguity proving `(): Trait`. + type Tait2 = impl Trait<(), Assoc = impl Trait>; + fn foo(x: Tait1) -> Tait2 { + let () = x; + } +} + +fn main() {}