diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ae55f8fb3aa6..7743a437858d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -61,7 +61,7 @@ use rustc::util::lev_distance::lev_distance; use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum}; use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField}; use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall}; -use syntax::ast::{ExprPath, ExprStruct, FnDecl}; +use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics}; use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn}; use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic}; @@ -3169,7 +3169,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { TraitImplementation => "implement", TraitDerivation => "derive", TraitObject => "reference", - TraitQPath => "extract an associated type from", + TraitQPath => "extract an associated item from", }; let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); @@ -3565,31 +3565,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - match result_def { - None => { - match self.resolve_path(ty.id, path, TypeNS, true) { - Some(def) => { - debug!("(resolving type) resolved `{:?}` to \ - type {:?}", - token::get_ident(path.segments.last().unwrap() .identifier), - def); - result_def = Some(def); - } - None => { - result_def = None; - } - } - } - Some(_) => {} // Continue. + if let None = result_def { + result_def = self.resolve_path(ty.id, path, TypeNS, true); } match result_def { Some(def) => { // Write the result into the def map. debug!("(resolving type) writing resolution for `{}` \ - (id {})", + (id {}) = {:?}", self.path_names_to_string(path), - path_id); + path_id, def); self.record_def(path_id, def); } None => { @@ -3609,6 +3595,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { TyQPath(ref qpath) => { self.resolve_type(&*qpath.self_type); self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath); + for ty in qpath.item_path.parameters.types().into_iter() { + self.resolve_type(&**ty); + } + for binding in qpath.item_path.parameters.bindings().into_iter() { + self.resolve_type(&*binding.ty); + } } TyPolyTraitRef(ref bounds) => { @@ -4400,15 +4392,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // The interpretation of paths depends on whether the path has // multiple elements in it or not. - ExprPath(ref path) => { + ExprPath(_) | ExprQPath(_) => { + let mut path_from_qpath; + let path = match expr.node { + ExprPath(ref path) => path, + ExprQPath(ref qpath) => { + self.resolve_type(&*qpath.self_type); + self.resolve_trait_reference(expr.id, &*qpath.trait_ref, TraitQPath); + path_from_qpath = qpath.trait_ref.path.clone(); + path_from_qpath.segments.push(qpath.item_path.clone()); + &path_from_qpath + } + _ => unreachable!() + }; // This is a local path in the value namespace. Walk through // scopes looking for it. - - let path_name = self.path_names_to_string(path); - match self.resolve_path(expr.id, path, ValueNS, true) { // Check if struct variant Some((DefVariant(_, _, true), _)) => { + let path_name = self.path_names_to_string(path); self.resolve_error(expr.span, format!("`{}` is a struct variant name, but \ this expression \ @@ -4423,7 +4425,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(def) => { // Write the result into the def map. debug!("(resolving expr) resolved `{}`", - path_name); + self.path_names_to_string(path)); self.record_def(expr.id, def); } @@ -4432,6 +4434,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // (The pattern matching def_tys where the id is in self.structs // matches on regular structs while excluding tuple- and enum-like // structs, which wouldn't result in this error.) + let path_name = self.path_names_to_string(path); match self.with_no_errors(|this| this.resolve_path(expr.id, path, TypeNS, false)) { Some((DefTy(struct_id, _), _)) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 815a6fe846da..f2a67029170b 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -767,7 +767,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { span: Span, path: &ast::Path, ref_kind: Option) { - if generated_code(path.span) { + if generated_code(span) { return } @@ -1307,9 +1307,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { visit::walk_expr(self, ex); }, ast::ExprPath(ref path) => { - self.process_path(ex.id, ex.span, path, None); + self.process_path(ex.id, path.span, path, None); visit::walk_path(self, path); } + ast::ExprQPath(ref qpath) => { + let mut path = qpath.trait_ref.path.clone(); + path.segments.push(qpath.item_path.clone()); + self.process_path(ex.id, ex.span, &path, None); + visit::walk_qpath(self, ex.span, &**qpath); + } ast::ExprStruct(ref path, ref fields, ref base) => self.process_struct_lit(ex, path, fields, base), ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), @@ -1439,7 +1445,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { "") } def::DefVariant(..) => { - paths_to_process.push((id, p.span, p.clone(), Some(ref_kind))) + paths_to_process.push((id, p.clone(), Some(ref_kind))) } // FIXME(nrc) what are these doing here? def::DefStatic(_, _) => {} @@ -1448,8 +1454,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { *def) } } - for &(id, span, ref path, ref_kind) in paths_to_process.iter() { - self.process_path(id, span, path, ref_kind); + for &(id, ref path, ref_kind) in paths_to_process.iter() { + self.process_path(id, path.span, path, ref_kind); } self.collecting = false; self.collected_paths.clear(); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 5c8c8b485d87..47346592c86b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -467,7 +467,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat, }; instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id), - def, pat.span, pat.id); + None, def, pat.span, pat.id); let pat_ty = fcx.node_ty(pat.id); 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, } else { ctor_scheme }; - instantiate_path(pcx.fcx, path, path_scheme, def, pat.span, pat.id); + instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id); let pat_ty = fcx.node_ty(pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d412ed39c727..e4c333a0e1ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3553,10 +3553,25 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, }; fcx.write_ty(id, oprnd_t); } - ast::ExprPath(ref pth) => { - let defn = lookup_def(fcx, pth.span, id); + ast::ExprPath(ref path) => { + let defn = lookup_def(fcx, path.span, id); let pty = type_scheme_for_def(fcx, expr.span, defn); - instantiate_path(fcx, pth, pty, defn, expr.span, expr.id); + instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id); + + // We always require that the type provided as the value for + // a type parameter outlives the moment of instantiation. + constrain_path_type_parameters(fcx, expr); + } + ast::ExprQPath(ref qpath) => { + // Require explicit type params for the trait. + let self_ty = fcx.to_ty(&*qpath.self_type); + astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None); + + let defn = lookup_def(fcx, expr.span, id); + let pty = type_scheme_for_def(fcx, expr.span, defn); + let mut path = qpath.trait_ref.path.clone(); + path.segments.push(qpath.item_path.clone()); + instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id); // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. @@ -4619,6 +4634,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, path: &ast::Path, type_scheme: TypeScheme<'tcx>, + opt_self_ty: Option>, def: def::Def, span: Span, node_id: ast::NodeId) { @@ -4776,6 +4792,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } } + if let Some(self_ty) = opt_self_ty { + // `::foo` shouldn't have resolved to a `Self`-less item. + assert_eq!(type_defs.len(subst::SelfSpace), 1); + substs.types.push(subst::SelfSpace, self_ty); + } // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user diff --git a/src/test/compile-fail/ufcs-qpath-missing-params.rs b/src/test/compile-fail/ufcs-qpath-missing-params.rs new file mode 100644 index 000000000000..5fa66eb98e1a --- /dev/null +++ b/src/test/compile-fail/ufcs-qpath-missing-params.rs @@ -0,0 +1,17 @@ +// Copyright 2014 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::borrow::IntoCow; + +fn main() { + ::into_cow("foo".to_string()); + //~^ ERROR wrong number of type arguments: expected 2, found 0 +} + diff --git a/src/test/compile-fail/ufcs-qpath-self-mismatch.rs b/src/test/compile-fail/ufcs-qpath-self-mismatch.rs new file mode 100644 index 000000000000..868c1eae4a9e --- /dev/null +++ b/src/test/compile-fail/ufcs-qpath-self-mismatch.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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::ops::Add; + +fn main() { + >::add(1, 2); + //~^ ERROR the trait `core::ops::Add` is not implemented for the type `i32` + >::add(1u32, 2); + //~^ ERROR mismatched types + >::add(1, 2u32); + //~^ ERROR mismatched types +} + diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs index 28b346c9ed4d..f8f92a56adb1 100644 --- a/src/test/run-pass/const-polymorphic-paths.rs +++ b/src/test/run-pass/const-polymorphic-paths.rs @@ -10,9 +10,11 @@ #![feature(macro_rules)] +use std::borrow::{Cow, IntoCow}; use std::collections::Bitv; use std::default::Default; use std::iter::FromIterator; +use std::ops::Add; use std::option::IntoIter as OptionIter; use std::rand::Rand; use std::rand::XorShiftRng as DummyRng; @@ -28,6 +30,11 @@ fn u8_as_i8(x: u8) -> i8 { x as i8 } fn odd(x: uint) -> bool { x % 2 == 1 } fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } +trait Size: Sized { + fn size() -> uint { std::mem::size_of::() } +} +impl Size for T {} + macro_rules! tests { ($($expr:expr, $ty:ty, ($($test:expr),*);)+) => (pub fn main() {$({ const C: $ty = $expr; @@ -70,14 +77,31 @@ tests! { // , (vec![b'f', b'o', b'o'], u8_as_i8); // Trait static methods. - // FIXME qualified path expressions aka UFCS i.e. ::method. + ::size, fn() -> uint, (); Default::default, fn() -> int, (); + ::default, fn() -> int, (); Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + ::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); Rand::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + ::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); // Trait non-static methods. Clone::clone, fn(&int) -> int, (&5); + ::clone, fn(&int) -> int, (&5); FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); - FromIterator::from_iter::>, fn(OptionIter) -> Vec - , (Some(5).into_iter()); + as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + FromIterator::from_iter::>, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + as FromIterator<_>>::from_iter::>, fn(OptionIter) -> Vec, + (Some(5).into_iter()); + Add::add, fn(i32, i32) -> i32, (5, 6); + >::add, fn(i32, i32) -> i32, (5, 6); + >::add, fn(i32, i32) -> i32, (5, 6); + >::into_cow, fn(String) -> Cow<'static, String, str>, + ("foo".to_string()); + >::into_cow, fn(String) -> Cow<'static, String, str>, + ("foo".to_string()); }