diff options
| author | bors <bors@rust-lang.org> | 2023-05-25 08:41:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-05-25 08:41:54 +0000 |
| commit | eb9da7bfa375ad58bcb946115f3191a2756785e5 (patch) | |
| tree | b0179deb3bd20c1475b8532f57162d6bda508410 | |
| parent | 0b011b7b7e5d1a1737aa3337f01b79fd5f56cf04 (diff) | |
| parent | dd981989726b297d46573ab5a03a661a31927c83 (diff) | |
Auto merge of #111473 - compiler-errors:opaques, r=lcnr
Handle opaques in the new solver (take 2?) Implement a new strategy for handling opaques in the new solver. First, queries now carry both their defining anchor and the opaques that were defined in the inference context at the time of canonicalization. These are both used to pre-populate the inference context used by the canonical query. Second, use the normalizes-to goal to handle opaque types in the new solver. This means that opaques are handled like projection aliases, but with their own rules: * Can only define opaques if they're "defining uses" (i.e. have unique params in all their substs). * Can only define opaques that are from the anchor. * Opaque type definitions are modulo regions. So that means `Opaque<'?0r> = HiddenTy1` and `Opaque<?'1r> = HiddenTy2` equate `HiddenTy1` and `HiddenTy2` instead of defining them as different opaque type keys.
42 files changed, 658 insertions, 189 deletions
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index dc20b371d92..d257145373f 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -4,8 +4,9 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::{Body, Promoted}; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::TyCtxt; use std::rc::Rc; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5124aa459b6..9277a262f97 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -26,7 +26,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{ - DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, + InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, }; use rustc_middle::mir::{ traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, @@ -36,6 +36,7 @@ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc_middle::query::Providers; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index e9b5c47ce23..7fc89e89a35 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -2,9 +2,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; -use rustc_infer::infer::{DefiningAnchor, InferCtxt}; use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 162828ee80b..cf204cff6b3 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -48,6 +48,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; +use crate::renumber::RegionCtxt; use crate::session_diagnostics::MoveUnsized; use crate::{ borrow_set::BorrowSet, @@ -183,6 +184,15 @@ pub(crate) fn type_check<'mir, 'tcx>( &mut borrowck_context, ); + // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering + // predefined opaques in the typeck root. + // FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since + // the HIR typeck map defining usages back to their definition params, + // they won't actually match up with the usages in this body... + if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + checker.register_predefined_opaques_in_new_solver(); + } + let mut verifier = TypeVerifier::new(&mut checker, promoted); verifier.visit_body(&body); @@ -1023,6 +1033,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { checker } + pub(super) fn register_predefined_opaques_in_new_solver(&mut self) { + // OK to use the identity substitutions for each opaque type key, since + // we remap opaques from HIR typeck back to their definition params. + let opaques: Vec<_> = self + .infcx + .tcx + .typeck(self.body.source.def_id().expect_local()) + .concrete_opaque_types + .iter() + .map(|(&def_id, &hidden_ty)| { + let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id); + (ty::OpaqueTypeKey { def_id, substs }, hidden_ty) + }) + .collect(); + + let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { + self.infcx.next_nll_region_var( + NllRegionVariableOrigin::Existential { from_forall: false }, + || RegionCtxt::Unknown, + ) + }); + + let param_env = self.param_env; + let result = self.fully_perform_op( + Locations::All(self.body.span), + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |ocx| { + for (key, hidden_ty) in renumbered_opaques { + ocx.register_infer_ok_obligations( + ocx.infcx.register_hidden_type_in_new_solver( + key, + param_env, + hidden_ty.ty, + )?, + ); + } + Ok(()) + }, + "register pre-defined opaques", + ), + ); + + if result.is_err() { + self.infcx.tcx.sess.delay_span_bug( + self.body.span, + "failed re-defining predefined opaques in mir typeck", + ); + } + } + fn body(&self) -> &Body<'tcx> { self.body } diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index f5f3d5de6b5..d6a2ffb7511 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -3,8 +3,8 @@ //! FIXME: Move this to a more general place. The utility of this extends to //! other areas of the compiler as well. -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCause; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::traits::{DefiningAnchor, ObligationCause}; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_trait_selection::traits::ObligationCtxt; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 933923f9dfc..3b2c052e8f4 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -13,11 +13,12 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{ItemKind, Node, PathSegment}; use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; use rustc_middle::middle::stability::EvalResult; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 95fb32ee1cd..294c3bb78a5 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; 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/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f8329965c43..cd99fc31212 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -24,7 +24,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::select; +use rustc_middle::traits::{select, DefiningAnchor}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -231,17 +231,6 @@ impl<'tcx> InferCtxtInner<'tcx> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum DefiningAnchor { - /// `DefId` of the item. - Bind(LocalDefId), - /// When opaque types are not resolved, we `Bubble` up, meaning - /// return the opaque/hidden type pair from query, for caller of query to handle it. - Bubble, - /// Used to catch type mismatch errors when handling opaque types. - Error, -} - pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, 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..9d5ec228d82 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,14 +1,14 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; -use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; -use crate::traits; +use crate::infer::{InferCtxt, InferOk}; +use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; use hir::OpaqueTyOrigin; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::{DefiningAnchor, ObligationCause}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::GenericArgKind; @@ -48,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,49 @@ 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 }) + } + + /// Registers an opaque's hidden type -- only should be used when the opaque + /// can be defined. For something more fallible -- checks the anchors, tries + /// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`. + pub fn register_hidden_type_in_new_solver( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + ) -> InferResult<'tcx, ()> { + assert!(self.tcx.trait_solver_next()); + let origin = self + .opaque_type_origin(opaque_type_key.def_id) + .expect("should be called for defining usages only"); + self.register_hidden_type( + opaque_type_key, + ObligationCause::dummy(), + param_env, + hidden_ty, + origin, + true, + ) + } + + pub fn add_item_bounds_for_hidden_type( + &self, + OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + hidden_ty: Ty<'tcx>, + obligations: &mut Vec<PredicateObligation<'tcx>>, + ) { + let tcx = self.tcx; let item_bounds = tcx.explicit_item_bounds(def_id); for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) { @@ -555,14 +601,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 +635,10 @@ impl<'tcx> InferCtxt<'tcx> { predicate.kind().skip_binder() { if projection.term.references_error() { - // No point on adding these obligations since there's a type error involved. - return Ok(InferOk { value: (), obligations: vec![] }); + // No point on adding any obligations since there's a type error involved. + obligations.clear(); + return; } - trace!("{:#?}", projection.term); } // Require that the predicate holds for the concrete type. debug!(?predicate); @@ -602,7 +649,6 @@ impl<'tcx> InferCtxt<'tcx> { predicate, )); } - Ok(InferOk { value: (), obligations }) } } diff --git a/compiler/rustc_infer/src/infer/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/arena.rs b/compiler/rustc_middle/src/arena.rs index 6a1a2a061dd..a149a61ec13 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -121,6 +121,7 @@ macro_rules! arena_types { >, [] bit_set_u32: rustc_index::bit_set::BitSet<u32>, [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, + [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>), [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 5b0b40cbfd9..0a903a76974 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -1108,3 +1108,14 @@ pub enum CodegenObligationError { Unimplemented, FulfillmentError, } + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub enum DefiningAnchor { + /// `DefId` of the item. + Bind(LocalDefId), + /// When opaque types are not resolved, we `Bubble` up, meaning + /// return the opaque/hidden type pair from query, for caller of query to handle it. + Bubble, + /// Used to catch type mismatch errors when handling opaque types. + Error, +} diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 1511c906d1e..2c5b64a59cd 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -5,13 +5,13 @@ use rustc_query_system::cache::Cache; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; -use crate::traits::Canonical; +use crate::traits::{Canonical, DefiningAnchor}; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; -pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>; +pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>; /// A goal is a statement, i.e. `predicate`, we want to prove /// given some assumptions, i.e. `param_env`. @@ -96,7 +96,31 @@ pub enum MaybeCause { Overflow, } -pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>; +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)] +pub struct QueryInput<'tcx, T> { + pub goal: Goal<'tcx, T>, + pub anchor: DefiningAnchor, + pub predefined_opaques_in_body: PredefinedOpaques<'tcx>, +} + +/// Additional constraints returned on success. +#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +pub struct PredefinedOpaquesData<'tcx> { + pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>); + +impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { + type Target = PredefinedOpaquesData<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>; pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>; @@ -165,3 +189,40 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { ControlFlow::Continue(()) } } + +// FIXME: Having to clone `region_constraints` for folding feels bad and +// probably isn't great wrt performance. +// +// Not sure how to fix this, maybe we should also intern `opaque_types` and +// `region_constraints` here or something. +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body( + PredefinedOpaquesData { + opaque_types: self + .opaque_types + .iter() + .map(|opaque| opaque.try_fold_with(folder)) + .collect::<Result<_, F::Error>>()?, + }, + )) + } + + fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { + TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData { + opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), + }) + } +} + +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>( + &self, + visitor: &mut V, + ) -> std::ops::ControlFlow<V::BreakTy> { + self.opaque_types.visit_with(visitor) + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 6c931a24462..2bde55bc4fd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -21,7 +21,9 @@ use crate::query::{IntoQueryParam, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve; -use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData}; +use crate::traits::solve::{ + ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, +}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, @@ -140,6 +142,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, + predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List<FieldIdx>>, } @@ -164,6 +167,7 @@ impl<'tcx> CtxtInterners<'tcx> { layout: Default::default(), adt_def: Default::default(), external_constraints: Default::default(), + predefined_opaques_in_body: Default::default(), fields: Default::default(), } } @@ -1520,6 +1524,8 @@ direct_interners! { adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>): ExternalConstraints -> ExternalConstraints<'tcx>, + predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): + PredefinedOpaques -> PredefinedOpaques<'tcx>, } macro_rules! slice_interners { 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_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index eb903ebfd99..ba05135638e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -518,6 +518,42 @@ impl<'tcx> TyCtxt<'tcx> { Ok(()) } + /// Checks whether each generic argument is simply a unique generic placeholder. + /// + /// This is used in the new solver, which canonicalizes params to placeholders + /// for better caching. + pub fn uses_unique_placeholders_ignoring_regions( + self, + substs: SubstsRef<'tcx>, + ) -> Result<(), NotUniqueParam<'tcx>> { + let mut seen = GrowableBitSet::default(); + for arg in substs { + match arg.unpack() { + // Ignore regions, since we can't resolve those in a canonicalized + // query in the trait solver. + GenericArgKind::Lifetime(_) => {} + GenericArgKind::Type(t) => match t.kind() { + ty::Placeholder(p) => { + if !seen.insert(p.bound.var) { + return Err(NotUniqueParam::DuplicateParam(t.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(t.into())), + }, + GenericArgKind::Const(c) => match c.kind() { + ty::ConstKind::Placeholder(p) => { + if !seen.insert(p.bound) { + return Err(NotUniqueParam::DuplicateParam(c.into())); + } + } + _ => return Err(NotUniqueParam::NotParam(c.into())), + }, + } + } + + Ok(()) + } + /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note /// that closures have a `DefId`, but the closure *expression* also /// has a `HirId` that is located within the context where the diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index d14e6244f7d..f32ff0442a4 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -2,7 +2,6 @@ use super::search_graph::OverflowHandler; use super::{EvalCtxt, SolverMode}; -use crate::solve::CanonicalResponseExt; use crate::traits::coherence; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; @@ -333,8 +332,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec<Candidate<'tcx>>, ) { let tcx = self.tcx(); - // FIXME: We also have to normalize opaque types, not sure where to best fit that in. - let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else { + let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return }; @@ -356,8 +354,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }), ); ecx.add_goal(normalizes_to_goal); - let _ = ecx.try_evaluate_added_goals()?; + let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { + debug!("self type normalization failed"); + })?; let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + debug!(?normalized_ty, "self type normalized"); // NOTE: Alternatively we could call `evaluate_goal` here and only // have a `Normalized` candidate. This doesn't work as long as we // use `CandidateSource` in winnowing. @@ -742,13 +743,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { SolverMode::Normal => { let param_env_responses = candidates .iter() - .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_))) + .filter(|c| { + matches!( + c.source, + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound + ) + }) .map(|c| c.result) .collect::<Vec<_>>(); if let Some(result) = self.try_merge_responses(¶m_env_responses) { - if result.has_only_region_constraints() { - return Ok(result); - } + // We strongly prefer alias and param-env bounds here, even if they affect inference. + // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11. + return Ok(result); } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 63a73f8d50d..f91c6727753 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -1,4 +1,4 @@ -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -9,7 +9,11 @@ use rustc_infer::infer::{ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; +use rustc_middle::traits::solve::{ + CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques, + PredefinedOpaquesData, QueryResult, +}; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -44,6 +48,9 @@ pub struct EvalCtxt<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, pub(super) var_values: CanonicalVarValues<'tcx>, + + predefined_opaques_in_body: PredefinedOpaques<'tcx>, + /// The highest universe index nameable by the caller. /// /// When we enter a new binder inside of the query we create new universes @@ -126,6 +133,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { let mut ecx = EvalCtxt { search_graph: &mut search_graph, infcx: self, + // Only relevant when canonicalizing the response, + // which we don't do within this evaluation context. + predefined_opaques_in_body: self + .tcx + .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), // Only relevant when canonicalizing the response. max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), @@ -162,29 +174,53 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { fn evaluate_canonical_goal( tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<'tcx>, - canonical_goal: CanonicalGoal<'tcx>, + canonical_input: CanonicalInput<'tcx>, ) -> QueryResult<'tcx> { // Deal with overflow, caching, and coinduction. // // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { + search_graph.with_new_goal(tcx, canonical_input, |search_graph| { let intercrate = match search_graph.solver_mode() { SolverMode::Normal => false, SolverMode::Coherence => true, }; - let (ref infcx, goal, var_values) = tcx + let (ref infcx, input, var_values) = tcx .infer_ctxt() .intercrate(intercrate) - .build_with_canonical(DUMMY_SP, &canonical_goal); + .with_opaque_type_inference(canonical_input.value.anchor) + .build_with_canonical(DUMMY_SP, &canonical_input); + + for &(a, b) in &input.predefined_opaques_in_body.opaque_types { + let InferOk { value: (), obligations } = infcx + .register_hidden_type_in_new_solver(a, input.goal.param_env, b) + .expect("expected opaque type instantiation to succeed"); + // We're only registering opaques already defined by the caller, + // so we're not responsible for proving that they satisfy their + // item bounds, unless we use them in a normalizes-to goal, + // which is handled in `EvalCtxt::unify_existing_opaque_tys`. + let _ = obligations; + } let mut ecx = EvalCtxt { infcx, var_values, - max_input_universe: canonical_goal.max_universe, + predefined_opaques_in_body: input.predefined_opaques_in_body, + max_input_universe: canonical_input.max_universe, search_graph, nested_goals: NestedGoals::new(), tainted: Ok(()), }; - ecx.compute_goal(goal) + + let result = ecx.compute_goal(input.goal); + + // When creating a query response we clone the opaque type constraints + // instead of taking them. This would cause an ICE here, since we have + // assertions against dropping an `InferCtxt` without taking opaques. + // FIXME: Once we remove support for the old impl we can remove this. + if input.anchor != DefiningAnchor::Error { + let _ = infcx.take_opaque_types(); + } + + result }) } @@ -199,7 +235,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; - let has_changed = !canonical_response.value.var_values.is_identity(); + let has_changed = !canonical_response.value.var_values.is_identity() + || !canonical_response.value.external_constraints.opaque_types.is_empty(); let (certainty, nested_goals) = self.instantiate_and_apply_query_response( goal.param_env, orig_values, @@ -418,6 +455,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let mut ecx = EvalCtxt { infcx: self.infcx, var_values: self.var_values, + predefined_opaques_in_body: self.predefined_opaques_in_body, max_input_universe: self.max_input_universe, search_graph: self.search_graph, nested_goals: self.nested_goals.clone(), @@ -682,4 +720,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | rustc_transmute::Answer::IfAny(_) => Err(NoSolution), } } + + pub(super) fn can_define_opaque_ty(&mut self, def_id: LocalDefId) -> bool { + self.infcx.opaque_type_origin(def_id).is_some() + } + + pub(super) fn register_opaque_ty( + &mut self, + a: ty::OpaqueTypeKey<'tcx>, + b: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Result<(), NoSolution> { + let InferOk { value: (), obligations } = + self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?; + self.add_goals(obligations.into_iter().map(|obligation| obligation.into())); + Ok(()) + } + + // Do something for each opaque/hidden pair defined with `def_id` in the + // current inference context. + pub(super) fn unify_existing_opaque_tys( + &mut self, + param_env: ty::ParamEnv<'tcx>, + key: ty::OpaqueTypeKey<'tcx>, + ty: Ty<'tcx>, + ) -> Vec<CanonicalResponse<'tcx>> { + // FIXME: Super inefficient to be cloning this... + let opaques = self.infcx.clone_opaque_types_for_query_response(); + + let mut values = vec![]; + for (candidate_key, candidate_ty) in opaques { + if candidate_key.def_id != key.def_id { + continue; + } + values.extend(self.probe(|ecx| { + for (a, b) in std::iter::zip(candidate_key.substs, key.substs) { + ecx.eq(param_env, a, b)?; + } + ecx.eq(param_env, candidate_ty, ty)?; + let mut obl = vec![]; + ecx.infcx.add_item_bounds_for_hidden_type( + candidate_key, + ObligationCause::dummy(), + param_env, + candidate_ty, + &mut obl, + ); + ecx.add_goals(obl.into_iter().map(Into::into)); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + })); + } + values + } } 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 67ad7fb4bd2..fdb209fbff8 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -8,16 +8,19 @@ /// section of the [rustc-dev-guide][c]. /// /// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; +use super::{CanonicalInput, Certainty, EvalCtxt, Goal}; use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer}; use crate::solve::{CanonicalResponse, QueryResult, Response}; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; +use rustc_infer::infer::InferOk; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData, MaybeCause}; -use rustc_middle::ty::{self, BoundVar, GenericArgKind}; +use rustc_middle::traits::solve::{ + ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, +}; +use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty}; use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; @@ -28,13 +31,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn canonicalize_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalGoal<'tcx>) { + ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) { let mut orig_values = Default::default(); let canonical_goal = Canonicalizer::canonicalize( self.infcx, CanonicalizeMode::Input, &mut orig_values, - goal, + QueryInput { + goal, + anchor: self.infcx.defining_use_anchor, + predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body( + PredefinedOpaquesData { + opaque_types: self.infcx.clone_opaque_types_for_query_response(), + }, + ), + }, ); (orig_values, canonical_goal) } @@ -138,7 +149,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { region_constraints, ) }); - let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + + let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); + // Only return opaque type keys for newly-defined opaques + opaque_types.retain(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }); + Ok(self .tcx() .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) @@ -164,10 +181,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?; - // FIXME: implement external constraints. - let ExternalConstraintsData { region_constraints, opaque_types: _ } = + let ExternalConstraintsData { region_constraints, opaque_types } = external_constraints.deref(); self.register_region_constraints(region_constraints); + self.register_opaque_types(param_env, opaque_types)?; Ok((certainty, nested_goals)) } @@ -287,4 +304,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let _ = member_constraint; } } + + fn register_opaque_types( + &mut self, + param_env: ty::ParamEnv<'tcx>, + opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], + ) -> Result<(), NoSolution> { + for &(a, b) in opaque_types { + let InferOk { value: (), obligations } = + self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?; + // It's sound to drop these obligations, since the normalizes-to goal + // is responsible for proving these obligations. + let _ = obligations; + } + Ok(()) + } } 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..26ace28f5fd 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 @@ -238,34 +239,34 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(), ); // Relate via substs - candidates.extend( - self.probe(|ecx| { - let span = tracing::span!( - tracing::Level::DEBUG, - "compute_alias_relate_goal(relate_via_substs)", - ?alias_lhs, - ?alias_rhs, - ?direction - ); - let _enter = span.enter(); - - match direction { - ty::AliasRelationDirection::Equate => { - ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; - } - ty::AliasRelationDirection::Subtype => { - ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; - } + let subst_relate_response = self.probe(|ecx| { + let span = tracing::span!( + tracing::Level::DEBUG, + "compute_alias_relate_goal(relate_via_substs)", + ?alias_lhs, + ?alias_rhs, + ?direction + ); + let _enter = span.enter(); + + match direction { + ty::AliasRelationDirection::Equate => { + ecx.eq(goal.param_env, alias_lhs, alias_rhs)?; + } + ty::AliasRelationDirection::Subtype => { + ecx.sub(goal.param_env, alias_lhs, alias_rhs)?; } + } - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }) - .ok(), - ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }); + candidates.extend(subst_relate_response); debug!(?candidates); if let Some(merged) = self.try_merge_responses(&candidates) { Ok(merged) + } else if let Ok(subst_relate_response) = subst_relate_response { + Ok(subst_relate_response) } else { self.flounder(&candidates) } 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..a5de4ddee82 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/opaques.rs @@ -0,0 +1,67 @@ +use rustc_middle::traits::query::NoSolution; +use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; +use rustc_middle::traits::Reveal; +use rustc_middle::ty; +use rustc_middle::ty::util::NotUniqueParam; + +use super::{EvalCtxt, SolverMode}; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + pub(super) fn normalize_opaque_type( + &mut self, + goal: Goal<'tcx, ty::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(), self.solver_mode()) { + (Reveal::UserFacing, SolverMode::Normal) => { + let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { + return Err(NoSolution); + }; + let opaque_ty = + ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs }; + // 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) { + return Err(NoSolution); + } + // FIXME: This may have issues when the substs contain aliases... + match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.substs) { + Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { + return self.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + Err(_) => { + return Err(NoSolution); + } + Ok(()) => {} + } + // Prefer opaques registered already. + let matches = self.unify_existing_opaque_tys(goal.param_env, opaque_ty, expected); + if !matches.is_empty() { + if let Some(response) = self.try_merge_responses(&matches) { + return Ok(response); + } else { + return self.flounder(&matches); + } + } + // Otherwise, define a new opaque type + self.register_opaque_ty(opaque_ty, expected, goal.param_env)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + (Reveal::UserFacing, SolverMode::Coherence) => { + 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).subst(tcx, opaque_ty.substs); + 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/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index d3228074421..7d7dfa2c837 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -22,19 +22,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - // To only compute normalization once for each projection we only - // normalize if the expected term is an unconstrained inference variable. - // - // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal - // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for - // `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) - } else { - self.set_normalizes_to_hack_goal(goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + match goal.predicate.projection_ty.kind(self.tcx()) { + ty::AliasKind::Projection => { + // To only compute normalization once for each projection we only + // normalize if the expected term is an unconstrained inference variable. + // + // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal + // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for + // `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) + } else { + self.set_normalizes_to_hack_goal(goal); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + ty::AliasKind::Opaque => self.normalize_opaque_type(goal), + ty::AliasKind::Inherent => bug!("IATs not supported here yet"), } } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs index e6941af7b57..56f126e9157 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs @@ -11,7 +11,7 @@ use super::StackDepth; use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; -use rustc_middle::traits::solve::{CanonicalGoal, QueryResult}; +use rustc_middle::traits::solve::{CanonicalInput, QueryResult}; rustc_index::newtype_index! { pub struct EntryIndex {} @@ -34,7 +34,7 @@ pub(super) struct ProvisionalEntry<'tcx> { // The goal for this entry. Should always be equal to the corresponding goal // in the lookup table. - pub(super) goal: CanonicalGoal<'tcx>, + pub(super) input: CanonicalInput<'tcx>, } pub(super) struct ProvisionalCache<'tcx> { @@ -42,7 +42,7 @@ pub(super) struct ProvisionalCache<'tcx> { // FIXME: This is only used to quickly check whether a given goal // is in the cache. We should experiment with using something like // `SsoHashSet` here because in most cases there are only a few entries. - pub(super) lookup_table: FxHashMap<CanonicalGoal<'tcx>, EntryIndex>, + pub(super) lookup_table: FxHashMap<CanonicalInput<'tcx>, EntryIndex>, } impl<'tcx> ProvisionalCache<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index c1904352574..19e4b23009a 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -8,7 +8,7 @@ use cache::ProvisionalCache; use overflow::OverflowData; use rustc_index::IndexVec; use rustc_middle::dep_graph::DepKind; -use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult}; +use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryResult}; use rustc_middle::ty::TyCtxt; use std::{collections::hash_map::Entry, mem}; @@ -19,7 +19,7 @@ rustc_index::newtype_index! { } struct StackElem<'tcx> { - goal: CanonicalGoal<'tcx>, + input: CanonicalInput<'tcx>, has_been_used: bool, } @@ -77,7 +77,7 @@ impl<'tcx> SearchGraph<'tcx> { } // ...or it depends on a goal with a lower depth. - let current_goal = self.stack[stack_depth].goal; + let current_goal = self.stack[stack_depth].input; let entry_index = self.provisional_cache.lookup_table[¤t_goal]; self.provisional_cache.entries[entry_index].depth != stack_depth } else { @@ -92,20 +92,20 @@ impl<'tcx> SearchGraph<'tcx> { fn try_push_stack( &mut self, tcx: TyCtxt<'tcx>, - goal: CanonicalGoal<'tcx>, + input: CanonicalInput<'tcx>, ) -> Result<(), QueryResult<'tcx>> { // Look at the provisional cache to check for cycles. let cache = &mut self.provisional_cache; - match cache.lookup_table.entry(goal) { + match cache.lookup_table.entry(input) { // No entry, simply push this goal on the stack after dealing with overflow. Entry::Vacant(v) => { if self.overflow_data.has_overflow(self.stack.len()) { - return Err(self.deal_with_overflow(tcx, goal)); + return Err(self.deal_with_overflow(tcx, input)); } - let depth = self.stack.push(StackElem { goal, has_been_used: false }); - let response = super::response_no_constraints(tcx, goal, Certainty::Yes); - let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal }); + let depth = self.stack.push(StackElem { input, has_been_used: false }); + let response = super::response_no_constraints(tcx, input, Certainty::Yes); + let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input }); v.insert(entry_index); Ok(()) } @@ -135,13 +135,13 @@ impl<'tcx> SearchGraph<'tcx> { // the stack is enough. if self.stack.raw[stack_depth.index()..] .iter() - .all(|g| g.goal.value.predicate.is_coinductive(tcx)) + .all(|g| g.input.value.goal.predicate.is_coinductive(tcx)) { Err(cache.provisional_result(entry_index)) } else { Err(super::response_no_constraints( tcx, - goal, + input, Certainty::Maybe(MaybeCause::Overflow), )) } @@ -161,18 +161,18 @@ impl<'tcx> SearchGraph<'tcx> { /// updated the provisional cache and we have to recompute the current goal. /// /// FIXME: Refer to the rustc-dev-guide entry once it exists. - #[instrument(level = "debug", skip(self, actual_goal), ret)] + #[instrument(level = "debug", skip(self, actual_input), ret)] fn try_finalize_goal( &mut self, - actual_goal: CanonicalGoal<'tcx>, + actual_input: CanonicalInput<'tcx>, response: QueryResult<'tcx>, ) -> bool { let stack_elem = self.stack.pop().unwrap(); - let StackElem { goal, has_been_used } = stack_elem; - assert_eq!(goal, actual_goal); + let StackElem { input, has_been_used } = stack_elem; + assert_eq!(input, actual_input); let cache = &mut self.provisional_cache; - let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap(); + let provisional_entry_index = *cache.lookup_table.get(&input).unwrap(); let provisional_entry = &mut cache.entries[provisional_entry_index]; // We eagerly update the response in the cache here. If we have to reevaluate // this goal we use the new response when hitting a cycle, and we definitely @@ -194,7 +194,7 @@ impl<'tcx> SearchGraph<'tcx> { cache.entries.truncate(provisional_entry_index.index() + 1); // ...and finally push our goal back on the stack and reevaluate it. - self.stack.push(StackElem { goal, has_been_used: false }); + self.stack.push(StackElem { input, has_been_used: false }); false } else { true @@ -204,17 +204,17 @@ impl<'tcx> SearchGraph<'tcx> { pub(super) fn with_new_goal( &mut self, tcx: TyCtxt<'tcx>, - canonical_goal: CanonicalGoal<'tcx>, + canonical_input: CanonicalInput<'tcx>, mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>, ) -> QueryResult<'tcx> { if self.should_use_global_cache() { - if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) { - debug!(?canonical_goal, ?result, "cache hit"); + if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) { + debug!(?canonical_input, ?result, "cache hit"); return result; } } - match self.try_push_stack(tcx, canonical_goal) { + match self.try_push_stack(tcx, canonical_input) { Ok(()) => {} // Our goal is already on the stack, eager return. Err(response) => return response, @@ -226,19 +226,19 @@ impl<'tcx> SearchGraph<'tcx> { let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || { self.repeat_while_none( |this| { - let result = this.deal_with_overflow(tcx, canonical_goal); + let result = this.deal_with_overflow(tcx, canonical_input); let _ = this.stack.pop().unwrap(); result }, |this| { let result = loop_body(this); - this.try_finalize_goal(canonical_goal, result).then(|| result) + this.try_finalize_goal(canonical_input, result).then(|| result) }, ) }); let cache = &mut self.provisional_cache; - let provisional_entry_index = *cache.lookup_table.get(&canonical_goal).unwrap(); + let provisional_entry_index = *cache.lookup_table.get(&canonical_input).unwrap(); let provisional_entry = &mut cache.entries[provisional_entry_index]; let depth = provisional_entry.depth; @@ -254,13 +254,13 @@ impl<'tcx> SearchGraph<'tcx> { // cycle participants without moving them to the global cache. let other_cycle_participants = provisional_entry_index.index() + 1; for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) { - let actual_index = cache.lookup_table.remove(&entry.goal); + let actual_index = cache.lookup_table.remove(&entry.input); debug_assert_eq!(Some(i), actual_index); debug_assert!(entry.depth == depth); } let current_goal = cache.entries.pop().unwrap(); - let actual_index = cache.lookup_table.remove(¤t_goal.goal); + let actual_index = cache.lookup_table.remove(¤t_goal.input); debug_assert_eq!(Some(provisional_entry_index), actual_index); debug_assert!(current_goal.depth == depth); @@ -274,7 +274,7 @@ impl<'tcx> SearchGraph<'tcx> { let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty(); if self.should_use_global_cache() && can_cache { tcx.new_solver_evaluation_cache.insert( - current_goal.goal, + current_goal.input, dep_node, current_goal.response, ); 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_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index aacbfbd3c87..e8c5a8fab2a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,9 +17,10 @@ use crate::traits::{ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor}; 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)) diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 6f81d343e0f..ddba03b0b12 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -3,9 +3,9 @@ // seems likely that they should eventually be merged into more // general routines. -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; -use rustc_middle::traits::CodegenObligationError; +use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::{ diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 149dffc7e31..f5b2753b797 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,5 +1,6 @@ -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; +use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; @@ -15,6 +16,7 @@ fn evaluate_obligation<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalPredicateGoal<'tcx>, ) -> Result<EvaluationResult, OverflowError> { + assert!(!tcx.trait_solver_next()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); // HACK This bubble is required for this tests to pass: // impl-trait/issue99642.rs diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 70dc7ccec63..b1cbd88ce27 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -1,8 +1,8 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCauseCode; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; +use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; diff --git a/tests/ui/dyn-star/param-env-infer.current.stderr b/tests/ui/dyn-star/param-env-infer.current.stderr index d0785c887d8..b3af7be7950 100644 --- a/tests/ui/dyn-star/param-env-infer.current.stderr +++ b/tests/ui/dyn-star/param-env-infer.current.stderr @@ -8,7 +8,7 @@ LL | #![feature(dyn_star, pointer_like_trait)] = note: `#[warn(incomplete_features)]` on by default error[E0282]: type annotations needed - --> $DIR/param-env-infer.rs:12:10 + --> $DIR/param-env-infer.rs:13:10 | LL | t as _ | ^ cannot infer type diff --git a/tests/ui/dyn-star/param-env-infer.next.stderr b/tests/ui/dyn-star/param-env-infer.next.stderr index d0785c887d8..64d76bb04b1 100644 --- a/tests/ui/dyn-star/param-env-infer.next.stderr +++ b/tests/ui/dyn-star/param-env-infer.next.stderr @@ -7,12 +7,67 @@ LL | #![feature(dyn_star, pointer_like_trait)] = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0282]: type annotations needed - --> $DIR/param-env-infer.rs:12:10 +error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}` + --> $DIR/param-env-infer.rs:11:60 | -LL | t as _ - | ^ cannot infer type +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires borrow-checking `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires promoting constants in MIR for `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires preparing `make_dyn_star` for borrow checking... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires match-checking `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building THIR for `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `make_dyn_star`... + --> $DIR/param-env-infer.rs:11:1 + | +LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`... + = note: ...which requires normalizing `make_dyn_star::{opaque#0}`... + = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/param-env-infer.rs:5:1 + | +LL | / #![feature(dyn_star, pointer_like_trait)] +LL | | +LL | | +LL | | use std::fmt::Debug; +... | +LL | | +LL | | fn main() {} + | |____________^ error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/dyn-star/param-env-infer.rs b/tests/ui/dyn-star/param-env-infer.rs index 9039dde5e93..1fb16d76853 100644 --- a/tests/ui/dyn-star/param-env-infer.rs +++ b/tests/ui/dyn-star/param-env-infer.rs @@ -9,8 +9,9 @@ use std::fmt::Debug; use std::marker::PointerLike; fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { + //[next]~^ ERROR cycle detected when computing type of `make_dyn_star::{opaque#0}` t as _ - //~^ ERROR type annotations needed + //[current]~^ ERROR type annotations needed } fn main() {} diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs index 531203d9c64..3c7fc7403b1 100644 --- a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs +++ b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs @@ -1,5 +1,8 @@ // compile-flags: -Ztrait-solver=next +// check-pass +// (should not pass, should be turned into a coherence-only test) + // check that when computing `alias-eq(<() as Foo<u16, T>>::Assoc, <() as Foo<?0, T>>::Assoc)` // we do not infer `?0 = u8` via the `for<STOP> (): Foo<u8, STOP>` impl or `?0 = u16` by // relating substs as either could be a valid solution. @@ -36,7 +39,6 @@ where { // `<() as Foo<u16, STOP>>::Assoc == <() as Foo<_, STOP>>::Assoc` let _: <() as Foo<u16, T>>::Assoc = output::<_, T>(); - //~^ error: type annotations needed // let _: <() as Foo<u16, T>>::Assoc = output::<u8, T>(); // OK // let _: <() as Foo<u16, T>>::Assoc = output::<u16, T>(); // OK diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr deleted file mode 100644 index a6712332c37..00000000000 --- a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/alias_eq_dont_use_normalizes_to_if_substs_eq.rs:38:41 - | -LL | let _: <() as Foo<u16, T>>::Assoc = output::<_, T>(); - | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `output` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs index d4cc380fa21..b036411be83 100644 --- a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs +++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs @@ -1,5 +1,8 @@ // compile-flags: -Ztrait-solver=next +// check-pass +// (should not pass, should be turned into a coherence-only test) + // check that a `alias-eq(<?0 as TraitB>::Assoc, <T as TraitB>::Assoc)` goal fails. // FIXME(deferred_projection_equality): add a test that this is true during coherence @@ -14,7 +17,6 @@ fn needs_a<T: TraitB>() -> T::Assoc { fn bar<T: TraitB>() { let _: <_ as TraitB>::Assoc = needs_a::<T>(); - //~^ error: type annotations needed } fn main() {} diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr deleted file mode 100644 index d063d8fce11..00000000000 --- a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0282]: type annotations needed - --> $DIR/alias_eq_substs_eq_not_intercrate.rs:16:12 - | -LL | let _: <_ as TraitB>::Assoc = needs_a::<T>(); - | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for associated type `<_ as TraitB>::Assoc` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0282`. |
