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.
This commit is contained in:
parent
5c3504799d
commit
3b6314c39b
|
@ -17,6 +17,7 @@ use syntax::attr;
|
|||
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 inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
|
|||
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 front::config;
|
|||
|
||||
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 encode_info_for_item(ecx: &EncodeContext,
|
|||
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 @@ impl PrivacyVisitor {
|
|||
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 @@ impl PrivacyVisitor {
|
|||
!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 @@ impl Resolver {
|
|||
&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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
// 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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
// 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 @@ impl Resolver {
|
|||
}
|
||||
|
||||
// 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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
}
|
||||
|
||||
// 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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
}
|
||||
|
||||
// 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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
|
||||
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 @@ impl Resolver {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl Resolver {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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 @@ impl Resolver {
|
|||
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::rscope::RegionParamNames;
|
|||
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.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
|
||||
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}
|
||||
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 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
|
|||
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 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
|
|||
}
|
||||
|
||||
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 @@ impl IdVisitor {
|
|||
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 @@ impl AstBuilder for @ExtCtxt {
|
|||
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 ast;
|
|||
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;
|
|||
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 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
|
|||
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 @@ impl Visitor<()> for NewNameFinderContext {
|
|||
// 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::{BytePos, mk_sp};
|
|||
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 @@ mod test {
|
|||
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 @@ mod test {
|
|||
|
||||
#[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 @@ mod test {
|
|||
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 @@ mod test {
|
|||
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 @@ mod test {
|
|||
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 @@ mod test {
|
|||
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)}],
|
||||
|
|
|
@ -97,6 +97,37 @@ enum restriction {
|
|||
type arg_or_capture_item = Either<arg, ()>;
|
||||
type item_info = (ident, item_, Option<~[Attribute]>);
|
||||
|
||||
/// How to parse a path. There are four different kinds of paths, all of which
|
||||
/// are parsed somewhat differently.
|
||||
#[deriving(Eq)]
|
||||
pub enum PathParsingMode {
|
||||
/// A path with no type parameters; e.g. `foo::bar::Baz`
|
||||
NoTypesAllowed,
|
||||
/// A path with a lifetime and type parameters, with no double colons
|
||||
/// before the type parameters; e.g. `foo::bar<'self>::Baz<T>`
|
||||
LifetimeAndTypesWithoutColons,
|
||||
/// A path with a lifetime and type parameters with double colons before
|
||||
/// the type parameters; e.g. `foo::bar::<'self>::Baz::<T>`
|
||||
LifetimeAndTypesWithColons,
|
||||
/// A path with a lifetime and type parameters with bounds before the last
|
||||
/// set of type parameters only; e.g. `foo::bar<'self>::Baz:X+Y<T>` This
|
||||
/// form does not use extra double colons.
|
||||
LifetimeAndTypesAndBounds,
|
||||
}
|
||||
|
||||
/// A pair of a path segment and group of type parameter bounds. (See `ast.rs`
|
||||
/// for the definition of a path segment.)
|
||||
struct PathSegmentAndBoundSet {
|
||||
segment: ast::PathSegment,
|
||||
bound_set: Option<OptVec<TyParamBound>>,
|
||||
}
|
||||
|
||||
/// A path paired with optional type bounds.
|
||||
struct PathAndBounds {
|
||||
path: ast::Path,
|
||||
bounds: Option<OptVec<TyParamBound>>,
|
||||
}
|
||||
|
||||
pub enum item_or_view_item {
|
||||
// Indicates a failure to parse any kind of item. The attributes are
|
||||
// returned.
|
||||
|
@ -1108,7 +1139,10 @@ impl Parser {
|
|||
} else if *self.token == token::MOD_SEP
|
||||
|| is_ident_or_path(self.token) {
|
||||
// NAMED TYPE
|
||||
let (path, bounds) = self.parse_type_path();
|
||||
let PathAndBounds {
|
||||
path,
|
||||
bounds
|
||||
} = self.parse_path(LifetimeAndTypesAndBounds);
|
||||
ty_path(path, bounds, self.get_id())
|
||||
} else {
|
||||
self.fatal(fmt!("expected type, found token %?",
|
||||
|
@ -1329,139 +1363,155 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
// parse a path into a vector of idents, whether the path starts
|
||||
// with ::, and a span.
|
||||
pub fn parse_path(&self) -> (~[ast::ident],bool,span) {
|
||||
/// Parses a path and optional type parameter bounds, depending on the
|
||||
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
|
||||
/// bounds are permitted and whether `::` must precede type parameter
|
||||
/// groups.
|
||||
pub fn parse_path(&self, mode: PathParsingMode) -> PathAndBounds {
|
||||
// Check for a whole path...
|
||||
let found = match *self.token {
|
||||
INTERPOLATED(token::nt_path(_)) => Some(self.bump_and_get()),
|
||||
_ => None,
|
||||
};
|
||||
match found {
|
||||
Some(INTERPOLATED(token::nt_path(path))) => {
|
||||
return PathAndBounds {
|
||||
path: path,
|
||||
bounds: None,
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let lo = self.span.lo;
|
||||
let is_global = self.eat(&token::MOD_SEP);
|
||||
let (ids,span{lo:_,hi,expn_info}) = self.parse_path_non_global();
|
||||
(ids,is_global,span{lo:lo,hi:hi,expn_info:expn_info})
|
||||
}
|
||||
|
||||
// parse a path beginning with an identifier into a vector of idents and a span
|
||||
pub fn parse_path_non_global(&self) -> (~[ast::ident],span) {
|
||||
let lo = self.span.lo;
|
||||
let mut ids = ~[];
|
||||
// must be at least one to begin:
|
||||
ids.push(self.parse_ident());
|
||||
// Parse any number of segments and bound sets. A segment is an
|
||||
// identifier followed by an optional lifetime and a set of types.
|
||||
// A bound set is a set of type parameter bounds.
|
||||
let mut segments = ~[];
|
||||
loop {
|
||||
// First, parse an identifier.
|
||||
match *self.token {
|
||||
token::MOD_SEP => {
|
||||
let is_ident = do self.look_ahead(1) |t| {
|
||||
match *t {
|
||||
token::IDENT(*) => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
if is_ident {
|
||||
self.bump();
|
||||
ids.push(self.parse_ident());
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
_ => break
|
||||
token::IDENT(*) => {}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
(ids, mk_sp(lo, self.last_span.hi))
|
||||
}
|
||||
let identifier = self.parse_ident();
|
||||
|
||||
// parse a path that doesn't have type parameters attached
|
||||
pub fn parse_path_without_tps(&self) -> ast::Path {
|
||||
maybe_whole!(deref self, nt_path);
|
||||
let (ids,is_global,sp) = self.parse_path();
|
||||
ast::Path { span: sp,
|
||||
global: is_global,
|
||||
idents: ids,
|
||||
rp: None,
|
||||
types: ~[] }
|
||||
}
|
||||
|
||||
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!(deref self, nt_path);
|
||||
let lo = self.span.lo;
|
||||
let path = self.parse_path_without_tps();
|
||||
if colons && !self.eat(&token::MOD_SEP) {
|
||||
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_move(|callback| callback());
|
||||
|
||||
// Parse the (obsolete) trailing region parameter, if any, which will
|
||||
// be written "foo/&x"
|
||||
let rp_slash = {
|
||||
if *self.token == token::BINOP(token::SLASH)
|
||||
&& self.look_ahead(1, |t| *t == token::BINOP(token::AND))
|
||||
{
|
||||
self.bump(); self.bump();
|
||||
self.obsolete(*self.last_span, ObsoleteLifetimeNotation);
|
||||
match *self.token {
|
||||
token::IDENT(sid, _) => {
|
||||
let span = self.span;
|
||||
self.bump();
|
||||
Some(ast::Lifetime {
|
||||
id: self.get_id(),
|
||||
span: *span,
|
||||
ident: sid
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
self.fatal(fmt!("Expected a lifetime name"));
|
||||
}
|
||||
}
|
||||
// Next, parse a colon and bounded type parameters, if applicable.
|
||||
let bound_set = if mode == LifetimeAndTypesAndBounds {
|
||||
self.parse_optional_ty_param_bounds()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Parse the '::' before type parameters if it's required. If
|
||||
// it is required and wasn't present, then we're done.
|
||||
if mode == LifetimeAndTypesWithColons &&
|
||||
!self.eat(&token::MOD_SEP) {
|
||||
segments.push(PathSegmentAndBoundSet {
|
||||
segment: ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
},
|
||||
bound_set: bound_set
|
||||
});
|
||||
break
|
||||
}
|
||||
};
|
||||
|
||||
// Parse any lifetime or type parameters which may appear:
|
||||
let (lifetimes, tps) = self.parse_generic_values();
|
||||
let hi = self.span.lo;
|
||||
// Parse the `<` before the lifetime and types, if applicable.
|
||||
let (any_lifetime_or_types, optional_lifetime, types) =
|
||||
if mode != NoTypesAllowed && self.eat(&token::LT) {
|
||||
// Parse an optional lifetime.
|
||||
let optional_lifetime = match *self.token {
|
||||
token::LIFETIME(*) => Some(self.parse_lifetime()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let rp = match (&rp_slash, &lifetimes) {
|
||||
(&Some(_), _) => rp_slash,
|
||||
(&None, v) => {
|
||||
if v.len() == 0 {
|
||||
None
|
||||
} else if v.len() == 1 {
|
||||
Some(*v.get(0))
|
||||
} else {
|
||||
self.fatal(fmt!("Expected at most one \
|
||||
lifetime name (for now)"));
|
||||
// Parse type parameters.
|
||||
let mut types = opt_vec::Empty;
|
||||
let mut need_comma = optional_lifetime.is_some();
|
||||
loop {
|
||||
// We're done if we see a `>`.
|
||||
match *self.token {
|
||||
token::GT | token::BINOP(token::SHR) => {
|
||||
self.expect_gt();
|
||||
break
|
||||
}
|
||||
_ => {} // Go on.
|
||||
}
|
||||
|
||||
if need_comma {
|
||||
self.expect(&token::COMMA)
|
||||
} else {
|
||||
need_comma = true
|
||||
}
|
||||
|
||||
types.push(self.parse_ty(false))
|
||||
}
|
||||
|
||||
(true, optional_lifetime, types)
|
||||
} else {
|
||||
(false, None, opt_vec::Empty)
|
||||
};
|
||||
|
||||
// Assemble and push the result.
|
||||
segments.push(PathSegmentAndBoundSet {
|
||||
segment: ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: optional_lifetime,
|
||||
types: types,
|
||||
},
|
||||
bound_set: bound_set
|
||||
});
|
||||
|
||||
// We're done if we don't see a '::', unless the mode required
|
||||
// a double colon to get here in the first place.
|
||||
if !(mode == LifetimeAndTypesWithColons &&
|
||||
!any_lifetime_or_types) {
|
||||
if !self.eat(&token::MOD_SEP) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble the span.
|
||||
let span = mk_sp(lo, self.last_span.hi);
|
||||
|
||||
// Assemble the path segments.
|
||||
let mut path_segments = ~[];
|
||||
let mut bounds = None;
|
||||
let last_segment_index = segments.len() - 1;
|
||||
for (i, segment_and_bounds) in segments.consume_iter().enumerate() {
|
||||
let PathSegmentAndBoundSet {
|
||||
segment: segment,
|
||||
bound_set: bound_set
|
||||
} = segment_and_bounds;
|
||||
path_segments.push(segment);
|
||||
|
||||
if bound_set.is_some() {
|
||||
if i != last_segment_index {
|
||||
self.span_err(span,
|
||||
"type parameter bounds are allowed only \
|
||||
before the last segment in a path")
|
||||
}
|
||||
|
||||
bounds = bound_set
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble the result.
|
||||
let path_and_bounds = PathAndBounds {
|
||||
path: ast::Path {
|
||||
span: span,
|
||||
global: is_global,
|
||||
segments: path_segments,
|
||||
},
|
||||
bounds: bounds,
|
||||
};
|
||||
|
||||
ast::Path {
|
||||
span: mk_sp(lo, hi),
|
||||
rp: rp,
|
||||
types: tps,
|
||||
.. path.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// 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, Option<OptVec<TyParamBound>>) {
|
||||
let mut bounds = None;
|
||||
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)
|
||||
path_and_bounds
|
||||
}
|
||||
|
||||
/// parses 0 or 1 lifetime
|
||||
|
@ -1789,7 +1839,7 @@ impl Parser {
|
|||
} else if *self.token == token::MOD_SEP ||
|
||||
is_ident(&*self.token) && !self.is_keyword(keywords::True) &&
|
||||
!self.is_keyword(keywords::False) {
|
||||
let pth = self.parse_path_with_tps(true);
|
||||
let pth = self.parse_path(LifetimeAndTypesWithColons).path;
|
||||
|
||||
// `!`, as an operator, is prefix, so we know this isn't that
|
||||
if *self.token == token::NOT {
|
||||
|
@ -2880,7 +2930,8 @@ impl Parser {
|
|||
let val = self.parse_literal_maybe_minus();
|
||||
if self.eat(&token::DOTDOT) {
|
||||
let end = if is_ident_or_path(tok) {
|
||||
let path = self.parse_path_with_tps(true);
|
||||
let path = self.parse_path(LifetimeAndTypesWithColons)
|
||||
.path;
|
||||
let hi = self.span.hi;
|
||||
self.mk_expr(lo, hi, expr_path(path))
|
||||
} else {
|
||||
|
@ -2909,7 +2960,7 @@ impl Parser {
|
|||
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
|
||||
pat = pat_range(start, end);
|
||||
} else if is_plain_ident(&*self.token) && !can_be_enum_or_struct {
|
||||
let name = self.parse_path_without_tps();
|
||||
let name = self.parse_path(NoTypesAllowed).path;
|
||||
let sub;
|
||||
if self.eat(&token::AT) {
|
||||
// parse foo @ pat
|
||||
|
@ -2921,7 +2972,8 @@ impl Parser {
|
|||
pat = pat_ident(bind_infer, name, sub);
|
||||
} else {
|
||||
// parse an enum pat
|
||||
let enum_path = self.parse_path_with_tps(true);
|
||||
let enum_path = self.parse_path(LifetimeAndTypesWithColons)
|
||||
.path;
|
||||
match *self.token {
|
||||
token::LBRACE => {
|
||||
self.bump();
|
||||
|
@ -2957,7 +3009,7 @@ impl Parser {
|
|||
}
|
||||
},
|
||||
_ => {
|
||||
if enum_path.idents.len()==1u {
|
||||
if enum_path.segments.len() == 1 {
|
||||
// it could still be either an enum
|
||||
// or an identifier pattern, resolve
|
||||
// will sort it out:
|
||||
|
@ -2992,7 +3044,7 @@ impl Parser {
|
|||
"expected identifier, found path");
|
||||
}
|
||||
// why a path here, and not just an identifier?
|
||||
let name = self.parse_path_without_tps();
|
||||
let name = self.parse_path(NoTypesAllowed).path;
|
||||
let sub = if self.eat(&token::AT) {
|
||||
Some(self.parse_pat())
|
||||
} else {
|
||||
|
@ -3109,7 +3161,7 @@ impl Parser {
|
|||
|
||||
// Potential trouble: if we allow macros with paths instead of
|
||||
// idents, we'd need to look ahead past the whole path here...
|
||||
let pth = self.parse_path_without_tps();
|
||||
let pth = self.parse_path(NoTypesAllowed).path;
|
||||
self.bump();
|
||||
|
||||
let id = if *self.token == token::LPAREN {
|
||||
|
@ -3785,7 +3837,7 @@ impl Parser {
|
|||
// parse a::B<~str,int>
|
||||
fn parse_trait_ref(&self) -> trait_ref {
|
||||
ast::trait_ref {
|
||||
path: self.parse_path_with_tps(false),
|
||||
path: self.parse_path(LifetimeAndTypesWithoutColons).path,
|
||||
ref_id: self.get_id(),
|
||||
}
|
||||
}
|
||||
|
@ -4701,7 +4753,7 @@ impl Parser {
|
|||
}
|
||||
|
||||
// item macro.
|
||||
let pth = self.parse_path_without_tps();
|
||||
let pth = self.parse_path(NoTypesAllowed).path;
|
||||
self.expect(&token::NOT);
|
||||
|
||||
// a 'special' identifier (like what `macro_rules!` uses)
|
||||
|
@ -4785,11 +4837,17 @@ impl Parser {
|
|||
let id = self.parse_ident();
|
||||
path.push(id);
|
||||
}
|
||||
let path = ast::Path { span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
idents: path,
|
||||
rp: None,
|
||||
types: ~[] };
|
||||
let path = ast::Path {
|
||||
span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
segments: path.consume_iter().transform(|identifier| {
|
||||
ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
return @spanned(lo, self.span.hi,
|
||||
view_path_simple(first_ident,
|
||||
path,
|
||||
|
@ -4815,11 +4873,17 @@ impl Parser {
|
|||
seq_sep_trailing_allowed(token::COMMA),
|
||||
|p| p.parse_path_list_ident()
|
||||
);
|
||||
let path = ast::Path { span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
idents: path,
|
||||
rp: None,
|
||||
types: ~[] };
|
||||
let path = ast::Path {
|
||||
span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
segments: path.consume_iter().transform(|identifier| {
|
||||
ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
return @spanned(lo, self.span.hi,
|
||||
view_path_list(path, idents, self.get_id()));
|
||||
}
|
||||
|
@ -4827,11 +4891,17 @@ impl Parser {
|
|||
// foo::bar::*
|
||||
token::BINOP(token::STAR) => {
|
||||
self.bump();
|
||||
let path = ast::Path { span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
idents: path,
|
||||
rp: None,
|
||||
types: ~[] };
|
||||
let path = ast::Path {
|
||||
span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
segments: path.consume_iter().transform(|identifier| {
|
||||
ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
return @spanned(lo, self.span.hi,
|
||||
view_path_glob(path, self.get_id()));
|
||||
}
|
||||
|
@ -4843,11 +4913,17 @@ impl Parser {
|
|||
_ => ()
|
||||
}
|
||||
let last = path[path.len() - 1u];
|
||||
let path = ast::Path { span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
idents: path,
|
||||
rp: None,
|
||||
types: ~[] };
|
||||
let path = ast::Path {
|
||||
span: mk_sp(lo, self.span.hi),
|
||||
global: false,
|
||||
segments: path.consume_iter().transform(|identifier| {
|
||||
ast::PathSegment {
|
||||
identifier: identifier,
|
||||
lifetime: None,
|
||||
types: opt_vec::Empty,
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
return @spanned(lo,
|
||||
self.last_span.hi,
|
||||
view_path_simple(last, path, self.get_id()));
|
||||
|
|
|
@ -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() {
|
||||
word(s.s, "<");
|
||||
let mut first = true;
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
word(s.s, "::")
|
||||
}
|
||||
|
||||
for r in path.rp.iter() {
|
||||
print_lifetime(s, r);
|
||||
if !path.types.is_empty() {
|
||||
word_space(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),
|
||||
}
|
||||
}
|
||||
|
||||
commasep(s, inconsistent, path.types, print_type);
|
||||
if colons_before_params {
|
||||
word(s.s, "::")
|
||||
}
|
||||
word(s.s, "<");
|
||||
|
||||
word(s.s, ">");
|
||||
for lifetime in segment.lifetime.iter() {
|
||||
print_lifetime(s, lifetime);
|
||||
if !segment.types.is_empty() {
|
||||
word_space(s, ",")
|
||||
}
|
||||
}
|
||||
|
||||
commasep(s,
|
||||
inconsistent,
|
||||
segment.types.map_to_vec(|t| (*t).clone()),
|
||||
print_type);
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue