summaryrefslogtreecommitdiff
path: root/compiler/rustc_trait_selection/src/traits/project.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/project.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs180
1 files changed, 170 insertions, 10 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index ea45412e47f..8e684b7ac23 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -16,6 +16,7 @@ use super::{
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+use crate::errors::InherentProjectionNormalizationOverflow;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
@@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
reveal: Reveal,
) -> bool {
match reveal {
- Reveal::UserFacing => value
- .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
+ Reveal::UserFacing => value.has_type_flags(
+ ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
+ | ty::TypeFlags::HAS_CT_PROJECTION,
+ ),
Reveal::All => value.has_type_flags(
ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_TY_OPAQUE
| ty::TypeFlags::HAS_CT_PROJECTION,
),
@@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
+
+ ty::Inherent if !data.has_escaping_bound_vars() => {
+ // This branch is *mostly* just an optimization: when we don't
+ // have escaping bound vars, we don't need to replace them with
+ // placeholders (see branch below). *Also*, we know that we can
+ // register an obligation to *later* project, since we know
+ // there won't be bound vars there.
+
+ let data = data.fold_with(self);
+
+ // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
+ // here like `ty::Projection`?
+ normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ }
+
+ ty::Inherent => {
+ let infcx = self.selcx.infcx;
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ let data = data.fold_with(self);
+ let ty = normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ );
+
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ ty,
+ )
+ }
}
}
@@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>(
Normalized { value: new_value, obligations: vec![trait_obligation] }
}
+/// Confirm and normalize the given inherent projection.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
+pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Ty<'tcx> {
+ let tcx = selcx.tcx();
+
+ if !tcx.recursion_limit().value_within_limit(depth) {
+ // Halt compilation because it is important that overflows never be masked.
+ tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
+ span: cause.span,
+ ty: alias_ty.to_string(),
+ });
+ }
+
+ let substs = compute_inherent_assoc_ty_substs(
+ selcx,
+ param_env,
+ alias_ty,
+ cause.clone(),
+ depth,
+ obligations,
+ );
+
+ // Register the obligations arising from the impl and from the associated type itself.
+ let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
+ for (predicate, span) in predicates {
+ let predicate = normalize_with_depth_to(
+ selcx,
+ param_env,
+ cause.clone(),
+ depth + 1,
+ predicate,
+ obligations,
+ );
+
+ let nested_cause = ObligationCause::new(
+ cause.span,
+ cause.body_id,
+ // FIXME(inherent_associated_types): Since we can't pass along the self type to the
+ // cause code, inherent projections will be printed with identity substitutions in
+ // diagnostics which is not ideal.
+ // Consider creating separate cause codes for this specific situation.
+ if span.is_dummy() {
+ super::ItemObligation(alias_ty.def_id)
+ } else {
+ super::BindingObligation(alias_ty.def_id, span)
+ },
+ );
+
+ obligations.push(Obligation::with_depth(
+ tcx,
+ nested_cause,
+ depth + 1,
+ param_env,
+ predicate,
+ ));
+ }
+
+ let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
+
+ let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
+ if ty.has_projections() {
+ ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
+ }
+
+ ty
+}
+
+pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> ty::SubstsRef<'tcx> {
+ let tcx = selcx.tcx();
+
+ let impl_def_id = tcx.parent(alias_ty.def_id);
+ let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
+
+ let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
+ let impl_ty =
+ normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
+
+ // Infer the generic parameters of the impl by unifying the
+ // impl type with the self type of the projection.
+ let self_ty = alias_ty.self_ty();
+ match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
+ Ok(mut ok) => obligations.append(&mut ok.obligations),
+ Err(_) => {
+ tcx.sess.delay_span_bug(
+ cause.span,
+ format!(
+ "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
+ ),
+ );
+ }
+ }
+
+ alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
+}
+
enum Projected<'tcx> {
Progress(Progress<'tcx>),
NoProgress(ty::Term<'tcx>),
@@ -1319,7 +1478,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
- let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs));
+ let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs);
let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
@@ -1682,10 +1841,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
if selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
- ty::Binder::dummy(
- selcx.tcx().at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
- )
- .without_const(),
+ ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty])
+ .without_const(),
),
) =>
{
@@ -1749,7 +1906,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
- &format!("Cannot project an associated type from `{:?}`", impl_source),
+ format!("Cannot project an associated type from `{:?}`", impl_source),
);
return Err(());
}
@@ -1948,8 +2105,11 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
)
});
if check_is_sized {
- let sized_predicate = ty::Binder::dummy(
- tcx.at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
+ let sized_predicate = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ obligation.cause.span(),
+ [self_ty],
)
.without_const();
obligations.push(obligation.with(tcx, sized_predicate));