Parse and typecheck (not kindcheck) bounds on trait paths.

This commit is contained in:
Ben Blum 2013-06-17 15:16:30 -04:00
parent 394f455b5e
commit ce857e3d60
37 changed files with 197 additions and 121 deletions

View file

@ -75,7 +75,7 @@ use parse::obsolete::{ObsoleteLet, ObsoleteFieldTerminator};
use parse::obsolete::{ObsoleteMoveInit, ObsoleteBinaryMove, ObsoleteSwap};
use parse::obsolete::{ObsoleteSyntax, ObsoleteLowerCaseKindBounds};
use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutOwnedPointer};
use parse::obsolete::{ObsoleteMutVector, ObsoleteImplVisibility};
use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
use parse::obsolete::{ObsoletePostFnTySigil};
@ -710,8 +710,8 @@ impl Parser {
} else if *self.token == token::MOD_SEP
|| is_ident_or_path(self.token) {
// NAMED TYPE
let path = self.parse_path_with_tps(false);
ty_path(path, self.get_id())
let (path, bounds) = self.parse_type_path();
ty_path(path, @bounds, self.get_id())
} else {
self.fatal(fmt!("expected type, found token %?",
*self.token));
@ -974,10 +974,8 @@ impl Parser {
types: ~[] }
}
// parse a path optionally with type parameters. If 'colons'
// is true, then type parameters must be preceded by colons,
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
pub fn parse_bounded_path_with_tps(&self, colons: bool,
before_tps: Option<&fn()>) -> @ast::Path {
debug!("parse_path_with_tps(colons=%b)", colons);
maybe_whole!(self, nt_path);
@ -987,6 +985,10 @@ impl Parser {
return path;
}
// If the path might have bounds on it, they should be parsed before
// the parameters, e.g. module::TraitName:B1+B2<T>
before_tps.map_consume(|callback| callback());
// Parse the (obsolete) trailing region parameter, if any, which will
// be written "foo/&x"
let rp_slash = {
@ -1038,6 +1040,25 @@ impl Parser {
.. copy *path }
}
// parse a path optionally with type parameters. If 'colons'
// is true, then type parameters must be preceded by colons,
// as in a::t::<t1,t2>
pub fn parse_path_with_tps(&self, colons: bool) -> @ast::Path {
self.parse_bounded_path_with_tps(colons, None)
}
// Like the above, but can also parse kind bounds in the case of a
// path to be used as a type that might be a trait.
pub fn parse_type_path(&self) -> (@ast::Path, OptVec<TyParamBound>) {
let mut bounds = opt_vec::Empty;
let path = self.parse_bounded_path_with_tps(false, Some(|| {
// Note: this closure might not even get called in the case of a
// macro-generated path. But that's the macro parser's job.
bounds = self.parse_optional_ty_param_bounds();
}));
(path, bounds)
}
/// parses 0 or 1 lifetime
pub fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
match *self.token {
@ -2847,16 +2868,6 @@ impl Parser {
spanned(lo, hi, bloc)
}
fn mk_ty_path(&self, i: ident) -> @Ty {
@Ty {
id: self.get_id(),
node: ty_path(
ident_to_path(*self.last_span, i),
self.get_id()),
span: *self.last_span,
}
}
fn parse_optional_purity(&self) -> ast::purity {
if self.eat_keyword(keywords::Pure) {
self.obsolete(*self.last_span, ObsoletePurity);
@ -2921,13 +2932,8 @@ impl Parser {
_ => break,
}
if self.eat(&token::BINOP(token::PLUS)) {
loop;
}
if is_ident_or_path(self.token) {
self.obsolete(*self.span,
ObsoleteTraitBoundSeparator);
if !self.eat(&token::BINOP(token::PLUS)) {
break;
}
}
@ -3284,14 +3290,19 @@ impl Parser {
let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) {
// New-style trait. Reinterpret the type as a trait.
let opt_trait_ref = match ty.node {
ty_path(path, node_id) => {
ty_path(path, @opt_vec::Empty, node_id) => {
Some(@trait_ref {
path: path,
ref_id: node_id
})
}
ty_path(*) => {
self.span_err(ty.span,
"bounded traits are only valid in type position");
None
}
_ => {
self.span_err(*self.span, "not a trait");
self.span_err(ty.span, "not a trait");
None
}
};