add eq constraints on associated constants
This commit is contained in:
parent
a34c079752
commit
0765999622
23 changed files with 195 additions and 113 deletions
|
@ -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 },
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<'_> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
}
|
||||
|
|
14
src/test/ui/associated-consts/assoc-const.rs
Normal file
14
src/test/ui/associated-consts/assoc-const.rs
Normal 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() {}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue