about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-11-04 20:41:00 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-11-06 08:56:29 -0800
commitb0ed151539cddb1c191f67f9f9597942919d44eb (patch)
tree976ed7cab726c0cdae81e0a18e28a27cbd5e4664 /src/libsyntax/parse/parser.rs
parent53ec6c3f9b495dd930cd061784251534bef58d74 (diff)
downloadrust-b0ed151539cddb1c191f67f9f9597942919d44eb.tar.gz
rust-b0ed151539cddb1c191f67f9f9597942919d44eb.zip
Cleanup how we handle proto in types, remove unsound subtyping
Fixes #1896 which was never truly fixed, just masked.
The given tests would have failed had they used `~fn()` and
not `@fn()`.  They now result in compilation errors.

Fixes #2978.

Necessary first step for #2202, #2263.
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs275
1 files changed, 173 insertions, 102 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 63545a69608..db3f6abbf7b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -50,8 +50,8 @@ use ast::{_mod, add, arg, arm, attribute,
              match_tok, method, mode, module_ns, mt, mul, mutability,
              named_field, neg, noreturn, not, pat, pat_box, pat_enum,
              pat_ident, pat_lit, pat_range, pat_rec, pat_region, pat_struct,
-             pat_tup, pat_uniq, pat_wild, path, private, proto, proto_bare,
-             proto_block, proto_box, proto_uniq, provided, public, pure_fn,
+             pat_tup, pat_uniq, pat_wild, path, private, Proto, ProtoBare,
+             ProtoBorrowed, ProtoBox, ProtoUniq, provided, public, pure_fn,
              purity, re_static, re_self, re_anon, re_named, region,
              rem, required, ret_style,
              return_val, self_ty, shl, shr, stmt, stmt_decl, stmt_expr,
@@ -61,14 +61,14 @@ use ast::{_mod, add, arg, arm, attribute,
              tt_tok, tt_nonterminal, tuple_variant_kind, Ty, ty_, ty_bot,
              ty_box, ty_field, ty_fn, ty_infer, ty_mac, ty_method, ty_nil,
              ty_param, ty_param_bound, ty_path, ty_ptr, ty_rec, ty_rptr,
-             ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length, type_value_ns,
-             uniq, unnamed_field, unsafe_blk, unsafe_fn,
+             ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length_vec,
+             type_value_ns, uniq, unnamed_field, unsafe_blk, unsafe_fn,
              variant, view_item, view_item_, view_item_export,
              view_item_import, view_item_use, view_path, view_path_glob,
              view_path_list, view_path_simple, visibility, vstore, vstore_box,
              vstore_fixed, vstore_slice, vstore_uniq,
              expr_vstore_fixed, expr_vstore_slice, expr_vstore_box,
-             expr_vstore_uniq};
+             expr_vstore_uniq, TyFn, Onceness, Once, Many};
 
 export file_type;
 export Parser;
@@ -287,30 +287,90 @@ impl Parser {
 
     pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
 
-    fn parse_ty_fn(purity: ast::purity, onceness: ast::Onceness) -> ty_ {
-        let proto, bounds;
+    fn token_is_fn_keyword(+tok: token::Token) -> bool {
+        self.token_is_keyword(~"pure", tok) ||
+            self.token_is_keyword(~"unsafe", tok) ||
+            self.token_is_keyword(~"once", tok) ||
+            self.token_is_keyword(~"fn", tok) ||
+            self.token_is_keyword(~"extern", tok)
+    }
+
+    fn parse_ty_fn(pre_proto: Option<ast::Proto>,
+                       pre_region_name: Option<ident>) -> ty_
+    {
+        /*
+
+        (&|~|@) [r/] [pure|unsafe] [once] fn [:K] (S) -> T
+        ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^    ^~~^ ^~^    ^
+           |     |     |             |        |    |     |
+           |     |     |             |        |    |   Return type
+           |     |     |             |        |  Argument types
+           |     |     |             |    Environment bounds
+           |     |     |          Once-ness (a.k.a., affine)
+           |     |   Purity
+           | Lifetime bound
+        Allocation type
+
+        */
+
+        // At this point, the allocation type and lifetime bound have been
+        // parsed.
+
+        let purity = parse_purity(&self);
+        let onceness = parse_onceness(&self);
+
+        let bounds, post_proto;
         if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
-            proto = ast::proto_bare;
+            post_proto = Some(ast::ProtoBare);
             bounds = @~[];
         } else {
             self.expect_keyword(~"fn");
-            proto = self.parse_fn_ty_proto();
+            post_proto = self.parse_fn_ty_proto();
             bounds = self.parse_optional_ty_param_bounds();
         };
-        ty_fn(proto, purity, onceness, bounds, self.parse_ty_fn_decl())
-    }
 
-    fn parse_ty_fn_with_onceness(purity: ast::purity) -> ty_ {
-        let onceness = self.parse_optional_onceness();
-        self.parse_ty_fn(purity, onceness)
-    }
+        let proto = match (pre_proto, post_proto) {
+            (None, None) => ast::ProtoBorrowed,
+            (Some(p), None) | (None, Some(p)) => p,
+            (Some(_), Some(_)) => {
+                self.fatal(~"cannot combine prefix and postfix \
+                             syntax for closure kind; note that \
+                             postfix syntax is obsolete");
+            }
+        };
+
+        let region = if pre_region_name.is_some() {
+            Some(self.region_from_name(pre_region_name))
+        } else {
+            None
+        };
+
+        return ty_fn(@TyFn {
+            proto: proto,
+            region: region,
+            purity: purity,
+            onceness: onceness,
+            bounds: bounds,
+            decl: self.parse_ty_fn_decl()
+        });
+
+        fn parse_purity(self: &Parser) -> purity {
+            if self.eat_keyword(~"pure") {
+                return pure_fn;
+            } else if self.eat_keyword(~"unsafe") {
+                return unsafe_fn;
+            } else {
+                return impure_fn;
+            }
+        }
 
-    fn parse_ty_fn_with_purity_and_onceness() -> ty_ {
-        let purity = self.parse_optional_purity();
-        self.parse_ty_fn_with_onceness(purity)
+        fn parse_onceness(self: &Parser) -> Onceness {
+            if self.eat_keyword(~"once") {Once} else {Many}
+        }
     }
 
+
     fn parse_ty_fn_decl() -> fn_decl {
         let inputs = do self.parse_unspanned_seq(
             token::LPAREN, token::RPAREN,
@@ -449,23 +509,6 @@ impl Parser {
         }
     }
 
-    // Parses something like "&x/" (note the trailing slash)
-    fn parse_region_with_sep() -> @region {
-        let name =
-            match copy self.token {
-              token::IDENT(sid, _) => {
-                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
-                    self.bump(); self.bump();
-                    Some(sid)
-                } else {
-                    None
-                }
-              }
-              _ => { None }
-            };
-        self.region_from_name(name)
-    }
-
     fn parse_ty(colons_before_params: bool) -> @Ty {
         maybe_whole!(self, nt_ty);
 
@@ -498,10 +541,10 @@ impl Parser {
             }
         } else if self.token == token::AT {
             self.bump();
-            ty_box(self.parse_mt())
+            self.parse_box_or_uniq_pointee(ast::ProtoBox, ty_box)
         } else if self.token == token::TILDE {
             self.bump();
-            ty_uniq(self.parse_mt())
+            self.parse_box_or_uniq_pointee(ast::ProtoUniq, ty_uniq)
         } else if self.token == token::BINOP(token::STAR) {
             self.bump();
             ty_ptr(self.parse_mt())
@@ -516,51 +559,77 @@ impl Parser {
             ty_rec(elems)
         } else if self.token == token::LBRACKET {
             self.expect(token::LBRACKET);
-            let mut t = ty_vec(self.parse_mt());
+            let mt = self.parse_mt();
 
             // Parse the `* 3` in `[ int * 3 ]`
-            match self.maybe_parse_fixed_vstore_with_star() {
-                None => {}
-                Some(suffix) => {
-                    t = ty_fixed_length(@{
-                        id: self.get_id(),
-                        node: t,
-                        span: mk_sp(lo, self.last_span.hi)
-                    }, suffix)
-                }
-            }
+            let t = match self.maybe_parse_fixed_vstore_with_star() {
+                None => ty_vec(mt),
+                Some(suffix) => ty_fixed_length_vec(mt, suffix)
+            };
             self.expect(token::RBRACKET);
             t
         } else if self.token == token::BINOP(token::AND) {
             self.bump();
-            let region = self.parse_region_with_sep();
-            let mt = self.parse_mt();
-            ty_rptr(region, mt)
-        } else if self.eat_keyword(~"once") {
-            self.parse_ty_fn(ast::impure_fn, ast::Once)
-        } else if self.eat_keyword(~"pure") {
-            self.parse_ty_fn_with_onceness(ast::pure_fn)
-        } else if self.eat_keyword(~"unsafe") {
-            self.parse_ty_fn_with_onceness(ast::unsafe_fn)
-        } else if self.is_keyword(~"fn") {
-            self.parse_ty_fn_with_onceness(ast::impure_fn)
-        } else if self.eat_keyword(~"extern") {
-            self.expect_keyword(~"fn");
-            ty_fn(proto_bare, ast::impure_fn, ast::Many, @~[],
-                  self.parse_ty_fn_decl())
+            self.parse_borrowed_pointee()
+        } else if self.token_is_fn_keyword(self.token) {
+            self.parse_ty_fn(None, None)
         } else if self.token == token::MOD_SEP || is_ident(self.token) {
             let path = self.parse_path_with_tps(colons_before_params);
             ty_path(path, self.get_id())
         } else { self.fatal(~"expected type"); };
 
         let sp = mk_sp(lo, self.last_span.hi);
-        return {
-            let node =
-                self.try_convert_ty_to_obsolete_fixed_length_vstore(sp, t);
-            @{id: self.get_id(),
-              node: node,
-              span: sp}
+        return @{id: self.get_id(), node: t, span: sp};
+    }
+
+    fn parse_box_or_uniq_pointee(
+        proto: ast::Proto,
+        ctor: &fn(+v: mt) -> ty_) -> ty_
+    {
+        // @foo/fn() or @fn() are parsed directly as fn types:
+        match copy self.token {
+            token::IDENT(rname, _) => {
+                if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
+                    self.token_is_fn_keyword(self.look_ahead(2u))
+                {
+                    self.bump(); self.bump();
+                    return self.parse_ty_fn(Some(proto), Some(rname));
+                } else if self.token_is_fn_keyword(self.token) {
+                    return self.parse_ty_fn(Some(proto), None);
+                }
+            }
+            _ => {}
+        }
+
+        // other things are parsed as @ + a type.  Note that constructs like
+        // @[] and @str will be resolved during typeck to slices and so forth,
+        // rather than boxed ptrs.  But the special casing of str/vec is not
+        // reflected in the AST type.
+        let mt = self.parse_mt();
+        ctor(mt)
+    }
+
+    fn parse_borrowed_pointee() -> ty_ {
+        // look for `&foo/` and interpret `foo` as the region name:
+        let rname = match copy self.token {
+            token::IDENT(sid, _) => {
+                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
+                    self.bump(); self.bump();
+                    Some(sid)
+                } else {
+                    None
+                }
+            }
+            _ => { None }
         };
+
+        if self.token_is_fn_keyword(self.token) {
+            return self.parse_ty_fn(Some(ProtoBorrowed), rname);
+        }
+
+        let r = self.region_from_name(rname);
+        let mt = self.parse_mt();
+        return ty_rptr(r, mt);
     }
 
     fn parse_arg_mode() -> mode {
@@ -691,16 +760,19 @@ impl Parser {
         }
     }
 
-    fn maybe_parse_fixed_vstore_with_star() -> Option<Option<uint>> {
+    fn maybe_parse_fixed_vstore_with_star() -> Option<uint> {
         if self.eat(token::BINOP(token::STAR)) {
             match copy self.token {
-              token::UNDERSCORE => {
-                self.bump(); Some(None)
-              }
-              token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 => {
-                self.bump(); Some(Some(i as uint))
-              }
-              _ => None
+                token::LIT_INT_UNSUFFIXED(i) if i >= 0i64 => {
+                    self.bump();
+                    Some(i as uint)
+                }
+                _ => {
+                    self.fatal(
+                        fmt!("expected integral vector length \
+                              but found `%s`",
+                             token_to_str(self.reader, self.token)));
+                }
             }
         } else {
             None
@@ -909,11 +981,13 @@ impl Parser {
         } else if self.eat_keyword(~"match") {
             return self.parse_alt_expr();
         } else if self.eat_keyword(~"fn") {
-            let proto = self.parse_fn_ty_proto();
-            match proto {
-              proto_bare => self.fatal(~"fn expr are deprecated, use fn@"),
-              _ => { /* fallthrough */ }
-            }
+            let opt_proto = self.parse_fn_ty_proto();
+            let proto = match opt_proto {
+                None | Some(ast::ProtoBare) => {
+                    self.fatal(~"fn expr are deprecated, use fn@")
+                }
+                Some(p) => { p }
+            };
             return self.parse_fn_expr(proto);
         } else if self.eat_keyword(~"unsafe") {
             return self.parse_block_expr(lo, unsafe_blk);
@@ -1055,9 +1129,6 @@ impl Parser {
             ex = expr_lit(@lit);
         }
 
-        let (hi, ex) =
-            self.try_convert_expr_to_obsolete_fixed_length_vstore(lo, hi, ex);
-
         return self.mk_expr(lo, hi, ex);
     }
 
@@ -1495,7 +1566,7 @@ impl Parser {
         return self.mk_expr(q.lo, q.hi, expr_if(q.cond, q.then, q.els));
     }
 
-    fn parse_fn_expr(proto: proto) -> @expr {
+    fn parse_fn_expr(proto: Proto) -> @expr {
         let lo = self.last_span.lo;
 
         // if we want to allow fn expression argument types to be inferred in
@@ -3188,23 +3259,23 @@ impl Parser {
         (id, item_enum(enum_definition, ty_params), None)
     }
 
-    fn parse_fn_ty_proto() -> proto {
+    fn parse_fn_ty_proto() -> Option<Proto> {
         match self.token {
-          token::AT => {
-            self.bump();
-            proto_box
-          }
-          token::TILDE => {
-            self.bump();
-            proto_uniq
-          }
-          token::BINOP(token::AND) => {
-            self.bump();
-            proto_block
-          }
-          _ => {
-            proto_block
-          }
+            token::AT => {
+                self.bump();
+                Some(ProtoBox)
+            }
+            token::TILDE => {
+                self.bump();
+                Some(ProtoUniq)
+            }
+            token::BINOP(token::AND) => {
+                self.bump();
+                Some(ProtoBorrowed)
+            }
+            _ => {
+                None
+            }
         }
     }