Skip to content

Commit 85ba817

Browse files
committed
rustc: implement fully qualified UFCS expressions.
1 parent b51026e commit 85ba817

File tree

7 files changed

+130
-38
lines changed

7 files changed

+130
-38
lines changed

src/librustc_resolve/lib.rs

+28-25
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ use rustc::util::lev_distance::lev_distance;
6161
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
6262
use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
6363
use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
64-
use syntax::ast::{ExprPath, ExprStruct, FnDecl};
64+
use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl};
6565
use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics};
6666
use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn};
6767
use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic};
@@ -3169,7 +3169,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
31693169
TraitImplementation => "implement",
31703170
TraitDerivation => "derive",
31713171
TraitObject => "reference",
3172-
TraitQPath => "extract an associated type from",
3172+
TraitQPath => "extract an associated item from",
31733173
};
31743174

31753175
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
@@ -3565,31 +3565,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
35653565
}
35663566
}
35673567

3568-
match result_def {
3569-
None => {
3570-
match self.resolve_path(ty.id, path, TypeNS, true) {
3571-
Some(def) => {
3572-
debug!("(resolving type) resolved `{:?}` to \
3573-
type {:?}",
3574-
token::get_ident(path.segments.last().unwrap() .identifier),
3575-
def);
3576-
result_def = Some(def);
3577-
}
3578-
None => {
3579-
result_def = None;
3580-
}
3581-
}
3582-
}
3583-
Some(_) => {} // Continue.
3568+
if let None = result_def {
3569+
result_def = self.resolve_path(ty.id, path, TypeNS, true);
35843570
}
35853571

35863572
match result_def {
35873573
Some(def) => {
35883574
// Write the result into the def map.
35893575
debug!("(resolving type) writing resolution for `{}` \
3590-
(id {})",
3576+
(id {}) = {:?}",
35913577
self.path_names_to_string(path),
3592-
path_id);
3578+
path_id, def);
35933579
self.record_def(path_id, def);
35943580
}
35953581
None => {
@@ -3609,6 +3595,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
36093595
TyQPath(ref qpath) => {
36103596
self.resolve_type(&*qpath.self_type);
36113597
self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
3598+
for ty in qpath.item_path.parameters.types().into_iter() {
3599+
self.resolve_type(&**ty);
3600+
}
3601+
for binding in qpath.item_path.parameters.bindings().into_iter() {
3602+
self.resolve_type(&*binding.ty);
3603+
}
36123604
}
36133605

36143606
TyPolyTraitRef(ref bounds) => {
@@ -4400,15 +4392,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
44004392
// The interpretation of paths depends on whether the path has
44014393
// multiple elements in it or not.
44024394

4403-
ExprPath(ref path) => {
4395+
ExprPath(_) | ExprQPath(_) => {
4396+
let mut path_from_qpath;
4397+
let path = match expr.node {
4398+
ExprPath(ref path) => path,
4399+
ExprQPath(ref qpath) => {
4400+
self.resolve_type(&*qpath.self_type);
4401+
self.resolve_trait_reference(expr.id, &*qpath.trait_ref, TraitQPath);
4402+
path_from_qpath = qpath.trait_ref.path.clone();
4403+
path_from_qpath.segments.push(qpath.item_path.clone());
4404+
&path_from_qpath
4405+
}
4406+
_ => unreachable!()
4407+
};
44044408
// This is a local path in the value namespace. Walk through
44054409
// scopes looking for it.
4406-
4407-
let path_name = self.path_names_to_string(path);
4408-
44094410
match self.resolve_path(expr.id, path, ValueNS, true) {
44104411
// Check if struct variant
44114412
Some((DefVariant(_, _, true), _)) => {
4413+
let path_name = self.path_names_to_string(path);
44124414
self.resolve_error(expr.span,
44134415
format!("`{}` is a struct variant name, but \
44144416
this expression \
@@ -4423,7 +4425,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
44234425
Some(def) => {
44244426
// Write the result into the def map.
44254427
debug!("(resolving expr) resolved `{}`",
4426-
path_name);
4428+
self.path_names_to_string(path));
44274429

44284430
self.record_def(expr.id, def);
44294431
}
@@ -4432,6 +4434,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
44324434
// (The pattern matching def_tys where the id is in self.structs
44334435
// matches on regular structs while excluding tuple- and enum-like
44344436
// structs, which wouldn't result in this error.)
4437+
let path_name = self.path_names_to_string(path);
44354438
match self.with_no_errors(|this|
44364439
this.resolve_path(expr.id, path, TypeNS, false)) {
44374440
Some((DefTy(struct_id, _), _))

src/librustc_trans/save/mod.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
767767
span: Span,
768768
path: &ast::Path,
769769
ref_kind: Option<recorder::Row>) {
770-
if generated_code(path.span) {
770+
if generated_code(span) {
771771
return
772772
}
773773

@@ -1307,9 +1307,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
13071307
visit::walk_expr(self, ex);
13081308
},
13091309
ast::ExprPath(ref path) => {
1310-
self.process_path(ex.id, ex.span, path, None);
1310+
self.process_path(ex.id, path.span, path, None);
13111311
visit::walk_path(self, path);
13121312
}
1313+
ast::ExprQPath(ref qpath) => {
1314+
let mut path = qpath.trait_ref.path.clone();
1315+
path.segments.push(qpath.item_path.clone());
1316+
self.process_path(ex.id, ex.span, &path, None);
1317+
visit::walk_qpath(self, ex.span, &**qpath);
1318+
}
13131319
ast::ExprStruct(ref path, ref fields, ref base) =>
13141320
self.process_struct_lit(ex, path, fields, base),
13151321
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
@@ -1439,7 +1445,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
14391445
"")
14401446
}
14411447
def::DefVariant(..) => {
1442-
paths_to_process.push((id, p.span, p.clone(), Some(ref_kind)))
1448+
paths_to_process.push((id, p.clone(), Some(ref_kind)))
14431449
}
14441450
// FIXME(nrc) what are these doing here?
14451451
def::DefStatic(_, _) => {}
@@ -1448,8 +1454,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
14481454
*def)
14491455
}
14501456
}
1451-
for &(id, span, ref path, ref_kind) in paths_to_process.iter() {
1452-
self.process_path(id, span, path, ref_kind);
1457+
for &(id, ref path, ref_kind) in paths_to_process.iter() {
1458+
self.process_path(id, path.span, path, ref_kind);
14531459
}
14541460
self.collecting = false;
14551461
self.collected_paths.clear();

src/librustc_typeck/check/_match.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
467467
};
468468

469469
instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id),
470-
def, pat.span, pat.id);
470+
None, def, pat.span, pat.id);
471471

472472
let pat_ty = fcx.node_ty(pat.id);
473473
demand::eqtype(fcx, pat.span, expected, pat_ty);
@@ -505,7 +505,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat,
505505
} else {
506506
ctor_scheme
507507
};
508-
instantiate_path(pcx.fcx, path, path_scheme, def, pat.span, pat.id);
508+
instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id);
509509

510510
let pat_ty = fcx.node_ty(pat.id);
511511
demand::eqtype(fcx, pat.span, expected, pat_ty);

src/librustc_typeck/check/mod.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -3553,10 +3553,25 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
35533553
};
35543554
fcx.write_ty(id, oprnd_t);
35553555
}
3556-
ast::ExprPath(ref pth) => {
3557-
let defn = lookup_def(fcx, pth.span, id);
3556+
ast::ExprPath(ref path) => {
3557+
let defn = lookup_def(fcx, path.span, id);
35583558
let pty = type_scheme_for_def(fcx, expr.span, defn);
3559-
instantiate_path(fcx, pth, pty, defn, expr.span, expr.id);
3559+
instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id);
3560+
3561+
// We always require that the type provided as the value for
3562+
// a type parameter outlives the moment of instantiation.
3563+
constrain_path_type_parameters(fcx, expr);
3564+
}
3565+
ast::ExprQPath(ref qpath) => {
3566+
// Require explicit type params for the trait.
3567+
let self_ty = fcx.to_ty(&*qpath.self_type);
3568+
astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None);
3569+
3570+
let defn = lookup_def(fcx, expr.span, id);
3571+
let pty = type_scheme_for_def(fcx, expr.span, defn);
3572+
let mut path = qpath.trait_ref.path.clone();
3573+
path.segments.push(qpath.item_path.clone());
3574+
instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id);
35603575

35613576
// We always require that the type provided as the value for
35623577
// a type parameter outlives the moment of instantiation.
@@ -4619,6 +4634,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
46194634
pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
46204635
path: &ast::Path,
46214636
type_scheme: TypeScheme<'tcx>,
4637+
opt_self_ty: Option<Ty<'tcx>>,
46224638
def: def::Def,
46234639
span: Span,
46244640
node_id: ast::NodeId) {
@@ -4776,6 +4792,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
47764792
}
47774793
}
47784794
}
4795+
if let Some(self_ty) = opt_self_ty {
4796+
// `<T as Trait>::foo` shouldn't have resolved to a `Self`-less item.
4797+
assert_eq!(type_defs.len(subst::SelfSpace), 1);
4798+
substs.types.push(subst::SelfSpace, self_ty);
4799+
}
47794800

47804801
// Now we have to compare the types that the user *actually*
47814802
// provided against the types that were *expected*. If the user
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2014 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::borrow::IntoCow;
12+
13+
fn main() {
14+
<String as IntoCow>::into_cow("foo".to_string());
15+
//~^ ERROR wrong number of type arguments: expected 2, found 0
16+
}
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 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::ops::Add;
12+
13+
fn main() {
14+
<i32 as Add<u32>>::add(1, 2);
15+
//~^ ERROR the trait `core::ops::Add<u32>` is not implemented for the type `i32`
16+
<i32 as Add<i32>>::add(1u32, 2);
17+
//~^ ERROR mismatched types
18+
<i32 as Add<i32>>::add(1, 2u32);
19+
//~^ ERROR mismatched types
20+
}
21+

src/test/run-pass/const-polymorphic-paths.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010

1111
#![feature(macro_rules)]
1212

13+
use std::borrow::{Cow, IntoCow};
1314
use std::collections::Bitv;
1415
use std::default::Default;
1516
use std::iter::FromIterator;
17+
use std::ops::Add;
1618
use std::option::IntoIter as OptionIter;
1719
use std::rand::Rand;
1820
use std::rand::XorShiftRng as DummyRng;
@@ -28,6 +30,11 @@ fn u8_as_i8(x: u8) -> i8 { x as i8 }
2830
fn odd(x: uint) -> bool { x % 2 == 1 }
2931
fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
3032

33+
trait Size: Sized {
34+
fn size() -> uint { std::mem::size_of::<Self>() }
35+
}
36+
impl<T> Size for T {}
37+
3138
macro_rules! tests {
3239
($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({
3340
const C: $ty = $expr;
@@ -70,14 +77,31 @@ tests! {
7077
// , (vec![b'f', b'o', b'o'], u8_as_i8);
7178

7279
// Trait static methods.
73-
// FIXME qualified path expressions aka UFCS i.e. <T as Trait>::method.
80+
<bool as Size>::size, fn() -> uint, ();
7481
Default::default, fn() -> int, ();
82+
<int as Default>::default, fn() -> int, ();
7583
Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
84+
<int as Rand>::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
7685
Rand::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
86+
<int as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
7787

7888
// Trait non-static methods.
7989
Clone::clone, fn(&int) -> int, (&5);
90+
<int as Clone>::clone, fn(&int) -> int, (&5);
8091
FromIterator::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
81-
FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>
82-
, (Some(5).into_iter());
92+
<Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
93+
(Some(5).into_iter());
94+
<Vec<int> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
95+
(Some(5).into_iter());
96+
FromIterator::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
97+
(Some(5).into_iter());
98+
<Vec<int> as FromIterator<_>>::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
99+
(Some(5).into_iter());
100+
Add::add, fn(i32, i32) -> i32, (5, 6);
101+
<i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
102+
<i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
103+
<String as IntoCow<_, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
104+
("foo".to_string());
105+
<String as IntoCow<'static, _, _>>::into_cow, fn(String) -> Cow<'static, String, str>,
106+
("foo".to_string());
83107
}

0 commit comments

Comments
 (0)