Implement generalized object and type parameter bounds (Fixes #16462)
This commit is contained in:
parent
3ee047ae1f
commit
1b487a8906
272 changed files with 6783 additions and 3154 deletions
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue