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.
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<A = Bar>` or
/// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct AssocTyConstraint {
pub struct AssocConstraint {
pub id: NodeId,
pub ident: Ident,
pub gen_args: Option<GenericArgs>,
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<A = Bar>`.
pub enum AssocConstraintKind {
/// E.g., `A = Bar` in `Foo<A = Bar>` where A is an associated type.
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>`.
Bound { bounds: GenericBounds },
}

View file

@ -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<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
smallvec![arm]
}
pub fn noop_visit_ty_constraint<T: MutVisitor>(
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
pub fn noop_visit_constraint<T: MutVisitor>(
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<T: MutVisitor>(
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<T: MutVisitor>(
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);
}

View file

@ -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);
}
}

View file

@ -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.

View file

@ -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 `<Bar = RhsTy>`.
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,

View file

@ -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) {

View file

@ -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;

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);
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);
}
}

View file

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

View file

@ -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);
}

View file

@ -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)
}
},

View file

@ -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. `<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>>;
impl<'tcx> PolyProjectionPredicate<'tcx> {

View file

@ -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<Item: Ord>`.
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 `<term>` in `Item = <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 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:

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)
}
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) {

View file

@ -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<Item: Debug>` to
//

View file

@ -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<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`
/// 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<Item = (ty::Predicate<'tcx>, 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)
}
}

View file

@ -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>(

View file

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

View file

@ -2117,7 +2117,8 @@ impl Clean<TypeBindingKind> 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(),
},
}

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 {
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,
}
}

View file

@ -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<String> {
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<String> {
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),
}
}
}