diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:32 +0000 |
commit | 4547b622d8d29df964fa2914213088b148c498fc (patch) | |
tree | 9fc6b25f3c3add6b745be9a2400a6e96140046e9 /compiler/rustc_traits | |
parent | Releasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz rustc-4547b622d8d29df964fa2914213088b148c498fc.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_traits')
-rw-r--r-- | compiler/rustc_traits/Cargo.toml | 7 | ||||
-rw-r--r-- | compiler/rustc_traits/src/chalk/db.rs | 43 | ||||
-rw-r--r-- | compiler/rustc_traits/src/chalk/lowering.rs | 127 | ||||
-rw-r--r-- | compiler/rustc_traits/src/codegen.rs | 88 | ||||
-rw-r--r-- | compiler/rustc_traits/src/dropck_outlives.rs | 209 | ||||
-rw-r--r-- | compiler/rustc_traits/src/evaluate_obligation.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_traits/src/implied_outlives_bounds.rs | 49 | ||||
-rw-r--r-- | compiler/rustc_traits/src/lib.rs | 3 | ||||
-rw-r--r-- | compiler/rustc_traits/src/normalize_erasing_regions.rs | 16 | ||||
-rw-r--r-- | compiler/rustc_traits/src/normalize_projection_ty.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_traits/src/type_op.rs | 229 |
11 files changed, 398 insertions, 382 deletions
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 951554c77..a432498ab 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -12,9 +12,10 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } -chalk-ir = "0.80.0" -chalk-engine = "0.80.0" -chalk-solve = "0.80.0" +rustc_target = { path = "../rustc_target" } +chalk-ir = "0.87.0" +chalk-engine = "0.87.0" +chalk-solve = "0.87.0" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_infer = { path = "../rustc_infer" } rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 0de28b826..344c8b93c 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -9,9 +9,9 @@ use rustc_middle::traits::ChalkRustInterner as RustInterner; use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; +use rustc_target::abi::{Integer, IntegerType}; use rustc_ast::ast; -use rustc_attr as attr; use rustc_hir::def_id::DefId; @@ -142,6 +142,8 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t Some(CoerceUnsized) } else if lang_items.dispatch_from_dyn_trait() == Some(def_id) { Some(DispatchFromDyn) + } else if lang_items.tuple_trait() == Some(def_id) { + Some(Tuple) } else { None }; @@ -216,21 +218,21 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t c: adt_def.repr().c(), packed: adt_def.repr().packed(), int: adt_def.repr().int.map(|i| match i { - attr::IntType::SignedInt(ty) => match ty { - ast::IntTy::Isize => int(chalk_ir::IntTy::Isize), - ast::IntTy::I8 => int(chalk_ir::IntTy::I8), - ast::IntTy::I16 => int(chalk_ir::IntTy::I16), - ast::IntTy::I32 => int(chalk_ir::IntTy::I32), - ast::IntTy::I64 => int(chalk_ir::IntTy::I64), - ast::IntTy::I128 => int(chalk_ir::IntTy::I128), + IntegerType::Pointer(true) => int(chalk_ir::IntTy::Isize), + IntegerType::Pointer(false) => uint(chalk_ir::UintTy::Usize), + IntegerType::Fixed(i, true) => match i { + Integer::I8 => int(chalk_ir::IntTy::I8), + Integer::I16 => int(chalk_ir::IntTy::I16), + Integer::I32 => int(chalk_ir::IntTy::I32), + Integer::I64 => int(chalk_ir::IntTy::I64), + Integer::I128 => int(chalk_ir::IntTy::I128), }, - attr::IntType::UnsignedInt(ty) => match ty { - ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize), - ast::UintTy::U8 => uint(chalk_ir::UintTy::U8), - ast::UintTy::U16 => uint(chalk_ir::UintTy::U16), - ast::UintTy::U32 => uint(chalk_ir::UintTy::U32), - ast::UintTy::U64 => uint(chalk_ir::UintTy::U64), - ast::UintTy::U128 => uint(chalk_ir::UintTy::U128), + IntegerType::Fixed(i, false) => match i { + Integer::I8 => uint(chalk_ir::UintTy::U8), + Integer::I16 => uint(chalk_ir::UintTy::U16), + Integer::I32 => uint(chalk_ir::UintTy::U32), + Integer::I64 => uint(chalk_ir::UintTy::U64), + Integer::I128 => uint(chalk_ir::UintTy::U128), }, }), }) @@ -570,6 +572,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t CoerceUnsized => lang_items.coerce_unsized_trait(), DiscriminantKind => lang_items.discriminant_kind_trait(), DispatchFromDyn => lang_items.dispatch_from_dyn_trait(), + Tuple => lang_items.tuple_trait(), }; def_id.map(chalk_ir::TraitId) } @@ -728,16 +731,16 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx ty::GenericParamDefKind::Lifetime => { let br = ty::BoundRegion { var: ty::BoundVar::from_usize(substs.len()), - kind: ty::BrAnon(substs.len() as u32), + kind: ty::BrAnon(substs.len() as u32, None), }; tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() } ty::GenericParamDefKind::Const { .. } => tcx - .mk_const(ty::ConstS { - kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), - ty: tcx.type_of(param.def_id), - }) + .mk_const( + ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)), + tcx.type_of(param.def_id), + ) .into(), }) } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 45d5ea93d..c4ab86e9e 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -89,24 +89,32 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' ty::PredicateKind::TypeWellFormedFromEnv(ty) => { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) } - ty::PredicateKind::Trait(predicate) => chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), - ), - ty::PredicateKind::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - ), - ty::PredicateKind::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { - ty: predicate.0.lower_into(interner), - lifetime: predicate.1.lower_into(interner), - }), - ), - ty::PredicateKind::Projection(predicate) => chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), - ), + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Trait( + predicate.trait_ref.lower_into(interner), + )) + } + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { + chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::LifetimeOutlives( + chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }, + )) + } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { + chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::TypeOutlives( + chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }, + )) + } + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq( + predicate.lower_into(interner), + )) + } ty::PredicateKind::WellFormed(arg) => match arg.unpack() { ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed( chalk_ir::WellFormed::Ty(ty.lower_into(interner)), @@ -121,6 +129,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate), }; let value = chalk_ir::ProgramClauseImplication { @@ -148,12 +157,12 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi collect_bound_vars(interner, interner.tcx, self.kind()); let value = match predicate { - ty::PredicateKind::Trait(predicate) => { + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), )) } - ty::PredicateKind::RegionOutlives(predicate) => { + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), @@ -161,7 +170,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi }), )) } - ty::PredicateKind::TypeOutlives(predicate) => { + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), @@ -169,7 +178,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi }), )) } - ty::PredicateKind::Projection(predicate) => { + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), )) @@ -212,6 +221,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } @@ -411,7 +421,11 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> { TyKind::Closure(closure, substitution) => { ty::Closure(closure.0, substitution.lower_into(interner)) } - TyKind::Generator(..) => unimplemented!(), + TyKind::Generator(generator, substitution) => ty::Generator( + generator.0, + substitution.lower_into(interner), + ast::Movability::Static, + ), TyKind::GeneratorWitness(..) => unimplemented!(), TyKind::Never => ty::Never, TyKind::Tuple(_len, substitution) => { @@ -498,18 +512,15 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t ty::DebruijnIndex::from_u32(var.debruijn.depth()), ty::BoundRegion { var: ty::BoundVar::from_usize(var.index), - kind: ty::BrAnon(var.index as u32), + kind: ty::BrAnon(var.index as u32, None), }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder { universe: ty::UniverseIndex::from_usize(p.ui.counter), - name: ty::BoundRegionKind::BrAnon(p.idx as u32), + name: ty::BoundRegionKind::BrAnon(p.idx as u32, None), }), chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static, - chalk_ir::LifetimeData::Empty(_) => { - bug!("Chalk should not have been passed an empty lifetime.") - } chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased, chalk_ir::LifetimeData::Phantom(void, _) => match *void {}, }; @@ -546,7 +557,7 @@ impl<'tcx> LowerInto<'tcx, ty::Const<'tcx>> for &chalk_ir::Const<RustInterner<'t chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(), chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned), }; - interner.tcx.mk_const(ty::ConstS { ty, kind }) + interner.tcx.mk_const(kind, ty) } } @@ -602,22 +613,22 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, self.kind()); let value = match predicate { - ty::PredicateKind::Trait(predicate) => { + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } - ty::PredicateKind::RegionOutlives(predicate) => { + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => { Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { a: predicate.0.lower_into(interner), b: predicate.1.lower_into(interner), })) } - ty::PredicateKind::TypeOutlives(predicate) => { + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(predicate)) => { Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { ty: predicate.0.lower_into(interner), lifetime: predicate.1.lower_into(interner), })) } - ty::PredicateKind::Projection(predicate) => { + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } ty::PredicateKind::WellFormed(_ty) => None, @@ -628,6 +639,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } @@ -637,7 +649,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' } impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>> - for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> + for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { fn lower_into( self, @@ -692,7 +704,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru trait_id: chalk_ir::TraitId(def_id), substitution: interner .tcx - .mk_substs_trait(self_ty, &[]) + .mk_substs_trait(self_ty, []) .lower_into(interner), }), ), @@ -737,26 +749,31 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, self.kind()); match predicate { - ty::PredicateKind::Trait(predicate) => Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::TraitBound( - predicate.trait_ref.lower_into(interner), - ), - )), - ty::PredicateKind::Projection(predicate) => Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), - )), - ty::PredicateKind::TypeOutlives(_predicate) => None, + ty::PredicateKind::Clause(ty::Clause::Trait(predicate)) => { + Some(chalk_ir::Binders::new( + binders, + chalk_solve::rust_ir::InlineBound::TraitBound( + predicate.trait_ref.lower_into(interner), + ), + )) + } + ty::PredicateKind::Clause(ty::Clause::Projection(predicate)) => { + Some(chalk_ir::Binders::new( + binders, + chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), + )) + } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_predicate)) => None, ty::PredicateKind::WellFormed(_ty) => None, - ty::PredicateKind::RegionOutlives(..) + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("unexpected predicate {}", &self) } @@ -933,7 +950,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } } - ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) { + ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) { Entry::Vacant(entry) => { entry.insert(chalk_ir::VariableKind::Lifetime); } @@ -991,13 +1008,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { ty::ReLateBound(index, br) if index == self.binder_index => match br.kind { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { Some(idx) => { - let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) }; + let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) }; return self.tcx.mk_region(ty::ReLateBound(index, new_br)); } None => panic!("Missing `BrNamed`."), }, ty::BrEnv => unimplemented!(), - ty::BrAnon(_) => {} + ty::BrAnon(..) => {} }, _ => (), }; @@ -1072,14 +1089,16 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { Some(idx) => { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(*idx), - kind: ty::BrAnon(*idx), + kind: ty::BrAnon(*idx, None), }; self.tcx.mk_region(ty::ReLateBound(self.binder_index, br)) } None => { let idx = self.named_regions.len() as u32; - let br = - ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) }; + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(idx), + kind: ty::BrAnon(idx, None), + }; self.named_regions.insert(_re.def_id, idx); self.tcx.mk_region(ty::ReLateBound(self.binder_index, br)) } @@ -1156,7 +1175,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> { match *r { ty::RePlaceholder(p) if p.universe == self.universe_index => { - if let ty::BoundRegionKind::BrAnon(anon) = p.name { + if let ty::BoundRegionKind::BrAnon(anon, _) = p.name { self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); } } diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs new file mode 100644 index 000000000..f8f74b732 --- /dev/null +++ b/compiler/rustc_traits/src/codegen.rs @@ -0,0 +1,88 @@ +// This file contains various trait resolution methods used by codegen. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::traits::FulfillmentErrorCode; +use rustc_middle::traits::CodegenObligationError; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; +use rustc_trait_selection::traits::{ + ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt, + Unimplemented, +}; + +/// Attempts to resolve an obligation to an `ImplSource`. The result is +/// a shallow `ImplSource` resolution, meaning that we do not +/// (necessarily) resolve all nested obligations on the impl. Note +/// that type check should guarantee to us that all nested +/// obligations *could be* resolved if we wanted to. +/// +/// This also expects that `trait_ref` is fully normalized. +pub fn codegen_select_candidate<'tcx>( + tcx: TyCtxt<'tcx>, + (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), +) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { + // We expect the input to be fully normalized. + debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_opaque_type_inference(DefiningAnchor::Bubble) + .build(); + //~^ HACK `Bubble` is required for + // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) + } + }; + + debug!(?selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx); + let impl_source = selection.map(|predicate| { + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + // `rustc_monomorphize::collector` assumes there are no type errors. + // Cycle errors are the only post-monomorphization errors possible; emit them now so + // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. + for err in errors { + if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); + } + } + return Err(CodegenObligationError::FulfillmentError); + } + + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); + + // Opaque types may have gotten their hidden types constrained, but we can ignore them safely + // as they will get constrained elsewhere, too. + // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass + let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); + + Ok(&*tcx.arena.alloc(impl_source)) +} diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index d5a8ca5ea..66ab742f1 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -2,20 +2,18 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; use rustc_trait_selection::traits::query::dropck_outlives::{ DropckConstraint, DropckOutlivesResult, }; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc_trait_selection::traits::{ - Normalized, ObligationCause, TraitEngine, TraitEngineExt as _, -}; +use rustc_trait_selection::traits::{Normalized, ObligationCause}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; @@ -27,120 +25,109 @@ fn dropck_outlives<'tcx>( ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", canonical_goal); - let (ref infcx, goal, canonical_inference_vars) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let tcx = infcx.tcx; - let ParamEnvAnd { param_env, value: for_ty } = goal; - - let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; - - // A stack of types left to process. Each round, we pop - // something from the stack and invoke - // `dtorck_constraint_for_ty`. This may produce new types that - // have to be pushed on the stack. This continues until we have explored - // all the reachable types from the type `for_ty`. - // - // Example: Imagine that we have the following code: - // - // ```rust - // struct A { - // value: B, - // children: Vec<A>, - // } - // - // struct B { - // value: u32 - // } - // - // fn f() { - // let a: A = ...; - // .. - // } // here, `a` is dropped - // ``` - // - // at the point where `a` is dropped, we need to figure out - // which types inside of `a` contain region data that may be - // accessed by any destructors in `a`. We begin by pushing `A` - // onto the stack, as that is the type of `a`. We will then - // invoke `dtorck_constraint_for_ty` which will expand `A` - // into the types of its fields `(B, Vec<A>)`. These will get - // pushed onto the stack. Eventually, expanding `Vec<A>` will - // lead to us trying to push `A` a second time -- to prevent - // infinite recursion, we notice that `A` was already pushed - // once and stop. - let mut ty_stack = vec![(for_ty, 0)]; - - // Set used to detect infinite recursion. - let mut ty_set = FxHashSet::default(); - - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - - let cause = ObligationCause::dummy(); - let mut constraints = DropckConstraint::empty(); - while let Some((ty, depth)) = ty_stack.pop() { - debug!( - "{} kinds, {} overflows, {} ty_stack", - result.kinds.len(), - result.overflows.len(), - ty_stack.len() - ); - dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; - - // "outlives" represent types/regions that may be touched - // by a destructor. - result.kinds.append(&mut constraints.outlives); - result.overflows.append(&mut constraints.overflows); - - // If we have even one overflow, we should stop trying to evaluate further -- - // chances are, the subsequent overflows for this evaluation won't provide useful - // information and will just decrease the speed at which we can emit these errors - // (since we'll be printing for just that much longer for the often enormous types - // that result here). - if !result.overflows.is_empty() { - break; - } + tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { + let tcx = ocx.infcx.tcx; + let ParamEnvAnd { param_env, value: for_ty } = goal; + + let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] }; + + // A stack of types left to process. Each round, we pop + // something from the stack and invoke + // `dtorck_constraint_for_ty`. This may produce new types that + // have to be pushed on the stack. This continues until we have explored + // all the reachable types from the type `for_ty`. + // + // Example: Imagine that we have the following code: + // + // ```rust + // struct A { + // value: B, + // children: Vec<A>, + // } + // + // struct B { + // value: u32 + // } + // + // fn f() { + // let a: A = ...; + // .. + // } // here, `a` is dropped + // ``` + // + // at the point where `a` is dropped, we need to figure out + // which types inside of `a` contain region data that may be + // accessed by any destructors in `a`. We begin by pushing `A` + // onto the stack, as that is the type of `a`. We will then + // invoke `dtorck_constraint_for_ty` which will expand `A` + // into the types of its fields `(B, Vec<A>)`. These will get + // pushed onto the stack. Eventually, expanding `Vec<A>` will + // lead to us trying to push `A` a second time -- to prevent + // infinite recursion, we notice that `A` was already pushed + // once and stop. + let mut ty_stack = vec![(for_ty, 0)]; + + // Set used to detect infinite recursion. + let mut ty_set = FxHashSet::default(); + + let cause = ObligationCause::dummy(); + let mut constraints = DropckConstraint::empty(); + while let Some((ty, depth)) = ty_stack.pop() { + debug!( + "{} kinds, {} overflows, {} ty_stack", + result.kinds.len(), + result.overflows.len(), + ty_stack.len() + ); + dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty, &mut constraints)?; + + // "outlives" represent types/regions that may be touched + // by a destructor. + result.kinds.append(&mut constraints.outlives); + result.overflows.append(&mut constraints.overflows); + + // If we have even one overflow, we should stop trying to evaluate further -- + // chances are, the subsequent overflows for this evaluation won't provide useful + // information and will just decrease the speed at which we can emit these errors + // (since we'll be printing for just that much longer for the often enormous types + // that result here). + if !result.overflows.is_empty() { + break; + } - // dtorck types are "types that will get dropped but which - // do not themselves define a destructor", more or less. We have - // to push them onto the stack to be expanded. - for ty in constraints.dtorck_types.drain(..) { - match infcx.at(&cause, param_env).normalize(ty) { - Ok(Normalized { value: ty, obligations }) => { - fulfill_cx.register_predicate_obligations(infcx, obligations); - - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - - match ty.kind() { - // All parameters live for the duration of the - // function. - ty::Param(..) => {} - - // A projection that we couldn't resolve - it - // might have a destructor. - ty::Projection(..) | ty::Opaque(..) => { - result.kinds.push(ty.into()); - } + // dtorck types are "types that will get dropped but which + // do not themselves define a destructor", more or less. We have + // to push them onto the stack to be expanded. + for ty in constraints.dtorck_types.drain(..) { + let Normalized { value: ty, obligations } = + ocx.infcx.at(&cause, param_env).query_normalize(ty)?; + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + + match ty.kind() { + // All parameters live for the duration of the + // function. + ty::Param(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::Projection(..) | ty::Opaque(..) => { + result.kinds.push(ty.into()); + } - _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); - } + _ => { + if ty_set.insert(ty) { + ty_stack.push((ty, depth + 1)); } } } - - // We don't actually expect to fail to normalize. - // That implies a WF error somewhere else. - Err(NoSolution) => { - return Err(NoSolution); - } } } - } - - debug!("dropck_outlives: result = {:#?}", result); - infcx.make_canonicalized_query_response(canonical_inference_vars, result, &mut *fulfill_cx) + debug!("dropck_outlives: result = {:#?}", result); + Ok(result) + }) } /// Returns a set of constraints that needs to be satisfied in diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 493d5de08..e94c8efe6 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -26,7 +26,7 @@ fn evaluate_obligation<'tcx>( let ParamEnvAnd { param_env, value: predicate } = goal; let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); - let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate); selcx.evaluate_root_obligation(&obligation) } diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 7d36b9558..010233d77 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -5,16 +5,15 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; use rustc_trait_selection::traits::wf; -use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::ObligationCtxt; use smallvec::{smallvec, SmallVec}; pub(crate) fn provide(p: &mut Providers) { @@ -28,18 +27,18 @@ fn implied_outlives_bounds<'tcx>( &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>, NoSolution, > { - tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ty) = key.into_parts(); - compute_implied_outlives_bounds(&infcx, param_env, ty) + compute_implied_outlives_bounds(ocx, param_env, ty) }) } fn compute_implied_outlives_bounds<'tcx>( - infcx: &InferCtxt<'tcx>, + ocx: &ObligationCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> Fallible<Vec<OutlivesBound<'tcx>>> { - let tcx = infcx.tcx; + let tcx = ocx.infcx.tcx; // Sometimes when we ask what it takes for T: WF, we get back that // U: WF is required; in that case, we push U onto this stack and @@ -52,8 +51,6 @@ fn compute_implied_outlives_bounds<'tcx>( let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> = vec![]; - let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx); - while let Some(arg) = wf_args.pop() { if !checked_wf_args.insert(arg) { continue; @@ -70,15 +67,15 @@ fn compute_implied_outlives_bounds<'tcx>( // FIXME(@lcnr): It's not really "always fine", having fewer implied // bounds can be backward incompatible, e.g. #101951 was caused by // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) - .unwrap_or_default(); + let obligations = + wf::obligations(ocx.infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP) + .unwrap_or_default(); // While these predicates should all be implied by other parts of // the program, they are still relevant as they may constrain // inference variables, which is necessary to add the correct // implied bounds in some cases, mostly when dealing with projections. - fulfill_cx.register_predicate_obligations( - infcx, + ocx.register_obligations( obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(), ); @@ -89,35 +86,37 @@ fn compute_implied_outlives_bounds<'tcx>( match obligation.predicate.kind().no_bound_vars() { None => None, Some(pred) => match pred { - ty::PredicateKind::Trait(..) + ty::PredicateKind::Clause(ty::Clause::Trait(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Projection(..) + | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, ty::PredicateKind::WellFormed(arg) => { wf_args.push(arg); None } - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { - Some(ty::OutlivesPredicate(r_a.into(), r_b)) - } + ty::PredicateKind::Clause(ty::Clause::RegionOutlives( + ty::OutlivesPredicate(r_a, r_b), + )) => Some(ty::OutlivesPredicate(r_a.into(), r_b)), - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => { - Some(ty::OutlivesPredicate(ty_a.into(), r_b)) - } + ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate( + ty_a, + r_b, + ))) => Some(ty::OutlivesPredicate(ty_a.into(), r_b)), }, } })); } - // Ensure that those obligations that we had to solve - // get solved *here*. - match fulfill_cx.select_all_or_error(infcx).as_slice() { + // This call to `select_all_or_error` is necessary to constrain inference variables, which we + // use further down when computing the implied bounds. + match ocx.select_all_or_error().as_slice() { [] => (), _ => return Err(NoSolution), } @@ -129,7 +128,7 @@ fn compute_implied_outlives_bounds<'tcx>( .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() { ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)], ty::GenericArgKind::Type(ty_a) => { - let ty_a = infcx.resolve_vars_if_possible(ty_a); + let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); implied_bounds_from_components(r_b, components) diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 0da28737f..9aa26667e 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -3,6 +3,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#![feature(let_chains)] #![recursion_limit = "256"] #[macro_use] @@ -11,6 +12,7 @@ extern crate tracing; extern crate rustc_middle; mod chalk; +mod codegen; mod dropck_outlives; mod evaluate_obligation; mod implied_outlives_bounds; @@ -30,4 +32,5 @@ pub fn provide(p: &mut Providers) { normalize_projection_ty::provide(p); normalize_erasing_regions::provide(p); type_op::provide(p); + p.codegen_select_candidate = codegen::codegen_select_candidate; } diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 2da64d73d..44fd8bfb3 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable}; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use std::sync::atomic::Ordering; @@ -29,12 +29,14 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + let ParamEnvAnd { param_env, value } = goal; let infcx = tcx.infer_ctxt().build(); let cause = ObligationCause::dummy(); - match infcx.at(&cause, param_env).normalize(value) { + match infcx.at(&cause, param_env).query_normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { // We don't care about the `obligations`; they are // always only region relations, and we are about to // erase those anyway: - debug_assert_eq!( + // This has been seen to fail in RL, so making it a non-debug assertion to better catch + // those cases. + assert_eq!( normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)), None, ); @@ -54,9 +56,10 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { - ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, - ty::PredicateKind::Trait(..) - | ty::PredicateKind::Projection(..) + ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..)) + | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false, + ty::PredicateKind::Clause(ty::Clause::Trait(..)) + | ty::PredicateKind::Clause(ty::Clause::Projection(..)) | ty::PredicateKind::WellFormed(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) @@ -64,6 +67,7 @@ fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { | ty::PredicateKind::Coerce(..) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::Ambiguous | ty::PredicateKind::TypeWellFormedFromEnv(..) => true, } } diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 98bb42c9a..e805eb428 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,6 +1,5 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; @@ -23,8 +22,8 @@ fn normalize_projection_ty<'tcx>( tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter_canonical_trait_query( &goal, - |infcx, fulfill_cx, ParamEnvAnd { param_env, value: goal }| { - let selcx = &mut SelectionContext::new(infcx); + |ocx, ParamEnvAnd { param_env, value: goal }| { + let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; let answer = traits::normalize_projection_type( @@ -35,7 +34,7 @@ fn normalize_projection_ty<'tcx>( 0, &mut obligations, ); - fulfill_cx.register_predicate_obligations(infcx, obligations); + ocx.register_obligations(obligations); // FIXME(associated_const_equality): All users of normalize_projection_ty expected // a type, but there is the possibility it could've been a const now. Maybe change // it to a Term later? diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index bca7458ed..7f964afde 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -1,26 +1,21 @@ use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _}; +use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{ - self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance, -}; -use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts}; -use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate}; +use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate}; +use rustc_middle::ty::{UserSelfTy, UserSubsts}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc_trait_selection::traits::query::type_op::eq::Eq; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; use rustc_trait_selection::traits::query::type_op::subtype::Subtype; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; -use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; +use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; use std::fmt; use std::iter::zip; @@ -42,17 +37,16 @@ fn type_op_ascribe_user_type<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None) + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { + type_op_ascribe_user_type_with_span(ocx, key, None) }) } /// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'tcx>, - fulfill_cx: &'a mut dyn TraitEngine<'tcx>, +pub fn type_op_ascribe_user_type_with_span<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>, span: Option<Span>, ) -> Result<(), NoSolution> { @@ -61,157 +55,81 @@ pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>( "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}", mir_ty, def_id, user_substs ); + let span = span.unwrap_or(DUMMY_SP); - let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx }; - cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?; - Ok(()) -} + let UserSubsts { user_self_ty, substs } = user_substs; + let tcx = ocx.infcx.tcx; + let cause = ObligationCause::dummy_with_span(span); -struct AscribeUserTypeCx<'me, 'tcx> { - infcx: &'me InferCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - span: Span, - fulfill_cx: &'me mut dyn TraitEngine<'tcx>, -} + let ty = tcx.bound_type_of(def_id).subst(tcx, substs); + let ty = ocx.normalize(&cause, param_env, ty); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); -impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { - fn normalize<T>(&mut self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID)) - } + ocx.eq(&cause, param_env, mir_ty, ty)?; - fn normalize_with_cause<T>(&mut self, value: T, cause: ObligationCause<'tcx>) -> T - where - T: TypeFoldable<'tcx>, - { - self.infcx - .partially_normalize_associated_types_in(cause, self.param_env, value) - .into_value_registering_obligations(self.infcx, self.fulfill_cx) - } + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution> - where - T: ToTrace<'tcx>, + debug!(?instantiated_predicates); + for (instantiated_predicate, predicate_span) in + zip(instantiated_predicates.predicates, instantiated_predicates.spans) { - self.infcx - .at(&ObligationCause::dummy_with_span(self.span), self.param_env) - .relate(a, variance, b)? - .into_value_registering_obligations(self.infcx, self.fulfill_cx); - Ok(()) - } - - fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) { - self.fulfill_cx.register_predicate_obligation( - self.infcx, - Obligation::new(cause, self.param_env, predicate), + let span = if span == DUMMY_SP { predicate_span } else { span }; + let cause = ObligationCause::new( + span, + hir::CRATE_HIR_ID, + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), ); - } + let instantiated_predicate = + ocx.normalize(&cause.clone(), param_env, instantiated_predicate); - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx + ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } - fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T - where - T: TypeFoldable<'tcx>, - { - EarlyBinder(value).subst(self.tcx(), substs) - } + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs); + let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty); - #[instrument(level = "debug", skip(self))] - fn relate_mir_and_user_ty( - &mut self, - mir_ty: Ty<'tcx>, - def_id: DefId, - user_substs: UserSubsts<'tcx>, - ) -> Result<(), NoSolution> { - let UserSubsts { user_self_ty, substs } = user_substs; - let tcx = self.tcx(); + ocx.eq(&cause, param_env, self_ty, impl_self_ty)?; - let ty = tcx.type_of(def_id); - let ty = self.subst(ty, substs); - let ty = self.normalize(ty); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - - self.relate(mir_ty, Variance::Invariant, ty)?; - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = - self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs); - - let cause = ObligationCause::dummy_with_span(self.span); - - debug!(?instantiated_predicates); - for (instantiated_predicate, predicate_span) in - zip(instantiated_predicates.predicates, instantiated_predicates.spans) - { - let span = if self.span == DUMMY_SP { predicate_span } else { self.span }; - let cause = ObligationCause::new( - span, - hir::CRATE_HIR_ID, - ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), - ); - let instantiated_predicate = - self.normalize_with_cause(instantiated_predicate, cause.clone()); - self.prove_predicate(instantiated_predicate, cause); - } - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - let impl_self_ty = self.tcx().type_of(impl_def_id); - let impl_self_ty = self.subst(impl_self_ty, &substs); - let impl_self_ty = self.normalize(impl_self_ty); - - self.relate(self_ty, Variance::Invariant, impl_self_ty)?; - - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) - .to_predicate(self.tcx()), - cause.clone(), - ); - } - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - self.prove_predicate( - ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), - cause, - ); - Ok(()) + let predicate: Predicate<'tcx> = + ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())).to_predicate(tcx); + ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate)); } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + let predicate: Predicate<'tcx> = + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx); + ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate)); + Ok(()) } fn type_op_eq<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { let (param_env, Eq { a, b }) = key.into_parts(); - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(a, b)? - .into_value_registering_obligations(infcx, fulfill_cx); - Ok(()) + Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?) }) } fn type_op_normalize<'tcx, T>( - infcx: &InferCtxt<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, ) -> Fallible<T> where @@ -219,8 +137,8 @@ where { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = - infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?; - fulfill_cx.register_predicate_obligations(infcx, obligations); + ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?; + ocx.register_obligations(obligations); Ok(value) } @@ -256,13 +174,9 @@ fn type_op_subtype<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { - tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| { let (param_env, Subtype { sub, sup }) = key.into_parts(); - infcx - .at(&ObligationCause::dummy(), param_env) - .sup(sup, sub)? - .into_value_registering_obligations(infcx, fulfill_cx); - Ok(()) + Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?) }) } @@ -274,8 +188,8 @@ fn type_op_prove_predicate<'tcx>( // impl-trait/issue-99642.rs tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query( &canonicalized, - |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); + |ocx, key| { + type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy()); Ok(()) }, ) @@ -284,12 +198,11 @@ fn type_op_prove_predicate<'tcx>( /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( - infcx: &'a InferCtxt<'tcx>, - fulfill_cx: &'a mut dyn TraitEngine<'tcx>, +pub fn type_op_prove_predicate_with_cause<'tcx>( + ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, cause: ObligationCause<'tcx>, ) { let (param_env, ProvePredicate { predicate }) = key.into_parts(); - fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); + ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate)); } |