From 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:20:39 +0200 Subject: Merging upstream version 1.70.0+dfsg1. Signed-off-by: Daniel Baumann --- .../src/traits/select/candidate_assembly.rs | 205 ++++++++-- .../src/traits/select/confirmation.rs | 86 ++--- .../rustc_trait_selection/src/traits/select/mod.rs | 412 ++++++++++----------- 3 files changed, 417 insertions(+), 286 deletions(-) (limited to 'compiler/rustc_trait_selection/src/traits/select') diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e91057356..1f5bbc178 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -5,12 +5,14 @@ //! candidates. See the [rustc dev guide] for more details. //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly + +use hir::def_id::DefId; use hir::LangItem; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_target::spec::abi::Abi; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -95,7 +97,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if lang_items.tuple_trait() == Some(def_id) { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if lang_items.pointer_like() == Some(def_id) { - self.assemble_candidate_for_ptr_sized(obligation, &mut candidates); + self.assemble_candidate_for_pointer_like(obligation, &mut candidates); + } else if lang_items.fn_ptr_trait() == Some(def_id) { + self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -290,6 +294,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + // Keep this function in sync with extract_tupled_inputs_and_output_from_callable + // until the old solver (and thus this function) is removed. + // Okay to skip binder because what we are inspecting doesn't involve bound regions. let self_ty = obligation.self_ty().skip_binder(); match *self_ty.kind() { @@ -298,31 +305,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; // Could wind up being a fn() type. } // Provide an impl, but only for suitable `fn` pointers. - ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { + ty::FnPtr(sig) => { + if sig.is_fn_trait_compatible() { candidates.vec.push(FnPointerCandidate { is_const: false }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). ty::FnDef(def_id, _) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() + if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - candidates - .vec - .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); - } + candidates + .vec + .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); } } _ => {} @@ -330,13 +325,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } /// Searches for impls that might apply to `obligation`. + #[instrument(level = "debug", skip(self, candidates))] fn assemble_candidates_from_impls( &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - debug!(?obligation, "assemble_candidates_from_impls"); - // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`) @@ -350,6 +344,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } + let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; + let obligation_substs = obligation.predicate.skip_binder().trait_ref.substs; self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), @@ -358,7 +354,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) { + if !drcx.substs_refs_may_unify(obligation_substs, impl_trait_ref.0.substs) { + return; + } + if self.reject_fn_ptr_impls( + impl_def_id, + obligation, + impl_trait_ref.skip_binder().self_ty(), + ) { return; } @@ -371,6 +374,99 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } + /// The various `impl Trait for T` in libcore are more like builtin impls for all function items + /// and function pointers and less like blanket impls. Rejecting them when they can't possibly apply (because + /// the obligation's self-type does not implement `FnPtr`) avoids reporting that the self type does not implement + /// `FnPtr`, when we wanted to report that it doesn't implement `Trait`. + #[instrument(level = "trace", skip(self), ret)] + fn reject_fn_ptr_impls( + &self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + impl_self_ty: Ty<'tcx>, + ) -> bool { + // Let `impl Trait for Vec` go through the normal rejection path. + if !matches!(impl_self_ty.kind(), ty::Param(..)) { + return false; + } + let Some(fn_ptr_trait) = self.tcx().lang_items().fn_ptr_trait() else { + return false; + }; + + for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates { + let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + = predicate.kind().skip_binder() else { continue }; + if fn_ptr_trait != pred.trait_ref.def_id { + continue; + } + trace!(?pred); + // Not the bound we're looking for + if pred.self_ty() != impl_self_ty { + continue; + } + + match obligation.self_ty().skip_binder().kind() { + // Fast path to avoid evaluating an obligation that trivially holds. + // There may be more bounds, but these are checked by the regular path. + ty::FnPtr(..) => return false, + // These may potentially implement `FnPtr` + ty::Placeholder(..) + | ty::Dynamic(_, _, _) + | ty::Alias(_, _) + | ty::Infer(_) + | ty::Param(..) => {} + + ty::Bound(_, _) => span_bug!( + obligation.cause.span(), + "cannot have escaping bound var in self type of {obligation:#?}" + ), + // These can't possibly implement `FnPtr` as they are concrete types + // and not `FnPtr` + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Error(_) => return true, + // FIXME: Function definitions could actually implement `FnPtr` by + // casting the ZST function def to a function pointer. + ty::FnDef(_, _) => return true, + } + + // Generic params can implement `FnPtr` if the predicate + // holds within its own environment. + let obligation = Obligation::new( + self.tcx(), + obligation.cause.clone(), + obligation.param_env, + self.tcx().mk_predicate(obligation.predicate.map_bound(|mut pred| { + pred.trait_ref = + self.tcx().mk_trait_ref(fn_ptr_trait, [pred.trait_ref.self_ty()]); + ty::PredicateKind::Clause(ty::Clause::Trait(pred)) + })), + ); + if let Ok(r) = self.infcx.evaluate_obligation(&obligation) { + if !r.may_apply() { + return true; + } + } + } + false + } + fn assemble_candidates_from_auto_impls( &mut self, obligation: &TraitObligation<'tcx>, @@ -783,6 +879,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let relevant_impl = self.tcx().find_map_relevant_impl( self.tcx().require_lang_item(LangItem::Drop, None), obligation.predicate.skip_binder().trait_ref.self_ty(), + TreatProjections::ForLookup, Some, ); @@ -845,15 +942,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_candidate_for_ptr_sized( + fn assemble_candidate_for_pointer_like( &mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { // The regions of a type don't affect the size of the type - let self_ty = self - .tcx() - .erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate.self_ty())); + let tcx = self.tcx(); + let self_ty = + tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty())); // But if there are inference variables, we have to wait until it's resolved. if self_ty.has_non_region_infer() { @@ -861,13 +958,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - let usize_layout = - self.tcx().layout_of(ty::ParamEnv::empty().and(self.tcx().types.usize)).unwrap().layout; - if let Ok(layout) = self.tcx().layout_of(obligation.param_env.and(self_ty)) - && layout.layout.size() == usize_layout.size() - && layout.layout.align().abi == usize_layout.align().abi + if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) { candidates.vec.push(BuiltinCandidate { has_nested: false }); } } + + fn assemble_candidates_for_fn_ptr_trait( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + match self_ty.skip_binder().kind() { + ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }), + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(..) + | ty::Foreign(..) + | ty::Str + | ty::Array(..) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Tuple(..) + | ty::Alias(..) + | ty::Param(..) + | ty::Bound(..) + | ty::Error(_) + | ty::Infer( + ty::InferTy::IntVar(_) + | ty::InferTy::FloatVar(_) + | ty::InferTy::FreshIntTy(_) + | ty::InferTy::FreshFloatTy(_), + ) => {} + ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)) => { + candidates.ambiguous = true; + } + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 21c158fd0..88121f865 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,8 +8,8 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::{ self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, @@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; -use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::vtable::{ count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, VtblSegment, @@ -131,6 +131,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; + // The obligations returned by confirmation are recursively evaluated + // so we need to make sure they have the correct depth. + for subobligation in impl_src.borrow_nested_obligations_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + if !obligation.predicate.is_const_if_const() { // normalize nested predicates according to parent predicate's constness. impl_src = impl_src.map(|mut o| { @@ -177,7 +183,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate, candidate) + .sup(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -253,15 +259,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - ensure_sufficient_stack(|| { - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - }) + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) } else { vec![] }; @@ -462,7 +466,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation_trait_ref, upcast_trait_ref) + .sup(DefineOpaqueTypes::No, obligation_trait_ref, upcast_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -601,10 +605,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, "confirm_fn_pointer_candidate"); let tcx = self.tcx(); - let self_ty = self + + let Some(self_ty) = self .infcx - .shallow_resolve(obligation.self_ty().no_bound_vars()) - .expect("fn pointer should not capture bound vars from predicate"); + .shallow_resolve(obligation.self_ty().no_bound_vars()) else + { + // FIXME: Ideally we'd support `for<'a> fn(&'a ()): Fn(&'a ())`, + // but we do not currently. Luckily, such a bound is not + // particularly useful, so we don't expect users to write + // them often. + return Err(SelectionError::Unimplemented); + }; + let sig = self_ty.fn_sig(tcx); let trait_ref = closure_trait_ref_and_return_type( tcx, @@ -819,11 +831,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); + // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs self.infcx .at(&obligation.cause, obligation.param_env) - // needed for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs - .define_opaque_types(true) - .sup(obligation_trait_ref, expected_trait_ref) + .sup(DefineOpaqueTypes::Yes, obligation_trait_ref, expected_trait_ref) .map(|InferOk { mut obligations, .. }| { obligations.extend(nested); obligations @@ -888,7 +899,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(target, source_trait) + .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); @@ -987,7 +998,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(target, source_trait) + .sup(DefineOpaqueTypes::No, target, source_trait) .map_err(|_| Unimplemented)?; nested.extend(obligations); @@ -1058,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(b, a) + .eq(DefineOpaqueTypes::No, b, a) .map_err(|_| Unimplemented)?; nested.extend(obligations); } @@ -1073,6 +1084,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tail_field = def .non_enum_variant() .fields + .raw .last() .expect("expected unsized ADT to have a tail field"); let tail_field_ty = tcx.type_of(tail_field.did); @@ -1106,19 +1118,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) + .eq(DefineOpaqueTypes::No, target, new_struct) .map_err(|_| Unimplemented)?; nested.extend(obligations); // Construct the nested `TailField: Unsize>` predicate. - nested.push(predicate_for_trait_def( + let tail_unsize_obligation = obligation.with( tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [source_tail, target_tail], - )); + tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]), + ); + nested.push(tail_unsize_obligation); } // `(.., T)` -> `(.., U)` @@ -1136,21 +1145,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) + .eq(DefineOpaqueTypes::No, target, new_tuple) .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `T: Unsize` predicate. - nested.push(ensure_sufficient_stack(|| { - predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [a_last, b_last], - ) - })); + // Add a nested `T: Unsize` predicate. + let last_unsize_obligation = obligation + .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last])); + nested.push(last_unsize_obligation); } _ => bug!("source: {source}, target: {target}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7f454fbb3..6bb53418b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,12 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection -// FIXME: The `map` field in ProvisionalEvaluationCache should be changed to -// a `FxIndexMap` to avoid query instability, but right now it causes a perf regression. This would be -// fixed or at least lightened by the addition of the `drain_filter` method to `FxIndexMap` -// Relevant: https://github.com/rust-lang/rust/pull/103723 and https://github.com/bluss/indexmap/issues/242 -#![allow(rustc::potential_query_instability)] - use self::EvaluationResult::*; use self::SelectionCandidate::*; @@ -17,7 +11,7 @@ use super::project; use super::project::normalize_with_depth_to; use super::project::ProjectionTyObligation; use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::util::closure_trait_ref_and_return_type; use super::wf; use super::{ ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, @@ -32,25 +26,23 @@ use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; use crate::traits::Unimplemented; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitEngine; use rustc_infer::traits::TraitEngineExt; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; -use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_session::config::TraitSolver; use rustc_span::symbol::sym; use std::cell::{Cell, RefCell}; @@ -178,14 +170,14 @@ struct TraitObligationStack<'prev, 'tcx> { } struct SelectionCandidateSet<'tcx> { - // A list of candidates that definitely apply to the current - // obligation (meaning: types unify). + /// A list of candidates that definitely apply to the current + /// obligation (meaning: types unify). vec: Vec>, - // If `true`, then there were candidates that might or might - // not have applied, but we couldn't tell. This occurs when some - // of the input types are type variables, in which case there are - // various "builtin" rules that might or might not trigger. + /// If `true`, then there were candidates that might or might + /// not have applied, but we couldn't tell. This occurs when some + /// of the input types are type variables, in which case there are + /// various "builtin" rules that might or might not trigger. ambiguous: bool, } @@ -211,7 +203,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, - freshener: infcx.freshener_keep_static(), + freshener: infcx.freshener(), intercrate_ambiguity_causes: None, query_mode: TraitQueryMode::Standard, } @@ -465,14 +457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if candidates.len() > 1 { let mut i = 0; while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + let should_drop_i = (0..candidates.len()).filter(|&j| i != j).any(|j| { self.candidate_should_be_dropped_in_favor_of( &candidates[i], &candidates[j], needs_infer, - ) + ) == DropVictim::Yes }); - if is_dup { + if should_drop_i { debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); } else { @@ -545,13 +537,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { self.evaluation_probe(|this| { - if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + if this.tcx().trait_solver_next() { + this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) + } else { this.evaluate_predicate_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), obligation.clone(), ) - } else { - this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) } }) } @@ -591,9 +583,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { where I: IntoIterator> + std::fmt::Debug, { - if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next { + if self.tcx().trait_solver_next() { + self.evaluate_predicates_recursively_in_new_solver(predicates) + } else { let mut result = EvaluatedToOk; - for obligation in predicates { + for mut obligation in predicates { + obligation.set_depth_from_parent(stack.depth()); let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, @@ -604,8 +599,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } Ok(result) - } else { - self.evaluate_predicates_recursively_in_new_solver(predicates) } } @@ -617,6 +610,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(); fulfill_cx.register_predicate_obligations(self.infcx, predicates); // True errors + // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? if !fulfill_cx.select_where_possible(self.infcx).is_empty() { return Ok(EvaluatedToErr); } @@ -661,12 +655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -677,12 +667,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { - Ok(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) + Ok(Ok(InferOk { obligations, .. })) => { + self.evaluate_predicates_recursively(previous_stack, obligations) } Ok(Err(_)) => Ok(EvaluatedToErr), Err(..) => Ok(EvaluatedToAmbig), @@ -755,9 +741,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { arg, obligation.cause.span, ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - + Some(obligations) => { cache.wf_args.borrow_mut().push((arg, previous_stack.depth())); let result = self.evaluate_predicates_recursively(previous_stack, obligations); @@ -778,14 +762,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { - // A global type with no late-bound regions can only - // contain the "'static" lifetime (any other lifetime - // would either be late-bound or local), so it is guaranteed - // to outlive any other lifetime - if pred.0.is_global() && !pred.0.has_late_bound_vars() { - Ok(EvaluatedToOk) - } else { + // A global type with no free lifetimes or generic parameters + // outlives anything. + if pred.0.has_free_regions() + || pred.0.has_late_bound_regions() + || pred.0.has_non_region_infer() + || pred.0.has_non_region_infer() + { Ok(EvaluatedToOkModuloRegions) + } else { + Ok(EvaluatedToOk) } } @@ -826,10 +812,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - self.add_depth( - subobligations.iter_mut(), - obligation.recursion_depth, - ); + // Need to explicitly set the depth of nested goals here as + // projection obligations can cycle by themselves and in + // `evaluate_predicates_recursively` we only add the depth + // for parent trait goals because only these get added to the + // `TraitObligationStackList`. + for subobligation in subobligations.iter_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } let res = self.evaluate_predicates_recursively( previous_stack, subobligations, @@ -909,38 +899,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if a.def.did == b.def.did && tcx.def_kind(a.def.did) == DefKind::AssocConst => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) .trace(c1, c2) - .eq(a.substs, b.substs) + .eq(DefineOpaqueTypes::No, a.substs, b.substs) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } (_, Unevaluated(_)) | (Unevaluated(_), _) => (), (_, _) => { - if let Ok(new_obligations) = self + if let Ok(InferOk { obligations, value: () }) = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(c1, c2) + .eq(DefineOpaqueTypes::No, c1, c2) { - let mut obligations = new_obligations.obligations; - self.add_depth( - obligations.iter_mut(), - obligation.recursion_depth, - ); return self.evaluate_predicates_recursively( previous_stack, - obligations.into_iter(), + obligations, ); } } @@ -965,8 +945,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2) - { + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + c1, + c2, + ) { Ok(inf_ok) => self.evaluate_predicates_recursively( previous_stack, inf_ok.into_obligations(), @@ -989,12 +972,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::TypeWellFormedFromEnv(..) => { bug!("TypeWellFormedFromEnv is only used for chalk") } - ty::PredicateKind::AliasEq(..) => { - bug!("AliasEq is only used for new solver") + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => { - match self.infcx.at(&obligation.cause, obligation.param_env).eq(ct.ty(), ty) { + match self.infcx.at(&obligation.cause, obligation.param_env).eq( + DefineOpaqueTypes::No, + ct.ty(), + ty, + ) { Ok(inf_ok) => self.evaluate_predicates_recursively( previous_stack, inf_ok.into_obligations(), @@ -1359,24 +1346,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result); } - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `InferCtxt.subtype_predicate` produce - /// subobligations without taking in a 'parent' depth, causing the - /// generated subobligations to have a `recursion_depth` of `0`. - /// - /// To ensure that obligation_depth never decreases, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - fn check_recursion_depth( &self, depth: usize, @@ -1752,7 +1721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); self.infcx .at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) + .sup(DefineOpaqueTypes::No, ty::Binder::dummy(placeholder_trait_ref), trait_bound) .map(|InferOk { obligations: _, value: () }| { // This method is called within a probe, so we can't have // inference variables and placeholders escape. @@ -1814,7 +1783,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let is_match = self .infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate, infer_projection) + .sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection) .map_or(false, |InferOk { obligations, value: () }| { self.evaluate_predicates_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), @@ -1842,16 +1811,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ProjectionMatchesProjection::No } } +} - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables and then we also attempt to evaluate recursive - // bounds to see if they are satisfied. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum DropVictim { + Yes, + No, +} + +impl DropVictim { + fn drop_if(should_drop: bool) -> DropVictim { + if should_drop { DropVictim::Yes } else { DropVictim::No } + } +} - /// Returns `true` if `victim` should be dropped in favor of +/// ## Winnowing +/// +/// Winnowing is the process of attempting to resolve ambiguity by +/// probing further. During the winnowing process, we unify all +/// type variables and then we also attempt to evaluate recursive +/// bounds to see if they are satisfied. +impl<'tcx> SelectionContext<'_, 'tcx> { + /// Returns `DropVictim::Yes` if `victim` should be dropped in favor of /// `other`. Generally speaking we will drop duplicate /// candidates and prefer where-clause candidates. /// @@ -1861,9 +1842,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { victim: &EvaluatedCandidate<'tcx>, other: &EvaluatedCandidate<'tcx>, needs_infer: bool, - ) -> bool { + ) -> DropVictim { if victim.candidate == other.candidate { - return true; + return DropVictim::Yes; } // Check if a bound would previously have been removed when normalizing @@ -1887,11 +1868,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // FIXME(@jswrenn): this should probably be more sophisticated - (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, // (*) - (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => true, - (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => false, + (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => { + DropVictim::Yes + } + (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => { + DropVictim::No + } (ParamCandidate(other), ParamCandidate(victim)) => { let same_except_bound_vars = other.skip_binder().trait_ref @@ -1905,28 +1890,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // or the current one if tied (they should both evaluate to the same answer). This is // probably best characterized as a "hack", since we might prefer to just do our // best to *not* create essentially duplicate candidates in the first place. - other.bound_vars().len() <= victim.bound_vars().len() + DropVictim::drop_if(other.bound_vars().len() <= victim.bound_vars().len()) } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref && victim.skip_binder().constness == ty::BoundConstness::NotConst && other.skip_binder().polarity == victim.skip_binder().polarity { // Drop otherwise equivalent non-const candidates in favor of const candidates. - true + DropVictim::Yes } else { - false + DropVictim::No } } // Drop otherwise equivalent non-const fn pointer candidates - (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes, - // Global bounds from the where clause should be ignored - // here (see issue #50825). Otherwise, we have a where - // clause so don't go around looking for impls. - // Arbitrarily give param candidates priority - // over projection and object candidates. ( - ParamCandidate(ref cand), + ParamCandidate(ref other_cand), ImplCandidate(..) | ClosureCandidate { .. } | GeneratorCandidate @@ -1939,11 +1919,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitAliasCandidate | ObjectCandidate(_) | ProjectionCandidate(..), - ) => !is_global(cand), - (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref cand)) => { + ) => { + // We have a where clause so don't go around looking + // for impls. Arbitrarily give param candidates priority + // over projection and object candidates. + // + // Global bounds from the where clause should be ignored + // here (see issue #50825). + DropVictim::drop_if(!is_global(other_cand)) + } + (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) + if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } } ( ImplCandidate(_) @@ -1956,18 +1944,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ParamCandidate(ref cand), + ParamCandidate(ref victim_cand), ) => { // Prefer these to a global where-clause bound // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() + DropVictim::drop_if( + is_global(victim_cand) && other.evaluation.must_apply_modulo_regions(), + ) } (ProjectionCandidate(i, _), ProjectionCandidate(j, _)) | (ObjectCandidate(i), ObjectCandidate(j)) => { // Arbitrarily pick the lower numbered candidate for backwards // compatibility reasons. Don't let this affect inference. - i < j && !needs_infer + DropVictim::drop_if(i < j && !needs_infer) } (ObjectCandidate(_), ProjectionCandidate(..)) | (ProjectionCandidate(..), ObjectCandidate(_)) => { @@ -1987,7 +1977,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { .. } | TraitAliasCandidate, - ) => true, + ) => DropVictim::Yes, ( ImplCandidate(..) @@ -2001,7 +1991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | BuiltinCandidate { .. } | TraitAliasCandidate, ObjectCandidate(_) | ProjectionCandidate(..), - ) => false, + ) => DropVictim::No, (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { // See if we can toss out `victim` based on specialization. @@ -2014,59 +2004,69 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); if other.evaluation.must_apply_modulo_regions() { if tcx.specializes((other_def, victim_def)) { - return true; + return DropVictim::Yes; } } - if other.evaluation.must_apply_considering_regions() { - match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { - Some(ty::ImplOverlapKind::Permitted { marker: true }) => { - // Subtle: If the predicate we are evaluating has inference - // variables, do *not* allow discarding candidates due to - // marker trait impls. - // - // Without this restriction, we could end up accidentally - // constraining inference variables based on an arbitrarily - // chosen trait impl. - // - // Imagine we have the following code: - // - // ```rust - // #[marker] trait MyTrait {} - // impl MyTrait for u8 {} - // impl MyTrait for bool {} - // ``` - // - // And we are evaluating the predicate `<_#0t as MyTrait>`. - // - // During selection, we will end up with one candidate for each - // impl of `MyTrait`. If we were to discard one impl in favor - // of the other, we would be left with one candidate, causing - // us to "successfully" select the predicate, unifying - // _#0t with (for example) `u8`. - // - // However, we have no reason to believe that this unification - // is correct - we've essentially just picked an arbitrary - // *possibility* for _#0t, and required that this be the *only* - // possibility. - // - // Eventually, we will either: - // 1) Unify all inference variables in the predicate through - // some other means (e.g. type-checking of a function). We will - // then be in a position to drop marker trait candidates - // without constraining inference variables (since there are - // none left to constrain) - // 2) Be left with some unconstrained inference variables. We - // will then correctly report an inference error, since the - // existence of multiple marker trait impls tells us nothing - // about which one should actually apply. - !needs_infer - } - Some(_) => true, - None => false, + match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { + // For #33140 the impl headers must be exactly equal, the trait must not have + // any associated items and there are no where-clauses. + // + // We can just arbitrarily drop one of the impls. + Some(ty::ImplOverlapKind::Issue33140) => { + assert_eq!(other.evaluation, victim.evaluation); + DropVictim::Yes } - } else { - false + // For candidates which already reference errors it doesn't really + // matter what we do 🤷 + Some(ty::ImplOverlapKind::Permitted { marker: false }) => { + DropVictim::drop_if(other.evaluation.must_apply_considering_regions()) + } + Some(ty::ImplOverlapKind::Permitted { marker: true }) => { + // Subtle: If the predicate we are evaluating has inference + // variables, do *not* allow discarding candidates due to + // marker trait impls. + // + // Without this restriction, we could end up accidentally + // constraining inference variables based on an arbitrarily + // chosen trait impl. + // + // Imagine we have the following code: + // + // ```rust + // #[marker] trait MyTrait {} + // impl MyTrait for u8 {} + // impl MyTrait for bool {} + // ``` + // + // And we are evaluating the predicate `<_#0t as MyTrait>`. + // + // During selection, we will end up with one candidate for each + // impl of `MyTrait`. If we were to discard one impl in favor + // of the other, we would be left with one candidate, causing + // us to "successfully" select the predicate, unifying + // _#0t with (for example) `u8`. + // + // However, we have no reason to believe that this unification + // is correct - we've essentially just picked an arbitrary + // *possibility* for _#0t, and required that this be the *only* + // possibility. + // + // Eventually, we will either: + // 1) Unify all inference variables in the predicate through + // some other means (e.g. type-checking of a function). We will + // then be in a position to drop marker trait candidates + // without constraining inference variables (since there are + // none left to constrain) + // 2) Be left with some unconstrained inference variables. We + // will then correctly report an inference error, since the + // existence of multiple marker trait impls tells us nothing + // about which one should actually apply. + DropVictim::drop_if( + !needs_infer && other.evaluation.must_apply_considering_regions(), + ) + } + None => DropVictim::No, } } @@ -2092,10 +2092,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { has_nested: true } | TraitAliasCandidate, - ) => false, + ) => DropVictim::No, } } +} +impl<'tcx> SelectionContext<'_, 'tcx> { fn sized_conditions( &mut self, obligation: &TraitObligation<'tcx>, @@ -2149,7 +2151,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None, ty::Infer(ty::TyVar(_)) => Ambiguous, - // We can make this an ICE if/once we actually instantiate the trait obligation. + // We can make this an ICE if/once we actually instantiate the trait obligation eagerly. ty::Bound(..) => None, ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { @@ -2257,7 +2259,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Adt(..) | ty::Alias(..) | ty::Param(..) => { + ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -2269,9 +2271,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ambiguous } - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + // We can make this an ICE if/once we actually instantiate the trait obligation eagerly. + ty::Bound(..) => None, + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } } @@ -2405,15 +2408,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { placeholder_ty, ) }); - let placeholder_obligation = predicate_for_trait_def( + + let obligation = Obligation::new( self.tcx(), - param_env, cause.clone(), - trait_def_id, - recursion_depth, - [normalized_ty], + param_env, + self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]), ); - obligations.push(placeholder_obligation); + obligations.push(obligation); obligations }) .collect() @@ -2507,7 +2509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let InferOk { obligations, .. } = self .infcx .at(&cause, obligation.param_env) - .eq(placeholder_obligation_trait_ref, impl_trait_ref) + .eq(DefineOpaqueTypes::No, placeholder_obligation_trait_ref, impl_trait_ref) .map_err(|e| { debug!("match_impl: failed eq_trait_refs due to `{}`", e.to_string(self.tcx())) })?; @@ -2523,19 +2525,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } - fn fast_reject_trait_refs( - &mut self, - obligation: &TraitObligation<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, - ) -> bool { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder }; - iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs) - .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp)) - } - /// Normalize `where_clause_trait_ref` and try to match it against /// `obligation`. If successful, return any predicates that /// result from the normalization. @@ -2557,7 +2546,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result>, ()> { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) + .sup(DefineOpaqueTypes::No, obligation.predicate.to_poly_trait_ref(), poly_trait_ref) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| ()) } @@ -2786,7 +2775,7 @@ struct ProvisionalEvaluationCache<'tcx> { /// - then we determine that `E` is in error -- we will then clear /// all cache values whose DFN is >= 4 -- in this case, that /// means the cached value for `F`. - map: RefCell, ProvisionalEvaluation>>, + map: RefCell, ProvisionalEvaluation>>, /// The stack of args that we assume to be true because a `WF(arg)` predicate /// is on the stack above (and because of wellformedness is coinductive). @@ -2934,12 +2923,13 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// have a performance impact in practice. fn on_completion(&self, dfn: usize) { debug!(?dfn, "on_completion"); - - for (fresh_trait_pred, eval) in - self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn) - { - debug!(?fresh_trait_pred, ?eval, "on_completion"); - } + self.map.borrow_mut().retain(|fresh_trait_pred, eval| { + if eval.from_dfn >= dfn { + debug!(?fresh_trait_pred, ?eval, "on_completion"); + return false; + } + true + }); } } @@ -3021,7 +3011,7 @@ fn bind_generator_hidden_types_above<'tcx>( if let ty::ReErased = r.kind() { let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), - kind: ty::BrAnon(counter, None), + kind: ty::BrAnon(None), }; counter += 1; r = tcx.mk_re_late_bound(current_depth, br); @@ -3037,7 +3027,7 @@ fn bind_generator_hidden_types_above<'tcx>( debug_assert!(!hidden_types.has_erased_regions()); } let bound_vars = tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain( - (num_bound_variables..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))), + (num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))), )); ty::Binder::bind_with_vars(hidden_types, bound_vars) } -- cgit v1.2.3