From efb3872a49df2d4ffe5bdc948d1d12637fa3ebd1 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Thu, 7 May 2015 01:52:38 -0600 Subject: [PATCH] Fix use of UFCS syntax to call methods on associated types. --- src/librustc_resolve/lib.rs | 23 ++++---- src/libsyntax/parse/parser.rs | 50 +++++------------ .../run-pass/associated-item-long-paths.rs | 55 +++++++++++++++++++ 3 files changed, 83 insertions(+), 45 deletions(-) create mode 100644 src/test/run-pass/associated-item-long-paths.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7abe5a84c5f..447230ada22 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2688,18 +2688,21 @@ fn resolve_possibly_assoc_item(&mut self, check_ribs: bool) -> AssocItemResolveResult { + let max_assoc_types; + match maybe_qself { - Some(&ast::QSelf { position: 0, .. }) => - return TypecheckRequired, - _ => {} + Some(qself) => { + if qself.position == 0 { + return TypecheckRequired; + } + max_assoc_types = path.segments.len() - qself.position; + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(id, path, max_assoc_types); + } + None => { + max_assoc_types = path.segments.len(); + } } - let max_assoc_types = if let Some(qself) = maybe_qself { - // Make sure the trait is valid. - let _ = self.resolve_trait_reference(id, path, 1); - path.segments.len() - qself.position - } else { - path.segments.len() - }; let mut resolution = self.with_no_errors(|this| { this.resolve_path(id, path, 0, namespace, check_ribs) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a7b1beace51..a5a667ae5ce 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -110,15 +110,6 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } -/// How to parse a qualified path, whether to allow trailing parameters. -#[derive(Copy, Clone, PartialEq)] -pub enum QPathParsingMode { - /// No trailing parameters, e.g. `::Item` - NoParameters, - /// Optional parameters, e.g. `::item::<'a, U>` - MaybeParameters, -} - /// How to parse a bound, whether to allow bound modifiers such as `?`. #[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { @@ -1360,7 +1351,7 @@ pub fn parse_ty_nopanic(&mut self) -> PResult> { } else if try!(self.eat_lt()) { let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); TyPath(Some(qself), path) } else if self.check(&token::ModSep) || @@ -1579,7 +1570,7 @@ pub fn parse_literal_maybe_minus(&mut self) -> PResult> { // QUALIFIED PATH `::IDENT[::]` // Assumes that the leading `<` has been parsed already. - pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) + pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { @@ -1600,29 +1591,18 @@ pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) try!(self.expect(&token::Gt)); try!(self.expect(&token::ModSep)); - let item_name = try!(self.parse_ident()); - let parameters = match mode { - QPathParsingMode::NoParameters => ast::PathParameters::none(), - QPathParsingMode::MaybeParameters => { - if try!(self.eat(&token::ModSep)) { - try!(self.expect_lt()); - // Consumed `item::<`, go look for types - let (lifetimes, types, bindings) = - try!(self.parse_generic_values_after_lt()); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - } else { - ast::PathParameters::none() - } + let segments = match mode { + LifetimeAndTypesWithoutColons => { + try!(self.parse_path_segments_without_colons()) + } + LifetimeAndTypesWithColons => { + try!(self.parse_path_segments_with_colons()) + } + NoTypesAllowed => { + try!(self.parse_path_segments_without_types()) } }; - path.segments.push(ast::PathSegment { - identifier: item_name, - parameters: parameters - }); + path.segments.extend(segments); if path.segments.len() == 1 { path.span.lo = self.last_span.lo; @@ -2097,7 +2077,7 @@ pub fn parse_bottom_expr(&mut self) -> PResult> { if try!(self.eat_lt()){ let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters)); + try!(self.parse_qualified_path(LifetimeAndTypesWithColons)); return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } @@ -3177,7 +3157,7 @@ fn parse_pat_range_end(&mut self) -> PResult> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path @@ -3271,7 +3251,7 @@ pub fn parse_pat_nopanic(&mut self) -> PResult> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path diff --git a/src/test/run-pass/associated-item-long-paths.rs b/src/test/run-pass/associated-item-long-paths.rs new file mode 100644 index 00000000000..4ad0187df7a --- /dev/null +++ b/src/test/run-pass/associated-item-long-paths.rs @@ -0,0 +1,55 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +// The main point of this test is to ensure that we can parse and resolve +// associated items on associated types. + +trait Foo { + type U; +} + +trait Bar { + // Note 1: Chains of associated items in a path won't type-check. + // Note 2: Associated consts can't depend on type parameters or `Self`, + // which are the only types that an associated type can be referenced on for + // now, so we can only test methods. + fn method() -> u32; + fn generic_method() -> usize; +} + +struct MyFoo; +struct MyBar; + +impl Foo for MyFoo { + type U = MyBar; +} + +impl Bar for MyBar { + fn method() -> u32 { + 2u32 + } + fn generic_method() -> usize { + size_of::() + } +} + +fn foo() + where T: Foo, + T::U: Bar, +{ + assert_eq!(2u32, ::U::method()); + assert_eq!(8usize, ::U::generic_method::()); +} + +fn main() { + foo::(); +}