use crate::traits::ProjectionCacheKey;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::ErrorReported;
+use rustc_errors::{Diagnostic, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::LateBoundRegionConversionTime;
impl IntercrateAmbiguityCause {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
- pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) {
+ pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) {
err.note(&self.intercrate_ambiguity_hint());
}
.map_err(|_| ())
}
- fn evaluate_where_clause<'o>(
+ fn where_clause_may_apply<'o>(
&mut self,
stack: &TraitObligationStack<'o, 'tcx>,
where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
})
}
+ /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and
+ /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT,
+ /// and applying this env_predicate constrains any of the obligation's GAT substitutions.
+ ///
+ /// This behavior is a somewhat of a hack to prevent overconstraining inference variables
+ /// in cases like #91762.
pub(super) fn match_projection_projections(
&mut self,
obligation: &ProjectionTyObligation<'tcx>,
env_predicate: PolyProjectionPredicate<'tcx>,
potentially_unnormalized_candidates: bool,
- ) -> bool {
+ ) -> ProjectionMatchesProjection {
let mut nested_obligations = Vec::new();
let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
infer_predicate.projection_ty
};
- self.infcx
+ let is_match = self
+ .infcx
.at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate, infer_projection)
.map_or(false, |InferOk { obligations, value: () }| {
nested_obligations.into_iter().chain(obligations),
)
.map_or(false, |res| res.may_apply())
- })
+ });
+
+ if is_match {
+ let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
+ // FIXME(generic-associated-types): Addresses aggressive inference in #92917.
+ // If this type is a GAT, and of the GAT substs resolve to something new,
+ // that means that we must have newly inferred something about the GAT.
+ // We should give up in that case.
+ if !generics.params.is_empty()
+ && obligation.predicate.substs[generics.parent_count..]
+ .iter()
+ .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
+ {
+ ProjectionMatchesProjection::Ambiguous
+ } else {
+ ProjectionMatchesProjection::Yes
+ }
+ } else {
+ ProjectionMatchesProjection::No
+ }
}
///////////////////////////////////////////////////////////////////////////
ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
ty::Tuple(tys) => Where(
- obligation
- .predicate
- .rebind(tys.last().into_iter().map(|k| k.expect_ty()).collect()),
+ obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
),
ty::Adt(def, substs) => {
ty::Tuple(tys) => {
// (*) binder moved here
- Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
+ Where(obligation.predicate.rebind(tys.iter().collect()))
}
ty::Closure(_, substs) => {
ty::Tuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
- t.rebind(tys.iter().map(|k| k.expect_ty()).collect())
+ t.rebind(tys.iter().collect())
}
ty::Closure(_, ref substs) => {
write!(f, "TraitObligationStack({:?})", self.obligation)
}
}
+
+pub enum ProjectionMatchesProjection {
+ Yes,
+ Ambiguous,
+ No,
+}