summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/autoderef.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/autoderef.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs78
1 files changed, 55 insertions, 23 deletions
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index ba2d4319a..d6d1498d7 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,6 +1,5 @@
use crate::errors::AutoDerefReachedRecursionLimit;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::NormalizeExt;
use crate::traits::{self, TraitEngine, TraitEngineExt};
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::TypeVisitableExt;
@@ -9,6 +8,7 @@ use rustc_session::Limit;
use rustc_span::def_id::LocalDefId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span;
+use rustc_trait_selection::traits::StructurallyNormalizeExt;
#[derive(Copy, Clone, Debug)]
pub enum AutoderefKind {
@@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
}
// Otherwise, deref if type is derefable:
- let (kind, new_ty) =
- if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
- (AutoderefKind::Builtin, mt.ty)
- } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
- (AutoderefKind::Overloaded, ty)
+ let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) =
+ self.state.cur_ty.builtin_deref(self.include_raw_pointers)
+ {
+ debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
+ // NOTE: we may still need to normalize the built-in deref in case
+ // we have some type like `&<Ty as Trait>::Assoc`, since users of
+ // autoderef expect this type to have been structurally normalized.
+ if self.infcx.tcx.trait_solver_next()
+ && let ty::Alias(ty::Projection, _) = ty.kind()
+ {
+ let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
+ self.state.obligations.extend(obligations);
+ (AutoderefKind::Builtin, normalized_ty)
} else {
- return None;
- };
+ (AutoderefKind::Builtin, ty)
+ }
+ } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+ (AutoderefKind::Overloaded, ty)
+ } else {
+ return None;
+ };
if new_ty.references_error() {
return None;
@@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
debug!("overloaded_deref_ty({:?})", ty);
-
let tcx = self.infcx.tcx;
// <ty as Deref>
- let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]);
-
+ let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
let obligation = traits::Obligation::new(
tcx,
cause.clone(),
@@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
return None;
}
- let normalized_ty = self
+ let (normalized_ty, obligations) =
+ self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?;
+ debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+ self.state.obligations.extend(obligations);
+
+ Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ }
+
+ #[instrument(level = "debug", skip(self), ret)]
+ pub fn structurally_normalize(
+ &self,
+ ty: Ty<'tcx>,
+ ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
+ let tcx = self.infcx.tcx;
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
+
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+ let normalized_ty = match self
.infcx
.at(&cause, self.param_env)
- .normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs));
- let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
- let normalized_ty =
- normalized_ty.into_value_registering_obligations(self.infcx, &mut *fulfillcx);
- let errors = fulfillcx.select_where_possible(&self.infcx);
+ .structurally_normalize(ty, &mut *fulfill_cx)
+ {
+ Ok(normalized_ty) => normalized_ty,
+ Err(errors) => {
+ // This shouldn't happen, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ debug!(?errors, "encountered errors while fulfilling");
+ return None;
+ }
+ };
+
+ let errors = fulfill_cx.select_where_possible(&self.infcx);
if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
+ debug!(?errors, "encountered errors while fulfilling");
return None;
}
- let obligations = fulfillcx.pending_obligations();
- debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
- self.state.obligations.extend(obligations);
- Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ Some((normalized_ty, fulfill_cx.pending_obligations()))
}
/// Returns the final type we ended up with, which may be an inference