diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 39339da9a0bfc..4851e637d3a62 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -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(); } } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0d1081ee26b77..3921187baa55e 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -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, } } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 8563bac0bbf87..2776370ba6f46 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -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, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 75705d40a6c80..d6c35dfef8888 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -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), + ); + } } } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 74c8d7b777722..be9021dc61989 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -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) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f1851150e38e8..42e6f3f6ef584 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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> { + 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. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8c07f154637e3..6fcb6ac5f4c0b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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, BTreeMap>>>, + proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>, + traits: &mut BTreeMap< + ty::PolyTraitRef<'tcx>, + BTreeMap>>, + >, fn_traits: &mut BTreeMap, 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>, fn_trait_ref: Option>, - return_ty: Option>>, + return_ty: Option>>, } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 851c4592f4fad..bd6c24445ef51 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -833,19 +833,30 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::Term<'tcx> { + fn relate>( + 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>( 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(), + }) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 50d0862905bbf..453e380f6e3a0 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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 { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index dc432905b1c7c..73873c8cf0d91 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -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; } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 05d2a373dc639..cc20c1179452c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -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) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 85135383b8062..43a961c5c9116 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 4995590baec23..4b53b624c72f1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -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!( diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs index acac76cdfaaf0..aea44841b8f12 100644 --- a/compiler/rustc_trait_selection/src/traits/relationships.rs +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -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; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e3b366c65bf5c..6a355b567e091 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -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) { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e651ff63c5249..dd98e4ae81b34 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -227,12 +227,24 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> { fn lower_into(self, interner: 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), } } } +/* +// 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>> for rustc_middle::ty::Term<'tcx> { + fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term> { + 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>> for Ty<'tcx> { fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty> { 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 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), } } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2866a7884a77a..a13eaa6f178de 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -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` 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>, { 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, diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index c8e1d8b190c9d..504807e87b69a 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -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 diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 590d65b7cba3f..bf362357ed073 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -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())) diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 8d06b8a7a170b..9f67713d585bd 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -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() { diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 09692d27e8fbe..18a4d8a475380 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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 { .. } => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f6af81769b7a1..6a3cdcc2c20da 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -272,9 +272,10 @@ impl Clean 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> for ty::OutlivesPredicate, ty: } } +impl<'tcx> Clean 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 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 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(¶m_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 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 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 for hir::TypeBinding<'_> { impl Clean 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(), }, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 4c81e75e8d630..0bad153280822 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -92,7 +92,7 @@ crate fn merge_bounds( bounds: &mut Vec, 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())); } } }, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 00c6e38839f54..ba771c0c1a1a4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1212,7 +1212,7 @@ impl Lifetime { crate enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec, bound_params: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec }, - 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 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 }, } 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"), } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8571a6a137f51..08840626259dc 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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(Cell>); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c8efa4bbbcc30..e77bd5c922313 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -162,7 +162,7 @@ impl FromWithTcx 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 for Type { } } +impl FromWithTcx 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 for FunctionPointer { fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self { let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 9466f84ffcd59..618c8aab86a19 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -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), } @@ -335,7 +335,7 @@ pub enum GenericParamDefKind { pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: String, bounds: Vec }, - 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")] diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 07d194476a5db..ad51707070f9f 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -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> X for V { diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index c0e65e520f23a..ca8bbbd8f9169 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -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; } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 865a36a5cd1d6..9162de3cceafa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -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 } diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index 09f9e1ee09990..68156df2ecea8 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -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())); } }