diff options
| author | Michael Goulet <michael@errs.io> | 2023-05-09 18:56:43 +0000 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2023-05-25 03:19:15 +0000 |
| commit | 4d80b8090c30980c03ff4bb6f47a7560ffaa68a4 (patch) | |
| tree | d45cf4788222a3542ea503f8083f516ecbb04855 | |
| parent | 7664dfe4331265d0b2b1ffb89c92d443886bec0b (diff) | |
| download | rust-4d80b8090c30980c03ff4bb6f47a7560ffaa68a4.tar.gz rust-4d80b8090c30980c03ff4bb6f47a7560ffaa68a4.zip | |
Pull out logic from #111131, plus some new logic in EvalCtxt::normalize_opaque_type
Co-authored-by: lcnr <rust@lcnr.de>
| -rw-r--r-- | compiler/rustc_infer/src/infer/combine.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/equate.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/lattice.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/nll_relate/mod.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/opaque_types.rs | 45 | ||||
| -rw-r--r-- | compiler/rustc_infer/src/infer/sub.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/fulfill.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/mod.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/opaques.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/project_goals.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/auto_trait.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_traits/src/chalk/lowering.rs | 2 |
13 files changed, 122 insertions, 43 deletions
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 79fc02c6c79..b6b935de68c 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -113,10 +113,7 @@ impl<'tcx> InferCtxt<'tcx> { bug!() } - (_, ty::Alias(AliasKind::Projection | AliasKind::Inherent, _)) - | (ty::Alias(AliasKind::Projection | AliasKind::Inherent, _), _) - if self.tcx.trait_solver_next() => - { + (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => { relation.register_type_relate_obligation(a, b); Ok(a) } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 793505e4ab2..42dfe4f6bb8 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -104,7 +104,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes - && def_id.is_local() => + && def_id.is_local() + && !self.tcx().trait_solver_next() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs index 7f4c141b97a..7190d33d299 100644 --- a/compiler/rustc_infer/src/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -108,9 +108,12 @@ where &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), ) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b), + (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() => + if this.define_opaque_types() == DefineOpaqueTypes::Yes + && def_id.is_local() + && !this.tcx().trait_solver_next() => { this.register_obligations( infcx diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 4ae6af5f5be..d3fd01b9642 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -491,16 +491,22 @@ where ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| { - self.tcx().sess.delay_span_bug( - self.delegate.span(), - "failure to relate an opaque to itself should result in an error later on", - ); - if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } - }), + ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => { + infcx.super_combine_tys(self, a, b).or_else(|err| { + // This behavior is only there for the old solver, the new solver + // shouldn't ever fail. Instead, it unconditionally emits an + // alias-relate goal. + assert!(!self.tcx().trait_solver_next()); + self.tcx().sess.delay_span_bug( + self.delegate.span(), + "failure to relate an opaque to itself should result in an error later on", + ); + if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) } + }) + } (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) - if def_id.is_local() => + if def_id.is_local() && !self.tcx().trait_solver_next() => { self.relate_opaques(a, b) } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 213b3f0fe0e..21df3291f36 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -2,7 +2,7 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; -use crate::traits; +use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; use rustc_data_structures::fx::FxIndexMap; @@ -48,9 +48,15 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, ) -> InferOk<'tcx, T> { + // We handle opaque types differently in the new solver. + if self.tcx.trait_solver_next() { + return InferOk { value, obligations: vec![] }; + } + if !value.has_opaque_types() { return InferOk { value, obligations: vec![] }; } + let mut obligations = vec![]; let replace_opaque_type = |def_id: DefId| { def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some()) @@ -521,9 +527,6 @@ impl<'tcx> InferCtxt<'tcx> { origin: hir::OpaqueTyOrigin, a_is_expected: bool, ) -> InferResult<'tcx, ()> { - let tcx = self.tcx; - let OpaqueTypeKey { def_id, substs } = opaque_type_key; - // Ideally, we'd get the span where *this specific `ty` came // from*, but right now we just use the span from the overall // value being folded. In simple cases like `-> impl Foo`, @@ -531,7 +534,7 @@ impl<'tcx> InferCtxt<'tcx> { // Foo, impl Bar)`. let span = cause.span; let prev = self.inner.borrow_mut().opaque_types().register( - OpaqueTypeKey { def_id, substs }, + opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }, origin, ); @@ -543,6 +546,26 @@ impl<'tcx> InferCtxt<'tcx> { Vec::new() }; + self.add_item_bounds_for_hidden_type( + opaque_type_key, + cause, + param_env, + hidden_ty, + &mut obligations, + ); + + Ok(InferOk { value: (), obligations }) + } + + pub fn add_item_bounds_for_hidden_type( + &self, + OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + obligations: &mut Vec<PredicateObligation<'tcx>>, + ) { + let tcx = self.tcx; let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { @@ -555,14 +578,15 @@ impl<'tcx> InferCtxt<'tcx> { // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. ty::Alias(ty::Projection, projection_ty) if !projection_ty.has_escaping_bound_vars() - && !tcx.is_impl_trait_in_trait(projection_ty.def_id) => + && !tcx.is_impl_trait_in_trait(projection_ty.def_id) + && !tcx.trait_solver_next() => { self.infer_projection( param_env, projection_ty, cause.clone(), 0, - &mut obligations, + obligations, ) } // Replace all other mentions of the same opaque type with the hidden type, @@ -588,10 +612,10 @@ impl<'tcx> InferCtxt<'tcx> { predicate.kind().skip_binder() { if projection.term.references_error() { - // No point on adding these obligations since there's a type error involved. - return Ok(InferOk { value: (), obligations: vec![] }); + // No point on adding any obligations since there's a type error involved. + obligations.clear(); + return; } - trace!("{:#?}", projection.term); } // Require that the predicate holds for the concrete type. debug!(?predicate); @@ -602,7 +626,6 @@ impl<'tcx> InferCtxt<'tcx> { predicate, )); } - Ok(InferOk { value: (), obligations }) } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index e0f29a8de8f..ceafafb5582 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -131,7 +131,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { (&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _) | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) if self.fields.define_opaque_types == DefineOpaqueTypes::Yes - && def_id.is_local() => + && def_id.is_local() + && !self.tcx().trait_solver_next() => { self.fields.obligations.extend( infcx diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c51548501ef..73f435d4840 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -996,17 +996,11 @@ impl<'tcx> Term<'tcx> { } } - /// This function returns the inner `AliasTy` if this term is a projection. - /// - /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly - /// deal with constants. - pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { + /// This function returns the inner `AliasTy` for a `ty::Alias` or `ConstKind::Unevaluated`. + pub fn to_alias_ty(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> { match self.unpack() { - TermKind::Ty(ty) => match ty.kind() { - ty::Alias(kind, alias_ty) => match kind { - AliasKind::Projection | AliasKind::Inherent => Some(*alias_ty), - AliasKind::Opaque => None, - }, + TermKind::Ty(ty) => match *ty.kind() { + ty::Alias(_kind, alias_ty) => Some(alias_ty), _ => None, }, TermKind::Const(ct) => match ct.kind() { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 32bd10f0beb..4a403196c7e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -133,12 +133,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(_, _, _) | ty::PredicateKind::ConstEvaluatable(_) - | ty::PredicateKind::TypeWellFormedFromEnv(_) | ty::PredicateKind::Ambiguous => { FulfillmentErrorCode::CodeSelectionError( SelectionError::Unimplemented, ) } + ty::PredicateKind::TypeWellFormedFromEnv(_) => { + bug!("unexpected goal: {goal:?}") + } }, root_obligation: obligation, }); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index d94679fef28..1427268f829 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -24,6 +24,7 @@ mod assembly; mod canonicalize; mod eval_ctxt; mod fulfill; +mod opaques; mod project_goals; mod search_graph; mod trait_goals; @@ -212,7 +213,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ); } - match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) { + match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) { (None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"), // RHS is not a projection, only way this is true is if LHS normalizes-to RHS diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs new file mode 100644 index 00000000000..1a770459338 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/opaques.rs @@ -0,0 +1,44 @@ +use rustc_infer::infer::InferOk; +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::traits::{ObligationCause, Reveal}; +use rustc_middle::ty::ProjectionPredicate; + +use super::{EvalCtxt, SolverMode}; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn normalize_opaque_type( + &mut self, + goal: Goal<'tcx, ProjectionPredicate<'tcx>>, + ) -> QueryResult<'tcx> { + let tcx = self.tcx(); + let opaque_ty = goal.predicate.projection_ty; + let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); + + match goal.param_env.reveal() { + Reveal::UserFacing => match self.solver_mode() { + SolverMode::Normal => self.probe(|ecx| { + // FIXME: Check that the usage is "defining" (all free params), otherwise bail. + // FIXME: This should probably just check the anchor directly + let InferOk { value: (), obligations } = self.infcx.handle_opaque_type( + expected, + tcx.mk_opaque(opaque_ty.def_id, opaque_ty.substs), + true, + &ObligationCause::dummy(), + goal.param_env, + )?; + // FIXME: Need to fold these to replace the opaque ty with the expected ty. + ecx.add_goals(obligations.into_iter().map(Into::into)); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + SolverMode::Coherence => { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + }, + Reveal::All => self.probe(|ecx| { + let actual = tcx.type_of(opaque_ty.def_id).subst(tcx, opaque_ty.substs); + ecx.eq(goal.param_env, expected, actual)?; + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }), + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index d3228074421..248b750b3bd 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -30,8 +30,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // `U` and equate it with `u32`. This means that we don't need a separate // projection cache in the solver. if self.term_is_fully_unconstrained(goal) { - let candidates = self.assemble_and_evaluate_candidates(goal); - self.merge_candidates(candidates) + match goal.predicate.projection_ty.kind(self.tcx()) { + ty::AliasKind::Projection => { + let candidates = self.assemble_and_evaluate_candidates(goal); + self.merge_candidates(candidates) + } + ty::AliasKind::Opaque => self.normalize_opaque_type(goal), + } } else { self.set_normalizes_to_hack_goal(goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 183c2401fc3..62d2aad5277 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -834,8 +834,10 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} + | ty::PredicateKind::Coerce(..) => {} + ty::PredicateKind::TypeWellFormedFromEnv(..) => { + bug!("predicate should only exist in the environment: {bound_predicate:?}") + } ty::PredicateKind::Ambiguous => return false, }; } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 2f9e480d8bd..e447ab94f64 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -679,7 +679,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { - bug!("unexpected predicate {}", &self) + bug!("unexpected predicate {self}") } }; value.map(|value| chalk_ir::Binders::new(binders, value)) |
