diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 079b9e43373..9d447f3b5cb 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -224,7 +224,7 @@ pub enum AngleBracketedArg { /// Argument for a generic parameter. Arg(GenericArg), /// Constraint for an associated item. - Constraint(AssocTyConstraint), + Constraint(AssocConstraint), } impl AngleBracketedArg { @@ -1843,19 +1843,21 @@ impl UintTy { /// A constraint on an associated type (e.g., `A = Bar` in `Foo` or /// `A: TraitA + TraitB` in `Foo`). #[derive(Clone, Encodable, Decodable, Debug)] -pub struct AssocTyConstraint { +pub struct AssocConstraint { pub id: NodeId, pub ident: Ident, pub gen_args: Option, - pub kind: AssocTyConstraintKind, + pub kind: AssocConstraintKind, pub span: Span, } -/// The kinds of an `AssocTyConstraint`. +/// The kinds of an `AssocConstraint`. #[derive(Clone, Encodable, Decodable, Debug)] -pub enum AssocTyConstraintKind { - /// E.g., `A = Bar` in `Foo`. +pub enum AssocConstraintKind { + /// E.g., `A = Bar` in `Foo` where A is an associated type. Equality { ty: P }, + /// E.g., `A = 3` in `Foo` where N is an associated const. + ConstEquality { c: AnonConst }, /// E.g. `A: TraitA + TraitB` in `Foo`. Bound { bounds: GenericBounds }, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 564a8a8c872..ba68ff691ca 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -165,8 +165,8 @@ pub trait MutVisitor: Sized { noop_visit_lifetime(l, self); } - fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) { - noop_visit_ty_constraint(t, self); + fn visit_constraint(&mut self, t: &mut AssocConstraint) { + noop_visit_constraint(t, self); } fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { @@ -430,8 +430,8 @@ pub fn noop_flat_map_arm(mut arm: Arm, vis: &mut T) -> SmallVec<[ smallvec![arm] } -pub fn noop_visit_ty_constraint( - AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint, +pub fn noop_visit_constraint( + AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint, vis: &mut T, ) { vis.visit_id(id); @@ -440,12 +440,9 @@ pub fn noop_visit_ty_constraint( vis.visit_generic_args(gen_args); } match kind { - AssocTyConstraintKind::Equality { ref mut ty } => { - vis.visit_ty(ty); - } - AssocTyConstraintKind::Bound { ref mut bounds } => { - visit_bounds(bounds, vis); - } + AssocConstraintKind::Equality { ref mut ty } => vis.visit_ty(ty), + AssocConstraintKind::ConstEquality { ref mut c } => vis.visit_anon_const(c), + AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis), } vis.visit_span(span); } @@ -555,7 +552,7 @@ pub fn noop_visit_angle_bracketed_parameter_data( let AngleBracketedArgs { args, span } = data; visit_vec(args, |arg| match arg { AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), - AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint), + AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint), }); vis.visit_span(span); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0b95270a4e1..f054f4de2f9 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized { fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) { walk_generic_arg(self, generic_arg) } - fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { - walk_assoc_ty_constraint(self, constraint) + fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) { + walk_assoc_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'ast Attribute) { walk_attribute(self, attr) @@ -464,7 +464,7 @@ where for arg in &data.args { match arg { AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a), - AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c), + AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c), } } } @@ -486,19 +486,15 @@ where } } -pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( - visitor: &mut V, - constraint: &'a AssocTyConstraint, -) { +pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) { visitor.visit_ident(constraint.ident); if let Some(ref gen_args) = constraint.gen_args { visitor.visit_generic_args(gen_args.span(), gen_args); } match constraint.kind { - AssocTyConstraintKind::Equality { ref ty } => { - visitor.visit_ty(ty); - } - AssocTyConstraintKind::Bound { ref bounds } => { + AssocConstraintKind::Equality { ref ty } => visitor.visit_ty(ty), + AssocConstraintKind::ConstEquality { ref c } => visitor.visit_anon_const(c), + AssocConstraintKind::Bound { ref bounds } => { walk_list!(visitor, visit_param_bound, bounds); } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 35eb716949a..450f4238584 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// returns a `hir::TypeBinding` representing `Item`. fn lower_assoc_ty_constraint( &mut self, - constraint: &AssocTyConstraint, + constraint: &AssocConstraint, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); @@ -997,10 +997,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let kind = match constraint.kind { - AssocTyConstraintKind::Equality { ref ty } => { + AssocConstraintKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } } - AssocTyConstraintKind::Bound { ref bounds } => { + AssocConstraintKind::ConstEquality { ref c } => { + hir::TypeBindingKind::Const { c: self.lower_anon_const(c) } + } + AssocConstraintKind::Bound { ref bounds } => { let mut capturable_lifetimes; let mut parent_def_id = self.current_hir_id_owner; // Piggy-back on the `impl Trait` context to figure out the correct behavior. diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 45920bb27d5..2c575cfdbdc 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -138,10 +138,11 @@ impl<'a> AstValidator<'a> { self.outer_impl_trait = old; } - fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) { + fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) { match constraint.kind { - AssocTyConstraintKind::Equality { .. } => {} - AssocTyConstraintKind::Bound { .. } => { + AssocConstraintKind::Equality { .. } => {} + AssocConstraintKind::ConstEquality { .. } => {} + AssocConstraintKind::Bound { .. } => { if self.is_assoc_ty_bound_banned { self.err_handler().span_err( constraint.span, @@ -150,7 +151,7 @@ impl<'a> AstValidator<'a> { } } } - self.visit_assoc_ty_constraint(constraint); + self.visit_assoc_constraint(constraint); } // Mirrors `visit::walk_ty`, but tracks relevant state. @@ -1277,7 +1278,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // are allowed to contain nested `impl Trait`. AngleBracketedArg::Constraint(constraint) => { self.with_impl_trait(None, |this| { - this.visit_assoc_ty_constraint_from_generic_args(constraint); + this.visit_assoc_constraint_from_generic_args(constraint); }); } } @@ -1586,11 +1587,11 @@ fn deny_equality_constraints( let len = assoc_path.segments.len() - 1; let gen_args = args.as_ref().map(|p| (**p).clone()); // Build ``. - let arg = AngleBracketedArg::Constraint(AssocTyConstraint { + let arg = AngleBracketedArg::Constraint(AssocConstraint { id: rustc_ast::node_id::DUMMY_NODE_ID, ident: *ident, gen_args, - kind: AssocTyConstraintKind::Equality { + kind: AssocConstraintKind::Equality { ty: predicate.rhs_ty.clone(), }, span: ident.span, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 85e35c942b9..0cc74a1ac0b 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId}; +use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId}; use rustc_ast::{PatKind, RangeEnd, VariantData}; use rustc_errors::struct_span_err; use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; @@ -622,8 +622,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind, span) } - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { - if let AssocTyConstraintKind::Bound { .. } = constraint.kind { + fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) { + if let AssocConstraintKind::Bound { .. } = constraint.kind { gate_feature_post!( &self, associated_type_bounds, @@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "associated type bounds are unstable" ) } - visit::walk_assoc_ty_constraint(self, constraint) + visit::walk_assoc_constraint(self, constraint) } fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 3980e6da682..a4a48cc8e8a 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_generic_args(self, path_span, generic_args) } - fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) { + fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) { self.count += 1; - walk_assoc_ty_constraint(self, constraint) + walk_assoc_constraint(self, constraint) } fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index dab2e1f5ee1..38186024467 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -952,16 +952,20 @@ impl<'a> State<'a> { } } - pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) { + pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) { self.print_ident(constraint.ident); constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); self.space(); match &constraint.kind { - ast::AssocTyConstraintKind::Equality { ty } => { + ast::AssocConstraintKind::Equality { ty } => { self.word_space("="); self.print_type(ty); } - ast::AssocTyConstraintKind::Bound { bounds } => { + ast::AssocConstraintKind::ConstEquality { c } => { + self.word_space("="); + self.print_expr_anon_const(c); + } + ast::AssocConstraintKind::Bound { bounds } => { self.print_type_bounds(":", &*bounds); } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 369b5e6da2d..039bb0db0aa 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2136,6 +2136,8 @@ pub enum TypeBindingKind<'hir> { Constraint { bounds: &'hir [GenericBound<'hir>] }, /// E.g., `Foo`. Equality { ty: &'hir Ty<'hir> }, + /// E.g., `Foo`. + Const { c: AnonConst }, } impl TypeBinding<'_> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 52c0538f1bc..56b32cde9d5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -827,9 +827,8 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>( visitor.visit_ident(type_binding.ident); visitor.visit_generic_args(type_binding.span, type_binding.gen_args); match type_binding.kind { - TypeBindingKind::Equality { ref ty } => { - visitor.visit_ty(ty); - } + TypeBindingKind::Equality { ref ty } => visitor.visit_ty(ty), + TypeBindingKind::Const { ref c } => visitor.visit_anon_const(c), TypeBindingKind::Constraint { bounds } => { walk_list!(visitor, visit_param_bound, bounds); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7675778ff88..a76af35a8e6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1756,6 +1756,10 @@ impl<'a> State<'a> { self.word_space("="); self.print_type(ty); } + hir::TypeBindingKind::Const { ref c } => { + self.word_space("="); + self.print_anon_const(c); + } hir::TypeBindingKind::Constraint { bounds } => { self.print_bounds(":", bounds); } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index cb51555f5ca..abecc8d1a8b 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -738,8 +738,9 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { | ast::GenericArg::Const(_) => false, }, ast::AngleBracketedArg::Constraint(c) => match c.kind { - ast::AssocTyConstraintKind::Bound { .. } => true, - ast::AssocTyConstraintKind::Equality { ref ty } => { + ast::AssocConstraintKind::Bound { .. } => true, + ast::AssocConstraintKind::ConstEquality { .. } => false, + ast::AssocConstraintKind::Equality { ref ty } => { involves_impl_trait(ty) } }, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d6e89e52b95..9e7e8dc838a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -814,6 +814,25 @@ pub struct ProjectionPredicate<'tcx> { pub ty: Ty<'tcx>, } +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T: TraitRef<..., Item = Const>` +/// 2. `>::Item == Const` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T: TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of +/// Form #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug)] +#[derive(HashStable, TypeFoldable)] +pub struct ConstPredicate<'tcx> { + pub projection: ProjectionTy<'tcx>, + pub c: &'tcx Const<'tcx>, +} + pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 7f8fadb33bd..7c2d8ba21a2 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,8 +4,8 @@ use crate::maybe_whole; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_ast::{ - self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint, - AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, + self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint, + AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, Path, PathSegment, QSelf, }; use rustc_errors::{pluralize, Applicability, PResult}; @@ -469,12 +469,9 @@ impl<'a> Parser<'a> { // Parse associated type constraint bound. let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; - AssocTyConstraintKind::Bound { bounds } + AssocConstraintKind::Bound { bounds } } else if self.eat(&token::Eq) { - // Parse associated type equality constraint - - let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?; - AssocTyConstraintKind::Equality { ty } + self.parse_assoc_equality_term(ident, self.prev_token.span)? } else { unreachable!(); }; @@ -482,11 +479,11 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); // Gate associated type bounds, e.g., `Iterator`. - if let AssocTyConstraintKind::Bound { .. } = kind { + if let AssocConstraintKind::Bound { .. } = kind { self.sess.gated_spans.gate(sym::associated_type_bounds, span); } let constraint = - AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; + AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; Ok(Some(AngleBracketedArg::Constraint(constraint))) } else { Ok(Some(AngleBracketedArg::Arg(arg))) @@ -499,22 +496,22 @@ impl<'a> Parser<'a> { /// Parse the term to the right of an associated item equality constraint. /// That is, parse `` in `Item = `. /// Right now, this only admits types in ``. - fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P> { + fn parse_assoc_equality_term( + &mut self, + ident: Ident, + eq: Span, + ) -> PResult<'a, AssocConstraintKind> { let arg = self.parse_generic_arg(None)?; let span = ident.span.to(self.prev_token.span); - match arg { - Some(GenericArg::Type(ty)) => return Ok(ty), - Some(GenericArg::Const(expr)) => { - self.struct_span_err(span, "cannot constrain an associated constant to a value") - .span_label(ident.span, "this associated constant...") - .span_label(expr.value.span, "...cannot be constrained to this value") - .emit(); - } + let ty = match arg { + Some(GenericArg::Type(ty)) => ty, + Some(GenericArg::Const(c)) => return Ok(AssocConstraintKind::ConstEquality { c }), Some(GenericArg::Lifetime(lt)) => { self.struct_span_err(span, "associated lifetimes are not supported") .span_label(lt.ident.span, "the lifetime is given here") .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") .emit(); + self.mk_ty(span, ast::TyKind::Err) } None => { let after_eq = eq.shrink_to_hi(); @@ -542,8 +539,8 @@ impl<'a> Parser<'a> { }; return Err(err); } - } - Ok(self.mk_ty(span, ast::TyKind::Err)) + }; + Ok(AssocConstraintKind::Equality { ty }) } /// We do not permit arbitrary expressions as const arguments. They must be one of: diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d665c12f762..963a625aaea 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -338,9 +338,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { - self.record("AssocTyConstraint", Id::None, constraint); - ast_visit::walk_assoc_ty_constraint(self, constraint) + fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) { + self.record("AssocConstraint", Id::None, constraint); + ast_visit::walk_assoc_constraint(self, constraint) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2ada1c0ddf4..2d847f6145d 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -124,6 +124,7 @@ struct ConvertedBinding<'a, 'tcx> { #[derive(Debug)] enum ConvertedBindingKind<'a, 'tcx> { Equality(Ty<'tcx>), + Const(&'tcx Const<'tcx>), Constraint(&'a [hir::GenericBound<'a>]), } @@ -604,7 +605,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TypeBindingKind::Equality { ty } => { ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) } - hir::TypeBindingKind::Constraint { bounds } => { + hir::TypeBindingKind::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) + } + hir::TypeBindingKind::Constraint { ref bounds } => { ConvertedBindingKind::Constraint(bounds) } }; @@ -1231,6 +1237,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { binding.span, )); } + ConvertedBindingKind::Const(c) => { + bounds.const_bounds.push(( + projection_ty.map_bound(|projection_ty| ty::ConstPredicate { + projection: projection_ty, + c, + }), + binding.span, + )); + } ConvertedBindingKind::Constraint(ast_bounds) => { // "Desugar" a constraint like `T: Iterator` to // diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 8bc3a48e5b5..47c3ea54575 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -37,6 +37,12 @@ pub struct Bounds<'tcx> { /// here. pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, + /// A list of const equality bounds. So if you had `T: + /// Iterator` this would include `::N => 4`. Note that the self-type is explicit + /// here. + pub const_bounds: Vec<(ty::Binder<'tcx, ty::ConstPredicate<'tcx>>, Span)>, + /// `Some` if there is *no* `?Sized` predicate. The `span` /// is the location in the source of the `T` declaration which can /// be cited as the source of the `T: Sized` requirement. @@ -48,14 +54,19 @@ impl<'tcx> Bounds<'tcx> { /// where-clauses). Because some of our bounds listings (e.g., /// regions) don't include the self-type, you must supply the /// self-type here (the `param_ty` parameter). - pub fn predicates( - &self, + pub fn predicates<'out, 's>( + &'s self, tcx: TyCtxt<'tcx>, param_ty: Ty<'tcx>, - ) -> Vec<(ty::Predicate<'tcx>, Span)> { + // the output must live shorter than the duration of the borrow of self and 'tcx. + ) -> impl Iterator, Span)> + 'out + where + 'tcx: 'out, + 's: 'out, + { // If it could be sized, and is, add the `Sized` predicate. let sized_predicate = self.implicitly_sized.and_then(|span| { - tcx.lang_items().sized_trait().map(|sized| { + tcx.lang_items().sized_trait().map(move |sized| { let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]), @@ -64,25 +75,39 @@ impl<'tcx> Bounds<'tcx> { }) }); - sized_predicate - .into_iter() - .chain(self.region_bounds.iter().map(|&(region_bound, span)| { - ( - region_bound - .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) - .to_predicate(tcx), - span, - ) - })) - .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { + let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| { + let pred = region_bound + .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) + .to_predicate(tcx); + (pred, span) + }); + let trait_bounds = + self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| { let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); (predicate, span) - })) - .chain( - self.projection_bounds - .iter() - .map(|&(projection, span)| (projection.to_predicate(tcx), span)), - ) - .collect() + }); + let projection_bounds = self + .projection_bounds + .iter() + .map(move |&(projection, span)| (projection.to_predicate(tcx), span)); + let const_bounds = self.const_bounds.iter().map(move |&(bound, span)| { + // FIXME(...): what about the projection's generics? + // Is this the right local defid? Or should I get the self ty then + let pred = bound + .map_bound(|cp| { + let got = + ty::Const::from_anon_const(tcx, cp.projection.item_def_id.expect_local()); + ty::PredicateKind::ConstEquate(cp.c, got) + }) + .to_predicate(tcx); + (pred, span) + }); + + sized_predicate + .into_iter() + .chain(region_preds) + .chain(trait_bounds) + .chain(projection_bounds) + .chain(const_bounds) } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index fbb630004ca..7cb100a0a83 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2450,7 +2450,7 @@ fn predicates_from_bound<'tcx>( ) -> Vec<(ty::Predicate<'tcx>, Span)> { let mut bounds = Bounds::default(); astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars); - bounds.predicates(astconv.tcx(), param_ty) + bounds.predicates(astconv.tcx(), param_ty).collect() } fn compute_sig_of_foreign_fn_decl<'tcx>( diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 26cad8fb180..6d992629a00 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -67,11 +67,11 @@ fn opaque_type_bounds<'tcx>( let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); // Opaque types are implicitly sized unless a `?Sized` bound is found >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); - let bounds = bounds.predicates(tcx, item_ty); + let preds = bounds.predicates(tcx, item_ty); + let bounds = tcx.arena.alloc_from_iter(preds); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds); - - tcx.arena.alloc_slice(&bounds) + bounds }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a5bc70a74ae..169cb618a7d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2117,7 +2117,8 @@ impl Clean for hir::TypeBindingKind<'_> { hir::TypeBindingKind::Equality { ref ty } => { TypeBindingKind::Equality { ty: ty.clean(cx) } } - hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint { + hir::TypeBindingKind::Const { c: _ } => todo!(), + hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint { bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(), }, } diff --git a/src/test/ui/associated-consts/assoc-const.rs b/src/test/ui/associated-consts/assoc-const.rs new file mode 100644 index 00000000000..9332d16afe5 --- /dev/null +++ b/src/test/ui/associated-consts/assoc-const.rs @@ -0,0 +1,14 @@ +// run-pass + +pub trait Foo { + const N: usize; +} + +pub struct Bar; + +impl Foo for Bar { + const N: usize = 3; +} + +fn foo>() {} +fn main() {} diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 3d3180521ab..d4f037677e0 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -645,12 +645,13 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool { } } -pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool { - use AssocTyConstraintKind::*; +pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool { + use AssocConstraintKind::*; eq_id(l.ident, r.ident) && match (&l.kind, &r.kind) { (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r), (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound), + (ConstEquality { c: l }, ConstEquality { c: r }) => eq_anon_const(l, r), _ => false, } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 88f5dc43245..4bad9742a0e 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> { Const(&'a ast::AnonConst), LifeTime(&'a ast::Lifetime), Type(&'a ast::Ty), - Binding(&'a ast::AssocTyConstraint), + Binding(&'a ast::AssocConstraint), } impl<'a> SegmentParam<'a> { @@ -176,9 +176,9 @@ impl<'a> Rewrite for SegmentParam<'a> { } } -impl Rewrite for ast::AssocTyConstraint { +impl Rewrite for ast::AssocConstraint { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - use ast::AssocTyConstraintKind::{Bound, Equality}; + use ast::AssocConstraintKind::{Bound, Equality, ConstEquality}; let mut result = String::with_capacity(128); result.push_str(rewrite_ident(context, self.ident)); @@ -192,8 +192,8 @@ impl Rewrite for ast::AssocTyConstraint { let infix = match (&self.kind, context.config.type_punctuation_density()) { (Bound { .. }, _) => ": ", - (Equality { .. }, TypeDensity::Wide) => " = ", - (Equality { .. }, TypeDensity::Compressed) => "=", + (ConstEquality { .. } | Equality { .. }, TypeDensity::Wide) => " = ", + (ConstEquality { .. } | Equality { .. }, TypeDensity::Compressed) => "=", }; result.push_str(infix); @@ -206,11 +206,12 @@ impl Rewrite for ast::AssocTyConstraint { } } -impl Rewrite for ast::AssocTyConstraintKind { +impl Rewrite for ast::AssocConstraintKind { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { match self { - ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape), - ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape), + ast::AssocConstraintKind::Equality { ty } => ty.rewrite(context, shape), + ast::AssocConstraintKind::ConstEquality { c } => c.rewrite(context, shape), + ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape), } } }