1
Fork 0

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

View file

@ -742,6 +742,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
ast::AssocConstraintKind::Equality { ref term } => { ast::AssocConstraintKind::Equality { ref term } => {
match term { match term {
Term::Ty(ty) => involves_impl_trait(ty), 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, Term::Const(_) => false,
} }
} }

View file

@ -152,6 +152,19 @@ impl<'tcx> AssocItems<'tcx> {
.find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) .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. /// Returns the associated item with the given name in the given `Namespace`, if one exists.
pub fn find_by_name_and_namespace( pub fn find_by_name_and_namespace(
&self, &self,

View file

@ -86,10 +86,14 @@ impl<'tcx> Const<'tcx> {
if let Some(lit_input) = lit_input { if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to // If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir. // mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { match tcx.at(expr.span).lit_to_const(lit_input) {
return Some(c); Ok(c) => return Some(c),
} else { Err(e) => {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const"); 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); self.add_projection_ty(projection_ty);
match term { match term {
Term::Ty(ty) => self.add_ty(ty), Term::Ty(ty) => self.add_ty(ty),
Term::Const(_c) => todo!(), Term::Const(c) => self.add_const(c),
} }
} }
ty::PredicateKind::WellFormed(arg) => { ty::PredicateKind::WellFormed(arg) => {

View file

@ -815,8 +815,8 @@ impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
} }
impl<'tcx> Term<'tcx> { impl<'tcx> Term<'tcx> {
pub fn ty(&self) -> Ty<'tcx> { pub fn ty(&self) -> Option<Ty<'tcx>> {
if let Term::Ty(ty) = self { ty } else { panic!("Expected type") } 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)) self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
} }
pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> { pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
self.map_bound(|predicate| if let Term::Ty(ty) = predicate.term { ty } else { todo!() }) self.map_bound(|predicate| predicate.term)
} }
/// The `DefId` of the `TraitItem` for the associated type. /// 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::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; 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_apfloat::ieee::{Double, Single};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sso::SsoHashSet; 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()); let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
// Projection type entry -- the def-id for naming, and the ty. // 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( self.insert_trait_and_projection(
trait_ref, trait_ref,
@ -850,8 +850,10 @@ pub trait PrettyPrinter<'tcx>:
} }
p!(")"); p!(")");
if !return_ty.skip_binder().is_unit() { if let Term::Ty(ty) = return_ty.skip_binder() {
p!("-> ", print(return_ty)); if !ty.is_unit() {
p!("-> ", print(return_ty));
}
} }
p!(write("{}", if paren_needed { ")" } else { "" })); p!(write("{}", if paren_needed { ")" } else { "" }));
@ -902,14 +904,15 @@ pub trait PrettyPrinter<'tcx>:
first = false; 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 { if !first {
p!(", "); p!(", ");
} }
p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident)); p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
// Skip printing `<[generator@] as Generator<_>>::Return` from async blocks // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
match ty.skip_binder().kind() { match ty.kind() {
ty::Projection(ty::ProjectionTy { item_def_id, .. }) ty::Projection(ty::ProjectionTy { item_def_id, .. })
if Some(*item_def_id) == self.tcx().lang_items().generator_return() => if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
{ {
@ -943,8 +946,11 @@ pub trait PrettyPrinter<'tcx>:
fn insert_trait_and_projection( fn insert_trait_and_projection(
&mut self, &mut self,
trait_ref: ty::PolyTraitRef<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>,
proj_ty: Option<(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, Ty<'tcx>>>>, traits: &mut BTreeMap<
ty::PolyTraitRef<'tcx>,
BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
>,
fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>, fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
) { ) {
let trait_def_id = trait_ref.def_id(); let trait_def_id = trait_ref.def_id();
@ -2716,5 +2722,5 @@ pub struct OpaqueFnEntry<'tcx> {
has_fn_once: bool, has_fn_once: bool,
fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>, fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
fn_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> { impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>( fn relate<R: TypeRelation<'tcx>>(
relation: &mut R, relation: &mut R,
a: ty::ProjectionPredicate<'tcx>, a: ty::ProjectionPredicate<'tcx>,
b: ty::ProjectionPredicate<'tcx>, b: ty::ProjectionPredicate<'tcx>,
) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
match (a.term, b.term) { Ok(ty::ProjectionPredicate {
(Term::Ty(a_ty), Term::Ty(b_ty)) => Ok(ty::ProjectionPredicate { projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, term: relation.relate(a.term, b.term)?.into(),
term: relation.relate(a_ty, b_ty)?.into(), })
}),
_ => todo!(),
}
} }
} }

View file

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

View file

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

View file

@ -6,7 +6,7 @@ use super::*;
use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use rustc_middle::ty::fold::TypeFolder; 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}; 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 { 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( fn evaluate_nested_obligations(
@ -663,7 +667,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// Additionally, we check if we've seen this predicate before, // Additionally, we check if we've seen this predicate before,
// to avoid rendering duplicate bounds to the user. // to avoid rendering duplicate bounds to the user.
if self.is_param_no_infer(p.skip_binder().projection_ty.substs) 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 && is_new_pred
{ {
debug!( debug!(
@ -752,7 +756,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// when we started out trying to unify // when we started out trying to unify
// some inference variables. See the comment above // some inference variables. See the comment above
// for more infomration // 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( if !self.evaluate_nested_obligations(
ty, ty,
v.into_iter(), v.into_iter(),
@ -774,7 +779,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// However, we should always make progress (either by generating // However, we should always make progress (either by generating
// subobligations or getting an error) when we started off with // subobligations or getting an error) when we started off with
// inference variables // 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) panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
} }
} }

View file

@ -1304,8 +1304,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
debug!( debug!(
"report_projection_error normalized_ty={:?} data.ty={:?}", "report_projection_error normalized_ty={:?} data.ty={:?}",
normalized_ty, normalized_ty, data.term,
data.term.ty()
); );
let is_normalized_ty_expected = !matches!( let is_normalized_ty_expected = !matches!(
@ -1315,16 +1314,17 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
| ObligationCauseCode::ObjectCastObligation(_) | ObligationCauseCode::ObjectCastObligation(_)
| ObligationCauseCode::OpaqueType | 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( if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected, is_normalized_ty_expected,
normalized_ty, normalized_ty,
data.term.ty(), data_ty,
) { ) {
values = Some(infer::ValuePairs::Types(ExpectedFound::new( values = Some(infer::ValuePairs::Types(ExpectedFound::new(
is_normalized_ty_expected, is_normalized_ty_expected,
normalized_ty, normalized_ty,
data.term.ty(), data_ty,
))); )));
err_buf = error; 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"); debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
let infcx = selcx.infcx(); let infcx = selcx.infcx();
match infcx // FIXME(...): Handle consts here as well as types.
.at(&obligation.cause, obligation.param_env) let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
.eq(normalized_ty, obligation.predicate.term.ty()) match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
{
Ok(InferOk { obligations: inferred_obligations, value: () }) => { Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations); obligations.extend(inferred_obligations);
Ok(Ok(Some(obligations))) Ok(Ok(Some(obligations)))
@ -1803,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
Ok(InferOk { value: _, obligations }) => { Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations); nested_obligations.extend(obligations);
assoc_ty_own_obligations(selcx, obligation, &mut nested_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) => { Err(e) => {
let msg = format!( 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 let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid, // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one. // 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); debug!("relationship: {:?}.output = true", vid);
engine.relationships().entry(vid).or_default().output = true; engine.relationships().entry(vid).or_default().output = true;
} }

View file

@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
} }
ty::PredicateKind::Projection(t) => { ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty); 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) => { ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg); wf.compute(arg);
@ -219,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// projection coming from another associated type. See // projection coming from another associated type. See
// `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`. // `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) = if let Some(&impl_item_id) =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_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>> { fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
chalk_ir::AliasEq { 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), 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> { impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'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)); 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), trait_bound: trait_ref.lower_into(interner),
associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id), associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(), 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)] #[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> { enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>), Equality(ty::Term<'tcx>),
Const(&'tcx Const<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]), Constraint(&'a [hir::GenericBound<'a>]),
} }
@ -604,12 +603,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let kind = match binding.kind { let kind = match binding.kind {
hir::TypeBindingKind::Equality { ref term } => match term { hir::TypeBindingKind::Equality { ref term } => match term {
hir::Term::Ty(ref ty) => { 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) => { hir::Term::Const(ref c) => {
let local_did = self.tcx().hir().local_def_id(c.hir_id); let local_did = self.tcx().hir().local_def_id(c.hir_id);
let c = Const::from_anon_const(self.tcx(), local_did); let c = Const::from_anon_const(self.tcx(), local_did);
ConvertedBindingKind::Const(&c) ConvertedBindingKind::Equality(c.into())
} }
}, },
hir::TypeBindingKind::Constraint { ref bounds } => { 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) .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some() .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 // Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized<'hir>( pub(crate) fn add_implicitly_sized<'hir>(
@ -1223,7 +1233,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
match binding.kind { match binding.kind {
ConvertedBindingKind::Equality(ty) => { ConvertedBindingKind::Equality(term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for: // the "projection predicate" for:
// //
@ -1231,16 +1241,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
bounds.projection_bounds.push(( bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty, projection_ty,
term: ty.into(), term: term,
}),
binding.span,
));
}
ConvertedBindingKind::Const(c) => {
bounds.projection_bounds.push((
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
projection_ty,
term: c.into(),
}), }),
binding.span, binding.span,
)); ));
@ -1391,8 +1392,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let pred = bound_predicate.rebind(pred); let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a // A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that. // `trait_object_dummy_self`, so check for that.
let references_self = let references_self = match pred.skip_binder().term {
pred.skip_binder().term.ty().walk().any(|arg| arg == dummy_self.into()); 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 // If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity. // 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>>, I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{ {
let mut matching_candidates = all_candidates() 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() { let bound = match matching_candidates.next() {
Some(bound) => bound, Some(bound) => bound,

View file

@ -279,7 +279,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None; 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); let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty={:?}", 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 // Extract the type from the projection. Note that there can
// be no bound variables in this type because the "self type" // be no bound variables in this type because the "self type"
// does not have any regions in it. // 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); 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 /// 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, 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 obligation = format!("{} = {}", projection_ty, fmt);
let quiet = format!("{} = {}", quiet_projection_ty, ty); let quiet = format!("{} = {}", quiet_projection_ty, fmt);
bound_span_label(projection_ty.self_ty(), &obligation, &quiet); bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty())) Some((obligation, projection_ty.self_ty()))

View file

@ -694,7 +694,10 @@ fn bounds_from_generic_predicates<'tcx>(
where_clauses.push(format!( where_clauses.push(format!(
"{} = {}", "{} = {}",
tcx.def_path_str(p.projection_ty.item_def_id), 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() { 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 { if self.is_fn_trait(trait_) && left_name == sym::Output {
ty_to_fn ty_to_fn
.entry(*ty.clone()) .entry(*ty.clone())
.and_modify(|e| *e = (e.0.clone(), Some(rhs.clone()))) .and_modify(|e| {
.or_insert((None, Some(rhs))); *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
.or_insert((None, Some(rhs.ty().unwrap().clone())));
continue; continue;
} }
@ -570,7 +572,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
GenericArgs::AngleBracketed { ref mut bindings, .. } => { GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding { bindings.push(TypeBinding {
name: left_name, name: left_name,
kind: TypeBindingKind::Equality { ty: rhs }, kind: TypeBindingKind::Equality { term: rhs },
}); });
} }
GenericArgs::Parenthesized { .. } => { 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(), bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
}, },
hir::WherePredicate::EqPredicate(ref wrp) => { hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) } 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> { impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate { fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, term } = self; let ty::ProjectionPredicate { projection_ty, term } = self;
let ty = term.ty(); WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
} }
} }
@ -614,7 +635,7 @@ fn clean_ty_generics(
if let Some(param_idx) = param_idx { if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) { if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p = p.clean(cx)?; let p: WherePredicate = p.clean(cx)?;
b.extend( b.extend(
p.get_bounds() p.get_bounds()
@ -624,13 +645,17 @@ fn clean_ty_generics(
.filter(|b| !b.is_sized_bound(cx)), .filter(|b| !b.is_sized_bound(cx)),
); );
let proj = projection.map(|p| { let proj = projection
(p.skip_binder().projection_ty.clean(cx), p.skip_binder().term.ty()) .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
});
if let Some(((_, trait_did, name), rhs)) = if let Some(((_, trait_did, name), rhs)) =
proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, 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; return None;
@ -649,7 +674,7 @@ fn clean_ty_generics(
if let Some(proj) = impl_trait_proj.remove(&idx) { if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj { for (trait_did, name, rhs) in proj {
let rhs = rhs.clean(cx); 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 { } else {
@ -1497,7 +1522,9 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
for pb in obj.projection_bounds() { for pb in obj.projection_bounds() {
bindings.push(TypeBinding { bindings.push(TypeBinding {
name: cx.tcx.associated_item(pb.item_def_id()).ident.name, 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 .ident
.name, .name,
kind: TypeBindingKind::Equality { kind: TypeBindingKind::Equality {
ty: proj.term.ty().clean(cx), term: proj.term.clean(cx),
}, },
}) })
} else { } else {
@ -2116,10 +2143,9 @@ impl Clean<TypeBinding> for hir::TypeBinding<'_> {
impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> { impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind { fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
match *self { match *self {
hir::TypeBindingKind::Equality { ref term } => match term { hir::TypeBindingKind::Equality { ref term } => {
hir::Term::Ty(ref ty) => TypeBindingKind::Equality { ty: ty.clean(cx) }, TypeBindingKind::Equality { term: term.clean(cx) }
hir::Term::Const(ref _c) => todo!(), }
},
hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint { hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(), 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>, bounds: &mut Vec<clean::GenericBound>,
trait_did: DefId, trait_did: DefId,
name: Symbol, name: Symbol,
rhs: &clean::Type, rhs: &clean::Term,
) -> bool { ) -> bool {
!bounds.iter_mut().any(|b| { !bounds.iter_mut().any(|b| {
let trait_ref = match *b { let trait_ref = match *b {
@ -110,14 +110,14 @@ crate fn merge_bounds(
PP::AngleBracketed { ref mut bindings, .. } => { PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding { bindings.push(clean::TypeBinding {
name, name,
kind: clean::TypeBindingKind::Equality { ty: rhs.clone() }, kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
}); });
} }
PP::Parenthesized { ref mut output, .. } => match output { 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 => { None => {
if *rhs != clean::Type::Tuple(Vec::new()) { if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
*output = Some(Box::new(rhs.clone())); *output = Some(Box::new(rhs.ty().unwrap().clone()));
} }
} }
}, },

View file

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

View file

@ -1442,11 +1442,11 @@ impl clean::TypeBinding {
display_fn(move |f| { display_fn(move |f| {
f.write_str(self.name.as_str())?; f.write_str(self.name.as_str())?;
match self.kind { match self.kind {
clean::TypeBindingKind::Equality { ref ty } => { clean::TypeBindingKind::Equality { ref term } => {
if f.alternate() { if f.alternate() {
write!(f, " = {:#}", ty.print(cx))?; write!(f, " = {:#}", term.print(cx))?;
} else { } else {
write!(f, " = {}", ty.print(cx))?; write!(f, " = {}", term.print(cx))?;
} }
} }
clean::TypeBindingKind::Constraint { ref bounds } => { 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 { crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
struct WithFormatter<F>(Cell<Option<F>>); 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 { fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
use clean::TypeBindingKind::*; use clean::TypeBindingKind::*;
match kind { match kind {
Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)), Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => { Constraint { bounds } => {
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) 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 { impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum TypeBindingKind { pub enum TypeBindingKind {
Equality(Type), Equality(Term),
Constraint(Vec<GenericBound>), Constraint(Vec<GenericBound>),
} }
@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
pub enum WherePredicate { pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
RegionPredicate { lifetime: String, 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
MaybeConst, 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)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
#[serde(tag = "kind", content = "inner")] #[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 --> $DIR/repeated_projection_type.rs:19:1
| |
LL | / impl<I, V: Id<This = (I,)>> X for V { 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 // one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { 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 // walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() { 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; return;
} }
} else if contains_ty(projection_predicate.term.ty(), self_ty) { } else if contains_ty(assoc_ty, self_ty) {
return; return;
} }
} }

View file

@ -243,9 +243,10 @@ fn check_other_call_arg<'tcx>(
if if trait_predicate.def_id() == deref_trait_id { if if trait_predicate.def_id() == deref_trait_id {
if let [projection_predicate] = projection_predicates[..] { if let [projection_predicate] = projection_predicates[..] {
let normalized_ty = 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, &[]) 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 { } else {
false 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 trait_pred.self_ty() == inp;
if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred); if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
then { 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())); 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())); args_to_check.push((i, "PartialOrd".to_string()));
} }
} }