1
Fork 0

IAT: Introduce AliasKind::Inherent

This commit is contained in:
León Orell Valerian Liehr 2023-03-21 01:46:52 +01:00
parent 6f8c0557e0
commit e8139dfd5a
No known key found for this signature in database
GPG key ID: D17A07215F68E713
82 changed files with 1008 additions and 167 deletions

View file

@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
diag
}
}
#[derive(Diagnostic)]
#[diag(trait_selection_inherent_projection_normalization_overflow)]
pub struct InherentProjectionNormalizationOverflow {
#[primary_span]
pub span: Span,
pub ty: String,
}

View file

@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection, ..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => {

View file

@ -655,7 +655,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection, ..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)),
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),

View file

@ -673,7 +673,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
| ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
| ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
ty::Param(..) => self.found_param_ty(ty),

View file

@ -1686,13 +1686,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
ty::Alias(ty::Projection, ..) => Some(12),
ty::Alias(ty::Opaque, ..) => Some(13),
ty::Never => Some(14),
ty::Adt(..) => Some(15),
ty::Generator(..) => Some(16),
ty::Foreign(..) => Some(17),
ty::GeneratorWitness(..) => Some(18),
ty::GeneratorWitnessMIR(..) => Some(19),
ty::Alias(ty::Inherent, ..) => Some(13),
ty::Alias(ty::Opaque, ..) => Some(14),
ty::Never => Some(15),
ty::Adt(..) => Some(16),
ty::Generator(..) => Some(17),
ty::Foreign(..) => Some(18),
ty::GeneratorWitness(..) => Some(19),
ty::GeneratorWitnessMIR(..) => Some(20),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}

View file

@ -49,7 +49,8 @@ pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::project::{normalize_projection_type, NormalizeExt};
pub use self::project::NormalizeExt;
pub use self::project::{normalize_inherent_projection, normalize_projection_type};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::specialize::specialization_graph::FutureCompatOverlapError;

View file

@ -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,95 @@ 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 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"
),
);
}
}
let substs = alias_ty.rebase_substs_onto_impl(impl_substs, tcx);
// 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
}
enum Projected<'tcx> {
Progress(Progress<'tcx>),
NoProgress(ty::Term<'tcx>),

View file

@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Opaque => ty.try_super_fold_with(self)?,
ty::Projection => {
ty::Projection | ty::Inherent => {
// See note in `rustc_trait_selection::traits::project`
let tcx = self.infcx.tcx;
let infcx = self.infcx;
let tcx = infcx.tcx;
// Just an optimization: When we don't have escaping bound vars,
// we don't need to replace them with placeholders.
let (data, maps) = if data.has_escaping_bound_vars() {
@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
// so we cannot canonicalize it.
let c_data = self
.infcx
let c_data = infcx
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = tcx.normalize_projection_ty(c_data)?;
let result = match kind {
ty::Projection => tcx.normalize_projection_ty(c_data),
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
_ => unreachable!(),
}?;
// We don't expect ambiguity.
if result.is_ambiguous() {
// Rustdoc normalizes possibly not well-formed types, so only
@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
}
return Err(NoSolution);
}
let InferOk { value: result, obligations } =
self.infcx.instantiate_query_response_and_region_obligations(
let InferOk { value: result, obligations } = infcx
.instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,

View file

@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// this trait and type.
}
ty::Param(..)
| ty::Alias(ty::Projection, ..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..) => {
// In these cases, we don't know what the actual

View file

@ -1268,7 +1268,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
ty::Alias(ty::Projection, ..) => {
ty::Alias(ty::Projection | ty::Inherent, ..) => {
let predicate = normalize_with_depth_to(
self,
obligation.param_env,

View file

@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
| ty::Alias(ty::Projection, ..)
| ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble constituent types of unexpected type: {:?}", t);

View file

@ -605,6 +605,9 @@ impl<'tcx> WfPredicates<'tcx> {
walker.skip_current_subtree(); // Subtree handled by compute_projection.
self.compute_projection(data);
}
ty::Alias(ty::Inherent, _) => {
// WF if their substs are WF.
}
ty::Adt(def, substs) => {
// WfNominalType