add eq constraints on associated constants

This commit is contained in:
kadmin 2021-07-30 08:56:45 +00:00
parent a34c079752
commit 0765999622
23 changed files with 195 additions and 113 deletions

View file

@ -224,7 +224,7 @@ pub enum AngleBracketedArg {
/// Argument for a generic parameter. /// Argument for a generic parameter.
Arg(GenericArg), Arg(GenericArg),
/// Constraint for an associated item. /// Constraint for an associated item.
Constraint(AssocTyConstraint), Constraint(AssocConstraint),
} }
impl AngleBracketedArg { impl AngleBracketedArg {
@ -1843,19 +1843,21 @@ impl UintTy {
/// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`). /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct AssocTyConstraint { pub struct AssocConstraint {
pub id: NodeId, pub id: NodeId,
pub ident: Ident, pub ident: Ident,
pub gen_args: Option<GenericArgs>, pub gen_args: Option<GenericArgs>,
pub kind: AssocTyConstraintKind, pub kind: AssocConstraintKind,
pub span: Span, pub span: Span,
} }
/// The kinds of an `AssocTyConstraint`. /// The kinds of an `AssocConstraint`.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum AssocTyConstraintKind { pub enum AssocConstraintKind {
/// E.g., `A = Bar` in `Foo<A = Bar>`. /// E.g., `A = Bar` in `Foo<A = Bar>` where A is an associated type.
Equality { ty: P<Ty> }, Equality { ty: P<Ty> },
/// E.g., `A = 3` in `Foo<N = 3>` where N is an associated const.
ConstEquality { c: AnonConst },
/// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`. /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
Bound { bounds: GenericBounds }, Bound { bounds: GenericBounds },
} }

View file

@ -165,8 +165,8 @@ pub trait MutVisitor: Sized {
noop_visit_lifetime(l, self); noop_visit_lifetime(l, self);
} }
fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) { fn visit_constraint(&mut self, t: &mut AssocConstraint) {
noop_visit_ty_constraint(t, self); noop_visit_constraint(t, self);
} }
fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) { fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@ -430,8 +430,8 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
smallvec![arm] smallvec![arm]
} }
pub fn noop_visit_ty_constraint<T: MutVisitor>( pub fn noop_visit_constraint<T: MutVisitor>(
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint, AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
vis: &mut T, vis: &mut T,
) { ) {
vis.visit_id(id); vis.visit_id(id);
@ -440,12 +440,9 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
vis.visit_generic_args(gen_args); vis.visit_generic_args(gen_args);
} }
match kind { match kind {
AssocTyConstraintKind::Equality { ref mut ty } => { AssocConstraintKind::Equality { ref mut ty } => vis.visit_ty(ty),
vis.visit_ty(ty); AssocConstraintKind::ConstEquality { ref mut c } => vis.visit_anon_const(c),
} AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
AssocTyConstraintKind::Bound { ref mut bounds } => {
visit_bounds(bounds, vis);
}
} }
vis.visit_span(span); vis.visit_span(span);
} }
@ -555,7 +552,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
let AngleBracketedArgs { args, span } = data; let AngleBracketedArgs { args, span } = data;
visit_vec(args, |arg| match arg { visit_vec(args, |arg| match arg {
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(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); vis.visit_span(span);
} }

View file

@ -190,8 +190,8 @@ pub trait Visitor<'ast>: Sized {
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) { fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
walk_generic_arg(self, generic_arg) walk_generic_arg(self, generic_arg)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
walk_assoc_ty_constraint(self, constraint) walk_assoc_constraint(self, constraint)
} }
fn visit_attribute(&mut self, attr: &'ast Attribute) { fn visit_attribute(&mut self, attr: &'ast Attribute) {
walk_attribute(self, attr) walk_attribute(self, attr)
@ -464,7 +464,7 @@ where
for arg in &data.args { for arg in &data.args {
match arg { match arg {
AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a), 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>>( pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
visitor: &mut V,
constraint: &'a AssocTyConstraint,
) {
visitor.visit_ident(constraint.ident); visitor.visit_ident(constraint.ident);
if let Some(ref gen_args) = constraint.gen_args { if let Some(ref gen_args) = constraint.gen_args {
visitor.visit_generic_args(gen_args.span(), gen_args); visitor.visit_generic_args(gen_args.span(), gen_args);
} }
match constraint.kind { match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => { AssocConstraintKind::Equality { ref ty } => visitor.visit_ty(ty),
visitor.visit_ty(ty); AssocConstraintKind::ConstEquality { ref c } => visitor.visit_anon_const(c),
} AssocConstraintKind::Bound { ref bounds } => {
AssocTyConstraintKind::Bound { ref bounds } => {
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds);
} }
} }

View file

@ -960,7 +960,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// returns a `hir::TypeBinding` representing `Item`. /// returns a `hir::TypeBinding` representing `Item`.
fn lower_assoc_ty_constraint( fn lower_assoc_ty_constraint(
&mut self, &mut self,
constraint: &AssocTyConstraint, constraint: &AssocConstraint,
mut itctx: ImplTraitContext<'_, 'hir>, mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::TypeBinding<'hir> { ) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@ -997,10 +997,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}; };
let kind = match constraint.kind { let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => { AssocConstraintKind::Equality { ref ty } => {
hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) } 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 capturable_lifetimes;
let mut parent_def_id = self.current_hir_id_owner; let mut parent_def_id = self.current_hir_id_owner;
// Piggy-back on the `impl Trait` context to figure out the correct behavior. // Piggy-back on the `impl Trait` context to figure out the correct behavior.

View file

@ -138,10 +138,11 @@ impl<'a> AstValidator<'a> {
self.outer_impl_trait = old; 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 { match constraint.kind {
AssocTyConstraintKind::Equality { .. } => {} AssocConstraintKind::Equality { .. } => {}
AssocTyConstraintKind::Bound { .. } => { AssocConstraintKind::ConstEquality { .. } => {}
AssocConstraintKind::Bound { .. } => {
if self.is_assoc_ty_bound_banned { if self.is_assoc_ty_bound_banned {
self.err_handler().span_err( self.err_handler().span_err(
constraint.span, 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. // 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`. // are allowed to contain nested `impl Trait`.
AngleBracketedArg::Constraint(constraint) => { AngleBracketedArg::Constraint(constraint) => {
self.with_impl_trait(None, |this| { 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 len = assoc_path.segments.len() - 1;
let gen_args = args.as_ref().map(|p| (**p).clone()); let gen_args = args.as_ref().map(|p| (**p).clone());
// Build `<Bar = RhsTy>`. // Build `<Bar = RhsTy>`.
let arg = AngleBracketedArg::Constraint(AssocTyConstraint { let arg = AngleBracketedArg::Constraint(AssocConstraint {
id: rustc_ast::node_id::DUMMY_NODE_ID, id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident, ident: *ident,
gen_args, gen_args,
kind: AssocTyConstraintKind::Equality { kind: AssocConstraintKind::Equality {
ty: predicate.rhs_ty.clone(), ty: predicate.rhs_ty.clone(),
}, },
span: ident.span, span: ident.span,

View file

@ -1,6 +1,6 @@
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; 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_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err; use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; 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) visit::walk_fn(self, fn_kind, span)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
if let AssocTyConstraintKind::Bound { .. } = constraint.kind { if let AssocConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!( gate_feature_post!(
&self, &self,
associated_type_bounds, associated_type_bounds,
@ -631,7 +631,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
"associated type bounds are unstable" "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) { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {

View file

@ -126,9 +126,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
self.count += 1; self.count += 1;
walk_generic_args(self, path_span, generic_args) 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; self.count += 1;
walk_assoc_ty_constraint(self, constraint) walk_assoc_constraint(self, constraint)
} }
fn visit_attribute(&mut self, _attr: &Attribute) { fn visit_attribute(&mut self, _attr: &Attribute) {
self.count += 1; self.count += 1;

View file

@ -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); self.print_ident(constraint.ident);
constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false)); constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
self.space(); self.space();
match &constraint.kind { match &constraint.kind {
ast::AssocTyConstraintKind::Equality { ty } => { ast::AssocConstraintKind::Equality { ty } => {
self.word_space("="); self.word_space("=");
self.print_type(ty); 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); self.print_type_bounds(":", &*bounds);
} }
} }

View file

@ -2136,6 +2136,8 @@ pub enum TypeBindingKind<'hir> {
Constraint { bounds: &'hir [GenericBound<'hir>] }, Constraint { bounds: &'hir [GenericBound<'hir>] },
/// E.g., `Foo<Bar = ()>`. /// E.g., `Foo<Bar = ()>`.
Equality { ty: &'hir Ty<'hir> }, Equality { ty: &'hir Ty<'hir> },
/// E.g., `Foo<N = 3>`.
Const { c: AnonConst },
} }
impl TypeBinding<'_> { impl TypeBinding<'_> {

View file

@ -827,9 +827,8 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
visitor.visit_ident(type_binding.ident); visitor.visit_ident(type_binding.ident);
visitor.visit_generic_args(type_binding.span, type_binding.gen_args); visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
match type_binding.kind { match type_binding.kind {
TypeBindingKind::Equality { ref ty } => { TypeBindingKind::Equality { ref ty } => visitor.visit_ty(ty),
visitor.visit_ty(ty); TypeBindingKind::Const { ref c } => visitor.visit_anon_const(c),
}
TypeBindingKind::Constraint { bounds } => { TypeBindingKind::Constraint { bounds } => {
walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_param_bound, bounds);
} }

View file

@ -1756,6 +1756,10 @@ impl<'a> State<'a> {
self.word_space("="); self.word_space("=");
self.print_type(ty); self.print_type(ty);
} }
hir::TypeBindingKind::Const { ref c } => {
self.word_space("=");
self.print_anon_const(c);
}
hir::TypeBindingKind::Constraint { bounds } => { hir::TypeBindingKind::Constraint { bounds } => {
self.print_bounds(":", bounds); self.print_bounds(":", bounds);
} }

View file

@ -738,8 +738,9 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
| ast::GenericArg::Const(_) => false, | ast::GenericArg::Const(_) => false,
}, },
ast::AngleBracketedArg::Constraint(c) => match c.kind { ast::AngleBracketedArg::Constraint(c) => match c.kind {
ast::AssocTyConstraintKind::Bound { .. } => true, ast::AssocConstraintKind::Bound { .. } => true,
ast::AssocTyConstraintKind::Equality { ref ty } => { ast::AssocConstraintKind::ConstEquality { .. } => false,
ast::AssocConstraintKind::Equality { ref ty } => {
involves_impl_trait(ty) involves_impl_trait(ty)
} }
}, },

View file

@ -814,6 +814,25 @@ pub struct ProjectionPredicate<'tcx> {
pub ty: Ty<'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. `<T as TraitRef<...>>::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>>; pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
impl<'tcx> PolyProjectionPredicate<'tcx> { impl<'tcx> PolyProjectionPredicate<'tcx> {

View file

@ -4,8 +4,8 @@ use crate::maybe_whole;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token}; use rustc_ast::token::{self, Token};
use rustc_ast::{ use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint, self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf, Path, PathSegment, QSelf,
}; };
use rustc_errors::{pluralize, Applicability, PResult}; use rustc_errors::{pluralize, Applicability, PResult};
@ -469,12 +469,9 @@ impl<'a> Parser<'a> {
// Parse associated type constraint bound. // Parse associated type constraint bound.
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?; let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds } AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) { } else if self.eat(&token::Eq) {
// Parse associated type equality constraint self.parse_assoc_equality_term(ident, self.prev_token.span)?
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
} else { } else {
unreachable!(); unreachable!();
}; };
@ -482,11 +479,11 @@ impl<'a> Parser<'a> {
let span = lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span);
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`. // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocTyConstraintKind::Bound { .. } = kind { if let AssocConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span); self.sess.gated_spans.gate(sym::associated_type_bounds, span);
} }
let constraint = 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))) Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else { } else {
Ok(Some(AngleBracketedArg::Arg(arg))) 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. /// Parse the term to the right of an associated item equality constraint.
/// That is, parse `<term>` in `Item = <term>`. /// That is, parse `<term>` in `Item = <term>`.
/// Right now, this only admits types in `<term>`. /// Right now, this only admits types in `<term>`.
fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> { fn parse_assoc_equality_term(
&mut self,
ident: Ident,
eq: Span,
) -> PResult<'a, AssocConstraintKind> {
let arg = self.parse_generic_arg(None)?; let arg = self.parse_generic_arg(None)?;
let span = ident.span.to(self.prev_token.span); let span = ident.span.to(self.prev_token.span);
match arg { let ty = match arg {
Some(GenericArg::Type(ty)) => return Ok(ty), Some(GenericArg::Type(ty)) => ty,
Some(GenericArg::Const(expr)) => { Some(GenericArg::Const(c)) => return Ok(AssocConstraintKind::ConstEquality { c }),
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();
}
Some(GenericArg::Lifetime(lt)) => { Some(GenericArg::Lifetime(lt)) => {
self.struct_span_err(span, "associated lifetimes are not supported") self.struct_span_err(span, "associated lifetimes are not supported")
.span_label(lt.ident.span, "the lifetime is given here") .span_label(lt.ident.span, "the lifetime is given here")
.help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`") .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
.emit(); .emit();
self.mk_ty(span, ast::TyKind::Err)
} }
None => { None => {
let after_eq = eq.shrink_to_hi(); let after_eq = eq.shrink_to_hi();
@ -542,8 +539,8 @@ impl<'a> Parser<'a> {
}; };
return Err(err); 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: /// We do not permit arbitrary expressions as const arguments. They must be one of:

View file

@ -338,9 +338,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_path_segment(self, path_span, path_segment) ast_visit::walk_path_segment(self, path_span, path_segment)
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) { fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
self.record("AssocTyConstraint", Id::None, constraint); self.record("AssocConstraint", Id::None, constraint);
ast_visit::walk_assoc_ty_constraint(self, constraint) ast_visit::walk_assoc_constraint(self, constraint)
} }
fn visit_attribute(&mut self, attr: &'v ast::Attribute) { fn visit_attribute(&mut self, attr: &'v ast::Attribute) {

View file

@ -124,6 +124,7 @@ struct ConvertedBinding<'a, 'tcx> {
#[derive(Debug)] #[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> { enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>), Equality(Ty<'tcx>),
Const(&'tcx Const<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]), Constraint(&'a [hir::GenericBound<'a>]),
} }
@ -604,7 +605,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TypeBindingKind::Equality { ty } => { hir::TypeBindingKind::Equality { ty } => {
ConvertedBindingKind::Equality(self.ast_ty_to_ty(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) ConvertedBindingKind::Constraint(bounds)
} }
}; };
@ -1231,6 +1237,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
binding.span, 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) => { ConvertedBindingKind::Constraint(ast_bounds) => {
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
// //

View file

@ -37,6 +37,12 @@ pub struct Bounds<'tcx> {
/// here. /// here.
pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, pub projection_bounds: Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
/// A list of const equality bounds. So if you had `T:
/// Iterator<N = 4>` this would include `<T as
/// Iterator>::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` /// `Some` if there is *no* `?Sized` predicate. The `span`
/// is the location in the source of the `T` declaration which can /// is the location in the source of the `T` declaration which can
/// be cited as the source of the `T: Sized` requirement. /// 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., /// where-clauses). Because some of our bounds listings (e.g.,
/// regions) don't include the self-type, you must supply the /// regions) don't include the self-type, you must supply the
/// self-type here (the `param_ty` parameter). /// self-type here (the `param_ty` parameter).
pub fn predicates( pub fn predicates<'out, 's>(
&self, &'s self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_ty: Ty<'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<Item = (ty::Predicate<'tcx>, Span)> + 'out
where
'tcx: 'out,
's: 'out,
{
// If it could be sized, and is, add the `Sized` predicate. // If it could be sized, and is, add the `Sized` predicate.
let sized_predicate = self.implicitly_sized.and_then(|span| { 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 { let trait_ref = ty::Binder::dummy(ty::TraitRef {
def_id: sized, def_id: sized,
substs: tcx.mk_substs_trait(param_ty, &[]), substs: tcx.mk_substs_trait(param_ty, &[]),
@ -64,25 +75,39 @@ impl<'tcx> Bounds<'tcx> {
}) })
}); });
sized_predicate let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
.into_iter() let pred = region_bound
.chain(self.region_bounds.iter().map(|&(region_bound, span)| { .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
( .to_predicate(tcx);
region_bound (pred, span)
.map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound)) });
.to_predicate(tcx), let trait_bounds =
span, self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
)
}))
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
(predicate, span) (predicate, span)
})) });
.chain( let projection_bounds = self
self.projection_bounds .projection_bounds
.iter() .iter()
.map(|&(projection, span)| (projection.to_predicate(tcx), span)), .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
) let const_bounds = self.const_bounds.iter().map(move |&(bound, span)| {
.collect() // 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)
} }
} }

View file

@ -2450,7 +2450,7 @@ fn predicates_from_bound<'tcx>(
) -> Vec<(ty::Predicate<'tcx>, Span)> { ) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default(); let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars); 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>( fn compute_sig_of_foreign_fn_decl<'tcx>(

View file

@ -67,11 +67,11 @@ fn opaque_type_bounds<'tcx>(
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds); let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found // Opaque types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); <dyn AstConv<'_>>::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); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
bounds
tcx.arena.alloc_slice(&bounds)
}) })
} }

View file

@ -2117,7 +2117,8 @@ impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
hir::TypeBindingKind::Equality { ref ty } => { hir::TypeBindingKind::Equality { ref ty } => {
TypeBindingKind::Equality { ty: ty.clean(cx) } 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(), bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
}, },
} }

View file

@ -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<F: Foo<N=3>>() {}
fn main() {}

View file

@ -645,12 +645,13 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
} }
} }
pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool { pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
use AssocTyConstraintKind::*; use AssocConstraintKind::*;
eq_id(l.ident, r.ident) eq_id(l.ident, r.ident)
&& match (&l.kind, &r.kind) { && match (&l.kind, &r.kind) {
(Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r), (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
(Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound), (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
(ConstEquality { c: l }, ConstEquality { c: r }) => eq_anon_const(l, r),
_ => false, _ => false,
} }
} }

View file

@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
Const(&'a ast::AnonConst), Const(&'a ast::AnonConst),
LifeTime(&'a ast::Lifetime), LifeTime(&'a ast::Lifetime),
Type(&'a ast::Ty), Type(&'a ast::Ty),
Binding(&'a ast::AssocTyConstraint), Binding(&'a ast::AssocConstraint),
} }
impl<'a> SegmentParam<'a> { 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<String> { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
use ast::AssocTyConstraintKind::{Bound, Equality}; use ast::AssocConstraintKind::{Bound, Equality, ConstEquality};
let mut result = String::with_capacity(128); let mut result = String::with_capacity(128);
result.push_str(rewrite_ident(context, self.ident)); 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()) { let infix = match (&self.kind, context.config.type_punctuation_density()) {
(Bound { .. }, _) => ": ", (Bound { .. }, _) => ": ",
(Equality { .. }, TypeDensity::Wide) => " = ", (ConstEquality { .. } | Equality { .. }, TypeDensity::Wide) => " = ",
(Equality { .. }, TypeDensity::Compressed) => "=", (ConstEquality { .. } | Equality { .. }, TypeDensity::Compressed) => "=",
}; };
result.push_str(infix); 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<String> { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match self { match self {
ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape), ast::AssocConstraintKind::Equality { ty } => ty.rewrite(context, shape),
ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape), ast::AssocConstraintKind::ConstEquality { c } => c.rewrite(context, shape),
ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
} }
} }
} }