From e656081b700b949bc914fedd6ad29b1ca3197660 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 24 Dec 2014 19:38:10 +1300 Subject: Accept `?Sized` as well as `Sized?` Includes a bit of refactoring to store `?` unbounds as bounds with a modifier, rather than in their own world, in the AST at least. --- src/libsyntax/parse/parser.rs | 95 +++++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 21 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 94b61ba56d2..4d1bf50f25f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,7 +15,7 @@ use self::ItemOrViewItem::*; use abi; use ast::{AssociatedType, BareFnTy, ClosureTy}; -use ast::{RegionTyParamBound, TraitTyParamBound}; +use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{ProvidedMethod, Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block}; @@ -117,6 +117,13 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } +/// How to parse a bound, whether to allow bound modifiers such as `?`. +#[deriving(Copy, PartialEq)] +pub enum BoundParsingMode { + Bare, + Modified, +} + enum ItemOrViewItem { /// Indicates a failure to parse any kind of item. The attributes are /// returned. @@ -1087,12 +1094,12 @@ impl<'a> Parser<'a> { let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: trait_ref }; let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds() + self.parse_ty_param_bounds(BoundParsingMode::Bare) } else { OwnedSlice::empty() }; let all_bounds = - Some(TraitTyParamBound(poly_trait_ref)).into_iter() + Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() .chain(other_bounds.into_vec().into_iter()) .collect(); ast::TyPolyTraitRef(all_bounds) @@ -1165,7 +1172,7 @@ impl<'a> Parser<'a> { // To be helpful, parse the proc as ever let _ = self.parse_legacy_lifetime_defs(lifetime_defs); let _ = self.parse_fn_args(false, false); - let _ = self.parse_colon_then_ty_param_bounds(); + let _ = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); let _ = self.parse_ret_ty(); self.obsolete(proc_span, ObsoleteProcType); @@ -1255,7 +1262,7 @@ impl<'a> Parser<'a> { inputs }; - let bounds = self.parse_colon_then_ty_param_bounds(); + let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); let output = self.parse_ret_ty(); let decl = P(FnDecl { @@ -1481,7 +1488,7 @@ impl<'a> Parser<'a> { return lhs; } - let bounds = self.parse_ty_param_bounds(); + let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); // In type grammar, `+` is treated like a binary operator, // and hence both L and R side are required. @@ -4022,13 +4029,14 @@ impl<'a> Parser<'a> { // Parses a sequence of bounds if a `:` is found, // otherwise returns empty list. - fn parse_colon_then_ty_param_bounds(&mut self) + fn parse_colon_then_ty_param_bounds(&mut self, + mode: BoundParsingMode) -> OwnedSlice { if !self.eat(&token::Colon) { OwnedSlice::empty() } else { - self.parse_ty_param_bounds() + self.parse_ty_param_bounds(mode) } } @@ -4036,14 +4044,20 @@ impl<'a> Parser<'a> { // where boundseq = ( polybound + boundseq ) | polybound // and polybound = ( 'for' '<' 'region '>' )? bound // and bound = 'region | trait_ref - // NB: The None/Some distinction is important for issue #7264. - fn parse_ty_param_bounds(&mut self) + fn parse_ty_param_bounds(&mut self, + mode: BoundParsingMode) -> OwnedSlice { let mut result = vec!(); loop { + let question_span = self.span; + let ate_question = self.eat(&token::Question); match self.token { token::Lifetime(lifetime) => { + if ate_question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } result.push(RegionTyParamBound(ast::Lifetime { id: ast::DUMMY_NODE_ID, span: self.span, @@ -4053,7 +4067,18 @@ impl<'a> Parser<'a> { } token::ModSep | token::Ident(..) => { let poly_trait_ref = self.parse_poly_trait_ref(); - result.push(TraitTyParamBound(poly_trait_ref)) + let modifier = if ate_question { + if mode == BoundParsingMode::Modified { + TraitBoundModifier::Maybe + } else { + self.span_err(question_span, + "unexpected `?`"); + TraitBoundModifier::None + } + } else { + TraitBoundModifier::None + }; + result.push(TraitTyParamBound(poly_trait_ref, modifier)) } _ => break, } @@ -4082,13 +4107,14 @@ impl<'a> Parser<'a> { } } - /// Matches typaram = (unbound`?`)? IDENT optbounds ( EQ ty )? + /// Matches typaram = (unbound `?`)? IDENT (`?` unbound)? optbounds ( EQ ty )? fn parse_ty_param(&mut self) -> TyParam { // This is a bit hacky. Currently we are only interested in a single // unbound, and it may only be `Sized`. To avoid backtracking and other // complications, we parse an ident, then check for `?`. If we find it, // we use the ident as the unbound, otherwise, we use it as the name of - // type param. + // type param. Even worse, for now, we need to check for `?` before or + // after the bound. let mut span = self.span; let mut ident = self.parse_ident(); let mut unbound = None; @@ -4099,7 +4125,14 @@ impl<'a> Parser<'a> { ident = self.parse_ident(); } - let bounds = self.parse_colon_then_ty_param_bounds(); + let mut bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified); + if let Some(unbound) = unbound { + let mut bounds_as_vec = bounds.into_vec(); + bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![], + trait_ref: unbound }, + TraitBoundModifier::Maybe)); + bounds = OwnedSlice::from_vec(bounds_as_vec); + }; let default = if self.check(&token::Eq) { self.bump(); @@ -4111,7 +4144,6 @@ impl<'a> Parser<'a> { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds, - unbound: unbound, default: default, span: span, } @@ -4253,7 +4285,7 @@ impl<'a> Parser<'a> { let bounded_ty = self.parse_ty(); if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds(); + let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); let hi = self.span.hi; let span = mk_sp(lo, hi); @@ -4740,15 +4772,23 @@ impl<'a> Parser<'a> { fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo { let ident = self.parse_ident(); let mut tps = self.parse_generics(); - let sized = self.parse_for_sized(); + let unbound = self.parse_for_sized(); // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds(); + let mut bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); + + if let Some(unbound) = unbound { + let mut bounds_as_vec = bounds.into_vec(); + bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![], + trait_ref: unbound }, + TraitBoundModifier::Maybe)); + bounds = OwnedSlice::from_vec(bounds_as_vec); + }; self.parse_where_clause(&mut tps); let meths = self.parse_trait_items(); - (ident, ItemTrait(unsafety, tps, sized, bounds, meths), None) + (ident, ItemTrait(unsafety, tps, bounds, meths), None) } fn parse_impl_items(&mut self) -> (Vec, Vec) { @@ -4967,12 +5007,25 @@ impl<'a> Parser<'a> { } fn parse_for_sized(&mut self) -> Option { + // FIXME, this should really use TraitBoundModifier, but it will get + // re-jigged shortly in any case, so leaving the hacky version for now. if self.eat_keyword(keywords::For) { let span = self.span; + let mut ate_question = false; + if self.eat(&token::Question) { + ate_question = true; + } let ident = self.parse_ident(); - if !self.eat(&token::Question) { + if self.eat(&token::Question) { + if ate_question { + self.span_err(span, + "unexpected `?`"); + } + ate_question = true; + } + if !ate_question { self.span_err(span, - "expected 'Sized?' after `for` in trait item"); + "expected `?Sized` after `for` in trait item"); return None; } let tref = Parser::trait_ref_from_ident(ident, span); -- cgit 1.4.1-3-g733a5 From 35a6f6247ba930425b5ffb8e6f33fbbe1da278cc Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sat, 27 Dec 2014 23:45:50 +1300 Subject: Fix spans for `use` view statements and their treatment in save-analysis --- src/librustc_trans/save/mod.rs | 6 +++--- src/librustc_trans/save/span_utils.rs | 4 ++-- src/libsyntax/parse/parser.rs | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index f491bc84b62..2a977b1085a 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1162,8 +1162,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } match i.node { - ast::ViewItemUse(ref path) => { - match path.node { + ast::ViewItemUse(ref item) => { + match item.node { ast::ViewPathSimple(ident, ref path, id) => { let sub_span = self.span.span_for_last_ident(path.span); let mod_id = match self.lookup_type_ref(id) { @@ -1184,7 +1184,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // 'use' always introduces an alias, if there is not an explicit // one, there is an implicit one. let sub_span = - match self.span.sub_span_before_token(path.span, token::Eq) { + match self.span.sub_span_after_keyword(item.span, keywords::As) { Some(sub_span) => Some(sub_span), None => sub_span, }; diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index e9d862d3781..244d0476832 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -294,8 +294,8 @@ impl<'a> SpanUtils<'a> { } pub fn sub_span_after_keyword(&self, - span: Span, - keyword: keywords::Keyword) -> Option { + span: Span, + keyword: keywords::Keyword) -> Option { let mut toks = self.retokenise_span(span); loop { let ts = toks.real_token(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 94b61ba56d2..8011507c512 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5917,7 +5917,7 @@ impl<'a> Parser<'a> { } - /// Matches view_path : MOD? IDENT EQ non_global_path + /// Matches view_path : MOD? non_global_path as IDENT /// | MOD? non_global_path MOD_SEP LBRACE RBRACE /// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE /// | MOD? non_global_path MOD_SEP STAR @@ -6029,7 +6029,7 @@ impl<'a> Parser<'a> { } let mut rename_to = path[path.len() - 1u]; let path = ast::Path { - span: mk_sp(lo, self.span.hi), + span: mk_sp(lo, self.last_span.hi), global: false, segments: path.into_iter().map(|identifier| { ast::PathSegment { @@ -6041,7 +6041,8 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::As) { rename_to = self.parse_ident() } - P(spanned(lo, self.last_span.hi, + P(spanned(lo, + self.last_span.hi, ViewPathSimple(rename_to, path, ast::DUMMY_NODE_ID))) } -- cgit 1.4.1-3-g733a5