ast and parser

This commit is contained in:
b-naber 2020-11-19 18:28:38 +01:00 committed by b-naber
parent e0ef0fc392
commit 823dbb38e4
5 changed files with 94 additions and 28 deletions

View File

@ -1845,6 +1845,7 @@ impl UintTy {
pub struct AssocTyConstraint {
pub id: NodeId,
pub ident: Ident,
pub gen_args: Option<GenericArgs>,
pub kind: AssocTyConstraintKind,
pub span: Span,
}

View File

@ -441,11 +441,14 @@ pub fn noop_flat_map_arm<T: MutVisitor>(mut arm: Arm, vis: &mut T) -> SmallVec<[
}
pub fn noop_visit_ty_constraint<T: MutVisitor>(
AssocTyConstraint { id, ident, kind, span }: &mut AssocTyConstraint,
AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
vis: &mut T,
) {
vis.visit_id(id);
vis.visit_ident(ident);
if let Some(ref mut gen_args) = gen_args {
vis.visit_generic_args(gen_args);
}
match kind {
AssocTyConstraintKind::Equality { ref mut ty } => {
vis.visit_ty(ty);

View File

@ -485,6 +485,9 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
constraint: &'a AssocTyConstraint,
) {
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);

View File

@ -1372,16 +1372,18 @@ fn deny_equality_constraints(
if param.ident == *ident {
let param = ident;
match &full_path.segments[qself.position..] {
[PathSegment { ident, .. }] => {
[PathSegment { ident, args, .. }] => {
// Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
let mut assoc_path = full_path.clone();
// Remove `Bar` from `Foo::Bar`.
assoc_path.segments.pop();
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 {
id: rustc_ast::node_id::DUMMY_NODE_ID,
ident: *ident,
gen_args,
kind: AssocTyConstraintKind::Equality {
ty: predicate.rhs_ty.clone(),
},

View File

@ -3,10 +3,9 @@ use super::{Parser, TokenType};
use crate::maybe_whole;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Token};
use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs,
};
use rustc_ast::{self as ast, AngleBracketedArg, AngleBracketedArgs, ParenthesizedArgs};
use rustc_ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode};
use rustc_ast::{GenericArg, GenericArgs};
use rustc_ast::{Path, PathSegment, QSelf};
use rustc_errors::{pluralize, Applicability, PResult};
use rustc_span::source_map::{BytePos, Span};
@ -414,32 +413,40 @@ impl<'a> Parser<'a> {
/// Parses a single argument in the angle arguments `<...>` of a path segment.
fn parse_angle_arg(&mut self) -> PResult<'a, Option<AngleBracketedArg>> {
if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon))
{
// Parse associated type constraint.
let lo = self.token.span;
let ident = self.parse_ident()?;
let kind = if self.eat(&token::Eq) {
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
} else if self.eat(&token::Colon) {
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds }
} else {
unreachable!();
};
let lo = self.token.span;
let arg = self.parse_generic_arg()?;
match arg {
Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) {
let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
let span = lo.to(self.prev_token.span);
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
AssocTyConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
// Parse associated type equality constraint
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocTyConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
AssocTyConstraintKind::Equality { ty }
} else {
unreachable!();
};
let span = lo.to(self.prev_token.span);
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocTyConstraintKind::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 };
Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else {
Ok(Some(AngleBracketedArg::Arg(arg)))
}
}
let constraint = AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, kind, span };
Ok(Some(AngleBracketedArg::Constraint(constraint)))
} else {
Ok(self.parse_generic_arg()?.map(AngleBracketedArg::Arg))
_ => Ok(None),
}
}
@ -534,4 +541,54 @@ impl<'a> Parser<'a> {
};
Ok(Some(arg))
}
fn get_ident_from_generic_arg(
&self,
gen_arg: GenericArg,
lo: Span,
) -> PResult<'a, (Ident, Option<GenericArgs>)> {
let gen_arg_span = gen_arg.span();
match gen_arg {
GenericArg::Type(t) => match t.into_inner().kind {
ast::TyKind::Path(qself, mut path) => {
if let Some(qself) = qself {
let mut err = self.struct_span_err(
gen_arg_span,
"qualified paths cannot be used in associated type constraints",
);
err.span_label(
qself.path_span,
"not allowed in associated type constraints",
);
return Err(err);
}
if path.segments.len() == 1 {
let path_seg = path.segments.remove(0);
let ident = path_seg.ident;
let gen_args = path_seg.args.map(|args| args.into_inner());
return Ok((ident, gen_args));
}
let err = self.struct_span_err(
path.span,
"paths with multiple segments cannot be used in associated type constraints",
);
return Err(err);
}
_ => {
let span = lo.to(self.prev_token.span);
let err = self.struct_span_err(
span,
"only path types can be used in associated type constraints",
);
return Err(err);
}
},
_ => {
let span = lo.to(self.prev_token.span);
let err = self
.struct_span_err(span, "only types can be used in associated type constraints");
return Err(err);
}
}
}
}