Skip to content

Commit efb3872

Browse files
committed
Fix use of UFCS syntax to call methods on associated types.
1 parent 6b3d66b commit efb3872

File tree

3 files changed

+83
-45
lines changed

3 files changed

+83
-45
lines changed

src/librustc_resolve/lib.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -2688,18 +2688,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
26882688
check_ribs: bool)
26892689
-> AssocItemResolveResult
26902690
{
2691+
let max_assoc_types;
2692+
26912693
match maybe_qself {
2692-
Some(&ast::QSelf { position: 0, .. }) =>
2693-
return TypecheckRequired,
2694-
_ => {}
2694+
Some(qself) => {
2695+
if qself.position == 0 {
2696+
return TypecheckRequired;
2697+
}
2698+
max_assoc_types = path.segments.len() - qself.position;
2699+
// Make sure the trait is valid.
2700+
let _ = self.resolve_trait_reference(id, path, max_assoc_types);
2701+
}
2702+
None => {
2703+
max_assoc_types = path.segments.len();
2704+
}
26952705
}
2696-
let max_assoc_types = if let Some(qself) = maybe_qself {
2697-
// Make sure the trait is valid.
2698-
let _ = self.resolve_trait_reference(id, path, 1);
2699-
path.segments.len() - qself.position
2700-
} else {
2701-
path.segments.len()
2702-
};
27032706

27042707
let mut resolution = self.with_no_errors(|this| {
27052708
this.resolve_path(id, path, 0, namespace, check_ribs)

src/libsyntax/parse/parser.rs

+15-35
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,6 @@ pub enum PathParsingMode {
110110
LifetimeAndTypesWithColons,
111111
}
112112

113-
/// How to parse a qualified path, whether to allow trailing parameters.
114-
#[derive(Copy, Clone, PartialEq)]
115-
pub enum QPathParsingMode {
116-
/// No trailing parameters, e.g. `<T as Trait>::Item`
117-
NoParameters,
118-
/// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
119-
MaybeParameters,
120-
}
121-
122113
/// How to parse a bound, whether to allow bound modifiers such as `?`.
123114
#[derive(Copy, Clone, PartialEq)]
124115
pub enum BoundParsingMode {
@@ -1360,7 +1351,7 @@ impl<'a> Parser<'a> {
13601351
} else if try!(self.eat_lt()) {
13611352

13621353
let (qself, path) =
1363-
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
1354+
try!(self.parse_qualified_path(NoTypesAllowed));
13641355

13651356
TyPath(Some(qself), path)
13661357
} else if self.check(&token::ModSep) ||
@@ -1579,7 +1570,7 @@ impl<'a> Parser<'a> {
15791570

15801571
// QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
15811572
// Assumes that the leading `<` has been parsed already.
1582-
pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
1573+
pub fn parse_qualified_path(&mut self, mode: PathParsingMode)
15831574
-> PResult<(QSelf, ast::Path)> {
15841575
let self_type = try!(self.parse_ty_sum());
15851576
let mut path = if try!(self.eat_keyword(keywords::As)) {
@@ -1600,29 +1591,18 @@ impl<'a> Parser<'a> {
16001591
try!(self.expect(&token::Gt));
16011592
try!(self.expect(&token::ModSep));
16021593

1603-
let item_name = try!(self.parse_ident());
1604-
let parameters = match mode {
1605-
QPathParsingMode::NoParameters => ast::PathParameters::none(),
1606-
QPathParsingMode::MaybeParameters => {
1607-
if try!(self.eat(&token::ModSep)) {
1608-
try!(self.expect_lt());
1609-
// Consumed `item::<`, go look for types
1610-
let (lifetimes, types, bindings) =
1611-
try!(self.parse_generic_values_after_lt());
1612-
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
1613-
lifetimes: lifetimes,
1614-
types: OwnedSlice::from_vec(types),
1615-
bindings: OwnedSlice::from_vec(bindings),
1616-
})
1617-
} else {
1618-
ast::PathParameters::none()
1619-
}
1594+
let segments = match mode {
1595+
LifetimeAndTypesWithoutColons => {
1596+
try!(self.parse_path_segments_without_colons())
1597+
}
1598+
LifetimeAndTypesWithColons => {
1599+
try!(self.parse_path_segments_with_colons())
1600+
}
1601+
NoTypesAllowed => {
1602+
try!(self.parse_path_segments_without_types())
16201603
}
16211604
};
1622-
path.segments.push(ast::PathSegment {
1623-
identifier: item_name,
1624-
parameters: parameters
1625-
});
1605+
path.segments.extend(segments);
16261606

16271607
if path.segments.len() == 1 {
16281608
path.span.lo = self.last_span.lo;
@@ -2097,7 +2077,7 @@ impl<'a> Parser<'a> {
20972077
if try!(self.eat_lt()){
20982078

20992079
let (qself, path) =
2100-
try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
2080+
try!(self.parse_qualified_path(LifetimeAndTypesWithColons));
21012081

21022082
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
21032083
}
@@ -3177,7 +3157,7 @@ impl<'a> Parser<'a> {
31773157
let (qself, path) = if try!(self.eat_lt()) {
31783158
// Parse a qualified path
31793159
let (qself, path) =
3180-
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
3160+
try!(self.parse_qualified_path(NoTypesAllowed));
31813161
(Some(qself), path)
31823162
} else {
31833163
// Parse an unqualified path
@@ -3271,7 +3251,7 @@ impl<'a> Parser<'a> {
32713251
let (qself, path) = if try!(self.eat_lt()) {
32723252
// Parse a qualified path
32733253
let (qself, path) =
3274-
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
3254+
try!(self.parse_qualified_path(NoTypesAllowed));
32753255
(Some(qself), path)
32763256
} else {
32773257
// Parse an unqualified path
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::mem::size_of;
12+
13+
// The main point of this test is to ensure that we can parse and resolve
14+
// associated items on associated types.
15+
16+
trait Foo {
17+
type U;
18+
}
19+
20+
trait Bar {
21+
// Note 1: Chains of associated items in a path won't type-check.
22+
// Note 2: Associated consts can't depend on type parameters or `Self`,
23+
// which are the only types that an associated type can be referenced on for
24+
// now, so we can only test methods.
25+
fn method() -> u32;
26+
fn generic_method<T>() -> usize;
27+
}
28+
29+
struct MyFoo;
30+
struct MyBar;
31+
32+
impl Foo for MyFoo {
33+
type U = MyBar;
34+
}
35+
36+
impl Bar for MyBar {
37+
fn method() -> u32 {
38+
2u32
39+
}
40+
fn generic_method<T>() -> usize {
41+
size_of::<T>()
42+
}
43+
}
44+
45+
fn foo<T>()
46+
where T: Foo,
47+
T::U: Bar,
48+
{
49+
assert_eq!(2u32, <T as Foo>::U::method());
50+
assert_eq!(8usize, <T as Foo>::U::generic_method::<f64>());
51+
}
52+
53+
fn main() {
54+
foo::<MyFoo>();
55+
}

0 commit comments

Comments
 (0)