提交 3b6314c3 编写于 作者: P Patrick Walton

librustc: Add support for type parameters in the middle of paths.

For example, `foo::<T>::bar::<U>`.

This doesn't enforce that the type parameters are in the right
positions, however.
上级 5c350479
......@@ -17,6 +17,7 @@
use syntax::codemap::dummy_sp;
use syntax::codemap;
use syntax::fold;
use syntax::opt_vec;
static STD_VERSION: &'static str = "0.8-pre";
......@@ -90,12 +91,18 @@ fn spanned<T>(x: T) -> codemap::spanned<T> {
let prelude_path = ast::Path {
span: dummy_sp(),
global: false,
idents: ~[
sess.ident_of("std"),
sess.ident_of("prelude")
segments: ~[
ast::PathSegment {
identifier: sess.ident_of("std"),
lifetime: None,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: sess.ident_of("prelude"),
lifetime: None,
types: opt_vec::Empty,
},
],
rp: None,
types: ~[]
};
let vp = @spanned(ast::view_path_glob(prelude_path, n2));
......
......@@ -16,14 +16,15 @@
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, span, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::attr::AttrMetaMethods;
type node_id_gen = @fn() -> ast::NodeId;
......@@ -383,19 +384,27 @@ fn nospan<T>(t: T) -> codemap::spanned<T> {
}
fn path_node(ids: ~[ast::ident]) -> ast::Path {
ast::Path { span: dummy_sp(),
global: false,
idents: ids,
rp: None,
types: ~[] }
ast::Path {
span: dummy_sp(),
global: false,
segments: ids.consume_iter().transform(|identifier| ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}).collect()
}
}
fn path_node_global(ids: ~[ast::ident]) -> ast::Path {
ast::Path { span: dummy_sp(),
global: true,
idents: ids,
rp: None,
types: ~[] }
ast::Path {
span: dummy_sp(),
global: true,
segments: ids.consume_iter().transform(|identifier| ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}).collect()
}
}
#[cfg(stage0)]
......
......@@ -988,7 +988,8 @@ fn add_to_index_(item: @item, ebml_w: &writer::Encoder,
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
match ty.node {
ast::ty_path(ref path, ref bounds, _) if path.idents.len() == 1 => {
ast::ty_path(ref path, ref bounds, _) if path.segments
.len() == 1 => {
assert!(bounds.is_none());
encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path));
......
......@@ -138,12 +138,20 @@ fn parse_path(st: &mut PState) -> @ast::Path {
':' => { next(st); next(st); }
c => {
if c == '(' {
return @ast::Path { span: dummy_sp(),
global: false,
idents: idents,
rp: None,
types: ~[] };
} else { idents.push(parse_ident_(st, is_last)); }
return @ast::Path {
span: dummy_sp(),
global: false,
segments: idents.consume_iter().transform(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}
}).collect()
};
} else {
idents.push(parse_ident_(st, is_last));
}
}
}
};
......
......@@ -141,7 +141,7 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
// to handle on-demand instantiation of functions via
// foo::<bar> in a const. Currently that is only done on
// a path in trans::callee that only works in block contexts.
if pth.types.len() != 0 {
if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
sess.span_err(
e.span, "paths in constants may only refer to \
items without type parameters");
......
......@@ -251,7 +251,9 @@ fn check_path(&mut self, span: span, def: def, path: &Path) {
match def {
def_static_method(method_id, _, _) => {
debug!("found static method def, checking it");
self.check_method_common(span, method_id, path.idents.last())
self.check_method_common(span,
method_id,
&path.segments.last().identifier)
}
def_fn(def_id, _) => {
if def_id.crate == LOCAL_CRATE {
......@@ -259,13 +261,19 @@ fn check_path(&mut self, span: span, def: def, path: &Path) {
!self.privileged_items.iter().any(|x| x == &def_id.node) {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
token::ident_to_str(
&path.segments
.last()
.identifier)));
}
} else if csearch::get_item_visibility(self.tcx.sess.cstore,
def_id) != public {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
token::ident_to_str(
&path.segments
.last()
.identifier)));
}
}
_ => {}
......
......@@ -827,7 +827,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
Some(&ast::def_trait(did)) |
Some(&ast::def_struct(did)) => {
if did.crate == ast::LOCAL_CRATE {
if cx.region_is_relevant(&path.rp) {
if cx.region_is_relevant(&path.segments.last().lifetime) {
cx.add_dep(did.node);
}
} else {
......@@ -837,7 +837,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
Some(variance) => {
debug!("reference to external, rp'd type %s",
pprust::ty_to_str(ty, sess.intr()));
if cx.region_is_relevant(&path.rp) {
if cx.region_is_relevant(&path.segments.last().lifetime) {
let rv = cx.add_variance(variance);
cx.add_rp(cx.item_id, rv)
}
......@@ -860,7 +860,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
ast::ty_path(ref path, _, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
for tp in path.types.iter() {
for tp in path.segments.iter().flat_map(|s| s.types.iter()) {
visitor.visit_ty(tp, cx);
}
}
......
......@@ -1277,7 +1277,7 @@ pub fn build_reduced_graph_for_item(@mut self,
&Ty {
node: ty_path(ref path, _, _),
_
} if path.idents.len() == 1 => {
} if path.segments.len() == 1 => {
let name = path_to_ident(path);
let new_parent = match parent.children.find(&name) {
......@@ -1476,20 +1476,22 @@ pub fn build_reduced_graph_for_view_item(@mut self,
let mut module_path = ~[];
match view_path.node {
view_path_simple(_, ref full_path, _) => {
let path_len = full_path.idents.len();
let path_len = full_path.segments.len();
assert!(path_len != 0);
for (i, ident) in full_path.idents.iter().enumerate() {
for (i, segment) in full_path.segments
.iter()
.enumerate() {
if i != path_len - 1 {
module_path.push(*ident);
module_path.push(segment.identifier)
}
}
}
view_path_glob(ref module_ident_path, _) |
view_path_list(ref module_ident_path, _, _) => {
for ident in module_ident_path.idents.iter() {
module_path.push(*ident);
for segment in module_ident_path.segments.iter() {
module_path.push(segment.identifier)
}
}
}
......@@ -1498,7 +1500,8 @@ pub fn build_reduced_graph_for_view_item(@mut self,
let module_ = self.get_module_from_parent(parent);
match view_path.node {
view_path_simple(binding, ref full_path, id) => {
let source_ident = *full_path.idents.last();
let source_ident =
full_path.segments.last().identifier;
let subclass = @SingleImport(binding,
source_ident);
self.build_import_directive(privacy,
......@@ -2109,6 +2112,14 @@ pub fn idents_to_str(@mut self, idents: &[ident]) -> ~str {
return result;
}
fn path_idents_to_str(@mut self, path: &Path) -> ~str {
let identifiers: ~[ast::ident] = path.segments
.iter()
.transform(|seg| seg.identifier)
.collect();
self.idents_to_str(identifiers)
}
pub fn import_directive_subclass_to_str(@mut self,
subclass: ImportDirectiveSubclass)
-> @str {
......@@ -3841,8 +3852,7 @@ pub fn resolve_trait_reference(@mut self,
reference_type: TraitReferenceType) {
match self.resolve_path(id, &trait_reference.path, TypeNS, true, visitor) {
None => {
let path_str = self.idents_to_str(trait_reference.path.idents);
let path_str = self.path_idents_to_str(&trait_reference.path);
let usage_str = match reference_type {
TraitBoundingTypeParameter => "bound type parameter with",
TraitImplementation => "implement",
......@@ -4141,8 +4151,8 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
let mut result_def = None;
// First, check to see whether the name is a primitive type.
if path.idents.len() == 1 {
let name = *path.idents.last();
if path.segments.len() == 1 {
let name = path.segments.last().identifier;
match self.primitive_type_table
.primitive_types
......@@ -4165,7 +4175,7 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
debug!("(resolving type) resolved `%s` to \
type %?",
self.session.str_of(
*path.idents.last()),
path.segments.last().identifier),
def);
result_def = Some(def);
}
......@@ -4184,14 +4194,15 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
// Write the result into the def map.
debug!("(resolving type) writing resolution for `%s` \
(id %d)",
self.idents_to_str(path.idents),
self.path_idents_to_str(path),
path_id);
self.record_def(path_id, def);
}
None => {
self.resolve_error
(ty.span, fmt!("use of undeclared type name `%s`",
self.idents_to_str(path.idents)));
(ty.span,
fmt!("use of undeclared type name `%s`",
self.path_idents_to_str(path)))
}
}
......@@ -4230,7 +4241,7 @@ pub fn resolve_pattern(@mut self,
do walk_pat(pattern) |pattern| {
match pattern.node {
pat_ident(binding_mode, ref path, _)
if !path.global && path.idents.len() == 1 => {
if !path.global && path.segments.len() == 1 => {
// The meaning of pat_ident with no type parameters
// depends on whether an enum variant or unit-like struct
......@@ -4241,7 +4252,7 @@ pub fn resolve_pattern(@mut self,
// such a value is simply disallowed (since it's rarely
// what you want).
let ident = path.idents[0];
let ident = path.segments[0].identifier;
match self.resolve_bare_identifier_pattern(ident) {
FoundStructOrEnumVariant(def)
......@@ -4351,7 +4362,9 @@ struct in scope",
}
// Check the types in the path pattern.
for ty in path.types.iter() {
for ty in path.segments
.iter()
.flat_map_(|seg| seg.types.iter()) {
self.resolve_type(ty, visitor);
}
}
......@@ -4375,7 +4388,7 @@ struct in scope",
path.span,
fmt!("`%s` is not an enum variant or constant",
self.session.str_of(
*path.idents.last())));
path.segments.last().identifier)))
}
None => {
self.resolve_error(path.span,
......@@ -4384,7 +4397,9 @@ struct in scope",
}
// Check the types in the path pattern.
for ty in path.types.iter() {
for ty in path.segments
.iter()
.flat_map_(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
}
......@@ -4402,8 +4417,10 @@ struct in scope",
self.resolve_error(
path.span,
fmt!("`%s` is not an enum variant, struct or const",
self.session.str_of(
*path.idents.last())));
self.session
.str_of(path.segments
.last()
.identifier)));
}
None => {
self.resolve_error(path.span,
......@@ -4413,7 +4430,9 @@ struct in scope",
}
// Check the types in the path pattern.
for ty in path.types.iter() {
for ty in path.segments
.iter()
.flat_map_(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
}
......@@ -4448,7 +4467,7 @@ struct in scope",
self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
self.idents_to_str(path.idents)));
self.path_idents_to_str(path)));
}
}
}
......@@ -4510,7 +4529,7 @@ pub fn resolve_path(@mut self,
visitor: &mut ResolveVisitor)
-> Option<def> {
// First, resolve the types.
for ty in path.types.iter() {
for ty in path.segments.iter().flat_map_(|s| s.types.iter()) {
self.resolve_type(ty, visitor);
}
......@@ -4520,12 +4539,17 @@ pub fn resolve_path(@mut self,
namespace);
}
let unqualified_def = self.resolve_identifier(
*path.idents.last(), namespace, check_ribs, path.span);
let unqualified_def = self.resolve_identifier(path.segments
.last()
.identifier,
namespace,
check_ribs,
path.span);
if path.idents.len() > 1 {
let def = self.resolve_module_relative_path(
path, self.xray_context, namespace);
if path.segments.len() > 1 {
let def = self.resolve_module_relative_path(path,
self.xray_context,
namespace);
match (def, unqualified_def) {
(Some(d), Some(ud)) if d == ud => {
self.session.add_lint(unnecessary_qualification,
......@@ -4640,12 +4664,12 @@ pub fn resolve_definition_of_name_in_module(@mut self,
pub fn intern_module_part_of_path(@mut self, path: &Path) -> ~[ident] {
let mut module_path_idents = ~[];
for (index, ident) in path.idents.iter().enumerate() {
if index == path.idents.len() - 1 {
for (index, segment) in path.segments.iter().enumerate() {
if index == path.segments.len() - 1 {
break;
}
module_path_idents.push(*ident);
module_path_idents.push(segment.identifier);
}
return module_path_idents;
......@@ -4681,7 +4705,7 @@ pub fn resolve_module_relative_path(@mut self,
}
}
let name = *path.idents.last();
let name = path.segments.last().identifier;
let def = match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace,
......@@ -4749,7 +4773,7 @@ pub fn resolve_crate_relative_path(@mut self,
}
}
let name = *path.idents.last();
let name = path.segments.last().identifier;
match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace,
......@@ -4969,7 +4993,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
Some(def) => {
// Write the result into the def map.
debug!("(resolving expr) resolved `%s`",
self.idents_to_str(path.idents));
self.path_idents_to_str(path));
// First-class methods are not supported yet; error
// out here.
......@@ -4989,8 +5013,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
self.record_def(expr.id, def);
}
None => {
let wrong_name = self.idents_to_str(
path.idents);
let wrong_name = self.path_idents_to_str(path);
if self.name_exists_in_scope_struct(wrong_name) {
self.resolve_error(expr.span,
fmt!("unresolved name `%s`. \
......@@ -5066,7 +5089,7 @@ pub fn resolve_expr(@mut self, expr: @expr, visitor: &mut ResolveVisitor) {
self.resolve_error(
path.span,
fmt!("`%s` does not name a structure",
self.idents_to_str(path.idents)));
self.path_idents_to_str(path)));
}
}
......
......@@ -559,7 +559,9 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
v
}
ast::expr_path(ref pth) => {
assert_eq!(pth.types.len(), 0);
// Assert that there are no type parameters in this path.
assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
let tcx = cx.tcx;
match tcx.def_map.find(&e.id) {
Some(&ast::def_fn(def_id, _purity)) => {
......
......@@ -63,7 +63,6 @@
use middle::typeck::lookup_def_tcx;
use std::result;
use std::vec;
use syntax::abi::AbiSet;
use syntax::{ast, ast_util};
use syntax::codemap::span;
......@@ -150,7 +149,8 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
// If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
let regions = match (&decl_generics.region_param, &path.rp) {
let regions = match (&decl_generics.region_param,
&path.segments.last().lifetime) {
(&None, &None) => {
opt_vec::Empty
}
......@@ -169,20 +169,34 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
}
(&Some(_), &Some(_)) => {
opt_vec::with(
ast_region_to_region(this, rscope, path.span, &path.rp))
ast_region_to_region(this,
rscope,
path.span,
&path.segments.last().lifetime))
}
};
// Convert the type parameters supplied by the user.
if !vec::same_length(*decl_generics.type_param_defs, path.types) {
let supplied_type_parameter_count =
path.segments.iter().flat_map_(|s| s.types.iter()).len_();
if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
this.tcx().sess.span_fatal(
path.span,
fmt!("wrong number of type arguments: expected %u but found %u",
decl_generics.type_param_defs.len(), path.types.len()));
decl_generics.type_param_defs.len(),
supplied_type_parameter_count));
}
let tps = path.segments
.iter()
.flat_map_(|s| s.types.iter())
.transform(|a_t| ast_ty_to_ty(this, rscope, a_t))
.collect();
substs {
regions: ty::NonerasedRegions(regions),
self_ty: self_ty,
tps: tps
}
let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps}
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,
......@@ -325,7 +339,7 @@ fn check_path_args(tcx: ty::ctxt,
path: &ast::Path,
flags: uint) {
if (flags & NO_TPS) != 0u {
if path.types.len() > 0u {
if !path.segments.iter().all(|s| s.types.is_empty()) {
tcx.sess.span_err(
path.span,
"type parameters are not allowed on this type");
......@@ -333,7 +347,7 @@ fn check_path_args(tcx: ty::ctxt,
}
if (flags & NO_REGIONS) != 0u {
if path.rp.is_some() {
if path.segments.last().lifetime.is_some() {
tcx.sess.span_err(
path.span,
"region parameters are not allowed on this type");
......
......@@ -3146,7 +3146,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
debug!(">>> instantiate_path");
let ty_param_count = tpt.generics.type_param_defs.len();
let ty_substs_len = pth.types.len();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
}
debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
tpt.repr(fcx.tcx()),
......@@ -3155,7 +3158,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
// determine the region bound, using the value given by the user
// (if any) and otherwise using a fresh region variable
let regions = match pth.rp {
let regions = match pth.segments.last().lifetime {
Some(_) => { // user supplied a lifetime parameter...
match tpt.generics.region_param {
None => { // ...but the type is not lifetime parameterized!
......@@ -3165,7 +3168,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
}
Some(_) => { // ...and the type is lifetime parameterized, ok.
opt_vec::with(
ast_region_to_region(fcx, fcx, span, &pth.rp))
ast_region_to_region(fcx,
fcx,
span,
&pth.segments.last().lifetime))
}
}
}
......@@ -3204,12 +3210,18 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
}
fcx.infcx().next_ty_vars(ty_param_count)
} else {
pth.types.map(|aty| fcx.to_ty(aty))
pth.segments
.iter()
.flat_map_(|s| s.types.iter())
.transform(|aty| fcx.to_ty(aty))
.collect()
};
let substs = substs {regions: ty::NonerasedRegions(regions),
self_ty: None,
tps: tps };
let substs = substs {
regions: ty::NonerasedRegions(regions),
self_ty: None,
tps: tps
};
fcx.write_ty_substs(node_id, tpt.ty, substs);
debug!("<<<");
......
......@@ -109,12 +109,21 @@ pub struct Path {
/// A `::foo` path, is relative to the crate root rather than current
/// module (like paths in an import).
global: bool,
/// The segments in the path (the things separated by ::)
idents: ~[ident],
/// "Region parameter", currently only one lifetime is allowed in a path.
rp: Option<Lifetime>,
/// These are the type parameters, ie, the `a, b` in `foo::bar::<a, b>`
types: ~[Ty],
/// The segments in the path: the things separated by `::`.
segments: ~[PathSegment],
}
/// A segment of a path: an identifier, an optional lifetime, and a set of
/// types.
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct PathSegment {
/// The identifier portion of this path segment.
identifier: ident,
/// The lifetime parameter for this path segment. Currently only one
/// lifetime parameter is allowed.
lifetime: Option<Lifetime>,
/// The type parameters for this path segment, if present.
types: OptVec<Ty>,
}
pub type CrateNum = int;
......
......@@ -28,8 +28,8 @@ pub fn path_name_i(idents: &[ident]) -> ~str {
idents.map(|i| token::interner_get(i.name)).connect("::")
}
pub fn path_to_ident(p: &Path) -> ident {
*p.idents.last()
pub fn path_to_ident(path: &Path) -> ident {
path.segments.last().identifier
}
pub fn local_def(id: NodeId) -> def_id {
......@@ -217,12 +217,18 @@ pub fn default_block(
}
}
pub fn ident_to_path(s: span, i: ident) -> Path {
ast::Path { span: s,
global: false,
idents: ~[i],
rp: None,
types: ~[] }
pub fn ident_to_path(s: span, identifier: ident) -> Path {
ast::Path {
span: s,
global: false,
segments: ~[
ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
pub fn ident_to_pat(id: NodeId, s: span, i: ident) -> @pat {
......@@ -420,7 +426,7 @@ fn visit_generics_helper(&self, generics: &Generics) {
impl Visitor<()> for IdVisitor {
fn visit_mod(&mut self,
module: &_mod,
_span: span,
_: span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);
......
......@@ -329,20 +329,6 @@ pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str {
}
}
pub fn expr_to_ident(cx: @ExtCtxt,
expr: @ast::expr,
err_msg: &str) -> ast::ident {
match expr.node {
ast::expr_path(ref p) => {
if p.types.len() > 0u || p.idents.len() != 1u {
cx.span_fatal(expr.span, err_msg);
}
return p.idents[0];
}
_ => cx.span_fatal(expr.span, err_msg)
}
}
pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
name: &str) {
if tts.len() != 0 {
......@@ -353,15 +339,15 @@ pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
pub fn get_single_str_from_tts(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree],
name: &str) -> @str {
name: &str)
-> @str {
if tts.len() != 1 {
cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
}
match tts[0] {
ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
_ =>
cx.span_fatal(sp, fmt!("%s requires a string.", name))
_ => cx.span_fatal(sp, fmt!("%s requires a string.", name)),
}
}
......
......@@ -233,18 +233,31 @@ fn path_ident(&self, span: span, id: ast::ident) -> ast::Path {
fn path_global(&self, span: span, strs: ~[ast::ident]) -> ast::Path {
self.path_all(span, true, strs, None, ~[])
}
fn path_all(&self, sp: span,
fn path_all(&self,
sp: span,
global: bool,
idents: ~[ast::ident],
mut idents: ~[ast::ident],
rp: Option<ast::Lifetime>,
types: ~[ast::Ty])
-> ast::Path {
-> ast::Path {
let last_identifier = idents.pop();
let mut segments: ~[ast::PathSegment] = idents.consume_iter()
.transform(|ident| {
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
}).collect();
segments.push(ast::PathSegment {
identifier: last_identifier,
lifetime: rp,
types: opt_vec::from(types),
});
ast::Path {
span: sp,
global: global,
idents: idents,
rp: rp,
types: types
segments: segments,
}
}
......
......@@ -12,6 +12,7 @@
use codemap::span;
use ext::base::*;
use ext::base;
use opt_vec;
use parse::token;
use parse::token::{str_to_ident};
......@@ -39,9 +40,13 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
ast::Path {
span: sp,
global: false,
idents: ~[res],
rp: None,
types: ~[],
segments: ~[
ast::PathSegment {
identifier: res,
lifetime: None,
types: opt_vec::Empty,
}
]
}
),
span: sp,
......
......@@ -19,6 +19,7 @@
use codemap::{span, spanned, ExpnInfo, NameAndSpan};
use ext::base::*;
use fold::*;
use opt_vec;
use parse;
use parse::{parse_item_from_source_str};
use parse::token;
......@@ -42,13 +43,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
match (*mac).node {
// Token-tree macros:
mac_invoc_tt(ref pth, ref tts) => {
if (pth.idents.len() > 1u) {
if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
// leaving explicit deref here to highlight unbox op:
match (*extsbox).find(&extname.name) {
......@@ -143,9 +144,13 @@ fn mk_simple_path(ident: ast::ident, span: span) -> ast::Path {
ast::Path {
span: span,
global: false,
idents: ~[ident],
rp: None,
types: ~[]
segments: ~[
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
......@@ -368,7 +373,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
_ => cx.span_bug(it.span, "invalid item macro invocation")
};
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let expanded = match (*extsbox).find(&extname.name) {
None => cx.span_fatal(pth.span,
......@@ -459,13 +464,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
_ => return orig(s, sp, fld)
};
if (pth.idents.len() > 1u) {
if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
None =>
......@@ -534,10 +539,14 @@ fn visit_pat(&mut self, pattern: @ast::pat, _: ()) {
// a path of length one:
&ast::Path {
global: false,
idents: [id],
span: _,
rp: _,
types: _
segments: [
ast::PathSegment {
identifier: id,
lifetime: _,
types: _
}
]
} => self.ident_accumulator.push(id),
// I believe these must be enums...
_ => ()
......
......@@ -16,8 +16,8 @@
use codemap;
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
use parse::parser::Parser;
use parse::attr::parser_attr;
use parse::parser::{LifetimeAndTypesWithoutColons, Parser};
use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
use parse::token;
......@@ -430,7 +430,9 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal {
_ => p.fatal(~"expected ident, found "
+ token::to_str(get_ident_interner(), p.token))
},
"path" => token::nt_path(~p.parse_path_with_tps(false)),
"path" => {
token::nt_path(~p.parse_path(LifetimeAndTypesWithoutColons).path)
}
"attr" => token::nt_attr(@p.parse_attribute(false)),
"tt" => {
*p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
......
......@@ -765,9 +765,11 @@ fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path {
ast::Path {
span: fld.new_span(p.span),
global: p.global,
idents: p.idents.map(|x| fld.fold_ident(*x)),
rp: p.rp,
types: p.types.map(|x| fld.fold_ty(x)),
segments: p.segments.map(|segment| ast::PathSegment {
identifier: fld.fold_ident(segment.identifier),
lifetime: segment.lifetime,
types: segment.types.map(|typ| fld.fold_ty(typ)),
})
}
}
......
......@@ -284,7 +284,11 @@ pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
}
pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
for tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); }
for segment in p.segments.iter() {
for typ in segment.types.iter() {
(v.visit_ty)(typ, (e.clone(), v))
}
}
}
pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {
......
......@@ -361,27 +361,47 @@ fn sp (a: uint, b: uint) -> span {
span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
}
#[test] fn path_exprs_1 () {
#[test] fn path_exprs_1() {
assert_eq!(string_to_expr(@"a"),
@ast::expr{id:1,
node:ast::expr_path(ast::Path {span:sp(0,1),
global:false,
idents:~[str_to_ident("a")],
rp:None,
types:~[]}),
span:sp(0,1)})
@ast::expr{
id: 1,
node: ast::expr_path(ast::Path {
span: sp(0, 1),
global: false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("a"),
lifetime: None,
types: ~[],
}
],
}),
span: sp(0, 1)
})
}
#[test] fn path_exprs_2 () {
assert_eq!(string_to_expr(@"::a::b"),
@ast::expr{id:1,
node:ast::expr_path(
ast::Path {span:sp(0,6),
global:true,
idents:strs_to_idents(~["a","b"]),
rp:None,
types:~[]}),
span:sp(0,6)})
@ast::expr {
id:1,
node: ast::expr_path(ast::Path {
span: sp(0, 6),
global: true,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("a"),
lifetime: None,
types: ~[],
},
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: ~[],
}
]
},
span: sp(0, 6))
})
}
#[should_fail]
......@@ -420,32 +440,43 @@ fn sp (a: uint, b: uint) -> span {
#[test] fn ret_expr() {
assert_eq!(string_to_expr(@"return d"),
@ast::expr{id:2,
node:ast::expr_ret(
Some(@ast::expr{id:1,
node:ast::expr_path(
ast::Path{span:sp(7,8),
global:false,
idents:~[str_to_ident("d")],
rp:None,
types:~[]
}),
span:sp(7,8)})),
span:sp(0,8)})
@ast::expr{
id:2,
node:ast::expr_ret(Some(@ast::expr{
id:1,
node:ast::expr_path(ast::Path{
span: sp(7, 8),
global: false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("d"),
lifetime: None,
types: opt_vec::Empty,
}
],
}),
span:sp(7,8)
})),
span:sp(0,8)
})
}
#[test] fn parse_stmt_1 () {
assert_eq!(string_to_stmt(@"b;"),
@spanned{
node: ast::stmt_expr(@ast::expr{
node: ast::stmt_expr(@ast::expr {
id: 1,
node: ast::expr_path(
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
node: ast::expr_path(ast::Path {
span:sp(0,1),
global:false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
}),
span: sp(0,1)},
2), // fixme
span: sp(0,1)})
......@@ -460,15 +491,20 @@ fn parser_done(p: Parser){
let parser = string_to_parser(@"b");
assert_eq!(parser.parse_pat(),
@ast::pat{id:1, // fixme
node: ast::pat_ident(ast::bind_infer,
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
node: ast::pat_ident(
ast::bind_infer,
ast::Path {
span:sp(0,1),
global:false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
},
None /* no idea */),
span: sp(0,1)});
parser_done(parser);
}
......@@ -483,21 +519,33 @@ fn parser_done(p: Parser){
span:sp(4,4), // this is bizarre...
// check this in the original parser?
global:false,
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
None, 2),
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("int"),
lifetime: None,
types: opt_vec::Empty,
}
],
}, None, 2),
span:sp(4,7)},
pat: @ast::pat{id:1,
node: ast::pat_ident(ast::bind_infer,
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
node: ast::pat_ident(
ast::bind_infer,
ast::Path {
span:sp(0,1),
global:false,
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
},
None // no idea
),
span: sp(0,1)},
id: 4 // fixme
})
......@@ -519,23 +567,37 @@ fn parser_done(p: Parser){
node: ast::ty_path(ast::Path{
span:sp(10,13),
global:false,
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
None, 2),
span:sp(10,13)},
pat: @ast::pat{id:1, // fixme
node: ast::pat_ident(
ast::bind_infer,
ast::Path{
span:sp(6,7),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
span: sp(6,7)},
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("int"),
lifetime: None,
types: opt_vec::Empty,
}
],
}, None, 2),
span:sp(10,13)
},
pat: @ast::pat {
id:1, // fixme
node: ast::pat_ident(
ast::bind_infer,
ast::Path {
span:sp(6,7),
global:false,
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
},
None // no idea
),
span: sp(6,7)
},
id: 4 // fixme
}],
output: ast::Ty{id:5, // fixme
......@@ -558,9 +620,18 @@ fn parser_done(p: Parser){
ast::Path{
span:sp(17,18),
global:false,
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
segments: ~[
ast::PathSegment {
identifier:
str_to_ident(
"b"),
lifetime:
None,
types:
opt_vec::Empty
}
],
}),
span: sp(17,18)},
7), // fixme
span: sp(17,18)}],
......
此差异已折叠。
......@@ -1501,34 +1501,52 @@ pub fn print_for_decl(s: @ps, loc: &ast::Local, coll: &ast::expr) {
print_expr(s, coll);
}
fn print_path_(s: @ps, path: &ast::Path, colons_before_params: bool,
fn print_path_(s: @ps,
path: &ast::Path,
colons_before_params: bool,
opt_bounds: &Option<OptVec<ast::TyParamBound>>) {
maybe_print_comment(s, path.span.lo);
if path.global { word(s.s, "::"); }
let mut first = true;
for id in path.idents.iter() {
if first { first = false; } else { word(s.s, "::"); }
print_ident(s, *id);
if path.global {
word(s.s, "::");
}
do opt_bounds.map |bounds| {
print_bounds(s, bounds, true);
};
if path.rp.is_some() || !path.types.is_empty() {
if colons_before_params { word(s.s, "::"); }
if path.rp.is_some() || !path.types.is_empty() {
let mut first = true;
for (i, segment) in path.segments.iter().enumerate() {
if first {
first = false
} else {
word(s.s, "::")
}
print_ident(s, segment.identifier);
if segment.lifetime.is_some() || !segment.types.is_empty() {
// If this is the last segment, print the bounds.
if i == path.segments.len() - 1 {
match *opt_bounds {
None => {}
Some(ref bounds) => print_bounds(s, bounds, true),
}
}
if colons_before_params {
word(s.s, "::")
}
word(s.s, "<");
for r in path.rp.iter() {
print_lifetime(s, r);
if !path.types.is_empty() {
word_space(s, ",");
for lifetime in segment.lifetime.iter() {
print_lifetime(s, lifetime);
if !segment.types.is_empty() {
word_space(s, ",")
}
}
commasep(s, inconsistent, path.types, print_type);
commasep(s,
inconsistent,
segment.types.map_to_vec(|t| (*t).clone()),
print_type);
word(s.s, ">");
word(s.s, ">")
}
}
}
......@@ -1819,7 +1837,7 @@ pub fn print_meta_item(s: @ps, item: &ast::MetaItem) {
pub fn print_view_path(s: @ps, vp: &ast::view_path) {
match vp.node {
ast::view_path_simple(ident, ref path, _) => {
if path.idents[path.idents.len()-1u] != ident {
if path.segments.last().identifier != ident {
print_ident(s, ident);
space(s.s);
word_space(s, "=");
......@@ -1899,8 +1917,9 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
_ => {
match input.pat.node {
ast::pat_ident(_, ref path, _) if
path.idents.len() == 1 &&
path.idents[0] == parse::token::special_idents::invalid => {
path.segments.len() == 1 &&
path.segments[0].identifier ==
parse::token::special_idents::invalid => {
// Do nothing.
}
_ => {
......
......@@ -319,8 +319,10 @@ pub fn walk_ty<E:Clone, V:Visitor<E>>(visitor: &mut V, typ: &Ty, env: E) {
}
pub fn walk_path<E:Clone, V:Visitor<E>>(visitor: &mut V, path: &Path, env: E) {
for typ in path.types.iter() {
visitor.visit_ty(typ, env.clone())
for segment in path.segments.iter() {
for typ in path.types.iter() {
visitor.visit_ty(typ, env.clone())
}
}
}
......
struct S<T> {
contents: T,
}
impl<T> S<T> {
fn new<U>(x: T, _: U) -> S<T> {
S {
contents: x,
}
}
}
fn main() {
let _ = S::<int>::new::<float>(1, 1.0);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册