1
Fork 0

Add AliasKind::Weak for type aliases.

Only use it when the type alias contains an opaque type.

Also does wf-checking on such type aliases.
This commit is contained in:
Oli Scherer 2023-03-07 12:03:11 +00:00
parent 4fdd07fe88
commit f3b7dd6388
86 changed files with 474 additions and 199 deletions

View file

@ -508,10 +508,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Alias(ty::Inherent, _)
| ty::Alias(ty::Weak, _)
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
};

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::Inherent, ..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => {

View file

@ -29,6 +29,7 @@ mod opaques;
mod project_goals;
mod search_graph;
mod trait_goals;
mod weak_types;
pub use eval_ctxt::{EvalCtxt, InferCtxtEvalExt};
pub use fulfill::FulfillmentCtxt;

View file

@ -57,6 +57,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
DefKind::AnonConst => self.normalize_anon_const(goal),
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
DefKind::TyAlias => self.normalize_weak_type(goal),
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
}
}

View file

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

View file

@ -0,0 +1,19 @@
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
use super::EvalCtxt;
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_weak_type(
&mut self,
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
let tcx = self.tcx();
let weak_ty = goal.predicate.projection_ty;
let expected = goal.predicate.term.ty().expect("no such thing as a const alias");
let actual = tcx.type_of(weak_ty.def_id).subst(tcx, weak_ty.substs);
self.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}

View file

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

View file

@ -1824,12 +1824,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Alias(ty::Projection, ..) => Some(12),
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::Alias(ty::Weak, ..) => Some(15),
ty::Never => Some(16),
ty::Adt(..) => Some(17),
ty::Generator(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::GeneratorWitness(..) => Some(20),
ty::GeneratorWitnessMIR(..) => Some(21),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}

View file

@ -3198,6 +3198,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
});
}
ObligationCauseCode::TypeAlias(ref nested, span, def_id) => {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
predicate,
param_env,
nested,
obligated_types,
seen_requirements,
)
});
let mut multispan = MultiSpan::from(span);
multispan.push_span_label(span, "required by this bound");
err.span_note(
multispan,
format!(
"required by a bound on the type alias `{}`",
self.infcx.tcx.item_name(def_id)
),
);
}
ObligationCauseCode::FunctionArgumentObligation {
arg_hir_id,
call_hir_id,

View file

@ -9,7 +9,7 @@ use rustc_span::def_id::LocalDefId;
pub use rustc_middle::traits::query::OutlivesBound;
type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub type Bounds<'a, 'tcx: 'a> = impl Iterator<Item = OutlivesBound<'tcx>> + 'a;
pub trait InferCtxtExt<'a, 'tcx> {
fn implied_outlives_bounds(
&self,

View file

@ -31,6 +31,7 @@ use rustc_infer::infer::at::At;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ImplSourceBuiltinData;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
@ -621,6 +622,30 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
ty::Weak => {
let infcx = self.selcx.infcx;
self.obligations.extend(
infcx
.tcx
.predicates_of(data.def_id)
.instantiate_own(infcx.tcx, data.substs)
.map(|(mut predicate, span)| {
if data.has_escaping_bound_vars() {
(predicate, ..) = BoundVarReplacer::replace_bound_vars(
infcx,
&mut self.universes,
predicate,
);
}
let mut cause = self.cause.clone();
cause.map_code(|code| {
ObligationCauseCode::TypeAlias(code, span, data.def_id)
});
Obligation::new(infcx.tcx, cause, self.param_env, predicate)
}),
);
infcx.tcx.type_of(data.def_id).subst(infcx.tcx, data.substs).fold_with(self)
}
ty::Inherent if !data.has_escaping_bound_vars() => {
// This branch is *mostly* just an optimization: when we don't
@ -1545,7 +1570,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
let bounds = match *obligation.predicate.self_ty().kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ref data) => {
tcx.item_bounds(data.def_id).subst(tcx, data.substs)
}

View file

@ -257,7 +257,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Opaque => ty.try_super_fold_with(self)?,
ty::Projection | ty::Inherent => {
ty::Projection | ty::Inherent | ty::Weak => {
// See note in `rustc_trait_selection::traits::project`
let infcx = self.infcx;
@ -282,6 +282,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = match kind {
ty::Projection => tcx.normalize_projection_ty(c_data),
ty::Weak => tcx.normalize_weak_ty(c_data),
ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
_ => unreachable!(),
}?;

View file

@ -143,7 +143,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, _) => {}
ty::Infer(ty::TyVar(_)) => {
span_bug!(

View file

@ -163,7 +163,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
// Excluding IATs here as they don't have meaningful item bounds.
// Excluding IATs and type aliases here as they don't have meaningful item bounds.
ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
(def_id, substs)
}

View file

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

View file

@ -731,6 +731,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
}
ty::Alias(ty::Weak, ty::AliasTy { def_id, substs, .. }) => {
let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations);
}
ty::Dynamic(data, r, _) => {
// WfObject
//