Implement generalized object and type parameter bounds (Fixes #16462)

This commit is contained in:
Niko Matsakis 2014-08-27 21:46:52 -04:00
parent 3ee047ae1f
commit 1b487a8906
272 changed files with 6783 additions and 3154 deletions

View file

@ -12,7 +12,7 @@
use abi;
use ast::{BareFnTy, ClosureTy};
use ast::{StaticRegionTyParamBound, OtherRegionTyParamBound, TraitTyParamBound};
use ast::{RegionTyParamBound, TraitTyParamBound};
use ast::{ProvidedMethod, Public, FnStyle};
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
@ -70,7 +70,7 @@ use parse;
use parse::attr::ParserAttr;
use parse::classify;
use parse::common::{SeqSep, seq_sep_none};
use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed};
use parse::common::{seq_sep_trailing_allowed};
use parse::lexer::Reader;
use parse::lexer::TokenAndSpan;
use parse::obsolete::*;
@ -120,7 +120,7 @@ pub enum PathParsingMode {
/// A path paired with optional type bounds.
pub struct PathAndBounds {
pub path: ast::Path,
pub bounds: Option<OwnedSlice<TyParamBound>>,
pub bounds: Option<ast::TyParamBounds>,
}
enum ItemOrViewItem {
@ -309,7 +309,7 @@ pub struct Parser<'a> {
pub tokens_consumed: uint,
pub restriction: restriction,
pub quote_depth: uint, // not (yet) related to the quasiquoter
pub reader: Box<Reader>,
pub reader: Box<Reader+'a>,
pub interner: Rc<token::IdentInterner>,
/// The set of seen errors about obsolete syntax. Used to suppress
/// extra detail when the same error is seen twice
@ -346,8 +346,11 @@ fn real_token(rdr: &mut Reader) -> TokenAndSpan {
}
impl<'a> Parser<'a> {
pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig,
mut rdr: Box<Reader>) -> Parser<'a> {
pub fn new(sess: &'a ParseSess,
cfg: ast::CrateConfig,
mut rdr: Box<Reader+'a>)
-> Parser<'a>
{
let tok0 = real_token(rdr);
let span = tok0.sp;
let placeholder = TokenAndSpan {
@ -1073,14 +1076,7 @@ impl<'a> Parser<'a> {
};
let (inputs, variadic) = self.parse_fn_args(false, false);
let bounds = {
if self.eat(&token::COLON) {
let (_, bounds) = self.parse_ty_param_bounds(false);
Some(bounds)
} else {
None
}
};
let bounds = self.parse_colon_then_ty_param_bounds();
let (ret_style, ret_ty) = self.parse_ret_ty();
let decl = P(FnDecl {
inputs: inputs,
@ -1168,14 +1164,7 @@ impl<'a> Parser<'a> {
(optional_unboxed_closure_kind, inputs)
};
let (region, bounds) = {
if self.eat(&token::COLON) {
let (region, bounds) = self.parse_ty_param_bounds(true);
(region, Some(bounds))
} else {
(None, None)
}
};
let bounds = self.parse_colon_then_ty_param_bounds();
let (return_style, output) = self.parse_ret_ty();
let decl = P(FnDecl {
@ -1199,7 +1188,7 @@ impl<'a> Parser<'a> {
bounds: bounds,
decl: decl,
lifetimes: lifetime_defs,
}, region)
})
}
}
}
@ -1687,7 +1676,7 @@ impl<'a> Parser<'a> {
Some(INTERPOLATED(token::NtPath(box path))) => {
return PathAndBounds {
path: path,
bounds: None,
bounds: None
}
}
_ => {}
@ -1744,25 +1733,31 @@ impl<'a> Parser<'a> {
}
}
// Next, parse a plus and bounded type parameters, if applicable.
let bounds = if mode == LifetimeAndTypesAndBounds {
let bounds = {
if self.eat(&token::BINOP(token::PLUS)) {
let (_, bounds) = self.parse_ty_param_bounds(false);
if bounds.len() == 0 {
let last_span = self.last_span;
self.span_err(last_span,
"at least one type parameter bound \
must be specified after the `+`");
}
Some(bounds)
} else {
None
// Next, parse a plus and bounded type parameters, if
// applicable. We need to remember whether the separate was
// present for later, because in some contexts it's a parse
// error.
let opt_bounds = {
if mode == LifetimeAndTypesAndBounds &&
self.eat(&token::BINOP(token::PLUS))
{
let bounds = self.parse_ty_param_bounds();
// For some reason that I do not fully understand, we
// do not permit an empty list in the case where it is
// introduced by a `+`, but we do for `:` and other
// separators. -nmatsakis
if bounds.len() == 0 {
let last_span = self.last_span;
self.span_err(last_span,
"at least one type parameter bound \
must be specified");
}
};
bounds
} else {
None
Some(bounds)
} else {
None
}
};
// Assemble the span.
@ -1775,7 +1770,7 @@ impl<'a> Parser<'a> {
global: is_global,
segments: segments,
},
bounds: bounds,
bounds: opt_bounds,
}
}
@ -3604,45 +3599,34 @@ impl<'a> Parser<'a> {
}
}
/// matches optbounds = ( ( : ( boundseq )? )? )
/// where boundseq = ( bound + boundseq ) | bound
/// and bound = 'static | ty
/// Returns "None" if there's no colon (e.g. "T");
/// Returns "Some(Empty)" if there's a colon but nothing after (e.g. "T:")
/// Returns "Some(stuff)" otherwise (e.g. "T:stuff").
/// NB: The None/Some distinction is important for issue #7264.
///
/// Note that the `allow_any_lifetime` argument is a hack for now while the
/// AST doesn't support arbitrary lifetimes in bounds on type parameters. In
/// the future, this flag should be removed, and the return value of this
/// function should be Option<~[TyParamBound]>
fn parse_ty_param_bounds(&mut self, allow_any_lifetime: bool)
-> (Option<ast::Lifetime>,
OwnedSlice<TyParamBound>) {
let mut ret_lifetime = None;
// Parses a sequence of bounds if a `:` is found,
// otherwise returns empty list.
fn parse_colon_then_ty_param_bounds(&mut self)
-> OwnedSlice<TyParamBound>
{
if !self.eat(&token::COLON) {
OwnedSlice::empty()
} else {
self.parse_ty_param_bounds()
}
}
// matches bounds = ( boundseq )?
// where boundseq = ( bound + boundseq ) | bound
// and bound = 'region | ty
// NB: The None/Some distinction is important for issue #7264.
fn parse_ty_param_bounds(&mut self)
-> OwnedSlice<TyParamBound>
{
let mut result = vec!();
loop {
match self.token {
token::LIFETIME(lifetime) => {
let lifetime_interned_string = token::get_ident(lifetime);
if lifetime_interned_string.equiv(&("'static")) {
result.push(StaticRegionTyParamBound);
if allow_any_lifetime && ret_lifetime.is_none() {
ret_lifetime = Some(ast::Lifetime {
id: ast::DUMMY_NODE_ID,
span: self.span,
name: lifetime.name
});
}
} else if allow_any_lifetime && ret_lifetime.is_none() {
ret_lifetime = Some(ast::Lifetime {
id: ast::DUMMY_NODE_ID,
span: self.span,
name: lifetime.name
});
} else {
result.push(OtherRegionTyParamBound(self.span));
}
result.push(RegionTyParamBound(ast::Lifetime {
id: ast::DUMMY_NODE_ID,
span: self.span,
name: lifetime.name
}));
self.bump();
}
token::MOD_SEP | token::IDENT(..) => {
@ -3662,7 +3646,7 @@ impl<'a> Parser<'a> {
}
}
return (ret_lifetime, OwnedSlice::from_vec(result));
return OwnedSlice::from_vec(result);
}
fn trait_ref_from_ident(ident: Ident, span: Span) -> ast::TraitRef {
@ -3699,16 +3683,7 @@ impl<'a> Parser<'a> {
ident = self.parse_ident();
}
let opt_bounds = {
if self.eat(&token::COLON) {
let (_, bounds) = self.parse_ty_param_bounds(false);
Some(bounds)
} else {
None
}
};
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
let bounds = opt_bounds.unwrap_or_default();
let bounds = self.parse_colon_then_ty_param_bounds();
let default = if self.token == token::EQ {
self.bump();
@ -3797,7 +3772,7 @@ impl<'a> Parser<'a> {
};
self.expect(&token::COLON);
let (_, bounds) = self.parse_ty_param_bounds(false);
let bounds = self.parse_ty_param_bounds();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
@ -4273,19 +4248,13 @@ impl<'a> Parser<'a> {
let mut tps = self.parse_generics();
let sized = self.parse_for_sized();
// Parse traits, if necessary.
let traits;
if self.token == token::COLON {
self.bump();
traits = self.parse_trait_ref_list(&token::LBRACE);
} else {
traits = Vec::new();
}
// Parse supertrait bounds.
let bounds = self.parse_colon_then_ty_param_bounds();
self.parse_where_clause(&mut tps);
let meths = self.parse_trait_methods();
(ident, ItemTrait(tps, sized, traits, meths), None)
(ident, ItemTrait(tps, sized, bounds, meths), None)
}
fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) {
@ -4319,12 +4288,10 @@ impl<'a> Parser<'a> {
// New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node {
TyPath(ref path, None, node_id) => {
Some(TraitRef {
path: /* bad */ (*path).clone(),
ref_id: node_id
})
Some(TraitRef { path: (*path).clone(),
ref_id: node_id })
}
TyPath(..) => {
TyPath(_, Some(_), _) => {
self.span_err(ty.span,
"bounded traits are only valid in type position");
None
@ -4359,15 +4326,6 @@ impl<'a> Parser<'a> {
}
}
/// Parse B + C<String,int> + D
fn parse_trait_ref_list(&mut self, ket: &token::Token) -> Vec<TraitRef> {
self.parse_seq_to_before_end(
ket,
seq_sep_trailing_disallowed(token::BINOP(token::PLUS)),
|p| p.parse_trait_ref()
)
}
/// Parse struct Foo { ... }
fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
let class_name = self.parse_ident();