Update term for use in more places

Replace use of `ty()` on term and use it in more places. This will allow more flexibility in the
future, but slightly worried it allows items which are consts which only accept types.
This commit is contained in:
kadmin 2022-01-10 23:39:21 +00:00
parent 67f56671d0
commit e7529d6a38
31 changed files with 284 additions and 128 deletions

View File

@ -7,7 +7,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, OpaqueTypeKey, Term, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;
@ -584,13 +584,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if let Term::Ty(ty) = projection.term {
if ty.references_error() {
// No point on adding these obligations since there's a type error involved.
return tcx.ty_error();
}
} else {
todo!();
if projection.term.references_error() {
return tcx.ty_error();
}
}

View File

@ -742,6 +742,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
ast::AssocConstraintKind::Equality { ref term } => {
match term {
Term::Ty(ty) => involves_impl_trait(ty),
// FIXME(...): This should check if the constant
// involves a trait impl, but for now ignore.
Term::Const(_) => false,
}
}

View File

@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
}
/// Returns the associated item with the given name and any of `AssocKind`, if one exists.
pub fn find_by_name_and_kinds(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
kinds: &[AssocKind],
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
.filter(|item| kinds.contains(&item.kind))
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
}
/// Returns the associated item with the given name in the given `Namespace`, if one exists.
pub fn find_by_name_and_namespace(
&self,

View File

@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
match tcx.at(expr.span).lit_to_const(lit_input) {
Ok(c) => return Some(c),
Err(e) => {
tcx.sess.delay_span_bug(
expr.span,
&format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
);
}
}
}

View File

@ -245,7 +245,7 @@ impl FlagComputation {
self.add_projection_ty(projection_ty);
match term {
Term::Ty(ty) => self.add_ty(ty),
Term::Const(_c) => todo!(),
Term::Const(c) => self.add_const(c),
}
}
ty::PredicateKind::WellFormed(arg) => {

View File

@ -815,8 +815,8 @@ impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
}
impl<'tcx> Term<'tcx> {
pub fn ty(&self) -> Ty<'tcx> {
if let Term::Ty(ty) = self { ty } else { panic!("Expected type") }
pub fn ty(&self) -> Option<Ty<'tcx>> {
if let Term::Ty(ty) = self { Some(ty) } else { None }
}
}
@ -861,8 +861,8 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
}
pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
self.map_bound(|predicate| if let Term::Ty(ty) = predicate.term { ty } else { todo!() })
pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
self.map_bound(|predicate| predicate.term)
}
/// The `DefId` of the `TraitItem` for the associated type.

View File

@ -1,6 +1,6 @@
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sso::SsoHashSet;
@ -799,7 +799,7 @@ pub trait PrettyPrinter<'tcx>:
let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
// Projection type entry -- the def-id for naming, and the ty.
let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
self.insert_trait_and_projection(
trait_ref,
@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
}
p!(")");
if !return_ty.skip_binder().is_unit() {
p!("-> ", print(return_ty));
if let Term::Ty(ty) = return_ty.skip_binder() {
if !ty.is_unit() {
p!("-> ", print(return_ty));
}
}
p!(write("{}", if paren_needed { ")" } else { "" }));
@ -902,14 +904,15 @@ pub trait PrettyPrinter<'tcx>:
first = false;
}
for (assoc_item_def_id, ty) in assoc_items {
for (assoc_item_def_id, term) in assoc_items {
let ty = if let Term::Ty(ty) = term.skip_binder() { ty } else { continue };
if !first {
p!(", ");
}
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
match ty.skip_binder().kind() {
match ty.kind() {
ty::Projection(ty::ProjectionTy { item_def_id, .. })
if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
{
@ -943,8 +946,11 @@ pub trait PrettyPrinter<'tcx>:
fn insert_trait_and_projection(
&mut self,
trait_ref: ty::PolyTraitRef<'tcx>,
proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
traits: &mut BTreeMap<
ty::PolyTraitRef<'tcx>,
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) {
let trait_def_id = trait_ref.def_id();
@ -2716,5 +2722,5 @@ pub struct OpaqueFnEntry<'tcx> {
has_fn_once: bool,
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
}

View File

@ -833,19 +833,30 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
}
}
impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: Self,
b: Self,
) -> RelateResult<'tcx, Self> {
Ok(match (a, b) {
(Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
(Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
_ => return Err(TypeError::Mismatch),
})
}
}
impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
a: ty::ProjectionPredicate<'tcx>,
b: ty::ProjectionPredicate<'tcx>,
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
match (a.term, b.term) {
(Term::Ty(a_ty), Term::Ty(b_ty)) => Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
term: relation.relate(a_ty, b_ty)?.into(),
}),
_ => todo!(),
}
Ok(ty::ProjectionPredicate {
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
term: relation.relate(a.term, b.term)?.into(),
})
}
}

View File

@ -1583,7 +1583,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
let ty = if let Term::Ty(ty) = projection_predicate.term {
ty
} else {
todo!();
panic!("Only types are permitted here");
};
Self {

View File

@ -128,8 +128,10 @@ where
polarity: _,
}) => self.visit_trait(trait_ref),
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
let ty = term.ty();
ty.visit_with(self)?;
match term {
ty::Term::Ty(ty) => ty.visit_with(self)?,
ty::Term::Const(ct) => ct.visit_with(self)?,
}
self.visit_projection_ty(projection_ty)
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@ -1186,10 +1188,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
}
for (poly_predicate, _) in bounds.projection_bounds {
if self.visit(poly_predicate.skip_binder().term.ty()).is_break()
|| self
.visit_projection_ty(poly_predicate.skip_binder().projection_ty)
.is_break()
let pred = poly_predicate.skip_binder();
let poly_pred_term = match pred.term {
ty::Term::Ty(ty) => self.visit(ty),
ty::Term::Const(ct) => self.visit(ct),
};
if poly_pred_term.is_break()
|| self.visit_projection_ty(pred.projection_ty).is_break()
{
return;
}

View File

@ -6,7 +6,7 @@ use super::*;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::{Region, RegionVid};
use rustc_middle::ty::{Region, RegionVid, Term};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -606,7 +606,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
if let Term::Ty(ty) = p.term().skip_binder() {
matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
} else {
false
}
}
fn evaluate_nested_obligations(
@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user.
if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
&& !p.ty().skip_binder().has_infer_types()
&& !p.term().skip_binder().has_infer_types()
&& is_new_pred
{
debug!(
@ -752,7 +756,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// when we started out trying to unify
// some inference variables. See the comment above
// for more infomration
if p.ty().skip_binder().has_infer_types() {
if p.term().skip_binder().ty().map_or(false, |ty| ty.has_infer_types())
{
if !self.evaluate_nested_obligations(
ty,
v.into_iter(),
@ -774,7 +779,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with
// inference variables
if p.ty().skip_binder().has_infer_types() {
if p.term().skip_binder().ty().map_or(false, |ty| ty.has_infer_types())
{
panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
}
}

View File

@ -1304,8 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
debug!(
"report_projection_error normalized_ty={:?} data.ty={:?}",
normalized_ty,
data.term.ty()
normalized_ty, data.term,
);
let is_normalized_ty_expected = !matches!(
@ -1315,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType
);
// FIXME(...): Handle Consts here
let data_ty = data.term.ty().unwrap();
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,
normalized_ty,
data.term.ty(),
data_ty,
) {
values = Some(infer::ValuePairs::Types(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
data.term.ty(),
data_ty,
)));
err_buf = error;

View File

@ -212,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
let infcx = selcx.infcx();
match infcx
.at(&obligation.cause, obligation.param_env)
.eq(normalized_ty, obligation.predicate.term.ty())
{
// FIXME(...): Handle consts here as well as types.
let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations)))
@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
Progress { ty: cache_entry.term.ty(), obligations: nested_obligations }
// FIXME(...): Handle consts here as well? Maybe this progress type should just take
// a term instead.
Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
}
Err(e) => {
let msg = format!(

View File

@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.ty().ty_vid() {
if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true;
}

View File

@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
}
ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
wf.compute(t.term.ty().into());
wf.compute(match t.term {
ty::Term::Ty(ty) => ty.into(),
ty::Term::Const(c) => c.into(),
})
}
ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg);
@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
if let ty::Projection(projection_ty) = proj.term.ty().kind() {
if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
if let Some(&impl_item_id) =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
{

View File

@ -227,12 +227,24 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
{
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
chalk_ir::AliasEq {
ty: self.term.ty().lower_into(interner),
ty: self.term.ty().unwrap().lower_into(interner),
alias: self.projection_ty.lower_into(interner),
}
}
}
/*
// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
match self {
ty::Term::Ty(ty) => ty.lower_into(interner).into(),
ty::Term::Const(c) => c.lower_into(interner).into(),
}
}
}
*/
impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@ -787,7 +799,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
value: self.term.ty().lower_into(interner),
value: self.term.ty().unwrap().lower_into(interner),
}
}
}

View File

@ -123,8 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>),
Const(&'tcx Const<'tcx>),
Equality(ty::Term<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]),
}
@ -604,12 +603,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let kind = match binding.kind {
hir::TypeBindingKind::Equality { ref term } => match term {
hir::Term::Ty(ref ty) => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
}
hir::Term::Const(ref c) => {
let local_did = self.tcx().hir().local_def_id(c.hir_id);
let c = Const::from_anon_const(self.tcx(), local_did);
ConvertedBindingKind::Const(&c)
ConvertedBindingKind::Equality(c.into())
}
},
hir::TypeBindingKind::Constraint { ref bounds } => {
@ -875,6 +874,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some()
}
fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kinds(
self.tcx(),
assoc_name,
&[ty::AssocKind::Type, ty::AssocKind::Const],
trait_def_id,
)
.is_some()
}
// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized<'hir>(
@ -1223,7 +1233,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
match binding.kind {
ConvertedBindingKind::Equality(ty) => {
ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
//
@ -1231,16 +1241,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: ty.into(),
}),
binding.span,
));
}
ConvertedBindingKind::Const(c) => {
bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: c.into(),
term: term,
}),
binding.span,
));
@ -1391,8 +1392,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
let references_self =
pred.skip_binder().term.ty().walk().any(|arg| arg == dummy_self.into());
let references_self = match pred.skip_binder().term {
ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
ty::Term::Const(c) => {
c.ty.walk().any(|arg| arg == dummy_self.into())
}
};
// If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity.
@ -1615,7 +1620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let mut matching_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
.filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
let bound = match matching_candidates.next() {
Some(bound) => bound,

View File

@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
};
let ret_param_ty = projection.skip_binder().term.ty();
// Since this is a return parameter type it is safe to unwrap.
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
@ -706,9 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Extract the type from the projection. Note that there can
// be no bound variables in this type because the "self type"
// does not have any regions in it.
let output_ty = self.resolve_vars_if_possible(predicate.term.ty());
let output_ty = self.resolve_vars_if_possible(predicate.term);
debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
Some(output_ty)
// FIXME(...): How to handle consts here? Will this always be a const?
Some(output_ty.ty().unwrap())
}
/// Converts the types that the user supplied, in case that doing

View File

@ -789,10 +789,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_def_id: projection_ty.item_def_id,
};
let ty: Ty<'_> = pred.skip_binder().term.ty();
let fmt = match pred.skip_binder().term {
ty::Term::Ty(ty) => format!("{}", ty),
ty::Term::Const(c) => format!("{}", c),
};
let obligation = format!("{} = {}", projection_ty, ty);
let quiet = format!("{} = {}", quiet_projection_ty, ty);
let obligation = format!("{} = {}", projection_ty, fmt);
let quiet = format!("{} = {}", quiet_projection_ty, fmt);
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))

View File

@ -694,7 +694,10 @@ fn bounds_from_generic_predicates<'tcx>(
where_clauses.push(format!(
"{} = {}",
tcx.def_path_str(p.projection_ty.item_def_id),
p.term.ty()
match p.term {
ty::Term::Ty(ty) => format!("{}", ty),
ty::Term::Const(c) => format!("{}", c),
}
));
}
let where_clauses = if where_clauses.is_empty() {

View File

@ -553,8 +553,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
if self.is_fn_trait(trait_) && left_name == sym::Output {
ty_to_fn
.entry(*ty.clone())
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
.or_insert((None, Some(rhs)));
.and_modify(|e| {
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
.or_insert((None, Some(rhs.ty().unwrap().clone())));
continue;
}
@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding {
name: left_name,
kind: TypeBindingKind::Equality { ty: rhs },
kind: TypeBindingKind::Equality { term: rhs },
});
}
GenericArgs::Parenthesized { .. } => {

View File

@ -272,9 +272,10 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => {
WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
}
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: wrp.lhs_ty.clean(cx),
rhs: wrp.rhs_ty.clean(cx).into(),
},
}
}
}
@ -352,11 +353,31 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
}
}
impl<'tcx> Clean<Term> for ty::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
match self {
ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
ty::Term::Const(c) => Term::Constant(c.clean(cx)),
}
}
}
impl<'tcx> Clean<Term> for hir::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> Term {
match self {
hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
hir::Term::Const(c) => {
let def_id = cx.tcx.hir().local_def_id(c.hir_id);
Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
}
}
}
}
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, term } = self;
let ty = term.ty();
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
}
}
@ -614,7 +635,7 @@ fn clean_ty_generics(
if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p = p.clean(cx)?;
let p: WherePredicate = p.clean(cx)?;
b.extend(
p.get_bounds()
@ -624,13 +645,17 @@ fn clean_ty_generics(
.filter(|b| !b.is_sized_bound(cx)),
);
let proj = projection.map(|p| {
(p.skip_binder().projection_ty.clean(cx), p.skip_binder().term.ty())
});
let proj = projection
.map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
if let Some(((_, trait_did, name), rhs)) =
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
{
impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
// FIXME(...): Remove this unwrap()
impl_trait_proj.entry(param_idx).or_default().push((
trait_did,
name,
rhs.ty().unwrap(),
));
}
return None;
@ -649,7 +674,7 @@ fn clean_ty_generics(
if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj {
let rhs = rhs.clean(cx);
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
}
}
} else {
@ -1497,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
for pb in obj.projection_bounds() {
bindings.push(TypeBinding {
name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
kind: TypeBindingKind::Equality {
term: pb.skip_binder().ty.clean(cx).into(),
},
});
}
@ -1568,7 +1595,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
.ident
.name,
kind: TypeBindingKind::Equality {
ty: proj.term.ty().clean(cx),
term: proj.term.clean(cx),
},
})
} else {
@ -2116,10 +2143,9 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
match *self {
hir::TypeBindingKind::Equality { ref term } => match term {
hir::Term::Ty(ref ty) => TypeBindingKind::Equality { ty: ty.clean(cx) },
hir::Term::Const(ref _c) => todo!(),
},
hir::TypeBindingKind::Equality { ref term } => {
TypeBindingKind::Equality { term: term.clean(cx) }
}
hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
},

View File

@ -92,7 +92,7 @@ crate fn merge_bounds(
bounds: &mut Vec<clean::GenericBound>,
trait_did: DefId,
name: Symbol,
rhs: &clean::Type,
rhs: &clean::Term,
) -> bool {
!bounds.iter_mut().any(|b| {
let trait_ref = match *b {
@ -110,14 +110,14 @@ crate fn merge_bounds(
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
name,
kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
});
}
PP::Parenthesized { ref mut output, .. } => match output {
Some(o) => assert_eq!(o.as_ref(), rhs),
Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
None => {
if *rhs != clean::Type::Tuple(Vec::new()) {
*output = Some(Box::new(rhs.clone()));
if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
*output = Some(Box::new(rhs.ty().unwrap().clone()));
}
}
},

View File

@ -1212,7 +1212,7 @@ impl Lifetime {
crate enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
EqPredicate { lhs: Type, rhs: Type },
EqPredicate { lhs: Type, rhs: Term },
}
impl WherePredicate {
@ -1308,7 +1308,12 @@ impl FnDecl {
FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
let bindings = trait_.bindings().unwrap();
FnRetTy::Return(bindings[0].ty().clone())
let ret_ty = bindings[0].term();
let ty = match ret_ty {
Term::Type(ty) => ty,
Term::Constant(_c) => unreachable!(),
};
FnRetTy::Return(ty.clone())
}
_ => panic!("unexpected desugaring of async function"),
},
@ -2121,6 +2126,24 @@ crate struct Constant {
crate kind: ConstantKind,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
crate enum Term {
Type(Type),
Constant(Constant),
}
impl Term {
crate fn ty(&self) -> Option<&Type> {
if let Term::Type(ty) = self { Some(ty) } else { None }
}
}
impl From<Type> for Term {
fn from(ty: Type) -> Self {
Term::Type(ty)
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
crate enum ConstantKind {
/// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
@ -2283,14 +2306,14 @@ crate struct TypeBinding {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate enum TypeBindingKind {
Equality { ty: Type },
Equality { term: Term },
Constraint { bounds: Vec<GenericBound> },
}
impl TypeBinding {
crate fn ty(&self) -> &Type {
crate fn term(&self) -> &Term {
match self.kind {
TypeBindingKind::Equality { ref ty } => ty,
TypeBindingKind::Equality { ref term } => term,
_ => panic!("expected equality type binding for parenthesized generic args"),
}
}

View File

@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
display_fn(move |f| {
f.write_str(self.name.as_str())?;
match self.kind {
clean::TypeBindingKind::Equality { ref ty } => {
clean::TypeBindingKind::Equality { ref term } => {
if f.alternate() {
write!(f, " = {:#}", ty.print(cx))?;
write!(f, " = {:#}", term.print(cx))?;
} else {
write!(f, " = {}", ty.print(cx))?;
write!(f, " = {}", term.print(cx))?;
}
}
clean::TypeBindingKind::Constraint { ref bounds } => {
@ -1492,6 +1492,18 @@ impl clean::GenericArg {
}
}
impl clean::types::Term {
crate fn print<'a, 'tcx: 'a>(
&'a self,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
match self {
clean::types::Term::Type(ty) => ty.print(cx),
_ => todo!(),
}
}
}
crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
struct WithFormatter<F>(Cell<Option<F>>);

View File

@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
use clean::TypeBindingKind::*;
match kind {
Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
}
@ -452,6 +452,15 @@ impl FromWithTcx<clean::Type> for Type {
}
}
impl FromWithTcx<clean::Term> for Term {
fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
match term {
clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
}
}
}
impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;

View File

@ -148,7 +148,7 @@ pub struct TypeBinding {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum TypeBindingKind {
Equality(Type),
Equality(Term),
Constraint(Vec<GenericBound>),
}
@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
EqPredicate { lhs: Type, rhs: Type },
EqPredicate { lhs: Type, rhs: Term },
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
MaybeConst,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum Term {
Type(Type),
Constant(Constant),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "kind", content = "inner")]

View File

@ -1,4 +1,4 @@
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
--> $DIR/repeated_projection_type.rs:19:1
|
LL | / impl<I, V: Id<This = (I,)>> X for V {

View File

@ -2141,12 +2141,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
let assoc_ty = match projection_predicate.term {
ty::Term::Ty(ty) => ty,
ty::Term::Const(c) => c.ty,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
if contains_adt_constructor(projection_predicate.term.ty(), self_adt) {
if contains_adt_constructor(assoc_ty, self_adt) {
return;
}
} else if contains_ty(projection_predicate.term.ty(), self_ty) {
} else if contains_ty(assoc_ty, self_ty) {
return;
}
}

View File

@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
if if trait_predicate.def_id() == deref_trait_id {
if let [projection_predicate] = projection_predicates[..] {
let normalized_ty =
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term.ty());
cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
implements_trait(cx, receiver_ty, deref_trait_id, &[])
&& get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
&& get_associated_type(cx, receiver_ty, deref_trait_id,
"Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
} else {
false
}

View File

@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
if trait_pred.self_ty() == inp;
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
then {
if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.term.ty()) {
if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
return_ty_pred.term.ty()) {
args_to_check.push((i, "Ord".to_string()));
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty()) {
} else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
args_to_check.push((i, "PartialOrd".to_string()));
}
}